track files copied from caravel
diff --git a/ngspice/digital_pll/digital_pll/digital_pll.spice b/ngspice/digital_pll/digital_pll/digital_pll.spice
new file mode 100644
index 0000000..cd88d48
--- /dev/null
+++ b/ngspice/digital_pll/digital_pll/digital_pll.spice
@@ -0,0 +1,43 @@
+*---------------------------------------------------------------------------
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+*---------------------------------------------------------------------------
+* All-digital Frequency-locked loop
+*---------------------------------------------------------------------------
+* To make this simulatable, the circuit is broken into the ring oscillator
+* and controller, separately, with the controller converted into an xspice
+* model.
+*
+* For simplicity, the DCO mode has been removed, so no external trim with
+* multiplexer.  Also no multiplexer on the internal reset.
+*---------------------------------------------------------------------------
+
+.include "digital_pll_controller.xspice"
+.include "ring_osc2x13.spice"
+
+.subckt digital_pll vdd vss reset osc clockp1 clockp0 div4 div3 div2 div1 div0
+
+X0 vdd vss clockp0 div0 div1 div2 div3 div4 osc reset trim0 trim1 trim2 trim3
++ trim4 trim5 trim6 trim7 trim8 trim9 trim10 trim11 trim12 trim13 trim14
++ trim15 trim16 trim17 trim18 trim19 trim20 trim21 trim22 trim23 trim24
++ trim25 digital_pll_controller
+
+X1 vdd vss clockp0 clockp1 reset trim0 trim1 trim2 trim3 trim4 trim5 trim6 trim7
++ trim8 trim9 trim10 trim11 trim12 trim13 trim14 trim15 trim16 trim17 trim18
++ trim19 trim20 trim21 trim22 trim23 trim24 trim25 ring_osc2x13
+
+.ends
+
+
diff --git a/ngspice/digital_pll/digital_pll/digital_pll_controller.xspice b/ngspice/digital_pll/digital_pll/digital_pll_controller.xspice
new file mode 100644
index 0000000..cbb0343
--- /dev/null
+++ b/ngspice/digital_pll/digital_pll/digital_pll_controller.xspice
@@ -0,0 +1,497 @@
+* XSpice netlist created from SPICE and liberty sources by spi2xspice.py
+* SPICE netlist created from verilog structural netlist module digital_pll_controller by vlog2Spice (qflow)
+*
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+******* EOF
+** End of included library /home/tim/projects/efabless/tech/SW/sky130A/libs.ref/sky130_fd_sc_hd/spice/sky130_fd_sc_hd.spice
+.subckt digital_pll_controller a_VPB a_VGND a_clock a_div_0_ a_div_1_ a_div_2_ a_div_3_ a_div_4_ a_osc a_reset a_trim_0_ a_trim_1_ a_trim_2_ a_trim_3_ a_trim_4_ a_trim_5_ a_trim_6_ a_trim_7_ a_trim_8_ a_trim_9_ a_trim_10_ a_trim_11_ a_trim_12_ a_trim_13_ a_trim_14_ a_trim_15_ a_trim_16_ a_trim_17_ a_trim_18_ a_trim_19_ a_trim_20_ a_trim_21_ a_trim_22_ a_trim_23_ a_trim_24_ a_trim_25_
+Asky130_fd_sc_hd__buf_1_insert11 [_64_] _64__bF$buf0 d_lut_sky130_fd_sc_hd__buf_1
+Asky130_fd_sc_hd__buf_1_insert10 [_64_] _64__bF$buf1 d_lut_sky130_fd_sc_hd__buf_1
+Asky130_fd_sc_hd__buf_1_insert9 [_64_] _64__bF$buf2 d_lut_sky130_fd_sc_hd__buf_1
+Asky130_fd_sc_hd__buf_1_insert8 [_64_] _64__bF$buf3 d_lut_sky130_fd_sc_hd__buf_1
+Asky130_fd_sc_hd__buf_1_insert7 [_4_] _4__bF$buf0 d_lut_sky130_fd_sc_hd__buf_1
+Asky130_fd_sc_hd__buf_1_insert6 [_4_] _4__bF$buf1 d_lut_sky130_fd_sc_hd__buf_1
+Asky130_fd_sc_hd__buf_1_insert5 [_4_] _4__bF$buf2 d_lut_sky130_fd_sc_hd__buf_1
+Asky130_fd_sc_hd__buf_1_insert4 [_4_] _4__bF$buf3 d_lut_sky130_fd_sc_hd__buf_1
+Asky130_fd_sc_hd__clkbuf_1_insert3 [clock] clock_bF$buf0 d_lut_sky130_fd_sc_hd__clkbuf_1
+Asky130_fd_sc_hd__clkbuf_1_insert2 [clock] clock_bF$buf1 d_lut_sky130_fd_sc_hd__clkbuf_1
+Asky130_fd_sc_hd__clkbuf_1_insert1 [clock] clock_bF$buf2 d_lut_sky130_fd_sc_hd__clkbuf_1
+Asky130_fd_sc_hd__clkbuf_1_insert0 [clock] clock_bF$buf3 d_lut_sky130_fd_sc_hd__clkbuf_1
+A_218_ [tint_1_ tint_0_] _194_ d_lut_sky130_fd_sc_hd__nor2_1
+A_219_ [tint_3_ tint_2_] _195_ d_lut_sky130_fd_sc_hd__nor2_1
+A_220_ [_194_ _195_] _196_ d_lut_sky130_fd_sc_hd__nand2_1
+A_221_ [tint_4_ _196_] _197_ d_lut_sky130_fd_sc_hd__nor2_1
+A_222_ [_197_] _217__0_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_223_ [tval_0_] _198_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_224_ [oscbuf_1_ oscbuf_2_] _199_ d_lut_sky130_fd_sc_hd__nor2_1
+A_225_ [oscbuf_1_ oscbuf_2_] _200_ d_lut_sky130_fd_sc_hd__nand2_1
+A_226_ [_200_] _201_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_227_ [_199_ _201_] _202_ d_lut_sky130_fd_sc_hd__or2_2
+A_228_ [_202_] _203_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_229_ [_203_ prep_0_] _204_ d_lut_sky130_fd_sc_hd__nand2_1
+A_230_ [prep_1_ prep_2_] _205_ d_lut_sky130_fd_sc_hd__nand2_1
+A_231_ [_205_ _204_] _206_ d_lut_sky130_fd_sc_hd__nor2_1
+A_232_ [count1_4_] _207_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_233_ [count0_4_] _208_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_234_ [_207_ _208_] _209_ d_lut_sky130_fd_sc_hd__nor2_1
+A_235_ [count1_4_ count0_4_] _210_ d_lut_sky130_fd_sc_hd__nor2_1
+A_236_ [_210_ _209_] _211_ d_lut_sky130_fd_sc_hd__or2_2
+A_237_ [count1_3_ count0_3_] _212_ d_lut_sky130_fd_sc_hd__and2_2
+A_238_ [count1_3_ count0_3_] _213_ d_lut_sky130_fd_sc_hd__nor2_1
+A_239_ [_213_] _214_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_240_ [count1_2_ count0_2_] _215_ d_lut_sky130_fd_sc_hd__and2_2
+A_241_ [_214_ _215_ _212_] _216_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_242_ [count1_1_ count0_1_] _5_ d_lut_sky130_fd_sc_hd__nand2_1
+A_243_ [count1_0_ count0_0_] _6_ d_lut_sky130_fd_sc_hd__nand2_1
+A_244_ [count1_1_ count0_1_] _7_ d_lut_sky130_fd_sc_hd__nor2_1
+A_245_ [_6_ _7_ _5_] _8_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_246_ [count1_2_ count0_2_] _9_ d_lut_sky130_fd_sc_hd__nor2_1
+A_247_ [_9_ _215_] _10_ d_lut_sky130_fd_sc_hd__nor2_1
+A_248_ [_213_ _212_] _11_ d_lut_sky130_fd_sc_hd__nor2_1
+A_249_ [_10_ _11_ _8_] _12_ d_lut_sky130_fd_sc_hd__nand3_1
+A_250_ [_12_ _216_ _211_] _13_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_251_ [_209_ _210_ _216_ _12_] _14_ d_lut_sky130_fd_sc_hd__o211a_1
+A_252_ [_14_ _13_ div_4_] _15_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_253_ [div_4_] _16_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_254_ [_211_ _12_ _216_] _17_ d_lut_sky130_fd_sc_hd__nand3_1
+A_255_ [_17_ _16_ _209_] _18_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_256_ [_15_ _18_] _19_ d_lut_sky130_fd_sc_hd__nand2_1
+A_257_ [div_3_] _20_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_258_ [_215_] _21_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_259_ [_10_ _8_] _22_ d_lut_sky130_fd_sc_hd__nand2_1
+A_260_ [_212_ _213_ _21_ _22_] _23_ d_lut_sky130_fd_sc_hd__o211ai_1
+A_261_ [_6_ _7_ _5_] _24_ d_lut_sky130_fd_sc_hd__o21a_1
+A_262_ [_9_ _24_ _215_] _25_ d_lut_sky130_fd_sc_hd__o21bai_1
+A_263_ [_25_ _11_] _26_ d_lut_sky130_fd_sc_hd__nand2_1
+A_264_ [_26_ _20_ _23_] _27_ d_lut_sky130_fd_sc_hd__nand3_1
+A_265_ [div_2_ _8_ _10_] _28_ d_lut_sky130_fd_sc_hd__xnor3_4
+A_266_ [_22_ _21_ _11_] _29_ d_lut_sky130_fd_sc_hd__nand3_1
+A_267_ [_21_ _22_ _212_ _213_] _30_ d_lut_sky130_fd_sc_hd__o2bb2ai_1
+A_268_ [_30_ div_3_ _29_] _31_ d_lut_sky130_fd_sc_hd__nand3_1
+A_269_ [div_0_] _32_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_270_ [count1_0_ count0_0_] _33_ d_lut_sky130_fd_sc_hd__xor2_1
+A_271_ [_33_ _32_] _34_ d_lut_sky130_fd_sc_hd__and2_2
+A_272_ [div_1_] _35_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_273_ [count1_1_ count0_1_] _36_ d_lut_sky130_fd_sc_hd__or2_2
+A_274_ [_36_ _5_] _37_ d_lut_sky130_fd_sc_hd__nand2_1
+A_275_ [_35_ _6_ _37_] _38_ d_lut_sky130_fd_sc_hd__xnor3_4
+A_276_ [_32_ _33_] _39_ d_lut_sky130_fd_sc_hd__nor2_1
+A_277_ [_34_ _39_ _38_] _40_ d_lut_sky130_fd_sc_hd__nor3_1
+A_278_ [_40_ _27_ _28_ _31_] _41_ d_lut_sky130_fd_sc_hd__nand4_1
+A_279_ [_41_ _19_] _42_ d_lut_sky130_fd_sc_hd__or2_2
+A_280_ [_36_ count1_0_ count0_0_ _5_] _43_ d_lut_sky130_fd_sc_hd__nand4_1
+A_281_ [count1_1_ count0_1_] _44_ d_lut_sky130_fd_sc_hd__and2_2
+A_282_ [_7_ _44_ _6_] _45_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_283_ [_45_ _43_ _35_] _46_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_284_ [_45_ _43_ _35_] _47_ d_lut_sky130_fd_sc_hd__nand3_1
+A_285_ [_33_ _32_] _48_ d_lut_sky130_fd_sc_hd__nand2_1
+A_286_ [_47_ _48_ _46_] _49_ d_lut_sky130_fd_sc_hd__a21o_2
+A_287_ [_27_ _31_ _28_ _49_] _50_ d_lut_sky130_fd_sc_hd__nand4_1
+A_288_ [_215_ _9_ _24_] _51_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_289_ [_51_ _22_ div_2_] _52_ d_lut_sky130_fd_sc_hd__a21boi_0
+A_290_ [_27_ _52_] _53_ d_lut_sky130_fd_sc_hd__nand2_1
+A_291_ [_50_ _31_ _53_ _19_] _54_ d_lut_sky130_fd_sc_hd__a31oi_1
+A_292_ [_12_ div_4_ _210_ _216_] _55_ d_lut_sky130_fd_sc_hd__nand4_1
+A_293_ [_55_] _56_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_294_ [tval_0_ tval_1_] _57_ d_lut_sky130_fd_sc_hd__nor2_1
+A_295_ [_197_ _57_] _58_ d_lut_sky130_fd_sc_hd__nand2_1
+A_296_ [_58_] _59_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_297_ [tval_0_ _59_ _56_ _54_ _42_] _60_ d_lut_sky130_fd_sc_hd__o221ai_1
+A_298_ [_15_ _18_] _61_ d_lut_sky130_fd_sc_hd__and2_2
+A_299_ [_50_ _31_ _53_] _62_ d_lut_sky130_fd_sc_hd__nand3_1
+A_300_ [_62_ _61_] _63_ d_lut_sky130_fd_sc_hd__nand2_1
+A_301_ [tint_4_] _64_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_302_ [tval_0_ tval_1_] _65_ d_lut_sky130_fd_sc_hd__nand2_1
+A_303_ [tint_1_ tint_0_] _66_ d_lut_sky130_fd_sc_hd__nand2_1
+A_304_ [_65_ _66_] _67_ d_lut_sky130_fd_sc_hd__nor2_1
+A_305_ [_67_ tint_3_ tint_2_] _68_ d_lut_sky130_fd_sc_hd__nand3_1
+A_306_ [_64__bF$buf3 _68_] _69_ d_lut_sky130_fd_sc_hd__nor2_1
+A_307_ [_69_] _70_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_308_ [_63_ tval_0_ _55_ _70_] _71_ d_lut_sky130_fd_sc_hd__nand4_1
+A_309_ [tval_0_ _42_ _206_ _71_ _60_] _72_ d_lut_sky130_fd_sc_hd__o2111ai_1
+A_310_ [_198_ _206_ _72_] _3__0_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_311_ [tval_1_] _73_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_312_ [_65_] _74_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_313_ [_57_ _74_] _75_ d_lut_sky130_fd_sc_hd__nor2_1
+A_314_ [_59_ _75_ _56_ _54_ _42_] _76_ d_lut_sky130_fd_sc_hd__o221ai_1
+A_315_ [_75_ _69_] _77_ d_lut_sky130_fd_sc_hd__nor2_1
+A_316_ [_63_ _55_ _77_] _78_ d_lut_sky130_fd_sc_hd__nand3_1
+A_317_ [tval_1_ _42_ _206_ _78_ _76_] _79_ d_lut_sky130_fd_sc_hd__o2111ai_1
+A_318_ [_73_ _206_ _79_] _3__1_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_319_ [tint_0_] _80_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_320_ [_206_] _81_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_321_ [_62_ _61_ _56_] _82_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_322_ [_80_ _65_] _83_ d_lut_sky130_fd_sc_hd__nor2_1
+A_323_ [tint_0_ _74_] _84_ d_lut_sky130_fd_sc_hd__nor2_1
+A_324_ [_83_ _84_ _70_] _85_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_325_ [_82_ _85_ _81_] _86_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_326_ [_63_ _55_] _87_ d_lut_sky130_fd_sc_hd__nand2_1
+A_327_ [_41_ _19_] _88_ d_lut_sky130_fd_sc_hd__nor2_1
+A_328_ [_57_ _80_] _89_ d_lut_sky130_fd_sc_hd__nand2_1
+A_329_ [_57_] _90_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_330_ [_90_ tint_0_] _91_ d_lut_sky130_fd_sc_hd__nand2_1
+A_331_ [_91_ _89_ _197_] _92_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_332_ [_88_ _80_] _93_ d_lut_sky130_fd_sc_hd__nand2_1
+A_333_ [_88_ _92_ _93_ _87_] _94_ d_lut_sky130_fd_sc_hd__o211ai_1
+A_334_ [_80_ _81_ _86_ _94_] _3__2_ d_lut_sky130_fd_sc_hd__a22oi_1
+A_335_ [tint_1_] _95_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_336_ [tint_1_ _83_] _96_ d_lut_sky130_fd_sc_hd__nor2_1
+A_337_ [_67_ _96_ _70_] _97_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_338_ [_82_ _97_ _81_] _98_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_339_ [_194_ _57_] _99_ d_lut_sky130_fd_sc_hd__nand2_1
+A_340_ [_89_ tint_1_] _100_ d_lut_sky130_fd_sc_hd__nand2_1
+A_341_ [_99_ _100_ _59_] _101_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_342_ [_88_ _95_] _102_ d_lut_sky130_fd_sc_hd__nand2_1
+A_343_ [_88_ _101_ _102_ _87_] _103_ d_lut_sky130_fd_sc_hd__o211ai_1
+A_344_ [_95_ _81_ _98_ _103_] _3__3_ d_lut_sky130_fd_sc_hd__a22oi_1
+A_345_ [tint_2_] _104_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_346_ [_194_ _57_ _104_] _105_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_347_ [tint_2_ _99_] _106_ d_lut_sky130_fd_sc_hd__nor2_1
+A_348_ [_106_ _105_ _58_] _107_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_349_ [_88_ tint_2_] _108_ d_lut_sky130_fd_sc_hd__nand2_1
+A_350_ [_107_ _88_ _56_ _54_ _108_] _109_ d_lut_sky130_fd_sc_hd__o221ai_1
+A_351_ [_67_ tint_2_] _110_ d_lut_sky130_fd_sc_hd__nand2_1
+A_352_ [_65_ _66_ _104_] _111_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_353_ [_111_ _110_ _69_] _112_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_354_ [_63_ _55_ _112_] _113_ d_lut_sky130_fd_sc_hd__nand3_1
+A_355_ [_109_ _206_ _113_] _114_ d_lut_sky130_fd_sc_hd__nand3_1
+A_356_ [_104_ _206_ _114_] _3__4_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_357_ [tint_3_] _115_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_358_ [tint_4_ _68_] _116_ d_lut_sky130_fd_sc_hd__nor2_1
+A_359_ [_115_ _110_ _116_] _117_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_360_ [_82_ _117_ _81_] _118_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_361_ [_90_ _196_] _119_ d_lut_sky130_fd_sc_hd__nor2_1
+A_362_ [_115_ _106_] _120_ d_lut_sky130_fd_sc_hd__nor2_1
+A_363_ [_119_ _120_] _121_ d_lut_sky130_fd_sc_hd__nor2_1
+A_364_ [_59_ _121_] _122_ d_lut_sky130_fd_sc_hd__nor2_1
+A_365_ [_88_ _115_] _123_ d_lut_sky130_fd_sc_hd__nand2_1
+A_366_ [_88_ _122_ _123_ _87_] _124_ d_lut_sky130_fd_sc_hd__o211ai_1
+A_367_ [_115_ _81_ _118_ _124_] _3__5_ d_lut_sky130_fd_sc_hd__a22oi_1
+A_368_ [_56_ _54_ _206_ _119_ _42_] _125_ d_lut_sky130_fd_sc_hd__o2111a_1
+A_369_ [_68_ _64__bF$buf2] _126_ d_lut_sky130_fd_sc_hd__nand2_1
+A_370_ [_206_ _126_] _127_ d_lut_sky130_fd_sc_hd__nand2_1
+A_371_ [_87_ _127_ _64__bF$buf1 _125_] _3__6_ d_lut_sky130_fd_sc_hd__o22ai_1
+A_372_ [prep_0_ _203_] _2__0_ d_lut_sky130_fd_sc_hd__or2_2
+A_373_ [prep_1_] _128_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_374_ [_128_ _203_ _204_] _2__1_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_375_ [_202_ prep_2_] _129_ d_lut_sky130_fd_sc_hd__nand2_1
+A_376_ [_128_ _202_ _129_] _2__2_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_377_ [count0_0_] _130_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_378_ [_202_ count1_0_] _131_ d_lut_sky130_fd_sc_hd__nand2_1
+A_379_ [_130_ _202_ _131_] _1__0_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_380_ [count0_1_] _132_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_381_ [_202_ count1_1_] _133_ d_lut_sky130_fd_sc_hd__nand2_1
+A_382_ [_132_ _202_ _133_] _1__1_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_383_ [count0_2_] _134_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_384_ [_202_ count1_2_] _135_ d_lut_sky130_fd_sc_hd__nand2_1
+A_385_ [_134_ _202_ _135_] _1__2_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_386_ [_203_ count0_3_] _136_ d_lut_sky130_fd_sc_hd__nand2_1
+A_387_ [_202_ count1_3_] _137_ d_lut_sky130_fd_sc_hd__nand2_1
+A_388_ [_136_ _137_] _1__3_ d_lut_sky130_fd_sc_hd__nand2_1
+A_389_ [_202_ count1_4_] _138_ d_lut_sky130_fd_sc_hd__nand2_1
+A_390_ [_208_ _202_ _138_] _1__4_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_391_ [_132_ _130_] _139_ d_lut_sky130_fd_sc_hd__nor2_1
+A_392_ [_139_] _140_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_393_ [_134_ _140_] _141_ d_lut_sky130_fd_sc_hd__nor2_1
+A_394_ [_141_ count0_3_] _142_ d_lut_sky130_fd_sc_hd__nand2_1
+A_395_ [_142_] _143_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_396_ [_143_ count0_4_] _144_ d_lut_sky130_fd_sc_hd__nand2_1
+A_397_ [_144_ count0_0_ _202_] _0__0_ d_lut_sky130_fd_sc_hd__nand3_1
+A_398_ [_132_ _130_] _145_ d_lut_sky130_fd_sc_hd__nand2_1
+A_399_ [_140_ _145_] _146_ d_lut_sky130_fd_sc_hd__nand2_1
+A_400_ [_144_ _146_ _203_] _0__1_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_401_ [_134_ _139_] _147_ d_lut_sky130_fd_sc_hd__xor2_1
+A_402_ [_144_ _147_ _203_] _0__2_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_403_ [count0_3_ _141_ _202_] _148_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_404_ [_143_ _208_ _148_] _0__3_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_405_ [_142_ _208_ _203_] _0__4_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_406_ [tint_3_ tint_2_] _149_ d_lut_sky130_fd_sc_hd__nand2_1
+A_407_ [_149_ _64__bF$buf0] _217__1_ d_lut_sky130_fd_sc_hd__nand2_1
+A_408_ [tint_3_ _104_] _150_ d_lut_sky130_fd_sc_hd__nor2_1
+A_409_ [_150_] _151_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_410_ [_66_ _151_] _152_ d_lut_sky130_fd_sc_hd__nor2_1
+A_411_ [_195_ tint_1_ _80_ _64__bF$buf3] _153_ d_lut_sky130_fd_sc_hd__nand4_1
+A_412_ [_195_] _154_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_413_ [tint_4_ _154_] _155_ d_lut_sky130_fd_sc_hd__nor2_1
+A_414_ [_155_ _95_] _217__6_ d_lut_sky130_fd_sc_hd__nand2_1
+A_415_ [_217__6_ _153_] _156_ d_lut_sky130_fd_sc_hd__nand2_1
+A_416_ [_80_ _64__bF$buf2 tint_1_] _157_ d_lut_sky130_fd_sc_hd__nand3_1
+A_417_ [_157_ _151_] _158_ d_lut_sky130_fd_sc_hd__nor2_1
+A_418_ [_158_] _159_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_419_ [_66_ _154_] _160_ d_lut_sky130_fd_sc_hd__nor2_1
+A_420_ [_95_ _150_ _160_] _161_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_421_ [tint_4_ _161_ _159_] _162_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_422_ [_156_ _162_] _217__5_ d_lut_sky130_fd_sc_hd__nor2_1
+A_423_ [_217__5_] _163_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_424_ [_64__bF$buf1 _152_ _163_] _217__2_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_425_ [_155_] _217__3_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_426_ [_95_ tint_0_] _164_ d_lut_sky130_fd_sc_hd__nand2_1
+A_427_ [_104_ tint_3_] _165_ d_lut_sky130_fd_sc_hd__nand2_1
+A_428_ [_164_ _165_] _166_ d_lut_sky130_fd_sc_hd__nor2_1
+A_429_ [_166_ _64__bF$buf0] _167_ d_lut_sky130_fd_sc_hd__nand2_1
+A_430_ [_152_ _64__bF$buf3] _168_ d_lut_sky130_fd_sc_hd__nand2_1
+A_431_ [_194_] _169_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_432_ [_165_ _169_] _170_ d_lut_sky130_fd_sc_hd__nor2_1
+A_433_ [_170_ _64__bF$buf2] _171_ d_lut_sky130_fd_sc_hd__nand2_1
+A_434_ [_168_ _171_] _172_ d_lut_sky130_fd_sc_hd__nand2_1
+A_435_ [_172_ _163_] _217__9_ d_lut_sky130_fd_sc_hd__nor2_1
+A_436_ [_217__9_ _167_] _173_ d_lut_sky130_fd_sc_hd__nand2_1
+A_437_ [_173_] _217__4_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_438_ [tint_4_ _149_ _169_] _174_ d_lut_sky130_fd_sc_hd__nor3_1
+A_439_ [tint_4_ _66_ _165_] _175_ d_lut_sky130_fd_sc_hd__nor3_1
+A_440_ [_165_ _157_] _176_ d_lut_sky130_fd_sc_hd__nor2_1
+A_441_ [_174_ _175_ _176_ _173_] _217__7_ d_lut_sky130_fd_sc_hd__nor4_1
+A_442_ [_104_ _194_ _115_ _64__bF$buf1] _217__8_ d_lut_sky130_fd_sc_hd__o211ai_1
+A_443_ [_156_] _217__10_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_444_ [_176_ _173_] _217__11_ d_lut_sky130_fd_sc_hd__nor2_1
+A_445_ [tint_4_ _161_] _177_ d_lut_sky130_fd_sc_hd__nor2_1
+A_446_ [_156_ _177_] _217__12_ d_lut_sky130_fd_sc_hd__nor2_1
+A_447_ [_217__9_] _178_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_448_ [_175_ _174_] _179_ d_lut_sky130_fd_sc_hd__nor2_1
+A_449_ [_179_ _167_] _180_ d_lut_sky130_fd_sc_hd__nand2_1
+A_450_ [tint_4_ _149_ _164_ _157_ _165_] _181_ d_lut_sky130_fd_sc_hd__o32ai_1
+A_451_ [_180_ _181_ _178_] _217__13_ d_lut_sky130_fd_sc_hd__nor3_1
+A_452_ [_95_ _80_ _104_ _115_ _64__bF$buf0] _217__14_ d_lut_sky130_fd_sc_hd__a311oi_1
+A_453_ [_154_ _66_ _169_ _151_] _182_ d_lut_sky130_fd_sc_hd__o22ai_1
+A_454_ [tint_4_ _95_ _149_] _183_ d_lut_sky130_fd_sc_hd__nor3_1
+A_455_ [tint_4_ _195_ _66_ _183_] _184_ d_lut_sky130_fd_sc_hd__a31oi_1
+A_456_ [_184_] _185_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_457_ [_181_ _185_] _186_ d_lut_sky130_fd_sc_hd__nor2_1
+A_458_ [_217__9_ _167_ _179_ _186_] _187_ d_lut_sky130_fd_sc_hd__nand4_1
+A_459_ [tint_4_ _182_ _187_] _217__15_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_460_ [_194_ _195_ _64__bF$buf3] _217__16_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_461_ [_64__bF$buf2 _161_] _188_ d_lut_sky130_fd_sc_hd__nor2_1
+A_462_ [_95_ tint_0_ _64__bF$buf1 _151_] _189_ d_lut_sky130_fd_sc_hd__nor4_1
+A_463_ [_188_ _189_ _187_] _217__17_ d_lut_sky130_fd_sc_hd__nor3_1
+A_464_ [_64__bF$buf0 _195_] _217__18_ d_lut_sky130_fd_sc_hd__nor2_1
+A_465_ [_149_ _66_ _64__bF$buf3] _217__19_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_466_ [_150_ _160_ tint_4_] _190_ d_lut_sky130_fd_sc_hd__o21ai_0
+A_467_ [_186_ _179_ _190_] _191_ d_lut_sky130_fd_sc_hd__nand3_1
+A_468_ [_170_ tint_4_ _166_] _192_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_469_ [_192_ _153_ _217__6_] _193_ d_lut_sky130_fd_sc_hd__nand3_1
+A_470_ [_172_ _193_ _162_ _191_] _217__20_ d_lut_sky130_fd_sc_hd__nor4_1
+A_471_ [_195_ _95_ _64__bF$buf2] _217__21_ d_lut_sky130_fd_sc_hd__a21oi_1
+A_472_ [_188_ _187_] _217__22_ d_lut_sky130_fd_sc_hd__nor2_1
+A_473_ [_191_ _173_] _217__24_ d_lut_sky130_fd_sc_hd__nor2_1
+A_474_ [_187_] _217__25_ d_lut_sky130_fd_sc_hd__clkinv_1
+A_475_ [reset] _4_ d_lut_sky130_fd_sc_hd__clkinv_2
+A_476_ [tint_4_] trim_23_ d_lut_sky130_fd_sc_hd__buf_2
+A_477_ [_217__0_] trim_0_ d_lut_sky130_fd_sc_hd__buf_2
+A_478_ [_217__1_] trim_1_ d_lut_sky130_fd_sc_hd__buf_2
+A_479_ [_217__2_] trim_2_ d_lut_sky130_fd_sc_hd__buf_2
+A_480_ [_217__3_] trim_3_ d_lut_sky130_fd_sc_hd__buf_2
+A_481_ [_217__4_] trim_4_ d_lut_sky130_fd_sc_hd__buf_2
+A_482_ [_217__5_] trim_5_ d_lut_sky130_fd_sc_hd__buf_2
+A_483_ [_217__6_] trim_6_ d_lut_sky130_fd_sc_hd__buf_2
+A_484_ [_217__7_] trim_7_ d_lut_sky130_fd_sc_hd__buf_2
+A_485_ [_217__8_] trim_8_ d_lut_sky130_fd_sc_hd__buf_2
+A_486_ [_217__9_] trim_9_ d_lut_sky130_fd_sc_hd__buf_2
+A_487_ [_217__10_] trim_10_ d_lut_sky130_fd_sc_hd__buf_2
+A_488_ [_217__11_] trim_11_ d_lut_sky130_fd_sc_hd__buf_2
+A_489_ [_217__12_] trim_12_ d_lut_sky130_fd_sc_hd__buf_2
+A_490_ [_217__13_] trim_13_ d_lut_sky130_fd_sc_hd__buf_2
+A_491_ [_217__14_] trim_14_ d_lut_sky130_fd_sc_hd__buf_2
+A_492_ [_217__15_] trim_15_ d_lut_sky130_fd_sc_hd__buf_2
+A_493_ [_217__16_] trim_16_ d_lut_sky130_fd_sc_hd__buf_2
+A_494_ [_217__17_] trim_17_ d_lut_sky130_fd_sc_hd__buf_2
+A_495_ [_217__18_] trim_18_ d_lut_sky130_fd_sc_hd__buf_2
+A_496_ [_217__19_] trim_19_ d_lut_sky130_fd_sc_hd__buf_2
+A_497_ [_217__20_] trim_20_ d_lut_sky130_fd_sc_hd__buf_2
+A_498_ [_217__21_] trim_21_ d_lut_sky130_fd_sc_hd__buf_2
+A_499_ [_217__22_] trim_22_ d_lut_sky130_fd_sc_hd__buf_2
+A_500_ [_217__24_] trim_24_ d_lut_sky130_fd_sc_hd__buf_2
+A_501_ [_217__25_] trim_25_ d_lut_sky130_fd_sc_hd__buf_2
+A_502_ _0__0_ clock_bF$buf3 NULL ~_4__bF$buf3 NULL NULL ddflop
+A_503_ _0__1_ clock_bF$buf2 NULL ~_4__bF$buf2 NULL NULL ddflop
+A_504_ _0__2_ clock_bF$buf1 NULL ~_4__bF$buf1 NULL NULL ddflop
+A_505_ _0__3_ clock_bF$buf0 NULL ~_4__bF$buf0 NULL NULL ddflop
+A_506_ _0__4_ clock_bF$buf3 NULL ~_4__bF$buf3 NULL NULL ddflop
+A_507_ _1__0_ clock_bF$buf2 NULL ~_4__bF$buf2 NULL NULL ddflop
+A_508_ _1__1_ clock_bF$buf1 NULL ~_4__bF$buf1 NULL NULL ddflop
+A_509_ _1__2_ clock_bF$buf0 NULL ~_4__bF$buf0 NULL NULL ddflop
+A_510_ _1__3_ clock_bF$buf3 NULL ~_4__bF$buf3 NULL NULL ddflop
+A_511_ _1__4_ clock_bF$buf2 NULL ~_4__bF$buf2 NULL NULL ddflop
+A_512_ osc clock_bF$buf1 NULL ~_4__bF$buf1 NULL NULL ddflop
+A_513_ oscbuf_0_ clock_bF$buf0 NULL ~_4__bF$buf0 NULL NULL ddflop
+A_514_ oscbuf_1_ clock_bF$buf3 NULL ~_4__bF$buf3 NULL NULL ddflop
+A_515_ _2__0_ clock_bF$buf2 NULL ~_4__bF$buf2 NULL NULL ddflop
+A_516_ _2__1_ clock_bF$buf1 NULL ~_4__bF$buf1 NULL NULL ddflop
+A_517_ _2__2_ clock_bF$buf0 NULL ~_4__bF$buf0 NULL NULL ddflop
+A_518_ _3__0_ clock_bF$buf3 NULL ~_4__bF$buf3 NULL NULL ddflop
+A_519_ _3__1_ clock_bF$buf2 NULL ~_4__bF$buf2 NULL NULL ddflop
+A_520_ _3__2_ clock_bF$buf1 NULL ~_4__bF$buf1 NULL NULL ddflop
+A_521_ _3__3_ clock_bF$buf0 NULL ~_4__bF$buf0 NULL NULL ddflop
+A_522_ _3__4_ clock_bF$buf3 NULL ~_4__bF$buf3 NULL NULL ddflop
+A_523_ _3__5_ clock_bF$buf2 NULL ~_4__bF$buf2 NULL NULL ddflop
+A_524_ _3__6_ clock_bF$buf1 NULL ~_4__bF$buf1 NULL NULL ddflop
+
+.model todig_1v95 adc_bridge(in_high=1.3 in_low=0.65 rise_delay=500p fall_delay=500p)
+.model toana_1v95 dac_bridge(out_high=1.95 out_low=0)
+
+.model ddflop d_dff(ic=0 rise_delay=50p fall_delay=50p)
+.model dzero d_pulldown(load=250f)
+.model done d_pullup(load=250f)
+
+AA2D1 [a_VPB] [VPB] todig_1v95
+AA2D2 [a_VGND] [VGND] todig_1v95
+AA2D3 [a_clock] [clock] todig_1v95
+AA2D4 [a_div_0_] [div_0_] todig_1v95
+AA2D5 [a_div_1_] [div_1_] todig_1v95
+AA2D6 [a_div_2_] [div_2_] todig_1v95
+AA2D7 [a_div_3_] [div_3_] todig_1v95
+AA2D8 [a_div_4_] [div_4_] todig_1v95
+AA2D9 [a_osc] [osc] todig_1v95
+AA2D10 [a_reset] [reset] todig_1v95
+AD2A1 [trim_0_] [a_trim_0_] toana_1v95
+AD2A2 [trim_1_] [a_trim_1_] toana_1v95
+AD2A3 [trim_2_] [a_trim_2_] toana_1v95
+AD2A4 [trim_3_] [a_trim_3_] toana_1v95
+AD2A5 [trim_4_] [a_trim_4_] toana_1v95
+AD2A6 [trim_5_] [a_trim_5_] toana_1v95
+AD2A7 [trim_6_] [a_trim_6_] toana_1v95
+AD2A8 [trim_7_] [a_trim_7_] toana_1v95
+AD2A9 [trim_8_] [a_trim_8_] toana_1v95
+AD2A10 [trim_9_] [a_trim_9_] toana_1v95
+AD2A11 [trim_10_] [a_trim_10_] toana_1v95
+AD2A12 [trim_11_] [a_trim_11_] toana_1v95
+AD2A13 [trim_12_] [a_trim_12_] toana_1v95
+AD2A14 [trim_13_] [a_trim_13_] toana_1v95
+AD2A15 [trim_14_] [a_trim_14_] toana_1v95
+AD2A16 [trim_15_] [a_trim_15_] toana_1v95
+AD2A17 [trim_16_] [a_trim_16_] toana_1v95
+AD2A18 [trim_17_] [a_trim_17_] toana_1v95
+AD2A19 [trim_18_] [a_trim_18_] toana_1v95
+AD2A20 [trim_19_] [a_trim_19_] toana_1v95
+AD2A21 [trim_20_] [a_trim_20_] toana_1v95
+AD2A22 [trim_21_] [a_trim_21_] toana_1v95
+AD2A23 [trim_22_] [a_trim_22_] toana_1v95
+AD2A24 [trim_23_] [a_trim_23_] toana_1v95
+AD2A25 [trim_24_] [a_trim_24_] toana_1v95
+AD2A26 [trim_25_] [a_trim_25_] toana_1v95
+
+.ends
+
+* sky130_fd_sc_hd__nand2_2 (!A) | (!B)
+.model d_lut_sky130_fd_sc_hd__nand2_2 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "1110")
+* sky130_fd_sc_hd__inv_2 (!A)
+.model d_lut_sky130_fd_sc_hd__inv_2 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "10")
+* sky130_fd_sc_hd__nor2_2 (!A&!B)
+.model d_lut_sky130_fd_sc_hd__nor2_2 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "1000")
+* sky130_fd_sc_hd__conb_1 1
+* sky130_fd_sc_hd__buf_1 (A)
+.model d_lut_sky130_fd_sc_hd__buf_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "01")
+* sky130_fd_sc_hd__clkbuf_1 (A)
+.model d_lut_sky130_fd_sc_hd__clkbuf_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "01")
+* sky130_fd_sc_hd__nor2_1 (!A&!B)
+.model d_lut_sky130_fd_sc_hd__nor2_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "1000")
+* sky130_fd_sc_hd__nand2_1 (!A) | (!B)
+.model d_lut_sky130_fd_sc_hd__nand2_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "1110")
+* sky130_fd_sc_hd__clkinv_1 (!A)
+.model d_lut_sky130_fd_sc_hd__clkinv_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "10")
+* sky130_fd_sc_hd__or2_2 (A) | (B)
+.model d_lut_sky130_fd_sc_hd__or2_2 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "0111")
+* sky130_fd_sc_hd__and2_2 (A&B)
+.model d_lut_sky130_fd_sc_hd__and2_2 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "0001")
+* sky130_fd_sc_hd__a21oi_1 (!A1&!B1) | (!A2&!B1)
+.model d_lut_sky130_fd_sc_hd__a21oi_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "11100000")
+* sky130_fd_sc_hd__o21ai_0 (!A1&!A2) | (!B1)
+.model d_lut_sky130_fd_sc_hd__o21ai_0 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "11111000")
+* sky130_fd_sc_hd__nand3_1 (!A) | (!B) | (!C)
+.model d_lut_sky130_fd_sc_hd__nand3_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "11111110")
+* sky130_fd_sc_hd__o211a_1 (A1&B1&C1) | (A2&B1&C1)
+.model d_lut_sky130_fd_sc_hd__o211a_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "0000000000000111")
+* sky130_fd_sc_hd__o211ai_1 (!A1&!A2) | (!B1) | (!C1)
+.model d_lut_sky130_fd_sc_hd__o211ai_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "1111111111111000")
+* sky130_fd_sc_hd__o21a_1 (A1&B1) | (A2&B1)
+.model d_lut_sky130_fd_sc_hd__o21a_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "00000111")
+* sky130_fd_sc_hd__o21bai_1 (!A1&!A2) | (B1_N)
+.model d_lut_sky130_fd_sc_hd__o21bai_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "10001111")
+* sky130_fd_sc_hd__xnor3_4 (!A&!B&!C) | (A&B&!C) | (A&!B&C) | (!A&B&C)
+.model d_lut_sky130_fd_sc_hd__xnor3_4 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "10010110")
+* sky130_fd_sc_hd__o2bb2ai_1 (!B1&!B2) | (A1_N&A2_N)
+.model d_lut_sky130_fd_sc_hd__o2bb2ai_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "1111000100010001")
+* sky130_fd_sc_hd__xor2_1 (A&!B) | (!A&B)
+.model d_lut_sky130_fd_sc_hd__xor2_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "0110")
+* sky130_fd_sc_hd__nor3_1 (!A&!B&!C)
+.model d_lut_sky130_fd_sc_hd__nor3_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "10000000")
+* sky130_fd_sc_hd__nand4_1 (!A) | (!B) | (!C) | (!D)
+.model d_lut_sky130_fd_sc_hd__nand4_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "1111111111111110")
+* sky130_fd_sc_hd__a21o_2 (A1&A2) | (B1)
+.model d_lut_sky130_fd_sc_hd__a21o_2 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "00011111")
+* sky130_fd_sc_hd__a21boi_0 (!A1&B1_N) | (!A2&B1_N)
+.model d_lut_sky130_fd_sc_hd__a21boi_0 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "00001110")
+* sky130_fd_sc_hd__a31oi_1 (!A1&!B1) | (!A2&!B1) | (!A3&!B1)
+.model d_lut_sky130_fd_sc_hd__a31oi_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "1111111000000000")
+* sky130_fd_sc_hd__o221ai_1 (!B1&!B2) | (!A1&!A2) | (!C1)
+.model d_lut_sky130_fd_sc_hd__o221ai_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "11111111111111111111100010001000")
+* sky130_fd_sc_hd__o2111ai_1 (!A1&!A2) | (!B1) | (!C1) | (!D1)
+.model d_lut_sky130_fd_sc_hd__o2111ai_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "11111111111111111111111111111000")
+* sky130_fd_sc_hd__a22oi_1 (!A1&!B1) | (!A1&!B2) | (!A2&!B1) | (!A2&!B2)
+.model d_lut_sky130_fd_sc_hd__a22oi_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "1110111011100000")
+* sky130_fd_sc_hd__o2111a_1 (A1&B1&C1&D1) | (A2&B1&C1&D1)
+.model d_lut_sky130_fd_sc_hd__o2111a_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "00000000000000000000000000000111")
+* sky130_fd_sc_hd__o22ai_1 (!B1&!B2) | (!A1&!A2)
+.model d_lut_sky130_fd_sc_hd__o22ai_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "1111100010001000")
+* sky130_fd_sc_hd__nor4_1 (!A&!B&!C&!D)
+.model d_lut_sky130_fd_sc_hd__nor4_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "1000000000000000")
+* sky130_fd_sc_hd__o32ai_1 (!A1&!A2&!A3) | (!B1&!B2)
+.model d_lut_sky130_fd_sc_hd__o32ai_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "11111111100000001000000010000000")
+* sky130_fd_sc_hd__a311oi_1 (!A1&!B1&!C1) | (!A2&!B1&!C1) | (!A3&!B1&!C1)
+.model d_lut_sky130_fd_sc_hd__a311oi_1 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "11111110000000000000000000000000")
+* sky130_fd_sc_hd__clkinv_2 (!A)
+.model d_lut_sky130_fd_sc_hd__clkinv_2 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "10")
+* sky130_fd_sc_hd__buf_2 (A)
+.model d_lut_sky130_fd_sc_hd__buf_2 d_lut (rise_delay=50p fall_delay=50p input_load=250f
++ table_values "01")
+* sky130_fd_sc_hd__dfrtp_2 IQ
+* sky130_fd_sc_hd__dfrtp_1 IQ
+* sky130_fd_sc_hd__dfrtp_4 IQ
+* sky130_fd_sc_hd__diode_2 (no function)
+.end
diff --git a/ngspice/digital_pll/digital_pll/digital_pll_tb.spice b/ngspice/digital_pll/digital_pll/digital_pll_tb.spice
new file mode 100644
index 0000000..c3d89ce
--- /dev/null
+++ b/ngspice/digital_pll/digital_pll/digital_pll_tb.spice
@@ -0,0 +1,64 @@
+*---------------------------------------------------------------------------
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+*---------------------------------------------------------------------------
+* Complete Digital PLL testbench
+*--------------------------------
+
+.lib "/home/tim/projects/efabless/tech/SW/sky130A/libs.tech/ngspice/sky130.lib.spice" tt
+
+.include "/home/tim/projects/efabless/tech/SW/sky130A/libs.ref/sky130_fd_sc_hd/spice/sky130_fd_sc_hd.spice"
+
+.include "digital_pll.spice"
+
+.option TEMP=27
+* .option RELTOL=1.0E-2
+
+* Instantiate the digital PLL
+
+X0 vdd vss reset osc clkp1 clkp0 div4 div3 div2 div1 div0 digital_pll
+
+* Power supply (note that all logic is 1.8V here)
+
+V0 vdd vss PWL(0.0 0.0 25n 1.8)
+V1 vss 0 0.0
+
+* Fixed divider value (connect resistors to power or ground)
+* divider value = 16  (10MHz * 16 = 160MHz clock)
+
+R0 div4 vdd 1
+R1 div3 gnd 1
+R2 div2 gnd 1
+R3 div1 gnd 1
+R4 div0 gnd 1
+
+* Run oscillator at 10MHz
+* Because DFFs don't handle reclocking well, keep the edges sharp.
+
+V2 osc vss PULSE(0.0 1.8 5n 10p 10p 50n 100n)
+
+* Reset pulse
+V3 reset vss PWL(0.0 1.8 0.1u 1.8 0.101u 0.0)
+
+* Transient analysis.  Note that trim updates every four cycles, or about
+* three updates per microsecond.  To update all 17 trim bits requires
+* 6us.
+
+.control
+tran 1n 8u
+plot V(osc)
+plot V(clkp0) V(clkp1)
+.endc
+.end
diff --git a/ngspice/digital_pll/digital_pll/inverter_tb.spi b/ngspice/digital_pll/digital_pll/inverter_tb.spi
new file mode 100644
index 0000000..36d5c18
--- /dev/null
+++ b/ngspice/digital_pll/digital_pll/inverter_tb.spi
@@ -0,0 +1,37 @@
+*---------------------------------------------------------------------------
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+*---------------------------------------------------------------------------
+* Simple testbench mainly to check SPICE model conversion from CDL
+* Plots the transient response of the smallest inverter in the HD standard cell library
+
+.lib "/home/tim/projects/efabless/tech/SW/sky130A/libs.tech/ngspice/sky130.lib.spice" tt
+.include "/home/tim/projects/efabless/tech/SW/sky130A/libs.ref/sky130_fd_sc_hd/spice/sky130_fd_sc_hd.spice"
+
+* .option TEMP=27
+
+X0 in vss vss vdd vdd out sky130_fd_sc_hd__inv_1
+
+V0 vdd vss PWL(0n 0.0 30n 1.8)
+V1 vss 0 0.0
+
+Vin in vss PWL(0n 0.0 100n 0.0 500n 1.8)
+
+* Transient analysis
+.control
+tran 1n 1u
+plot V(in) V(out)
+.endc
+.end
diff --git a/ngspice/digital_pll/digital_pll/ring_osc2x13.spice b/ngspice/digital_pll/digital_pll/ring_osc2x13.spice
new file mode 100644
index 0000000..5553f2c
--- /dev/null
+++ b/ngspice/digital_pll/digital_pll/ring_osc2x13.spice
@@ -0,0 +1,264 @@
+*---------------------------------------------------------------------------
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+*---------------------------------------------------------------------------
+* SPICE netlist created from verilog structural netlist module ring_osc2x13 by vlog2Spice (qflow)
+* Warning: This file contains <> array delimiters in net names_
+* Note: Library sky130_fd_sc_hd_spice has been removed;  reference library as an
+* include file from the testbench instead_
+
+.subckt ring_osc2x13 VPB VGND clockp<0> clockp<1> reset trim<0> trim<1>
++ trim<2> trim<3> trim<4> trim<5> trim<6> trim<7> trim<8> trim<9>
++ trim<10> trim<11> trim<12> trim<13> trim<14> trim<15> trim<16> trim<17>
++ trim<18> trim<19> trim<20> trim<21> trim<22> trim<23> trim<24> trim<25>
++ 
+
+X_1_ _0_<0> VGND VGND VPB VPB clockp<0> sky130_fd_sc_hd__buf_2
+X_2_ _0_<1> VGND VGND VPB VPB clockp<1> sky130_fd_sc_hd__buf_2
+Xdstage<0>_id_delaybuf0  dstage<0>_id_in VGND VGND VPB VPB dstage<0>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<0>_id_delaybuf1  dstage<0>_id_ts VGND VGND VPB VPB dstage<0>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<0>_id_delayen0  dstage<0>_id_d2 trim<0> VGND VGND VPB VPB 
++ dstage<0>_id_out
++ sky130_fd_sc_hd__einvp_2
+Xdstage<0>_id_delayen1  dstage<0>_id_d0 trim<13> VGND VGND VPB VPB 
++ dstage<0>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<0>_id_delayenb0  dstage<0>_id_ts trim<0> VGND VGND VPB VPB 
++ dstage<0>_id_out
++ sky130_fd_sc_hd__einvn_8
+Xdstage<0>_id_delayenb1  dstage<0>_id_ts trim<13> VGND VGND VPB VPB 
++ dstage<0>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<0>_id_delayint0  dstage<0>_id_d1 VGND VGND VPB VPB dstage<0>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xdstage<10>_id_delaybuf0  dstage<10>_id_in VGND VGND VPB VPB dstage<10>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<10>_id_delaybuf1  dstage<10>_id_ts VGND VGND VPB VPB dstage<10>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<10>_id_delayen0  dstage<10>_id_d2 trim<10> VGND VGND VPB VPB 
++ dstage<10>_id_out
++ sky130_fd_sc_hd__einvp_2
+Xdstage<10>_id_delayen1  dstage<10>_id_d0 trim<23> VGND VGND VPB VPB 
++ dstage<10>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<10>_id_delayenb0  dstage<10>_id_ts trim<10> VGND VGND VPB VPB 
++ dstage<10>_id_out
++ sky130_fd_sc_hd__einvn_8
+Xdstage<10>_id_delayenb1  dstage<10>_id_ts trim<23> VGND VGND VPB VPB 
++ dstage<10>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<10>_id_delayint0  dstage<10>_id_d1 VGND VGND VPB VPB dstage<10>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xdstage<11>_id_delaybuf0  dstage<10>_id_out VGND VGND VPB VPB dstage<11>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<11>_id_delaybuf1  dstage<11>_id_ts VGND VGND VPB VPB dstage<11>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<11>_id_delayen0  dstage<11>_id_d2 trim<11> VGND VGND VPB VPB 
++ dstage<11>_id_out
++ sky130_fd_sc_hd__einvp_2
+Xdstage<11>_id_delayen1  dstage<11>_id_d0 trim<24> VGND VGND VPB VPB 
++ dstage<11>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<11>_id_delayenb0  dstage<11>_id_ts trim<11> VGND VGND VPB VPB 
++ dstage<11>_id_out
++ sky130_fd_sc_hd__einvn_8
+Xdstage<11>_id_delayenb1  dstage<11>_id_ts trim<24> VGND VGND VPB VPB 
++ dstage<11>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<11>_id_delayint0  dstage<11>_id_d1 VGND VGND VPB VPB dstage<11>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xdstage<1>_id_delaybuf0  dstage<0>_id_out VGND VGND VPB VPB dstage<1>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<1>_id_delaybuf1  dstage<1>_id_ts VGND VGND VPB VPB dstage<1>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<1>_id_delayen0  dstage<1>_id_d2 trim<1> VGND VGND VPB VPB 
++ dstage<1>_id_out
++ sky130_fd_sc_hd__einvp_2
+Xdstage<1>_id_delayen1  dstage<1>_id_d0 trim<14> VGND VGND VPB VPB 
++ dstage<1>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<1>_id_delayenb0  dstage<1>_id_ts trim<1> VGND VGND VPB VPB 
++ dstage<1>_id_out
++ sky130_fd_sc_hd__einvn_8
+Xdstage<1>_id_delayenb1  dstage<1>_id_ts trim<14> VGND VGND VPB VPB 
++ dstage<1>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<1>_id_delayint0  dstage<1>_id_d1 VGND VGND VPB VPB dstage<1>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xdstage<2>_id_delaybuf0  dstage<1>_id_out VGND VGND VPB VPB dstage<2>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<2>_id_delaybuf1  dstage<2>_id_ts VGND VGND VPB VPB dstage<2>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<2>_id_delayen0  dstage<2>_id_d2 trim<2> VGND VGND VPB VPB 
++ dstage<2>_id_out
++ sky130_fd_sc_hd__einvp_2
+Xdstage<2>_id_delayen1  dstage<2>_id_d0 trim<15> VGND VGND VPB VPB 
++ dstage<2>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<2>_id_delayenb0  dstage<2>_id_ts trim<2> VGND VGND VPB VPB 
++ dstage<2>_id_out
++ sky130_fd_sc_hd__einvn_8
+Xdstage<2>_id_delayenb1  dstage<2>_id_ts trim<15> VGND VGND VPB VPB 
++ dstage<2>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<2>_id_delayint0  dstage<2>_id_d1 VGND VGND VPB VPB dstage<2>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xdstage<3>_id_delaybuf0  dstage<2>_id_out VGND VGND VPB VPB dstage<3>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<3>_id_delaybuf1  dstage<3>_id_ts VGND VGND VPB VPB dstage<3>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<3>_id_delayen0  dstage<3>_id_d2 trim<3> VGND VGND VPB VPB 
++ dstage<3>_id_out
++ sky130_fd_sc_hd__einvp_2
+Xdstage<3>_id_delayen1  dstage<3>_id_d0 trim<16> VGND VGND VPB VPB 
++ dstage<3>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<3>_id_delayenb0  dstage<3>_id_ts trim<3> VGND VGND VPB VPB 
++ dstage<3>_id_out
++ sky130_fd_sc_hd__einvn_8
+Xdstage<3>_id_delayenb1  dstage<3>_id_ts trim<16> VGND VGND VPB VPB 
++ dstage<3>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<3>_id_delayint0  dstage<3>_id_d1 VGND VGND VPB VPB dstage<3>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xdstage<4>_id_delaybuf0  dstage<3>_id_out VGND VGND VPB VPB dstage<4>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<4>_id_delaybuf1  dstage<4>_id_ts VGND VGND VPB VPB dstage<4>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<4>_id_delayen0  dstage<4>_id_d2 trim<4> VGND VGND VPB VPB 
++ dstage<4>_id_out
++ sky130_fd_sc_hd__einvp_2
+Xdstage<4>_id_delayen1  dstage<4>_id_d0 trim<17> VGND VGND VPB VPB 
++ dstage<4>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<4>_id_delayenb0  dstage<4>_id_ts trim<4> VGND VGND VPB VPB 
++ dstage<4>_id_out
++ sky130_fd_sc_hd__einvn_8
+Xdstage<4>_id_delayenb1  dstage<4>_id_ts trim<17> VGND VGND VPB VPB 
++ dstage<4>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<4>_id_delayint0  dstage<4>_id_d1 VGND VGND VPB VPB dstage<4>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xdstage<5>_id_delaybuf0  dstage<4>_id_out VGND VGND VPB VPB dstage<5>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<5>_id_delaybuf1  dstage<5>_id_ts VGND VGND VPB VPB dstage<5>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<5>_id_delayen0  dstage<5>_id_d2 trim<5> VGND VGND VPB VPB 
++ dstage<5>_id_out
++ sky130_fd_sc_hd__einvp_2
+Xdstage<5>_id_delayen1  dstage<5>_id_d0 trim<18> VGND VGND VPB VPB 
++ dstage<5>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<5>_id_delayenb0  dstage<5>_id_ts trim<5> VGND VGND VPB VPB 
++ dstage<5>_id_out
++ sky130_fd_sc_hd__einvn_8
+Xdstage<5>_id_delayenb1  dstage<5>_id_ts trim<18> VGND VGND VPB VPB 
++ dstage<5>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<5>_id_delayint0  dstage<5>_id_d1 VGND VGND VPB VPB dstage<5>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xdstage<6>_id_delaybuf0  dstage<5>_id_out VGND VGND VPB VPB dstage<6>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<6>_id_delaybuf1  dstage<6>_id_ts VGND VGND VPB VPB dstage<6>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<6>_id_delayen0  dstage<6>_id_d2 trim<6> VGND VGND VPB VPB 
++ dstage<6>_id_out
++ sky130_fd_sc_hd__einvp_2
+Xdstage<6>_id_delayen1  dstage<6>_id_d0 trim<19> VGND VGND VPB VPB 
++ dstage<6>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<6>_id_delayenb0  dstage<6>_id_ts trim<6> VGND VGND VPB VPB 
++ dstage<6>_id_out
++ sky130_fd_sc_hd__einvn_8
+Xdstage<6>_id_delayenb1  dstage<6>_id_ts trim<19> VGND VGND VPB VPB 
++ dstage<6>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<6>_id_delayint0  dstage<6>_id_d1 VGND VGND VPB VPB dstage<6>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xdstage<7>_id_delaybuf0  dstage<6>_id_out VGND VGND VPB VPB dstage<7>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<7>_id_delaybuf1  dstage<7>_id_ts VGND VGND VPB VPB dstage<7>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<7>_id_delayen0  dstage<7>_id_d2 trim<7> VGND VGND VPB VPB 
++ dstage<7>_id_out
++ sky130_fd_sc_hd__einvp_2
+Xdstage<7>_id_delayen1  dstage<7>_id_d0 trim<20> VGND VGND VPB VPB 
++ dstage<7>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<7>_id_delayenb0  dstage<7>_id_ts trim<7> VGND VGND VPB VPB 
++ dstage<7>_id_out
++ sky130_fd_sc_hd__einvn_8
+Xdstage<7>_id_delayenb1  dstage<7>_id_ts trim<20> VGND VGND VPB VPB 
++ dstage<7>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<7>_id_delayint0  dstage<7>_id_d1 VGND VGND VPB VPB dstage<7>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xdstage<8>_id_delaybuf0  dstage<7>_id_out VGND VGND VPB VPB dstage<8>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<8>_id_delaybuf1  dstage<8>_id_ts VGND VGND VPB VPB dstage<8>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<8>_id_delayen0  dstage<8>_id_d2 trim<8> VGND VGND VPB VPB 
++ dstage<8>_id_out
++ sky130_fd_sc_hd__einvp_2
+Xdstage<8>_id_delayen1  dstage<8>_id_d0 trim<21> VGND VGND VPB VPB 
++ dstage<8>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<8>_id_delayenb0  dstage<8>_id_ts trim<8> VGND VGND VPB VPB 
++ dstage<8>_id_out
++ sky130_fd_sc_hd__einvn_8
+Xdstage<8>_id_delayenb1  dstage<8>_id_ts trim<21> VGND VGND VPB VPB 
++ dstage<8>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<8>_id_delayint0  dstage<8>_id_d1 VGND VGND VPB VPB dstage<8>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xdstage<9>_id_delaybuf0  dstage<8>_id_out VGND VGND VPB VPB dstage<9>_id_ts sky130_fd_sc_hd__clkbuf_2
+Xdstage<9>_id_delaybuf1  dstage<9>_id_ts VGND VGND VPB VPB dstage<9>_id_d0 sky130_fd_sc_hd__clkbuf_1
+Xdstage<9>_id_delayen0  dstage<9>_id_d2 trim<9> VGND VGND VPB VPB 
++ dstage<10>_id_in
++ sky130_fd_sc_hd__einvp_2
+Xdstage<9>_id_delayen1  dstage<9>_id_d0 trim<22> VGND VGND VPB VPB 
++ dstage<9>_id_d1
++ sky130_fd_sc_hd__einvp_2
+Xdstage<9>_id_delayenb0  dstage<9>_id_ts trim<9> VGND VGND VPB VPB 
++ dstage<10>_id_in
++ sky130_fd_sc_hd__einvn_8
+Xdstage<9>_id_delayenb1  dstage<9>_id_ts trim<22> VGND VGND VPB VPB 
++ dstage<9>_id_d1
++ sky130_fd_sc_hd__einvn_4
+Xdstage<9>_id_delayint0  dstage<9>_id_d1 VGND VGND VPB VPB dstage<9>_id_d2 sky130_fd_sc_hd__clkinv_1
+Xibufp00 dstage<0>_id_in VGND VGND VPB VPB c<0> sky130_fd_sc_hd__clkinv_2
+Xibufp01 c<0> VGND VGND VPB VPB _0_<0> sky130_fd_sc_hd__clkinv_8
+Xibufp10 dstage<5>_id_out VGND VGND VPB VPB c<1> sky130_fd_sc_hd__clkinv_2
+Xibufp11 c<1> VGND VGND VPB VPB _0_<1> sky130_fd_sc_hd__clkinv_8
+Xiss_const1  VGND VGND VPB VPB iss_one _noconnect_1_ sky130_fd_sc_hd__conb_1
+Xiss_ctrlen0  reset trim<12> VGND VGND VPB VPB 
++ iss_ctrl0
++ sky130_fd_sc_hd__or2_2
+Xiss_delaybuf0  dstage<11>_id_out VGND VGND VPB VPB iss_d0 sky130_fd_sc_hd__clkbuf_1
+Xiss_delayen0  iss_d2 trim<12> VGND VGND VPB VPB 
++ dstage<0>_id_in
++ sky130_fd_sc_hd__einvp_2
+Xiss_delayen1  iss_d0 trim<25> VGND VGND VPB VPB 
++ iss_d1
++ sky130_fd_sc_hd__einvp_2
+Xiss_delayenb0  dstage<11>_id_out iss_ctrl0 VGND VGND VPB VPB 
++ dstage<0>_id_in
++ sky130_fd_sc_hd__einvn_8
+Xiss_delayenb1  dstage<11>_id_out trim<25> VGND VGND VPB VPB 
++ iss_d1
++ sky130_fd_sc_hd__einvn_4
+Xiss_delayint0  iss_d1 VGND VGND VPB VPB iss_d2 sky130_fd_sc_hd__clkinv_1
+Xiss_reseten0  iss_one reset VGND VGND VPB VPB 
++ dstage<0>_id_in
++ sky130_fd_sc_hd__einvp_1
+Xantenna_0 reset VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<25> trim<25> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<24> trim<24> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<23> trim<23> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<22> trim<22> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<21> trim<21> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<20> trim<20> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<19> trim<19> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<18> trim<18> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<17> trim<17> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<16> trim<16> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<15> trim<15> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<14> trim<14> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<13> trim<13> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<12> trim<12> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<11> trim<11> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<10> trim<10> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<9> trim<9> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<8> trim<8> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<7> trim<7> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<6> trim<6> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<5> trim<5> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<4> trim<4> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<3> trim<3> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<2> trim<2> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<1> trim<1> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1<0> trim<0> VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+
+.ends
+.end
diff --git a/ngspice/digital_pll/digital_pll/ring_osc2x13.spice.bak b/ngspice/digital_pll/digital_pll/ring_osc2x13.spice.bak
new file mode 100644
index 0000000..c49b71c
--- /dev/null
+++ b/ngspice/digital_pll/digital_pll/ring_osc2x13.spice.bak
@@ -0,0 +1,264 @@
+*---------------------------------------------------------------------------
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+*---------------------------------------------------------------------------
+* SPICE netlist created from verilog structural netlist module ring_osc2x13 by vlog2Spice (qflow)
+* Warning: This file contains [] array delimiters in net names.
+* Note: Library sky130_fd_sc_hd.spice has been removed;  reference library as an
+* include file from the testbench instead.
+
+.subckt ring_osc2x13 VPB VGND clockp[0] clockp[1] reset trim[0] trim[1]
++ trim[2] trim[3] trim[4] trim[5] trim[6] trim[7] trim[8] trim[9]
++ trim[10] trim[11] trim[12] trim[13] trim[14] trim[15] trim[16] trim[17]
++ trim[18] trim[19] trim[20] trim[21] trim[22] trim[23] trim[24] trim[25]
++ 
+
+X_1_ _0_[0] VGND VGND VPB VPB clockp[0] sky130_fd_sc_hd__buf_2
+X_2_ _0_[1] VGND VGND VPB VPB clockp[1] sky130_fd_sc_hd__buf_2
+X\dstage[0].id.delaybuf0  \dstage[0].id.in\ VGND VGND VPB VPB \dstage[0].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[0].id.delaybuf1  \dstage[0].id.ts\ VGND VGND VPB VPB \dstage[0].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[0].id.delayen0  \dstage[0].id.d2\ trim[0] VGND VGND VPB VPB 
++ \dstage[0].id.out\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[0].id.delayen1  \dstage[0].id.d0\ trim[13] VGND VGND VPB VPB 
++ \dstage[0].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[0].id.delayenb0  \dstage[0].id.ts\ trim[0] VGND VGND VPB VPB 
++ \dstage[0].id.out\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[0].id.delayenb1  \dstage[0].id.ts\ trim[13] VGND VGND VPB VPB 
++ \dstage[0].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[0].id.delayint0  \dstage[0].id.d1\ VGND VGND VPB VPB \dstage[0].id.d2\ sky130_fd_sc_hd__clkinv_1
+X\dstage[10].id.delaybuf0  \dstage[10].id.in\ VGND VGND VPB VPB \dstage[10].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[10].id.delaybuf1  \dstage[10].id.ts\ VGND VGND VPB VPB \dstage[10].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[10].id.delayen0  \dstage[10].id.d2\ trim[10] VGND VGND VPB VPB 
++ \dstage[10].id.out\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[10].id.delayen1  \dstage[10].id.d0\ trim[23] VGND VGND VPB VPB 
++ \dstage[10].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[10].id.delayenb0  \dstage[10].id.ts\ trim[10] VGND VGND VPB VPB 
++ \dstage[10].id.out\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[10].id.delayenb1  \dstage[10].id.ts\ trim[23] VGND VGND VPB VPB 
++ \dstage[10].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[10].id.delayint0  \dstage[10].id.d1\ VGND VGND VPB VPB \dstage[10].id.d2\ sky130_fd_sc_hd__clkinv_1
+X\dstage[11].id.delaybuf0  \dstage[10].id.out\ VGND VGND VPB VPB \dstage[11].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[11].id.delaybuf1  \dstage[11].id.ts\ VGND VGND VPB VPB \dstage[11].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[11].id.delayen0  \dstage[11].id.d2\ trim[11] VGND VGND VPB VPB 
++ \dstage[11].id.out\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[11].id.delayen1  \dstage[11].id.d0\ trim[24] VGND VGND VPB VPB 
++ \dstage[11].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[11].id.delayenb0  \dstage[11].id.ts\ trim[11] VGND VGND VPB VPB 
++ \dstage[11].id.out\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[11].id.delayenb1  \dstage[11].id.ts\ trim[24] VGND VGND VPB VPB 
++ \dstage[11].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[11].id.delayint0  \dstage[11].id.d1\ VGND VGND VPB VPB \dstage[11].id.d2\ sky130_fd_sc_hd__clkinv_1
+X\dstage[1].id.delaybuf0  \dstage[0].id.out\ VGND VGND VPB VPB \dstage[1].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[1].id.delaybuf1  \dstage[1].id.ts\ VGND VGND VPB VPB \dstage[1].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[1].id.delayen0  \dstage[1].id.d2\ trim[1] VGND VGND VPB VPB 
++ \dstage[1].id.out\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[1].id.delayen1  \dstage[1].id.d0\ trim[14] VGND VGND VPB VPB 
++ \dstage[1].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[1].id.delayenb0  \dstage[1].id.ts\ trim[1] VGND VGND VPB VPB 
++ \dstage[1].id.out\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[1].id.delayenb1  \dstage[1].id.ts\ trim[14] VGND VGND VPB VPB 
++ \dstage[1].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[1].id.delayint0  \dstage[1].id.d1\ VGND VGND VPB VPB \dstage[1].id.d2\ sky130_fd_sc_hd__clkinv_1
+X\dstage[2].id.delaybuf0  \dstage[1].id.out\ VGND VGND VPB VPB \dstage[2].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[2].id.delaybuf1  \dstage[2].id.ts\ VGND VGND VPB VPB \dstage[2].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[2].id.delayen0  \dstage[2].id.d2\ trim[2] VGND VGND VPB VPB 
++ \dstage[2].id.out\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[2].id.delayen1  \dstage[2].id.d0\ trim[15] VGND VGND VPB VPB 
++ \dstage[2].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[2].id.delayenb0  \dstage[2].id.ts\ trim[2] VGND VGND VPB VPB 
++ \dstage[2].id.out\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[2].id.delayenb1  \dstage[2].id.ts\ trim[15] VGND VGND VPB VPB 
++ \dstage[2].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[2].id.delayint0  \dstage[2].id.d1\ VGND VGND VPB VPB \dstage[2].id.d2\ sky130_fd_sc_hd__clkinv_1
+X\dstage[3].id.delaybuf0  \dstage[2].id.out\ VGND VGND VPB VPB \dstage[3].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[3].id.delaybuf1  \dstage[3].id.ts\ VGND VGND VPB VPB \dstage[3].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[3].id.delayen0  \dstage[3].id.d2\ trim[3] VGND VGND VPB VPB 
++ \dstage[3].id.out\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[3].id.delayen1  \dstage[3].id.d0\ trim[16] VGND VGND VPB VPB 
++ \dstage[3].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[3].id.delayenb0  \dstage[3].id.ts\ trim[3] VGND VGND VPB VPB 
++ \dstage[3].id.out\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[3].id.delayenb1  \dstage[3].id.ts\ trim[16] VGND VGND VPB VPB 
++ \dstage[3].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[3].id.delayint0  \dstage[3].id.d1\ VGND VGND VPB VPB \dstage[3].id.d2\ sky130_fd_sc_hd__clkinv_1
+X\dstage[4].id.delaybuf0  \dstage[3].id.out\ VGND VGND VPB VPB \dstage[4].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[4].id.delaybuf1  \dstage[4].id.ts\ VGND VGND VPB VPB \dstage[4].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[4].id.delayen0  \dstage[4].id.d2\ trim[4] VGND VGND VPB VPB 
++ \dstage[4].id.out\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[4].id.delayen1  \dstage[4].id.d0\ trim[17] VGND VGND VPB VPB 
++ \dstage[4].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[4].id.delayenb0  \dstage[4].id.ts\ trim[4] VGND VGND VPB VPB 
++ \dstage[4].id.out\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[4].id.delayenb1  \dstage[4].id.ts\ trim[17] VGND VGND VPB VPB 
++ \dstage[4].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[4].id.delayint0  \dstage[4].id.d1\ VGND VGND VPB VPB \dstage[4].id.d2\ sky130_fd_sc_hd__clkinv_1
+X\dstage[5].id.delaybuf0  \dstage[4].id.out\ VGND VGND VPB VPB \dstage[5].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[5].id.delaybuf1  \dstage[5].id.ts\ VGND VGND VPB VPB \dstage[5].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[5].id.delayen0  \dstage[5].id.d2\ trim[5] VGND VGND VPB VPB 
++ \dstage[5].id.out\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[5].id.delayen1  \dstage[5].id.d0\ trim[18] VGND VGND VPB VPB 
++ \dstage[5].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[5].id.delayenb0  \dstage[5].id.ts\ trim[5] VGND VGND VPB VPB 
++ \dstage[5].id.out\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[5].id.delayenb1  \dstage[5].id.ts\ trim[18] VGND VGND VPB VPB 
++ \dstage[5].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[5].id.delayint0  \dstage[5].id.d1\ VGND VGND VPB VPB \dstage[5].id.d2\ sky130_fd_sc_hd__clkinv_1
+X\dstage[6].id.delaybuf0  \dstage[5].id.out\ VGND VGND VPB VPB \dstage[6].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[6].id.delaybuf1  \dstage[6].id.ts\ VGND VGND VPB VPB \dstage[6].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[6].id.delayen0  \dstage[6].id.d2\ trim[6] VGND VGND VPB VPB 
++ \dstage[6].id.out\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[6].id.delayen1  \dstage[6].id.d0\ trim[19] VGND VGND VPB VPB 
++ \dstage[6].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[6].id.delayenb0  \dstage[6].id.ts\ trim[6] VGND VGND VPB VPB 
++ \dstage[6].id.out\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[6].id.delayenb1  \dstage[6].id.ts\ trim[19] VGND VGND VPB VPB 
++ \dstage[6].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[6].id.delayint0  \dstage[6].id.d1\ VGND VGND VPB VPB \dstage[6].id.d2\ sky130_fd_sc_hd__clkinv_1
+X\dstage[7].id.delaybuf0  \dstage[6].id.out\ VGND VGND VPB VPB \dstage[7].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[7].id.delaybuf1  \dstage[7].id.ts\ VGND VGND VPB VPB \dstage[7].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[7].id.delayen0  \dstage[7].id.d2\ trim[7] VGND VGND VPB VPB 
++ \dstage[7].id.out\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[7].id.delayen1  \dstage[7].id.d0\ trim[20] VGND VGND VPB VPB 
++ \dstage[7].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[7].id.delayenb0  \dstage[7].id.ts\ trim[7] VGND VGND VPB VPB 
++ \dstage[7].id.out\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[7].id.delayenb1  \dstage[7].id.ts\ trim[20] VGND VGND VPB VPB 
++ \dstage[7].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[7].id.delayint0  \dstage[7].id.d1\ VGND VGND VPB VPB \dstage[7].id.d2\ sky130_fd_sc_hd__clkinv_1
+X\dstage[8].id.delaybuf0  \dstage[7].id.out\ VGND VGND VPB VPB \dstage[8].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[8].id.delaybuf1  \dstage[8].id.ts\ VGND VGND VPB VPB \dstage[8].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[8].id.delayen0  \dstage[8].id.d2\ trim[8] VGND VGND VPB VPB 
++ \dstage[8].id.out\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[8].id.delayen1  \dstage[8].id.d0\ trim[21] VGND VGND VPB VPB 
++ \dstage[8].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[8].id.delayenb0  \dstage[8].id.ts\ trim[8] VGND VGND VPB VPB 
++ \dstage[8].id.out\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[8].id.delayenb1  \dstage[8].id.ts\ trim[21] VGND VGND VPB VPB 
++ \dstage[8].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[8].id.delayint0  \dstage[8].id.d1\ VGND VGND VPB VPB \dstage[8].id.d2\ sky130_fd_sc_hd__clkinv_1
+X\dstage[9].id.delaybuf0  \dstage[8].id.out\ VGND VGND VPB VPB \dstage[9].id.ts\ sky130_fd_sc_hd__clkbuf_2
+X\dstage[9].id.delaybuf1  \dstage[9].id.ts\ VGND VGND VPB VPB \dstage[9].id.d0\ sky130_fd_sc_hd__clkbuf_1
+X\dstage[9].id.delayen0  \dstage[9].id.d2\ trim[9] VGND VGND VPB VPB 
++ \dstage[10].id.in\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[9].id.delayen1  \dstage[9].id.d0\ trim[22] VGND VGND VPB VPB 
++ \dstage[9].id.d1\
++ sky130_fd_sc_hd__einvp_2
+X\dstage[9].id.delayenb0  \dstage[9].id.ts\ trim[9] VGND VGND VPB VPB 
++ \dstage[10].id.in\
++ sky130_fd_sc_hd__einvn_8
+X\dstage[9].id.delayenb1  \dstage[9].id.ts\ trim[22] VGND VGND VPB VPB 
++ \dstage[9].id.d1\
++ sky130_fd_sc_hd__einvn_4
+X\dstage[9].id.delayint0  \dstage[9].id.d1\ VGND VGND VPB VPB \dstage[9].id.d2\ sky130_fd_sc_hd__clkinv_1
+Xibufp00 \dstage[0].id.in\ VGND VGND VPB VPB c[0] sky130_fd_sc_hd__clkinv_2
+Xibufp01 c[0] VGND VGND VPB VPB _0_[0] sky130_fd_sc_hd__clkinv_8
+Xibufp10 \dstage[5].id.out\ VGND VGND VPB VPB c[1] sky130_fd_sc_hd__clkinv_2
+Xibufp11 c[1] VGND VGND VPB VPB _0_[1] sky130_fd_sc_hd__clkinv_8
+X\iss.const1  VGND VGND VPB VPB \iss.one\ _noconnect_1_ sky130_fd_sc_hd__conb_1
+X\iss.ctrlen0  reset trim[12] VGND VGND VPB VPB 
++ \iss.ctrl0\
++ sky130_fd_sc_hd__or2_2
+X\iss.delaybuf0  \dstage[11].id.out\ VGND VGND VPB VPB \iss.d0\ sky130_fd_sc_hd__clkbuf_1
+X\iss.delayen0  \iss.d2\ trim[12] VGND VGND VPB VPB 
++ \dstage[0].id.in\
++ sky130_fd_sc_hd__einvp_2
+X\iss.delayen1  \iss.d0\ trim[25] VGND VGND VPB VPB 
++ \iss.d1\
++ sky130_fd_sc_hd__einvp_2
+X\iss.delayenb0  \dstage[11].id.out\ \iss.ctrl0\ VGND VGND VPB VPB 
++ \dstage[0].id.in\
++ sky130_fd_sc_hd__einvn_8
+X\iss.delayenb1  \dstage[11].id.out\ trim[25] VGND VGND VPB VPB 
++ \iss.d1\
++ sky130_fd_sc_hd__einvn_4
+X\iss.delayint0  \iss.d1\ VGND VGND VPB VPB \iss.d2\ sky130_fd_sc_hd__clkinv_1
+X\iss.reseten0  \iss.one\ reset VGND VGND VPB VPB 
++ \dstage[0].id.in\
++ sky130_fd_sc_hd__einvp_1
+Xantenna_0 reset VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[25] trim[25] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[24] trim[24] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[23] trim[23] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[22] trim[22] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[21] trim[21] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[20] trim[20] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[19] trim[19] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[18] trim[18] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[17] trim[17] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[16] trim[16] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[15] trim[15] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[14] trim[14] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[13] trim[13] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[12] trim[12] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[11] trim[11] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[10] trim[10] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[9] trim[9] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[8] trim[8] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[7] trim[7] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[6] trim[6] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[5] trim[5] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[4] trim[4] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[3] trim[3] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[2] trim[2] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[1] trim[1] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+Xantenna_1[0] trim[0] VGND VGND VPB VPB sky130_fd_sc_hd__diode_2
+
+.ends
+.end
diff --git a/ngspice/digital_pll/digital_pll/ring_osc2x13_tb.spice b/ngspice/digital_pll/digital_pll/ring_osc2x13_tb.spice
new file mode 100644
index 0000000..b2c3cae
--- /dev/null
+++ b/ngspice/digital_pll/digital_pll/ring_osc2x13_tb.spice
@@ -0,0 +1,58 @@
+*---------------------------------------------------------------------------
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+*---------------------------------------------------------------------------
+* Ring oscillator testbench---simple check of ring oscillator
+* at several trim levels
+
+.lib "/home/tim/projects/efabless/tech/SW/sky130A/libs.tech/ngspice/sky130.lib.spice" tt
+
+.include "/home/tim/projects/efabless/tech/SW/sky130A/libs.ref/sky130_fd_sc_hd/spice/sky130_fd_sc_hd.spice"
+
+.include "ring_osc2x13.spice"
+
+.option TEMP=27
+* .option RELTOL=1.0E-1
+* .option RSHUNT=1.0E20
+
+* Instantiate the ring oscillator
+* Tie trims together in four sets
+
+X0 vdd vss clockp0 clockp1 reset trim0 trim1 trim0 trim1 trim0 trim1 trim0
++ trim1 trim0 trim1 trim0 trim1 trim0 trim3 trim2 trim3 trim2 trim3 trim2
++ trim3 trim2 trim3 trim2 trim3 trim2 trim3 ring_osc2x13
+
+* Power supply (note that all logic is 1.8V here)
+
+V0 vdd vss PWL(0n 0.0 30n 1.8)
+V1 vss 0 0.0
+
+* Trim values (connect resistors to power or ground)
+* divider value = 12
+
+V2 trim0 gnd PULSE(0.0 1.8 200n 2n 2n 1u 2u)
+V3 trim1 gnd PULSE(0.0 1.8 400n 2n 2n 1u 2u)
+V4 trim2 gnd PULSE(0.0 1.8 600n 2n 2n 1u 2u)
+V5 trim3 gnd PULSE(0.0 1.8 800n 2n 2n 1u 2u)
+
+* Reset
+V6 reset gnd PWL(0n 1.8 48n 1.8 50n 0.0)
+
+* Transient analysis
+.control
+tran 100p 1u
+plot V(clockp0) V(clockp1)
+.endc
+.end
diff --git a/ngspice/digital_pll/digital_pll/ring_osc2x13_tb2.spice b/ngspice/digital_pll/digital_pll/ring_osc2x13_tb2.spice
new file mode 100644
index 0000000..93406af
--- /dev/null
+++ b/ngspice/digital_pll/digital_pll/ring_osc2x13_tb2.spice
@@ -0,0 +1,80 @@
+*---------------------------------------------------------------------------
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+*---------------------------------------------------------------------------
+* Ring oscillator testbench---simple check of ring oscillator
+* at several trim levels
+
+.lib "/home/tim/projects/efabless/tech/SW/sky130A/libs.tech/ngspice/sky130.lib.spice" tt
+
+.include "/home/tim/projects/efabless/tech/SW/sky130A/libs.ref/sky130_fd_sc_hd/spice/sky130_fd_sc_hd.spice"
+
+.include "ring_osc2x13.spice"
+
+.option TEMP=27
+* .option RELTOL=1.0E-1
+* .option RSHUNT=1.0E20
+
+* Instantiate the ring oscillator
+* Tie trims together in four sets
+
+X0 vdd vss clockp0 clockp1 reset trim00 trim01 trim02 trim03 trim04 trim05 trim06
++ trim07 trim08 trim09 trim10 trim11 trim12 trim13 trim14 trim15 trim16 trim17
++ trim18 trim19 trim20 trim21 trim22 trim23 trim24 trim25 ring_osc2x13
+
+* Power supply (note that all logic is 1.8V here)
+
+V00 vdd vss PWL(0n 0.0 30n 1.8)
+V01 vss 0 0.0
+
+* Trim values (connect resistors to power or ground)
+* divider value = 12
+
+V02 trim00 gnd PULSE(0.0 1.8 40n 2n 2n 1u 2u)
+V03 trim01 gnd PULSE(0.0 1.8 80n 2n 2n 1u 2u)
+V04 trim02 gnd PULSE(0.0 1.8 120n 2n 2n 1u 2u)
+V05 trim03 gnd PULSE(0.0 1.8 160n 2n 2n 1u 2u)
+V06 trim04 gnd PULSE(0.0 1.8 200n 2n 2n 1u 2u)
+V07 trim05 gnd PULSE(0.0 1.8 240n 2n 2n 1u 2u)
+V08 trim06 gnd PULSE(0.0 1.8 280n 2n 2n 1u 2u)
+V09 trim07 gnd PULSE(0.0 1.8 320n 2n 2n 1u 2u)
+V10 trim08 gnd PULSE(0.0 1.8 360n 2n 2n 1u 2u)
+V11 trim09 gnd PULSE(0.0 1.8 400n 2n 2n 1u 2u)
+V12 trim10 gnd PULSE(0.0 1.8 440n 2n 2n 1u 2u)
+V13 trim11 gnd PULSE(0.0 1.8 480n 2n 2n 1u 2u)
+V14 trim12 gnd PULSE(0.0 1.8 520n 2n 2n 1u 2u)
+V15 trim13 gnd PULSE(0.0 1.8 560n 2n 2n 1u 2u)
+V16 trim14 gnd PULSE(0.0 1.8 600n 2n 2n 1u 2u)
+V17 trim15 gnd PULSE(0.0 1.8 640n 2n 2n 1u 2u)
+V18 trim16 gnd PULSE(0.0 1.8 680n 2n 2n 1u 2u)
+V19 trim17 gnd PULSE(0.0 1.8 720n 2n 2n 1u 2u)
+V20 trim18 gnd PULSE(0.0 1.8 760n 2n 2n 1u 2u)
+V21 trim19 gnd PULSE(0.0 1.8 800n 2n 2n 1u 2u)
+V22 trim20 gnd PULSE(0.0 1.8 840n 2n 2n 1u 2u)
+V23 trim21 gnd PULSE(0.0 1.8 880n 2n 2n 1u 2u)
+V24 trim22 gnd PULSE(0.0 1.8 920n 2n 2n 1u 2u)
+V25 trim23 gnd PULSE(0.0 1.8 960n 2n 2n 1u 2u)
+V26 trim24 gnd PULSE(0.0 1.8 800n 2n 2n 1u 2u)
+V27 trim25 gnd PULSE(0.0 1.8 840n 2n 2n 1u 2u)
+
+* Reset
+V6 reset gnd PWL(0n 1.8 8n 1.8 10n 0.0)
+
+* Transient analysis
+.control
+tran 100p 1u
+plot V(clockp0) V(clockp1)
+.endc
+.end
diff --git a/ngspice/simple_por/simple_por/current_test.spice b/ngspice/simple_por/simple_por/current_test.spice
new file mode 100644
index 0000000..da74e24
--- /dev/null
+++ b/ngspice/simple_por/simple_por/current_test.spice
@@ -0,0 +1,85 @@
+*---------------------------------------------------------------------------
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+*---------------------------------------------------------------------------
+* Simple POR circuit for Caravel current mirror test
+*-------------------------------------------------------------------
+
+.lib /home/tim/projects/efabless/tech/SW/sky130A/libs.tech/ngspice/sky130.lib.spice tt
+
+* Note: 20 resistors of length 25um connected in series
+Xres1 vdda vin vss sky130_fd_pr__res_xhigh_po_0p69 l=500
+Xres2 vin vss vss sky130_fd_pr__res_xhigh_po_0p69 l=149
+
+* voltage sources at 0V for measuring current in each branch
+
+Vm1 vssm1 vss   DC=0
+Vm2 vdda  vddm2 DC=0
+Vm3 vdda  vddm3 DC=0
+Vm4 vssm4 vss   DC=0
+Vm5 vssm5 vss   DC=0
+Vm6 vdda  vddm6 DC=0
+Vm7 vdda  vddm7 DC=0
+
+*   D     G     S     B
+Xm1 casc1 vin   vssm1 vss  sky130_fd_pr__nfet_g5v0d10v5 w=2 l=0.8 m=1
+Xc1 mir1  casc1 casc1 vdda sky130_fd_pr__pfet_g5v0d10v5 w=2 l=0.8 m=1
+Xm2 mir1  mir1  vddm2 vdda sky130_fd_pr__pfet_g5v0d10v5 w=2 l=0.8 m=8
+Xm3 mir2  mir1  vddm3 vdda sky130_fd_pr__pfet_g5v0d10v5 w=2 l=0.8 m=1
+Xc2 casc2 casc1 mir2  vdda sky130_fd_pr__pfet_g5v0d10v5 w=2 l=0.8 m=1
+Xm4 casc2 casc2 vssm4 vss  sky130_fd_pr__nfet_g5v0d10v5 w=2 l=0.8 m=7
+Xm5 casc3 casc2 vssm5 vss  sky130_fd_pr__nfet_g5v0d10v5 w=2 l=0.8 m=1
+Xc3 mir3  casc3 casc3 vdda sky130_fd_pr__pfet_g5v0d10v5 w=2 l=0.8 m=1
+Xm6 mir3  mir3  vddm6 vdda sky130_fd_pr__pfet_g5v0d10v5 w=2 l=0.8 m=7
+Xm7 mir4  mir3  vddm7 vdda sky130_fd_pr__pfet_g5v0d10v5 w=2 l=0.8 m=1
+Xc4 vcap  casc3 mir4  vdda sky130_fd_pr__pfet_g5v0d10v5 w=2 l=0.8 m=1
+
+* Check branch currents in each mirror branch.
+* 1st branch should be 240nA
+* 2nd branch should be  30nA
+* 3rd branch should be   4.3nA
+* 4th branch should be 612pA
+*
+* Result:  vin sits at 0.7590 (close to 0.7575 target)
+* I(Vm1/2) = 202.80 nA
+* I(Vm3/4) =  26.10 nA	(should be /8) actually /7.77
+* I(Vm5/6) =   4.58 nA	(should be /7) actually /5.70
+* I(Vm7)   =   0.67 pA	(should be /7) actually /6.80
+
+*----------------------------
+* Testbench circuit
+*----------------------------
+Vpwr vdda vss DC=3.3
+Rgnd vss 0 0.01
+Rload vcap vss 1MEG
+*----------------------------
+
+*----------------------------
+* Testbench control
+*----------------------------
+.control
+op
+print V(vin)
+print I(Vm1)
+print I(Vm2)
+print I(Vm3)
+print I(Vm4)
+print I(Vm5)
+print I(Vm6)
+print I(Vm7)
+.endc
+
+.end
+
diff --git a/ngspice/simple_por/simple_por/simple_por.spice b/ngspice/simple_por/simple_por/simple_por.spice
new file mode 100644
index 0000000..2aa5265
--- /dev/null
+++ b/ngspice/simple_por/simple_por/simple_por.spice
@@ -0,0 +1,229 @@
+*---------------------------------------------------------------------------
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+*---------------------------------------------------------------------------
+* NGSPICE file created from simple_por.ext - technology: sky130A
+
+.subckt sky130_fd_pr__cap_mim_m3_2_W5U4AW VSUBS m4_n3179_n3100# c2_n3079_n3000#
+X0 c2_n3079_n3000# m4_n3179_n3100# sky130_fd_pr__cap_mim_m3_2 l=3e+07u w=3e+07u
+.ends
+
+.subckt sky130_fd_sc_hvl__buf_8 A VGND VNB VPB VPWR X
+X0 VPWR A a_45_443# VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X1 VGND a_45_443# X VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X2 VPWR a_45_443# X VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X3 VGND a_45_443# X VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X4 VGND a_45_443# X VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X5 a_45_443# A VGND VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X6 X a_45_443# VGND VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X7 X a_45_443# VGND VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X8 VGND A a_45_443# VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X9 VPWR a_45_443# X VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X10 X a_45_443# VGND VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X11 X a_45_443# VGND VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X12 VPWR a_45_443# X VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X13 VPWR a_45_443# X VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X14 VPWR A a_45_443# VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X15 a_45_443# A VPWR VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X16 VGND A a_45_443# VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X17 X a_45_443# VPWR VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X18 X a_45_443# VPWR VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X19 VGND a_45_443# X VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X20 X a_45_443# VPWR VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X21 X a_45_443# VPWR VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+.ends
+
+.subckt sky130_fd_pr__pfet_g5v0d10v5_ZEUEFZ VSUBS a_n465_n200# a_n247_n200# a_n29_n200#
++ a_843_n200# w_n1101_n497# a_n843_n297# a_625_n200# a_683_n297# a_n625_n297# a_407_n200#
++ a_465_n297# a_n407_n297# a_247_n297# a_n901_n200# a_189_n200# a_29_n297# a_n189_n297#
++ a_n683_n200#
+X0 a_407_n200# a_247_n297# a_189_n200# w_n1101_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X1 a_843_n200# a_683_n297# a_625_n200# w_n1101_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X2 a_n465_n200# a_n625_n297# a_n683_n200# w_n1101_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X3 a_189_n200# a_29_n297# a_n29_n200# w_n1101_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X4 a_625_n200# a_465_n297# a_407_n200# w_n1101_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X5 a_n247_n200# a_n407_n297# a_n465_n200# w_n1101_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X6 a_n683_n200# a_n843_n297# a_n901_n200# w_n1101_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X7 a_n29_n200# a_n189_n297# a_n247_n200# w_n1101_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+.ends
+
+.subckt sky130_fd_pr__nfet_g5v0d10v5_TGFUGS VSUBS a_n80_n288# a_n574_n200# a_n356_n200#
++ a_n138_n200# a_n734_n288# a_574_n288# a_n516_n288# a_356_n288# a_80_n200# a_n298_n288#
++ a_138_n288# w_n962_n458# a_734_n200# a_516_n200# a_298_n200# a_n792_n200#
+X0 a_516_n200# a_356_n288# a_298_n200# VSUBS sky130_fd_pr__nfet_g5v0d10v5 w=2e+06u l=800000u
+X1 a_n574_n200# a_n734_n288# a_n792_n200# VSUBS sky130_fd_pr__nfet_g5v0d10v5 w=2e+06u l=800000u
+X2 a_298_n200# a_138_n288# a_80_n200# VSUBS sky130_fd_pr__nfet_g5v0d10v5 w=2e+06u l=800000u
+X3 a_80_n200# a_n80_n288# a_n138_n200# VSUBS sky130_fd_pr__nfet_g5v0d10v5 w=2e+06u l=800000u
+X4 a_734_n200# a_574_n288# a_516_n200# VSUBS sky130_fd_pr__nfet_g5v0d10v5 w=2e+06u l=800000u
+X5 a_n356_n200# a_n516_n288# a_n574_n200# VSUBS sky130_fd_pr__nfet_g5v0d10v5 w=2e+06u l=800000u
+X6 a_n138_n200# a_n298_n288# a_n356_n200# VSUBS sky130_fd_pr__nfet_g5v0d10v5 w=2e+06u l=800000u
+.ends
+
+.subckt sky130_fd_pr__res_xhigh_po_0p69_S5N9F3 VSUBS a_n2578_n2932# a_5142_2500# a_n1034_n2932#
++ a_n262_2500# a_1668_2500# a_n262_n2932# a_n3736_2500# a_3984_n2932# a_n2192_2500#
++ a_3984_2500# a_2440_n2932# a_2440_2500# a_4370_n2932# a_3598_2500# a_2054_2500#
++ a_n4508_n2932# a_510_2500# a_n4122_2500# a_n2964_n2932# a_124_2500# a_n4894_n2932#
++ a_1282_n2932# a_124_n2932# a_n1420_n2932# a_4370_2500# a_n3350_n2932# a_n648_n2932#
++ a_n648_2500# a_n5280_n2932# a_n1420_2500# a_n2964_2500# a_n2578_2500# a_n1034_2500#
++ a_2826_n2932# a_n2192_n2932# a_2826_2500# a_4756_n2932# w_n5446_n3098# a_1282_2500#
++ a_3212_n2932# a_n4894_2500# a_n3350_2500# a_n4508_2500# a_5142_n2932# a_896_2500#
++ a_510_n2932# a_1668_n2932# a_n1806_n2932# a_4756_2500# a_n3736_n2932# a_3598_n2932#
++ a_3212_2500# a_2054_n2932# a_896_n2932# a_n5280_2500# a_n4122_n2932# a_n1806_2500#
+X0 a_n3350_n2932# a_n3350_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X1 a_n4508_n2932# a_n4508_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X2 a_n2578_n2932# a_n2578_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X3 a_n1420_n2932# a_n1420_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X4 a_n4894_n2932# a_n4894_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X5 a_n3736_n2932# a_n3736_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X6 a_3598_n2932# a_3598_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X7 a_124_n2932# a_124_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X8 a_4756_n2932# a_4756_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X9 a_n2964_n2932# a_n2964_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X10 a_1668_n2932# a_1668_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X11 a_n1806_n2932# a_n1806_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X12 a_n648_n2932# a_n648_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X13 a_3984_n2932# a_3984_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X14 a_2826_n2932# a_2826_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X15 a_510_n2932# a_510_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X16 a_n4122_n2932# a_n4122_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X17 a_n2192_n2932# a_n2192_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X18 a_5142_n2932# a_5142_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X19 a_n1034_n2932# a_n1034_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X20 a_2054_n2932# a_2054_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X21 a_4370_n2932# a_4370_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X22 a_3212_n2932# a_3212_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X23 a_1282_n2932# a_1282_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X24 a_n262_n2932# a_n262_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X25 a_n5280_n2932# a_n5280_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X26 a_2440_n2932# a_2440_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+X27 a_896_n2932# a_896_2500# VSUBS sky130_fd_pr__res_xhigh_po_0p69 l=2.5e+07u
+.ends
+
+.subckt sky130_fd_pr__pfet_g5v0d10v5_3YBPVB VSUBS a_n138_n200# w_n338_n497# a_80_n200#
++ a_n80_n297#
+X0 a_80_n200# a_n80_n297# a_n138_n200# w_n338_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+.ends
+
+.subckt sky130_fd_sc_hvl__schmittbuf_1 A VGND VNB VPB VPWR X
+X0 a_64_207# VPWR VPB sky130_fd_pr__res_generic_pd__hv w=290000u l=3.11e+06u
+X1 a_231_463# A a_117_181# VPB sky130_fd_pr__pfet_g5v0d10v5 w=750000u l=500000u
+X2 a_217_207# A a_117_181# VNB sky130_fd_pr__nfet_g5v0d10v5 w=420000u l=500000u
+X3 VPWR A a_231_463# VPB sky130_fd_pr__pfet_g5v0d10v5 w=750000u l=500000u
+X4 a_217_207# a_117_181# a_64_207# VNB sky130_fd_pr__nfet_g5v0d10v5 w=420000u l=500000u
+X5 X a_117_181# VGND VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X6 a_78_463# VGND VNB sky130_fd_pr__res_generic_nd__hv w=290000u l=1.355e+06u
+X7 X a_117_181# VPWR VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X8 VGND A a_217_207# VNB sky130_fd_pr__nfet_g5v0d10v5 w=420000u l=500000u
+X9 a_231_463# a_117_181# a_78_463# VPB sky130_fd_pr__pfet_g5v0d10v5 w=750000u l=500000u
+.ends
+
+.subckt sky130_fd_pr__pfet_g5v0d10v5_YUHPXE VSUBS a_n138_n200# w_n338_n497# a_80_n200#
++ a_n80_n297#
+X0 a_80_n200# a_n80_n297# a_n138_n200# w_n338_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+.ends
+
+.subckt sky130_fd_pr__nfet_g5v0d10v5_PKVMTM VSUBS a_n80_n288# a_n138_n200# a_80_n200#
++ w_n308_n458#
+X0 a_80_n200# a_n80_n288# a_n138_n200# VSUBS sky130_fd_pr__nfet_g5v0d10v5 w=2e+06u l=800000u
+.ends
+
+.subckt sky130_fd_pr__nfet_g5v0d10v5_ZK8HQC VSUBS a_n80_n288# a_n138_n200# a_80_n200#
++ w_n308_n458#
+X0 a_80_n200# a_n80_n288# a_n138_n200# VSUBS sky130_fd_pr__nfet_g5v0d10v5 w=2e+06u l=800000u
+.ends
+
+.subckt sky130_fd_pr__cap_mim_m3_1_WRT4AW VSUBS m3_n3136_n3100# c1_n3036_n3000#
+X0 c1_n3036_n3000# m3_n3136_n3100# sky130_fd_pr__cap_mim_m3_1 l=3e+07u w=3e+07u
+.ends
+
+.subckt sky130_fd_pr__pfet_g5v0d10v5_YEUEBV VSUBS w_n992_n497# a_n574_n200# a_n356_n200#
++ a_n138_n200# a_80_n200# a_n80_n297# a_734_n200# a_n734_n297# a_516_n200# a_574_n297#
++ a_n516_n297# a_356_n297# a_298_n200# a_n298_n297# a_138_n297# a_n792_n200#
+X0 a_734_n200# a_574_n297# a_516_n200# w_n992_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X1 a_n356_n200# a_n516_n297# a_n574_n200# w_n992_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X2 a_n138_n200# a_n298_n297# a_n356_n200# w_n992_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X3 a_516_n200# a_356_n297# a_298_n200# w_n992_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X4 a_n574_n200# a_n734_n297# a_n792_n200# w_n992_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X5 a_298_n200# a_138_n297# a_80_n200# w_n992_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+X6 a_80_n200# a_n80_n297# a_n138_n200# w_n992_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+.ends
+
+.subckt sky130_fd_pr__pfet_g5v0d10v5_YUHPBG VSUBS a_n138_n200# w_n338_n497# a_80_n200#
++ a_n80_n297#
+X0 a_80_n200# a_n80_n297# a_n138_n200# w_n338_n497# sky130_fd_pr__pfet_g5v0d10v5 w=2e+06u l=800000u
+.ends
+
+.subckt sky130_fd_sc_hvl__inv_8 A VGND VNB VPB VPWR Y
+X0 Y A VPWR VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X1 Y A VGND VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X2 Y A VGND VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X3 VPWR A Y VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X4 VPWR A Y VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X5 VPWR A Y VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X6 VGND A Y VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X7 VGND A Y VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X8 Y A VPWR VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X9 Y A VPWR VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X10 Y A VPWR VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X11 Y A VGND VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X12 VPWR A Y VPB sky130_fd_pr__pfet_g5v0d10v5 w=1.5e+06u l=500000u
+X13 VGND A Y VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X14 VGND A Y VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+X15 Y A VGND VNB sky130_fd_pr__nfet_g5v0d10v5 w=750000u l=500000u
+.ends
+
+.subckt simple_por vdd3v3 vdd1v8 vss porb_h por_l porb_l
+Xsky130_fd_pr__cap_mim_m3_2_W5U4AW_0 vss sky130_fd_sc_hvl__schmittbuf_1_0/A vss sky130_fd_pr__cap_mim_m3_2_W5U4AW
+Xsky130_fd_sc_hvl__buf_8_1 out vss vss vdd1v8 vdd1v8 porb_l sky130_fd_sc_hvl__buf_8
+Xsky130_fd_pr__pfet_g5v0d10v5_ZEUEFZ_0 vss vdd3v3 m1_502_7653# vdd3v3 vdd3v3 vdd3v3
++ m1_502_7653# m1_502_7653# m1_502_7653# m1_502_7653# vdd3v3 m1_502_7653# m1_502_7653#
++ m1_502_7653# vdd3v3 m1_502_7653# m1_502_7653# m1_502_7653# m1_502_7653# sky130_fd_pr__pfet_g5v0d10v5_ZEUEFZ
+Xsky130_fd_pr__nfet_g5v0d10v5_TGFUGS_0 vss m1_721_6815# vss m1_721_6815# vss m1_721_6815#
++ m1_721_6815# m1_721_6815# m1_721_6815# m1_721_6815# m1_721_6815# m1_721_6815# vss
++ vss m1_721_6815# vss m1_721_6815# sky130_fd_pr__nfet_g5v0d10v5_TGFUGS
+Xsky130_fd_pr__res_xhigh_po_0p69_S5N9F3_0 vss li_2935_165# vss li_4479_165# li_4866_5813#
++ li_7182_5813# li_5251_165# li_1778_5813# li_9111_165# li_3322_5813# li_9498_5813#
++ li_7567_165# li_7954_5813# li_9883_165# li_8726_5813# li_7182_5813# li_619_165#
++ li_5638_5813# li_1006_5813# li_2163_165# li_5638_5813# li_619_165# li_6795_165#
++ li_5251_165# li_3707_165# li_9498_5813# li_2163_165# li_4479_165# li_4866_5813#
++ vss li_4094_5813# li_2550_5813# li_2550_5813# li_4094_5813# li_8339_165# li_2935_165#
++ li_7954_5813# li_9883_165# vss li_6410_5813# li_8339_165# vss li_1778_5813# li_1006_5813#
++ vss li_6410_5813# li_6023_165# li_6795_165# li_3707_165# vdd3v3 li_1391_165# li_9111_165#
++ li_8726_5813# li_7567_165# li_6023_165# vss li_1391_165# li_3322_5813# sky130_fd_pr__res_xhigh_po_0p69_S5N9F3
+Xsky130_fd_pr__pfet_g5v0d10v5_3YBPVB_0 vss m1_2993_7658# vdd3v3 m1_721_6815# m1_185_6573#
++ sky130_fd_pr__pfet_g5v0d10v5_3YBPVB
+Xsky130_fd_sc_hvl__schmittbuf_1_0 sky130_fd_sc_hvl__schmittbuf_1_0/A vss vss vdd3v3
++ vdd3v3 out sky130_fd_sc_hvl__schmittbuf_1
+Xsky130_fd_pr__pfet_g5v0d10v5_3YBPVB_1 vss m1_2756_6573# vdd3v3 m1_4283_8081# m1_2756_6573#
++ sky130_fd_pr__pfet_g5v0d10v5_3YBPVB
+Xsky130_fd_pr__pfet_g5v0d10v5_3YBPVB_2 vss m1_6249_7690# vdd3v3 sky130_fd_sc_hvl__schmittbuf_1_0/A
++ m1_2756_6573# sky130_fd_pr__pfet_g5v0d10v5_3YBPVB
+Xsky130_fd_pr__pfet_g5v0d10v5_3YBPVB_3 vss m1_185_6573# vdd3v3 m1_502_7653# m1_185_6573#
++ sky130_fd_pr__pfet_g5v0d10v5_3YBPVB
+Xsky130_fd_pr__pfet_g5v0d10v5_YUHPXE_0 vss vdd3v3 vdd3v3 m1_6249_7690# m1_4283_8081#
++ sky130_fd_pr__pfet_g5v0d10v5_YUHPXE
+Xsky130_fd_pr__nfet_g5v0d10v5_PKVMTM_0 vss m1_721_6815# vss m1_2756_6573# vss sky130_fd_pr__nfet_g5v0d10v5_PKVMTM
+Xsky130_fd_pr__nfet_g5v0d10v5_ZK8HQC_1 vss li_2550_5813# vss m1_185_6573# vss sky130_fd_pr__nfet_g5v0d10v5_ZK8HQC
+Xsky130_fd_pr__cap_mim_m3_1_WRT4AW_0 vss vss sky130_fd_sc_hvl__schmittbuf_1_0/A sky130_fd_pr__cap_mim_m3_1_WRT4AW
+Xsky130_fd_pr__pfet_g5v0d10v5_YEUEBV_0 vss vdd3v3 m1_4283_8081# vdd3v3 m1_4283_8081#
++ vdd3v3 m1_4283_8081# m1_4283_8081# m1_4283_8081# vdd3v3 m1_4283_8081# m1_4283_8081#
++ m1_4283_8081# m1_4283_8081# m1_4283_8081# m1_4283_8081# vdd3v3 sky130_fd_pr__pfet_g5v0d10v5_YEUEBV
+Xsky130_fd_pr__pfet_g5v0d10v5_YUHPBG_0 vss vdd3v3 vdd3v3 m1_2993_7658# m1_502_7653#
++ sky130_fd_pr__pfet_g5v0d10v5_YUHPBG
+Xsky130_fd_sc_hvl__inv_8_0 out vss vss vdd1v8 vdd1v8 por_l sky130_fd_sc_hvl__inv_8
+Xsky130_fd_sc_hvl__fill_4_0 vss vss vdd3v3 vdd3v3 sky130_fd_sc_hvl__fill_4
+Xsky130_fd_sc_hvl__buf_8_0 out vss vss vdd3v3 vdd3v3 porb_h sky130_fd_sc_hvl__buf_8
+.ends
+
diff --git a/ngspice/simple_por/simple_por/simple_por_tb.spice b/ngspice/simple_por/simple_por/simple_por_tb.spice
new file mode 100644
index 0000000..18fc1dc
--- /dev/null
+++ b/ngspice/simple_por/simple_por/simple_por_tb.spice
@@ -0,0 +1,51 @@
+*---------------------------------------------------------------------------
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+*---------------------------------------------------------------------------
+* Simple POR circuit for Caravel
+*-------------------------------------------------------------------
+*
+* Architecture: see simple_por.spice
+* Response of this circuit by ngspice simulation is a ~15ms delay.
+*-------------------------------------------------------------------
+
+.lib /home/tim/projects/efabless/tech/SW/sky130A/libs.tech/ngspice/sky130.lib.spice tt
+.include /home/tim/projects/efabless/tech/SW/sky130A/libs.ref/sky130_fd_sc_hvl/spice/sky130_fd_sc_hvl.spice
+.include simple_por.spice
+
+*----------------------------
+* Testbench circuit
+*----------------------------
+Vpwr vdda vss DC=0 PWL(0.0 0 100u 0 5m 3.3)
+Vdig vccd vss DC=0 PWL(0.0 0 300u 0 5.3m 1.8)
+Rgnd vss 0 0.01
+Cload1 porb_h  vss 1E-12
+Cload2 por_l  vss 1E-12
+Cload3 porb_l vss 1E-12
+Xpor vdda vccd vss porb_h por_l porb_l simple_por
+*----------------------------
+
+*----------------------------
+* Testbench control
+*----------------------------
+.control
+tran 10u 20m
+plot porb_h
+plot por_l
+plot porb_l
+.endc
+
+.end
+
diff --git a/ngspice/simple_por/simple_por/threshold_test_tb.spice b/ngspice/simple_por/simple_por/threshold_test_tb.spice
new file mode 100644
index 0000000..4d064d0
--- /dev/null
+++ b/ngspice/simple_por/simple_por/threshold_test_tb.spice
@@ -0,0 +1,47 @@
+*---------------------------------------------------------------------------
+* SPDX-FileCopyrightText: 2020 Efabless Corporation
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     https://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* SPDX-License-Identifier: Apache-2.0
+*---------------------------------------------------------------------------
+* Threshold test for POR circuit
+* Determine gate voltage at which the HV NFET draws 240nA nominal
+*
+* Result:  0.7575V
+*-------------------------------------------------------------------
+
+.lib /home/tim/projects/efabless/tech/SW/sky130A/libs.tech/ngspice/sky130.lib.spice tt
+
+
+*----------------------------
+* Testbench circuit
+*----------------------------
+Rtest vdda mir1 1MEG
+Xm1 mir1 vin vss vss sky130_fd_pr__nfet_g5v0d10v5 w=2 l=0.8
+
+Vgate vin vss DC=0
+Vpwr vdda vss DC=3.3
+Rgnd vss 0 0.1
+
+*----------------------------
+* Testbench control
+*----------------------------
+.control
+* DC sweep from 0.7 to 0.8V
+dc Vgate 0.7 0.8 0.001
+wrdata test.data Vpwr#branch vin
+
+.endc
+
+.end
+
diff --git a/scripts/scripts/compositor.py b/scripts/scripts/compositor.py
new file mode 100755
index 0000000..ec48636
--- /dev/null
+++ b/scripts/scripts/compositor.py
@@ -0,0 +1,133 @@
+#!/bin/env python3
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+#
+# compositor.py ---
+#
+#    Compose the final GDS for caravel from the caravel GDS, seal ring
+#    GDS, and fill GDS.
+#
+
+import sys
+import os
+import re
+import subprocess
+
+def usage():
+    print("compositor.py [layout_name] [-keep]")
+    return 0
+
+if __name__ == '__main__':
+
+    if len(sys.argv) == 1:
+        usage()
+        sys.exit(0)
+
+    optionlist = []
+    arguments = []
+
+    debugmode = False
+    keepmode = False
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            optionlist.append(option)
+        else:
+            arguments.append(option)
+
+    if len(arguments) > 1:
+        print("Wrong number of arguments given to compositor.py.")
+        usage()
+        sys.exit(0)
+
+    if len(arguments) == 1:
+        project = arguments[0]
+    else:
+        project = 'caravel'
+
+    if '-debug' in optionlist:
+        debugmode = True
+    if '-keep' in optionlist:
+        keepmode = True
+
+    magdir = '../mag'
+    rcfile = magdir + '/.magicrc'
+
+    with open(magdir + '/compose_final.tcl', 'w') as ofile:
+        print('#!/bin/env wish', file=ofile)
+        print('drc off', file=ofile)
+
+        print('load ' + project + ' -dereference', file=ofile)
+        print('select top cell', file=ofile)
+
+        # Ceate a cell to represent the generated fill.  There are
+        # no magic layers corresponding to the fill shape data, and
+        # it's gigabytes anyway, so we don't want to deal with any
+        # actual data.  So it's just a placeholder.
+
+        print('set bbox [box values]', file=ofile)
+        print('load ' + project + '_fill_pattern', file=ofile)
+        print('snap internal', file=ofile)
+        print('box values {*}$bbox', file=ofile)
+        print('paint comment', file=ofile)
+        print('property GDS_FILE ../gds/' + project + '_fill_pattern.gds', file=ofile)
+        print('property GDS_START 0', file=ofile)
+        print('property FIXED_BBOX "$bbox"', file=ofile)
+
+        # Now go back to the project top level and place the fill cell.
+        print('load ' + project, file=ofile)
+        print('select top cell', file=ofile)	
+        print('getcell ' + project + '_fill_pattern child 0 0', file=ofile)
+
+        # Move existing origin to (6um, 6um) for seal ring placement
+        print('move origin -6um -6um', file=ofile)
+
+        # Read in abstract view of seal ring
+        print('box position 0 0', file=ofile)
+        print('getcell advSeal_6um_gen', file=ofile)
+
+        # Generate final GDS
+        print('puts stdout "Writing final GDS. . . "', file=ofile)
+        print('flush stdout', file=ofile)
+        print('gds write ../gds/' + project + '_final.gds', file=ofile)
+        print('quit -noprompt', file=ofile)
+
+    myenv = os.environ.copy()
+    # Abstract views are appropriate for final composition
+    myenv['MAGTYPE'] = 'maglef'
+
+    mproc = subprocess.run(['magic', '-dnull', '-noconsole',
+		'-rcfile', rcfile, magdir + '/compose_final.tcl'],
+		stdin = subprocess.DEVNULL,
+		stdout = subprocess.PIPE,
+		stderr = subprocess.PIPE,
+		cwd = magdir,
+		env = myenv,
+		universal_newlines = True)
+    if mproc.stdout:
+        for line in mproc.stdout.splitlines():
+            print(line)
+    if mproc.stderr:
+        print('Error message output from magic:')
+        for line in mproc.stderr.splitlines():
+            print(line)
+        if mproc.returncode != 0:
+            print('ERROR:  Magic exited with status ' + str(mproc.returncode))
+
+    if not keepmode:
+        os.remove(magdir + '/compose_final.tcl')
+
+    exit(0)
diff --git a/scripts/scripts/generate_fill.py b/scripts/scripts/generate_fill.py
new file mode 100755
index 0000000..6b4cbcd
--- /dev/null
+++ b/scripts/scripts/generate_fill.py
@@ -0,0 +1,111 @@
+#!/bin/env python3
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+#
+# generate_fill.py ---
+#
+#    Run the fill generation on the caravel top level.
+#
+
+import sys
+import os
+import re
+import subprocess
+
+def usage():
+    print("generate_fill.py [layout_name] [-keep]")
+    return 0
+
+if __name__ == '__main__':
+
+    if len(sys.argv) == 1:
+        usage()
+        sys.exit(0)
+
+    optionlist = []
+    arguments = []
+
+    debugmode = False
+    keepmode = False
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            optionlist.append(option)
+        else:
+            arguments.append(option)
+
+    if len(arguments) > 1:
+        print("Wrong number of arguments given to generate_fill.py.")
+        usage()
+        sys.exit(0)
+
+    if len(arguments) == 1:
+        project = arguments[0]
+    else:
+        project = 'caravel'
+
+    if '-debug' in optionlist:
+        debugmode = True
+    if '-keep' in optionlist:
+        keepmode = True
+
+    magdir = '../mag'
+    rcfile = magdir + '/.magicrc'
+
+    with open(magdir + '/generate_fill.tcl', 'w') as ofile:
+        print('#!/bin/env wish', file=ofile)
+        print('drc off', file=ofile)
+        print('load ' + project + ' -dereference', file=ofile)
+        print('select top cell', file=ofile)
+        print('expand', file=ofile)
+
+        # Flatten into a cell with a new name
+        print('puts stdout "Flattening layout. . . "', file=ofile)
+        print('flatten -nolabels ' + project + '_fill_pattern', file=ofile)
+        print('load ' + project + '_fill_pattern', file=ofile)
+
+        # Remove any GDS_FILE reference
+        print('property GDS_FILE ""', file=ofile)
+        print('cif ostyle wafflefill', file=ofile)
+        print('puts stdout "Writing GDS. . . "', file=ofile)
+        print('gds write ../gds/' + project + '_fill_pattern.gds', file=ofile)
+        print('quit -noprompt', file=ofile)
+
+    myenv = os.environ.copy()
+    myenv['MAGTYPE'] = 'mag'
+
+    mproc = subprocess.run(['magic', '-dnull', '-noconsole',
+		'-rcfile', rcfile, magdir + '/generate_fill.tcl'],
+		stdin = subprocess.DEVNULL,
+		stdout = subprocess.PIPE,
+		stderr = subprocess.PIPE,
+		cwd = magdir,
+		env = myenv,
+		universal_newlines = True)
+    if mproc.stdout:
+        for line in mproc.stdout.splitlines():
+            print(line)
+    if mproc.stderr:
+        print('Error message output from magic:')
+        for line in mproc.stderr.splitlines():
+            print(line)
+        if mproc.returncode != 0:
+            print('ERROR:  Magic exited with status ' + str(mproc.returncode))
+
+    if not keepmode:
+        os.remove(magdir + '/generate_fill.tcl')
+
+    exit(0)
diff --git a/scripts/scripts/set_user_id.py b/scripts/scripts/set_user_id.py
new file mode 100755
index 0000000..3975354
--- /dev/null
+++ b/scripts/scripts/set_user_id.py
@@ -0,0 +1,224 @@
+#!/bin/env python3
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+#
+# set_user_id.py ---
+#
+# Manipulate the magic database, GDS, and verilog source files for the
+# user_id_programming block to set the user ID number.
+#
+# The user ID number is a 32-bit value that is passed to this routine
+# as an integer.
+#
+# user_id_programming layout map:
+# Positions marked (in microns) for value = 0.  For value = 1, move
+# the via 0.92um to the left.
+#
+# Layout grid is 0.46um x 0.34um with half-pitch offset (0.23um, 0.17um)
+#
+# Signal        Via position (um)
+# name		X      Y     
+#--------------------------------
+# mask_rev[0]   14.49  9.35
+# mask_rev[1]	16.33  9.35
+# mask_rev[2]	10.35 20.23
+# mask_rev[3]	 8.05  9.35
+# mask_rev[4]	28.29  9.35
+# mask_rev[5]	21.85 25.67
+# mask_rev[6]	 8.05 20.23
+# mask_rev[7]   20.47  9.35
+# mask_rev[8]   17.25 17.85
+# mask_rev[9]   25.53 12.07
+# mask_rev[10]  22.31 20.23
+# mask_rev[11]  13.11  9.35
+# mask_rev[12]	23.69 23.29
+# mask_rev[13]	24.15 12.07
+# mask_rev[14]	13.57 17.85
+# mask_rev[15]	23.23  6.97
+# mask_rev[16]	24.15 17.85
+# mask_rev[17]	 8.51 17.85
+# mask_rev[18]	23.69 20.23
+# mask_rev[19]	10.81 23.29
+# mask_rev[20]	14.95  6.97
+# mask_rev[21]	18.17 23.29
+# mask_rev[22]	21.39 17.85
+# mask_rev[23]	26.45 25.67
+# mask_rev[24]	 9.89 17.85
+# mask_rev[25]	15.87 17.85
+# mask_rev[26]	26.45 17.85
+# mask_rev[27]	 8.51  6.97
+# mask_rev[28]	10.81  9.35
+# mask_rev[29]	27.83 20.23
+# mask_rev[30]	16.33 23.29
+# mask_rev[31]	 8.05 14.79
+#--------------------------------
+
+import os
+import sys
+import re
+
+def usage():
+    print("set_user_id.py <user_id_value> [<path_to_project>]")
+    return 0
+
+if __name__ == '__main__':
+
+    # Coordinate pairs in microns for the zero position on each bit
+    mask_rev = (
+	(14.49,  9.35), (16.33,  9.35), (10.35, 20.23), ( 8.05,  9.35),
+	(28.29,  9.35), (21.85, 25.67), ( 8.05, 20.23), (20.47,  9.35),
+	(17.25, 17.85), (25.53, 12.07), (22.31, 20.23), (13.11,  9.35),
+	(23.69, 23.29), (24.15, 12.07), (13.57, 17.85), (23.23,  6.97),
+	(24.15, 17.85), ( 8.51, 17.85), (23.69, 20.23), (10.81, 23.29),
+	(14.95,  6.97), (18.17, 23.29), (21.39, 17.85), (26.45, 25.67),
+	( 9.89, 17.85), (15.87, 17.85), (26.45, 17.85), ( 8.51,  6.97),
+	(10.81,  9.35), (27.83, 20.23), (16.33, 23.29), ( 8.05, 14.79));
+
+    optionlist = []
+    arguments = []
+
+    debugmode = False
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            optionlist.append(option)
+        else:
+            arguments.append(option)
+
+    if len(arguments) != 1 and len(arguments) != 2:
+        if len(arguments) != 0:
+            print("Wrong number of arguments given to cleanup_unref.py.")
+        usage()
+        sys.exit(0)
+
+    if '-debug' in optionlist:
+        debugmode = True
+
+    user_id_value = arguments[0]
+
+    # Convert to binary
+    user_id_bits = '{0:032b}'.format(int(user_id_value))
+
+    if len(arguments) == 2:
+        user_project_path = arguments[1]
+    else:
+        user_project_path = os.getcwd()
+
+    magpath = user_project_path + '/mag'
+    gdspath = user_project_path + '/gds'
+    vpath = user_project_path + '/verilog'
+    errors = 0 
+
+    if os.path.isdir(gdspath):
+
+        # Bytes leading up to via position are:
+        viarec = "00 06 0d 02 00 43 00 06 0e 02 00 2c 00 2c 10 03 "
+        viabytes = bytes.fromhex(viarec)
+
+        # Read the GDS file.  If a backup was made of the zero-value
+        # program, then use it.
+
+        gdsbak = gdspath + '/user_id_prog_zero.gds'
+        gdsfile = gdspath + '/user_id_programming.gds'
+
+        if os.path.isfile(gdsbak):
+            with open(gdsbak, 'rb') as ifile:
+                gdsdata = ifile.read()
+        else:
+            with open(gdsfile, 'rb') as ifile:
+                gdsdata = ifile.read()
+
+        for i in range(0,32):
+            # Ignore any zero bits.
+            if user_id_bits[i] == '0':
+                continue
+
+            coords = mask_rev[i]
+            xum = coords[0]
+            yum = coords[1]
+
+            # Contact is 0.17 x 0.17, so add and subtract 0.085 to get
+            # the corner positions.
+
+            xllum = xum - 0.085
+            yllum = yum - 0.085
+            xurum = xum + 0.085
+            yurum = yum + 0.085
+ 
+            # Get the 4-byte hex values for the corner coordinates
+            xllnm = round(xllum * 1000)
+            yllnm = round(yllum * 1000)
+            xllhex = '{0:08x}'.format(xllnm)
+            yllhex = '{0:08x}'.format(yllnm)
+            xurnm = round(xurum * 1000)
+            yurnm = round(yurum * 1000)
+            xurhex = '{0:08x}'.format(xurnm)
+            yurhex = '{0:08x}'.format(yurnm)
+
+            # Magic's GDS output for vias always starts at the lower left
+            # corner and goes counterclockwise, repeating the first point.
+            viaoldposdata = viarec + xllhex + yllhex + xurhex + yllhex
+            viaoldposdata += xurhex + yurhex + xllhex + yurhex + xllhex + yllhex
+            
+            # For "one" bits, the X position is moved 0.92 microns to the left
+            newxllum = xllum - 0.92
+            newxurum = xurum - 0.92
+
+            # Get the 4-byte hex values for the new corner coordinates
+            newxllnm = round(newxllum * 1000)
+            newxllhex = '{0:08x}'.format(newxllnm)
+            newxurnm = round(newxurum * 1000)
+            newxurhex = '{0:08x}'.format(newxurnm)
+
+            vianewposdata = viarec + newxllhex + yllhex + newxurhex + yllhex
+            vianewposdata += newxurhex + yurhex + newxllhex + yurhex + newxllhex + yllhex
+
+            # Diagnostic
+            if debugmode:
+                print('Bit ' + str(i) + ':')
+                print('Via position ({0:3.2f}, {1:3.2f}) to ({2:3.2f}, {3:3.2f})'.format(xllum, yllum, xurum, yurum))
+                print('Old hex string = ' + viaoldposdata)
+                print('New hex string = ' + vianewposdata)
+
+            # Convert hex strings to byte arrays
+            viaoldbytedata = bytearray.fromhex(viaoldposdata)
+            vianewbytedata = bytearray.fromhex(vianewposdata)
+
+            # Replace the old data with the new
+            if viaoldbytedata not in gdsdata:
+                print('Error: via not found for bit position ' + str(i))
+                errors += 1 
+            else:
+                gdsdata = gdsdata.replace(viaoldbytedata, vianewbytedata)
+
+        if errors == 0:
+            # Keep a copy of the original 
+            if not os.path.isfile(gdsbak):
+                os.rename(gdsfile, gdsbak)
+
+            with open(gdsfile, 'wb') as ofile:
+                ofile.write(gdsdata)
+
+            print('Done!')
+            
+        else:
+            print('There were errors in processing.  No file written.')
+            sys.exit(1)
+
+    else:
+        print('No directory ' + gdspath + ' found.')
+        sys.exit(1)
+    sys.exit(0)
diff --git a/utils/utils/MAGIC.txt b/utils/utils/MAGIC.txt
new file mode 100644
index 0000000..78b4d56
--- /dev/null
+++ b/utils/utils/MAGIC.txt
@@ -0,0 +1,31 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+####
+
+1) You must set the PDK_ROOT variable
+
+export PDK_ROOT=~/foss/pdks/open_pdks/sky130;
+export PDKPATH=$PDK_ROOT/sky130A ;
+
+2) Useful misc utils
+
+
+
+load caravel -dereference
+drc style drc(full)
+drc why
+drc find 10 ; findbox zoom
diff --git a/utils/utils/README.txt b/utils/utils/README.txt
new file mode 100644
index 0000000..78b4d56
--- /dev/null
+++ b/utils/utils/README.txt
@@ -0,0 +1,31 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+####
+
+1) You must set the PDK_ROOT variable
+
+export PDK_ROOT=~/foss/pdks/open_pdks/sky130;
+export PDKPATH=$PDK_ROOT/sky130A ;
+
+2) Useful misc utils
+
+
+
+load caravel -dereference
+drc style drc(full)
+drc why
+drc find 10 ; findbox zoom
diff --git a/utils/utils/addmpwseal.tcl b/utils/utils/addmpwseal.tcl
new file mode 100644
index 0000000..b562f93
--- /dev/null
+++ b/utils/utils/addmpwseal.tcl
@@ -0,0 +1,25 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+drc off
+gds readonly true
+gds rescale false
+gds read ../gds/sram_1rw1r_32_256_8_sky130_lp1.gds
+load ./caravel.mag
+select top cell
+move origin -7.165um -7.120um
+box position 0 0
+getcell advSeal_6um_gen
+gds write caravel.mpw.gds
diff --git a/utils/utils/core_scripts/README.md b/utils/utils/core_scripts/README.md
new file mode 100644
index 0000000..b14c1db
--- /dev/null
+++ b/utils/utils/core_scripts/README.md
@@ -0,0 +1,20 @@
+<!---
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+-->
+# What is this?
+
+Core scripts are doing the actual work, scripts under ../scripts are the ones that should be used.
\ No newline at end of file
diff --git a/utils/utils/core_scripts/magic-drc.sh b/utils/utils/core_scripts/magic-drc.sh
new file mode 100644
index 0000000..5f5068d
--- /dev/null
+++ b/utils/utils/core_scripts/magic-drc.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+# To call: ./magic-drc.sh <target_path> <design_name> <pdk-root> <target-type> <pdk-name> <output_path>
+
+export TARGET_DIR=$1
+export DESIGN_NAME=$2
+export PDK_ROOT=$3
+export TARGET_TYPE=$4
+export PDK=$5
+export OUT_DIR=$6
+export TCL_CALL_PATH=${7:-$(pwd)}
+
+echo "Running Magic..."
+export MAGIC_MAGICRC=$PDK_ROOT/$PDK/libs.tech/magic/sky130A.magicrc
+
+magic \
+    -noconsole \
+    -dnull \
+    -rcfile $MAGIC_MAGICRC \
+    $TCL_CALL_PATH/magic-drc.tcl \
+    </dev/null \
+    |& tee $OUT_DIR/magic_drc.log
+
+TEST=$OUT_DIR/$DESIGN_NAME.magic.drc
+
+crashSignal=$(find $TEST)
+if ! [[ $crashSignal ]]; then echo "DRC Check FAILED"; exit -1; fi
+
+
+Test_Magic_violations=$(grep "COUNT: " $TEST -s | tail -1 | sed -r 's/[^0-9]*//g')
+if ! [[ $Test_Magic_violations ]]; then Test_Magic_violations=-1; fi
+if [ $Test_Magic_violations -ne -1 ]; then Test_Magic_violations=$(((Test_Magic_violations+3)/4)); fi
+
+echo "Test # of DRC Violations:"
+echo $Test_Magic_violations
+
+if [ 0 -ne $Test_Magic_violations ]; then echo "DRC Check FAILED"; exit -1; fi
+
+echo "DRC Check Passed"
+exit 0
diff --git a/utils/utils/core_scripts/magic-drc.tcl b/utils/utils/core_scripts/magic-drc.tcl
new file mode 100755
index 0000000..6768d3c
--- /dev/null
+++ b/utils/utils/core_scripts/magic-drc.tcl
@@ -0,0 +1,74 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+if { $::env(TARGET_TYPE) == "gds"} {
+	gds read $::env(TARGET_DIR)/$::env(DESIGN_NAME).gds
+} else {
+	if { $::env(TARGET_TYPE) == "mag" } {
+		load $::env(TARGET_DIR)/$::env(DESIGN_NAME).mag
+	} else {
+		def read $::env(TARGET_DIR)/$::env(DESIGN_NAME).def
+	}
+}
+
+set fout [open $::env(OUT_DIR)/$::env(DESIGN_NAME).magic.drc w]
+set oscale [cif scale out]
+set cell_name $::env(DESIGN_NAME)
+magic::suspendall
+puts stdout "\[INFO\]: Loading $cell_name\n"
+flush stdout
+load $cell_name
+select top cell
+drc euclidean on
+drc style drc(full)
+drc check
+set drcresult [drc listall why]
+
+
+set count 0
+puts $fout "$cell_name"
+puts $fout "----------------------------------------"
+foreach {errtype coordlist} $drcresult {
+	puts $fout $errtype
+	puts $fout "----------------------------------------"
+	foreach coord $coordlist {
+	    set bllx [expr {$oscale * [lindex $coord 0]}]
+	    set blly [expr {$oscale * [lindex $coord 1]}]
+	    set burx [expr {$oscale * [lindex $coord 2]}]
+	    set bury [expr {$oscale * [lindex $coord 3]}]
+	    set coords [format " %.3f %.3f %.3f %.3f" $bllx $blly $burx $bury]
+	    puts $fout "$coords"
+	    set count [expr {$count + 1} ]
+	}
+	puts $fout "----------------------------------------"
+}
+
+puts $fout "\[INFO\]: COUNT: $count"
+puts $fout "\[INFO\]: Should be divided by 3 or 4"
+
+puts $fout ""
+close $fout
+
+puts stdout "\[INFO\]: COUNT: $count"
+puts stdout "\[INFO\]: Should be divided by 3 or 4"
+puts stdout "\[INFO\]: DRC Checking DONE ($::env(OUT_DIR)/$::env(DESIGN_NAME).magic.drc)"
+flush stdout
+
+puts stdout "\[INFO\]: Saving mag view with DRC errors($::env(OUT_DIR)/$::env(DESIGN_NAME).magic.drc.mag)"
+# WARNING: changes the name of the cell; keep as last step
+save $::env(OUT_DIR)/$::env(DESIGN_NAME).magic.drc.mag
+puts stdout "\[INFO\]: Saved"
+
+exit 0
diff --git a/utils/utils/core_scripts/magic-ext.sh b/utils/utils/core_scripts/magic-ext.sh
new file mode 100644
index 0000000..68bfc39
--- /dev/null
+++ b/utils/utils/core_scripts/magic-ext.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+# To call: ./magic-ext.sh <target_path> <design_name> <pdk-root> <target-type> <pdk-name> <output_path>
+
+export TARGET_DIR=$1
+export DESIGN_NAME=$2
+export PDK_ROOT=$3
+export TARGET_TYPE=$4
+export PDK=$5
+export OUT_DIR=$6
+export TCL_CALL_PATH=${7:-$(pwd)}
+
+echo "Running Magic..."
+export MAGIC_MAGICRC=$PDK_ROOT/$PDK/libs.tech/magic/sky130A.magicrc
+
+magic \
+    -noconsole \
+    -dnull \
+    -rcfile $MAGIC_MAGICRC \
+    $TCL_CALL_PATH/magic-ext.tcl \
+    </dev/null \
+    |& tee $OUT_DIR/magic_ext.log
diff --git a/utils/utils/core_scripts/magic-ext.tcl b/utils/utils/core_scripts/magic-ext.tcl
new file mode 100644
index 0000000..5a05dcb
--- /dev/null
+++ b/utils/utils/core_scripts/magic-ext.tcl
@@ -0,0 +1,44 @@
+#!/usr/bin/tclsh
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+puts "Performing Spice Extractions..."
+
+if { ![file isdirectory $::env(OUT_DIR)] } {
+	exec mkdir $::env(OUT_DIR)/
+}
+
+
+if { $::env(TARGET_TYPE) == "gds"} {
+	gds read $::env(TARGET_DIR)/$::env(DESIGN_NAME).gds
+} else {
+	if { $::env(TARGET_TYPE) == "mag" } {
+		load $::env(TARGET_DIR)/$::env(DESIGN_NAME).mag
+	} else {
+		def read $::env(TARGET_DIR)/$::env(DESIGN_NAME).def
+	}
+}
+
+load $::env(DESIGN_NAME) -dereference
+cd $::env(OUT_DIR)/
+extract do local
+# extract warn all
+extract
+ext2spice lvs
+ext2spice $::env(DESIGN_NAME).ext
+feedback save $::env(OUT_DIR)/magic_extraction_feedback.txt
+
+puts "Done!"
\ No newline at end of file
diff --git a/utils/utils/drc-def-sky130A.sh b/utils/utils/drc-def-sky130A.sh
new file mode 100644
index 0000000..671b14a
--- /dev/null
+++ b/utils/utils/drc-def-sky130A.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+# To call: ./drc-def-sky130A.sh <target_path> <design_name> <pdk-root> [<output_path> default is <target_path>/results/]
+
+export TARGET_DIR=$1
+export DESIGN_NAME=$2
+export PDK_ROOT=$3
+export OUT_DIR=${4:-$TARGET_DIR/results/}
+export TCL_CALL_PATH=$(pwd)/core_scripts
+
+if ! [[ -d "$OUT_DIR" ]]
+then
+    mkdir $OUT_DIR
+fi
+bash ./core_scripts/magic-drc.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "def" "sky130A" $OUT_DIR $TCL_CALL_PATH
diff --git a/utils/utils/drc-gds-sky130A.sh b/utils/utils/drc-gds-sky130A.sh
new file mode 100644
index 0000000..4c1d6d8
--- /dev/null
+++ b/utils/utils/drc-gds-sky130A.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+# To call: ./drc-gds-sky130A.sh <target_path> <design_name> <pdk-root> [<output_path> default is <target_path>/results/]
+
+export TARGET_DIR=$1
+export DESIGN_NAME=$2
+export PDK_ROOT=$3
+export OUT_DIR=${4:-$TARGET_DIR/results/}
+export TCL_CALL_PATH=$(pwd)/core_scripts
+
+if ! [[ -d "$OUT_DIR" ]]
+then
+    mkdir $OUT_DIR
+fi
+
+bash ./core_scripts/magic-drc.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "gds" "sky130A" $OUT_DIR $TCL_CALL_PATH
diff --git a/utils/utils/drc-mag-sky130A.sh b/utils/utils/drc-mag-sky130A.sh
new file mode 100644
index 0000000..2bbecd3
--- /dev/null
+++ b/utils/utils/drc-mag-sky130A.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+# To call: ./drc-mag-sky130A.sh <target_path> <design_name> <pdk-root> [<output_path> default is <target_path>/results/]
+
+export TARGET_DIR=$1
+export DESIGN_NAME=$2
+export PDK_ROOT=$3
+export OUT_DIR=${4:-$TARGET_DIR/results/}
+export TCL_CALL_PATH=$(pwd)/core_scripts
+
+if ! [[ -d "$OUT_DIR" ]]
+then
+    mkdir $OUT_DIR
+fi
+bash ./core_scripts/magic-drc.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "mag" "sky130A" $OUT_DIR $TCL_CALL_PATH
diff --git a/utils/utils/examples/README.md b/utils/utils/examples/README.md
new file mode 100644
index 0000000..10f7a37
--- /dev/null
+++ b/utils/utils/examples/README.md
@@ -0,0 +1,19 @@
+<!---
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+-->
+This folder contains miscelleneous useful scripts
+THIS IS STILL WORK IN PROGRESSS - SUGGESTIONS ARE WELCOME THROUGH ISSUES
diff --git a/utils/utils/examples/addmpwseal.tcl b/utils/utils/examples/addmpwseal.tcl
new file mode 100644
index 0000000..79e4b9e
--- /dev/null
+++ b/utils/utils/examples/addmpwseal.tcl
@@ -0,0 +1,26 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+drc off
+gds readonly true
+gds read ../gds/sram_1rw1r_32_256_8_sky130_lp1.gds
+load openram_tc_1kb.mag
+select top cell
+move origin -1015um -1272.5um
+box position 0 0
+getcell advSeal_6um_gen
+save
+gds write ../gds/openram_tc_1kb.gds
+
diff --git a/utils/utils/examples/create-project.sh b/utils/utils/examples/create-project.sh
new file mode 100755
index 0000000..5b5b69c
--- /dev/null
+++ b/utils/utils/examples/create-project.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+cat <<'EOT' > .gitignore
+.DS_Store
+*.vcd
+*.raw
+*.vvp
+a.out
+EOT
+mkdir scripts		; echo "This folder contains miscelleneous useful scripts" > scripts/README.md 
+mkdir def		; echo "This folder contains *.def files related to this project" > def/README.md 
+mkdir gds		; echo "This folder contains *.gds files related to this project" > gds/README.md 
+mkdir verilog		; echo "This folder contains *.v   files related to this project" > verilog/README.md 
+mkdir mag		; echo "This folder contains *.mag files related to this project" > mag/README.md 
+mkdir lef		; echo "This folder contains *.lef files related to this project" > lef/README.md 
+mkdir macros		; echo "This folder contains subcell & macro files related to this project" > macros/README.md 
+mkdir doc		; echo "This folder contains documents related to this project" > doc/README.md 
+mkdir ngspice		; echo "This folder contains ngspice related files related to this project" > ngspice/README.md 
+mkdir openlane		; echo "This folder contains openlane related files related to this project" > openlane/README.md 
+mkdir pkg		; echo "This folder contains packaging-related files related to this project" > pkg/README.md
+mkdir test		; echo "This folder contains test-related files related to this project" > test/README.md
+mkdir xspice		; echo "This folder contains xspice files related to this project" > xspice/README.md
+mkdir spi		; echo "This folder contains *.spi files related to this project" > spi/README.md
+mkdir qflow		; echo "This folder contains qflow-related files related to this project" > qflow/README.md
diff --git a/utils/utils/examples/dot.magicrc b/utils/utils/examples/dot.magicrc
new file mode 100644
index 0000000..42f2fb2
--- /dev/null
+++ b/utils/utils/examples/dot.magicrc
@@ -0,0 +1,65 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+puts stdout "Sourcing design .magicrc for technology sky130A ..."
+
+# Put grid on 0.005 pitch.  This is important, as some commands don't
+# rescale the grid automatically (such as lef read?).
+
+set scalefac [tech lambda]
+if {[lindex $scalefac 1] < 2} {
+    scalegrid 1 2
+}
+
+# drc off
+drc euclidean on
+
+# default pdk 
+# set SW_PDK_ROOT "/ef/tech/SW.2"
+set PDK "sky130A"
+set SCL_VARIANT "sky130_fd_sc_hd"
+set IO_VARIANT "sky130_fd_io"
+set PDKPATH "$::env(SW_PDK_ROOT)/$PDK"
+
+# loading technology
+tech load "$PDKPATH/libs.tech/magic/current/$PDK.tech"
+
+# load device generator
+source "$PDKPATH/libs.tech/magic/current/$PDK.tcl"
+
+
+# load bind keys (optional)
+source "$PDKPATH/libs.tech/magic/current/$PDK-BindKeys"
+
+# set units to lambda grid 
+snap lambda
+
+# add path to reference cells
+set MAGPATH "$PDKPATH/libs.ref/$SCL_VARIANT/mag/*.mag"
+
+
+addpath "$PDKPATH/libs.ref/sky130_fd_pr_base/mag"
+addpath "$PDKPATH/libs.ref/$IO_VARIANT/mag"
+addpath "$PDKPATH/libs.ref/$SCL_VARIANT/mag"
+
+# addpath ${MAGPATH}/s8fmlt
+
+# add path to GDS cells
+
+# add path to IP from catalog.  This procedure defined in the PDK script.
+catch {magic::query_mylib_ip}
+# add path to local IP from user design space.  Defined in the PDK script.
+catch {magic::query_my_projects}
diff --git a/utils/utils/examples/drc-mag.sh b/utils/utils/examples/drc-mag.sh
new file mode 100644
index 0000000..7229f45
--- /dev/null
+++ b/utils/utils/examples/drc-mag.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+export MAGTYPE=mag ;
+export BASE=/home/mk/zooz/ ;
+export PDKPATH=$BASE/pdks/ef-skywater-s8/EFS8A ;
+
+magic -dnull -noconsole -rcfile $PDKPATH/libs.tech/magic/current/EFS8A.magicrc <<EOF
+gds polygon subcell true
+gds warning default
+gds read $1.gds
+load $1
+cellname delete \(UNNAMED\)
+writeall force
+select top cell
+expand
+drc on
+drc euclidean on
+drc check
+drc catchup
+drc listall 
+drc listall why
+drc count total
+drc count
+quit -noprompt
+EOF
diff --git a/utils/utils/examples/drc-maglef.sh b/utils/utils/examples/drc-maglef.sh
new file mode 100644
index 0000000..42f622f
--- /dev/null
+++ b/utils/utils/examples/drc-maglef.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+export MAGTYPE=maglef ;
+export BASE=/home/mk/zooz/ ;
+export PDKPATH=$BASE/pdks/ef-skywater-s8/EFS8A ;
+
+magic -dnull -noconsole -rcfile $PDKPATH/libs.tech/magic/current/EFS8A.magicrc <<EOF
+gds polygon subcell true
+gds warning default
+gds read $1.gds
+load $1
+cellname delete \(UNNAMED\)
+writeall force
+select top cell
+expand
+drc on
+drc euclidean on
+drc check
+drc catchup
+drc listall 
+drc listall why
+drc count total
+drc count
+quit -noprompt
+EOF
diff --git a/utils/utils/examples/drc.sh b/utils/utils/examples/drc.sh
new file mode 100755
index 0000000..7229f45
--- /dev/null
+++ b/utils/utils/examples/drc.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+export MAGTYPE=mag ;
+export BASE=/home/mk/zooz/ ;
+export PDKPATH=$BASE/pdks/ef-skywater-s8/EFS8A ;
+
+magic -dnull -noconsole -rcfile $PDKPATH/libs.tech/magic/current/EFS8A.magicrc <<EOF
+gds polygon subcell true
+gds warning default
+gds read $1.gds
+load $1
+cellname delete \(UNNAMED\)
+writeall force
+select top cell
+expand
+drc on
+drc euclidean on
+drc check
+drc catchup
+drc listall 
+drc listall why
+drc count total
+drc count
+quit -noprompt
+EOF
diff --git a/utils/utils/examples/edit.tcl b/utils/utils/examples/edit.tcl
new file mode 100644
index 0000000..f1766ad
--- /dev/null
+++ b/utils/utils/examples/edit.tcl
@@ -0,0 +1,26 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+drc off
+puts "Small delay..."
+set macro_mags "digital_pll.mag lvlshiftdown.mag striVe2_soc.mag striVe_clkrst.mag striVe_spi.mag"
+
+gds readonly yes
+gds rescale no
+gds read ../gds/sram_1rw1r_32_256_8_sky130.gds
+lef read ../lef/sram.abs.lef
+foreach ff $macro_mags { drc off; load $ff -dereference; after 1000; select top cell; property LEFview TRUE }
+load striVe2 -dereference
+select top cell
diff --git a/utils/utils/examples/ext-gds.sh b/utils/utils/examples/ext-gds.sh
new file mode 100644
index 0000000..c3efd7e
--- /dev/null
+++ b/utils/utils/examples/ext-gds.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+export MAGTYPE=maglef ;
+export BASE=/home/mk/zooz/ ;
+export PDKPATH=$BASE/pdks/ef-skywater-s8/EFS8A ;
+
+magic -dnull -noconsole -rcfile $PDKPATH/libs.tech/magic/current/EFS8A.magicrc <<EOF
+gds polygon subcell true
+gds warning default
+gds read $1.gds
+load $1.mag
+save $1.mag
+writeall force
+select top cell
+extract style ngspice(si)
+extract
+ext2spice hierarchy on
+ext2spice format ngspice
+ext2spice cthresh infinite
+ext2spice rthresh infinite
+ext2spice renumber offS
+ext2spice scale off
+ext2spice blackbox on
+ext2spice subcircuit top auto
+ext2spice global off
+ext2spice $1.ext
+quit -noprompt
+EOF
diff --git a/utils/utils/examples/ext-mag.sh b/utils/utils/examples/ext-mag.sh
new file mode 100644
index 0000000..a62a831
--- /dev/null
+++ b/utils/utils/examples/ext-mag.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+export MAGTYPE=mag ;
+export BASE=/home/mk/zooz/ ;
+export PDKPATH=$BASE/pdks/ef-skywater-s8/EFS8A ;
+
+magic -dnull -noconsole -rcfile $PDKPATH/libs.tech/magic/current/EFS8A.magicrc <<EOF
+load $1.mag
+save $1.mag
+writeall force
+select top cell
+extract style ngspice(si)
+extract
+ext2spice hierarchy on
+ext2spice format ngspice
+ext2spice cthresh infinite
+ext2spice rthresh infinite
+ext2spice renumber offS
+ext2spice scale off
+ext2spice blackbox on
+ext2spice subcircuit top auto
+ext2spice global off
+ext2spice $1.ext
+quit -noprompt
+EOF
diff --git a/utils/utils/examples/ext.sh b/utils/utils/examples/ext.sh
new file mode 100644
index 0000000..b414e8b
--- /dev/null
+++ b/utils/utils/examples/ext.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+export MAGTYPE=maglef ;
+export BASE=/home/mk/zooz/ ;
+export PDKPATH=$BASE/pdks/ef-skywater-s8/EFS8A ;
+
+magic -dnull -noconsole -rcfile $PDKPATH/libs.tech/magic/current/EFS8A.magicrc <<EOF
+gds polygon subcell true
+gds warning default
+gds read $1.gds
+load $1.mag
+save $1.mag
+writeall force
+select top cell
+extract style ngspice(si)
+extract
+ext2spice hierarchy on
+ext2spice format ngspice
+ext2spice cthresh infinite
+ext2spice rthresh infinite
+ext2spice renumber off
+ext2spice scale off
+ext2spice blackbox on
+ext2spice subcircuit top auto
+ext2spice global off
+ext2spice $1.ext
+quit -noprompt
+EOF
diff --git a/utils/utils/examples/extract.tcl b/utils/utils/examples/extract.tcl
new file mode 100644
index 0000000..a38c9cb
--- /dev/null
+++ b/utils/utils/examples/extract.tcl
@@ -0,0 +1,31 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+lef read $::env(PDKPATH)/libs.ref/techLEF/scs8hd/scs8hd_tech.lef
+set macro_mags "openram_tc_core.mag"
+
+# lef read ../lef/sram_1rw1r_32_256_8_sky130_lp1.lef
+
+foreach ff $macro_mags { drc off; after 500; load $ff -dereference; select top cell; property LEFview TRUE }
+
+load openram_tc_1kb -dereference
+
+select top cell
+extract do local
+extract
+ext2spice lvs
+ext2spice openram_tc_1kb.ext
+feedback save extract.tcl.log
+exit
diff --git a/utils/utils/examples/lvs.sh b/utils/utils/examples/lvs.sh
new file mode 100755
index 0000000..3a5043e
--- /dev/null
+++ b/utils/utils/examples/lvs.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+/ef/apps/bin/netgen -noconsole << EOF
+readnet spice $1.spice
+readnet spice $1.sp
+lvs {$1.spice sram_2_16_sky130} {sram_2_16_sky130.sp sram_2_16_sky130} setup.tcl sram_2_16_sky130.lvs.report
+quit
+EOF
diff --git a/utils/utils/examples/mag2gds.tcl b/utils/utils/examples/mag2gds.tcl
new file mode 100644
index 0000000..8d7057d
--- /dev/null
+++ b/utils/utils/examples/mag2gds.tcl
@@ -0,0 +1,33 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+# assumes an /ef tree or at least a symlink
+drc off
+gds readonly true
+gds rescale false
+set ::env(MAGTYPE) mag
+
+# gds read <hard macros read as-is.gds>
+gds read ../gds/sram_1rw1r_32_256_8_sky130_lp1.gds
+
+load sram_1rw1r_32_256_8_sky130 -dereference
+load openram_tc_core -dereference
+load openram_tc_1kb -dereference
+
+select top cell
+
+cif *hier write disable
+
+gds write openram_tc_1kb.gds
diff --git a/utils/utils/examples/magic_drc.tcl b/utils/utils/examples/magic_drc.tcl
new file mode 100755
index 0000000..554a4c6
--- /dev/null
+++ b/utils/utils/examples/magic_drc.tcl
@@ -0,0 +1,71 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+set ::env(DESIGN_NAME) openram_tc_1kb
+drc off
+lef read ../lef/sram_1rw1r_32_256_8_sky130_lp1.lef
+load sram_1rw1r_32_256_8_sky130 -dereference
+load openram_tc_core -dereference
+load openram_tc_1kb -dereference
+
+drc style drc(full)
+drc euclidean on
+
+set fout [open drc.log w]
+set oscale [cif scale out]
+set cell_name $::env(DESIGN_NAME)
+magic::suspendall
+puts stdout "\[INFO\]: Loading $cell_name\n"
+flush stdout
+load $cell_name
+select top cell
+drc check
+set drcresult [drc listall why]
+
+
+set count 0
+puts $fout "$cell_name"
+puts $fout "----------------------------------------"
+foreach {errtype coordlist} $drcresult {
+	puts $fout $errtype
+	puts $fout "----------------------------------------"
+	foreach coord $coordlist {
+	    set bllx [expr {$oscale * [lindex $coord 0]}]
+	    set blly [expr {$oscale * [lindex $coord 1]}]
+	    set burx [expr {$oscale * [lindex $coord 2]}]
+	    set bury [expr {$oscale * [lindex $coord 3]}]
+	    set coords [format " %.3f %.3f %.3f %.3f" $bllx $blly $burx $bury]
+	    puts $fout "$coords"
+	    set count [expr {$count + 1} ]
+	}
+	puts $fout "----------------------------------------"
+}
+
+puts $fout "\[INFO\]: COUNT: $count"
+puts $fout "\[INFO\]: Should be divided by 3 or 4"
+
+puts $fout ""
+close $fout
+
+puts stdout "\[INFO\]: COUNT: $count"
+puts stdout "\[INFO\]: Should be divided by 3 or 4"
+puts stdout "\[INFO\]: DRC Checking DONE ($::env(DESIGN_NAME).drc)"
+flush stdout
+
+puts stdout "\[INFO\]: Saving mag view with DRC errors($::env(DESIGN_NAME).drc.mag)"
+# WARNING: changes the name of the cell; keep as last step
+save $::env(DESIGN_NAME).drc.mag
+puts stdout "\[INFO\]: Saved"
+
+exit 0
diff --git a/utils/utils/examples/pfg.sh b/utils/utils/examples/pfg.sh
new file mode 100755
index 0000000..9d8def1
--- /dev/null
+++ b/utils/utils/examples/pfg.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+export PDKPATH=/home/mk/zooz/pdks/ef-skywater-s8/EFS8A
+export MAGTYPE=mag 
+
+padring \
+-L $PDKPATH/libs.ref/lef/s8iom0s8/s8iom0s8.lef \
+-L $PDKPATH/libs.ref/lef/s8iom0s8/power_pads_lib.lef \
+--def padframe.def padframe.cfg 
+
+magic -rcfile $PDKPATH/libs.tech/magic/current/EFS8A.magicrc -noc -dnull <<EOF
+def read padframe.def
+save padframe
+select top cell
+lef write padframe.lef
+gds write padframe.gds
+exit
+EOF
+
+
+
+
+
diff --git a/utils/utils/examples/run_openram_tc_1kb.sh b/utils/utils/examples/run_openram_tc_1kb.sh
new file mode 100755
index 0000000..408ce96
--- /dev/null
+++ b/utils/utils/examples/run_openram_tc_1kb.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+#
+# Run netgen on striVe (top level)
+#
+
+NETGEN_SETUP=$PDK_ROOT/EFS8A/libs.tech/netgen/EFS8A_setup.tcl
+
+netgen -batch lvs "../spi/openram_tc_1kb.spice openram_tc_1kb" "../verilog/gl/openram_tc_1kb.synthesis.v openram_tc_1kb" ${NETGEN_SETUP} openram_tc_1kb_comp.out -json | tee openram_tc_1kb_comp_lvs.log
diff --git a/utils/utils/examples/setup.tcl b/utils/utils/examples/setup.tcl
new file mode 100644
index 0000000..193dd2f
--- /dev/null
+++ b/utils/utils/examples/setup.tcl
@@ -0,0 +1,27 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+# We must flatten these because the ports are disconnected
+flatten class {-circuit1 dummy_cell_6t}
+flatten class {-circuit1 dummy_cell_1rw_1r}
+flatten class {-circuit1 dummy_cell_1w_1r}
+flatten class {-circuit1 bitcell_array_0}
+flatten class {-circuit1 pbitcell_0}
+flatten class {-circuit1 pbitcell_1}
+property {-circuit1 nshort} remove as ad ps pd
+property {-circuit1 pshort} remove as ad ps pd
+property {-circuit2 nshort} remove as ad ps pd
+property {-circuit2 pshort} remove as ad ps pd
+permute transistors
diff --git a/utils/utils/examples/wrap.tcl b/utils/utils/examples/wrap.tcl
new file mode 100644
index 0000000..fc2c87e
--- /dev/null
+++ b/utils/utils/examples/wrap.tcl
@@ -0,0 +1,28 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+drc off
+gds readonly yes
+gds rescale no
+
+gds read ../macros/sram/riscv-sky130/sram_1rw1r_32_256_8_sky130.gds
+load sram_1rw1r_32_256_8_sky130
+
+select top cell
+property LEFview "TRUE"
+
+save pk_sram_1rw1r_32_256_8_sky130.mag
+
+# exec sed -i -E "/^.*GDS_END.*$/d" sram_1rw1r_32_256_8_sky130_original.mag
diff --git a/utils/utils/examples/wrap2.tcl b/utils/utils/examples/wrap2.tcl
new file mode 100644
index 0000000..db1db3c
--- /dev/null
+++ b/utils/utils/examples/wrap2.tcl
@@ -0,0 +1,36 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+drc off
+gds readonly yes
+gds rescale no
+
+lef read ../lef/sram.abs.con.lef
+load sram_1rw1r_32_256_8_sky130
+
+select top cell
+expand
+property LEFview ""
+property LEFsymmetry ""
+property LEFclass ""
+
+box position 5um 5um
+getcell pk_sram_1rw1r_32_256_8_sky130
+
+save sram_1rw1r_32_256_8_sky130.mag
+
+gds write output.gds
+
+save
diff --git a/utils/utils/examples/xor.drc b/utils/utils/examples/xor.drc
new file mode 100644
index 0000000..14896ee
--- /dev/null
+++ b/utils/utils/examples/xor.drc
@@ -0,0 +1,42 @@
+# A general XOR script
+# (https://www.klayout.de/forum/discussion/100/xor-vs-diff-tool)
+# This script uses KLayout's DRC language to implement a generic
+# XOR between two layouts. The name of the layouts is given
+# in $a and $b.
+
+# For layout-to-layout XOR with multiple cores, run this script with
+#   ./klayout -r xor.drc -rd thr=NUM_CORES -rd top_cell=TOP_CELL_NAME -rd a=a.gds -rd b=b.gds -rd ol=xor.gds -zz
+# (replace NUM_CORES by the desired number of cores to utilize
+
+# enable timing output
+verbose
+
+# set up input a
+a = source($a, $top_cell)
+
+# set up input b
+b = source($b, $top_cell)
+
+$o && report("XOR #{$a} vs. #{$b}", $o)
+$ol && target($ol, $co || "XOR")
+
+$thr && threads($thr) || threads(2)
+
+# collect all common layers
+layers = {}
+[ a.layout, b.layout ].each do |ly|
+  ly.layer_indices.each do |li|
+    i = ly.get_info(li)
+    layers[i.to_s] = i
+  end
+end
+
+# perform the XOR's
+layers.keys.sort.each do |l|
+  i = layers[l]
+  info("--- Running XOR for #{l} ---")
+  x = a.input(l) ^ b.input(l)
+  info("XOR differences: #{x.data.size}")
+  $o && x.output(l, "XOR results for layer #{l}")
+  $ol && x.output(i.layer, i.datatype, i.name)
+end
diff --git a/utils/utils/examples/xor.sh b/utils/utils/examples/xor.sh
new file mode 100755
index 0000000..6911062
--- /dev/null
+++ b/utils/utils/examples/xor.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+: ${1?"Usage: $0 file1.gds file2.gds <top_level_module_name>"}
+: ${2?"Usage: $0 file1.gds file2.gds <top_level_module_name>"}
+: ${3?"Usage: $0 file1.gds file2.gds <top_level_module_name>"}
+
+klayout -r $(dirname $0)/xor.drc -rd top_cell=$3 -rd a=$1 -rd b=$2 -rd thr=$(nproc) -rd ol=xor.gds -zz
diff --git a/utils/utils/ext-def-sky130A.sh b/utils/utils/ext-def-sky130A.sh
new file mode 100644
index 0000000..51ec955
--- /dev/null
+++ b/utils/utils/ext-def-sky130A.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+# To call: ./ext-def-sky130A.sh <target_path> <design_name> <pdk-root> [<output_path> default is <target_path>/results/]
+
+export TARGET_DIR=$1
+export DESIGN_NAME=$2
+export PDK_ROOT=$3
+export OUT_DIR=${4:-$TARGET_DIR/results/}
+export TCL_CALL_PATH=$(pwd)/core_scripts
+
+if ! [[ -d "$OUT_DIR" ]]
+then
+    mkdir $OUT_DIR
+fi
+
+bash ./core_scripts/magic-ext.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "def" "sky130A" $OUT_DIR $TCL_CALL_PATH
diff --git a/utils/utils/ext-gds-sky130A.sh b/utils/utils/ext-gds-sky130A.sh
new file mode 100644
index 0000000..35071b8
--- /dev/null
+++ b/utils/utils/ext-gds-sky130A.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+# To call: ./ext-gds-sky130A.sh <target_path> <design_name> <pdk-root> [<output_path> default is <target_path>/results/]
+
+export TARGET_DIR=$1
+export DESIGN_NAME=$2
+export PDK_ROOT=$3
+export OUT_DIR=${4:-$TARGET_DIR/results/}
+export TCL_CALL_PATH=$(pwd)/core_scripts
+
+if ! [[ -d "$OUT_DIR" ]]
+then
+    mkdir $OUT_DIR
+fi
+
+bash ./core_scripts/magic-ext.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "gds" "sky130A" $OUT_DIR $TCL_CALL_PATH
diff --git a/utils/utils/ext-mag-sky130A.sh b/utils/utils/ext-mag-sky130A.sh
new file mode 100644
index 0000000..b57ec31
--- /dev/null
+++ b/utils/utils/ext-mag-sky130A.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+# To call: ./ext-mag-sky130A.sh <target_path> <design_name> <pdk-root> [<output_path> default is <target_path>/results/]
+
+export TARGET_DIR=$1
+export DESIGN_NAME=$2
+export PDK_ROOT=$3
+export OUT_DIR=${4:-$TARGET_DIR/results/}
+export TCL_CALL_PATH=$(pwd)/core_scripts
+
+if ! [[ -d "$OUT_DIR" ]]
+then
+    mkdir $OUT_DIR
+fi
+
+bash ./core_scripts/magic-ext.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "mag" "sky130A" $OUT_DIR $TCL_CALL_PATH
diff --git a/utils/utils/gds2mag-mag.local.sh b/utils/utils/gds2mag-mag.local.sh
new file mode 100755
index 0000000..110358b
--- /dev/null
+++ b/utils/utils/gds2mag-mag.local.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+export PDK_ROOT=~/foss/pdks/open_pdks/sky130;
+export MAGTYPE=mag ; 
+export PDKPATH=$PDK_ROOT/sky130A ;
+export MAGIC=magic
+
+
+$MAGIC  -dnull -noconsole << EOF
+#------------------------------------------------------
+drc off
+#---------------------------------gds polygon subcell true
+gds warning default
+gds readonly true
+gds rescale false
+#---------------------------------tech unlock *
+gds read $1
+load ${1%.gds}
+#---------------------------------readspice ${1%.gds}.sp
+cellname delete "(UNNAMED)"
+save ${1%.gds}.mag
+quit -noprompt
+EOF
diff --git a/utils/utils/gds2mag-mag.sh b/utils/utils/gds2mag-mag.sh
new file mode 100755
index 0000000..d53b156
--- /dev/null
+++ b/utils/utils/gds2mag-mag.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+export PDK_ROOT=~/foss/pdks/open_pdks/sky130;
+export MAGTYPE=mag ; 
+export PDKPATH=$PDK_ROOT/sky130A ;
+export MAGIC=magic
+
+
+$MAGIC -rcfile $PDKPATH/libs.tech/magic/current/sky130A.magicrc -dnull -noconsole << EOF
+#------------------------------------------------------
+drc off
+#---------------------------------gds polygon subcell true
+gds warning default
+gds readonly true
+gds rescale false
+#---------------------------------tech unlock *
+gds read $1
+load ${1%.gds}
+#---------------------------------readspice ${1%.gds}.sp
+cellname delete "(UNNAMED)"
+save ${1%.gds}.mag
+quit -noprompt
+EOF
diff --git a/utils/utils/lef2maglef.sh b/utils/utils/lef2maglef.sh
new file mode 100755
index 0000000..455c4a6
--- /dev/null
+++ b/utils/utils/lef2maglef.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+export PDK_ROOT=~/foss/pdks/open_pdks/sky130;
+export MAGTYPE=mag ; 
+export PDKPATH=$PDK_ROOT/sky130A ;
+export MAGIC=magic
+
+
+$MAGIC -rcfile $PDKPATH/libs.tech/magic/current/sky130A.magicrc -dnull -noconsole << EOX 
+drc off
+lef read $1.lef
+load $1
+save $1.lef.mag
+#writeall force $1.lef.mag
+
+		# copy GDS properties from the MAG view into the MAGLEF view
+		set gds_properties [list]
+		set fp [open $1.mag r]
+			set mag_lines [split [read \$fp] "\n"]
+			foreach line \$mag_lines {
+				if { [string first "string GDS_" \$line] != -1 } {
+					lappend gds_properties \$line
+				}
+			}
+		close \$fp
+		set fp [open $1.lef.mag r]
+			set mag_lines [split [read \$fp] "\n"]
+			set new_mag_lines [list]
+			foreach line \$mag_lines {
+				if { [string first "<< end >>" \$line] != -1 } {
+					lappend new_mag_lines [join \$gds_properties "\n"]
+				}
+				lappend new_mag_lines \$line
+			}
+		close \$fp
+		set fp [open $1.lef.mag w]
+			puts \$fp [join \$new_mag_lines "\n"]
+		close \$fp
+
+
+quit
+EOX
+
+mv -f $1.lef.mag ../maglef/$1.mag
+rm -f $1.lef
diff --git a/utils/utils/mag2maglef-mag.sh b/utils/utils/mag2maglef-mag.sh
new file mode 100755
index 0000000..2934887
--- /dev/null
+++ b/utils/utils/mag2maglef-mag.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+export PDK_ROOT=~/foss/pdks/open_pdks/sky130;
+export MAGTYPE=mag ; 
+export PDKPATH=$PDK_ROOT/sky130A ;
+export MAGIC=magic
+
+$MAGIC -rcfile $PDKPATH/libs.tech/magic/current/sky130A.magicrc -dnull -noconsole  <<EOF
+drc off
+load $1.mag
+select top cell
+expand
+lef write $1.lef -hide 
+quit -noprompt
+EOF
+
+$MAGIC -rcfile $PDKPATH/libs.tech/magic/current/sky130A.magicrc -dnull -noconsole << EOX 
+drc off
+lef read $1.lef
+load $1
+save $1.lef.mag
+#writeall force $1.lef.mag
+
+		# copy GDS properties from the MAG view into the MAGLEF view
+		set gds_properties [list]
+		set fp [open $1.mag r]
+			set mag_lines [split [read \$fp] "\n"]
+			foreach line \$mag_lines {
+				if { [string first "string GDS_" \$line] != -1 } {
+					lappend gds_properties \$line
+				}
+			}
+		close \$fp
+		set fp [open $1.lef.mag r]
+			set mag_lines [split [read \$fp] "\n"]
+			set new_mag_lines [list]
+			foreach line \$mag_lines {
+				if { [string first "<< end >>" \$line] != -1 } {
+					lappend new_mag_lines [join \$gds_properties "\n"]
+				}
+				lappend new_mag_lines \$line
+			}
+		close \$fp
+		set fp [open $1.lef.mag w]
+			puts \$fp [join \$new_mag_lines "\n"]
+		close \$fp
+
+
+quit
+EOX
+
+mv -f $1.lef.mag ../maglef/$1.mag
+rm -f $1.lef
diff --git a/utils/utils/mag2maglef-maglef.localrc.sh b/utils/utils/mag2maglef-maglef.localrc.sh
new file mode 100755
index 0000000..f167252
--- /dev/null
+++ b/utils/utils/mag2maglef-maglef.localrc.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+export PDK_ROOT=~/foss/pdks/open_pdks/sky130;
+export MAGTYPE=maglef ; 
+export PDKPATH=$PDK_ROOT/sky130A ;
+export MAGIC=magic
+
+$MAGIC -dnull -noconsole  <<EOF
+drc off
+load $1.mag
+select top cell
+expand
+lef write $1.lef -hide
+quit -noprompt
+EOF
+
+$MAGIC -dnull -noconsole << EOX 
+drc off
+lef read $1.lef
+load $1
+save $1.lef.mag
+#writeall force $1.lef.mag
+
+		# copy GDS properties from the MAG view into the MAGLEF view
+		set gds_properties [list]
+		set fp [open $1.mag r]
+			set mag_lines [split [read \$fp] "\n"]
+			foreach line \$mag_lines {
+				if { [string first "string GDS_" \$line] != -1 } {
+					lappend gds_properties \$line
+				}
+			}
+		close \$fp
+		set fp [open $1.lef.mag r]
+			set mag_lines [split [read \$fp] "\n"]
+			set new_mag_lines [list]
+			foreach line \$mag_lines {
+				if { [string first "<< end >>" \$line] != -1 } {
+					lappend new_mag_lines [join \$gds_properties "\n"]
+				}
+				lappend new_mag_lines \$line
+			}
+		close \$fp
+		set fp [open $1.lef.mag w]
+			puts \$fp [join \$new_mag_lines "\n"]
+		close \$fp
+
+
+quit
+EOX
+
+mv -f $1.lef.mag ../maglef/$1.mag
+rm -f $1.lef
diff --git a/utils/utils/mag2maglef-maglef.sh b/utils/utils/mag2maglef-maglef.sh
new file mode 100755
index 0000000..e70fbd3
--- /dev/null
+++ b/utils/utils/mag2maglef-maglef.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# SPDX-License-Identifier: Apache-2.0
+
+
+export PDK_ROOT=~/foss/pdks/open_pdks/sky130;
+export MAGTYPE=maglef ; 
+export PDKPATH=$PDK_ROOT/sky130A ;
+export MAGIC=magic
+
+$MAGIC -rcfile $PDKPATH/libs.tech/magic/current/sky130A.magicrc -dnull -noconsole  <<EOF
+drc off
+load $1.mag
+select top cell
+expand
+lef write $1.lef 
+quit -noprompt
+EOF
+
+$MAGIC -rcfile $PDKPATH/libs.tech/magic/current/sky130A.magicrc -dnull -noconsole << EOX 
+drc off
+lef read $1.lef
+load $1
+save $1.lef.mag
+#writeall force $1.lef.mag
+
+		# copy GDS properties from the MAG view into the MAGLEF view
+		set gds_properties [list]
+		set fp [open $1.mag r]
+			set mag_lines [split [read \$fp] "\n"]
+			foreach line \$mag_lines {
+				if { [string first "string GDS_" \$line] != -1 } {
+					lappend gds_properties \$line
+				}
+			}
+		close \$fp
+		set fp [open $1.lef.mag r]
+			set mag_lines [split [read \$fp] "\n"]
+			set new_mag_lines [list]
+			foreach line \$mag_lines {
+				if { [string first "<< end >>" \$line] != -1 } {
+					lappend new_mag_lines [join \$gds_properties "\n"]
+				}
+				lappend new_mag_lines \$line
+			}
+		close \$fp
+		set fp [open $1.lef.mag w]
+			puts \$fp [join \$new_mag_lines "\n"]
+		close \$fp
+
+
+quit
+EOX
+
+mv -f $1.lef.mag ../maglef/$1.mag
+rm -f $1.lef
diff --git a/utils/utils/magicDrc b/utils/utils/magicDrc
new file mode 100755
index 0000000..fa6f783
--- /dev/null
+++ b/utils/utils/magicDrc
@@ -0,0 +1,888 @@
+#!/bin/bash
+# SPDX-FileCopyrightText: 2015, 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (C) 2015, 2020 efabless Corporation. All Rights Reserved.
+# filter out most options, so magic Natively sees/handles *only* -T <file>.
+# for-bash\
+  declare -a C ; declare -a N ; export _CE= _NE= _M0=           ;\
+  for i in "$@" ; do _M0="$_M0${_M0:+ }\"${i//\"/\\\"}\""; done ;\
+  while getopts "NFT:S:l:P:" o; do                      \
+    : echo got "optchar $o, with optarg $OPTARG" ;\
+    case "$o" in S)                               \
+      C+=(-${o} "$OPTARG")                       ;\
+       continue ; esac                           ;\
+    case "$o" in P)                               \
+      C+=(-${o} "$OPTARG")                       ;\
+       continue ; esac                           ;\
+    case "$o" in F|N)                             \
+      C+=(-${o})                                 ;\
+       continue ; esac                           ;\
+    case "$o" in l)                               \
+      C+=(-${o} "$OPTARG")                       ;\
+       continue ; esac                           ;\
+    case "$o" in T)                               \
+      N+=(-${o} "$OPTARG")                       ;\
+       continue ; esac                           ;\
+  done                ;\
+  shift $((OPTIND-1)) ;\
+  for i in "${C[@]}" ; do _CE="$_CE${_CE:+ }\"${i//\"/\\\"}\""; done ;\
+  for i in "${N[@]}" ; do _NE="$_NE${_NE:+ }\"${i//\"/\\\"}\""; done ;\
+  exec magic -dnull -noconsole "${N[@]}" <"$0"
+# for-magic:
+# magicDrc: run magic-DRC in batch on a .mag file, tabulate/pareto the error counts.
+#
+# magicDrc [-T <techfilePath>] [-S <drcStyleName>] [-P <N> ] [-l FILE_NAME] <magFileName>
+#  -T name specific techfile (def .tech extension), passed to magic itself only, overrides tech implied by magFileName
+#  -S if given, changes from techfile's default drc style (perhaps "drc(fast)") to named style, for example: -S "drc(full)"
+#  -l if given, enumerates EVERY individual error bbox to the FILE_NAME
+#  -N if given, do Not use -dereference option of load for topcell (not available in older magics)
+#  -F flatten top cell in-memory only, not saved (experimental)
+#  -P do crude drc performance measurement. At top-cell, do 'drc find' <N> times and report time per call.
+#   Stdout will log a pareto of error type by count regardless.
+#
+# <magFileName>: names a .mag file, the toplevel of the hier. to DRC/pareto
+#
+# Normal magic init. files are STILL sourced: ~/.magicrc and either $CWD/.magicrc or $CWD/magic_setup.
+# (This would NOT happen if -rcfile magic cmd-line option were used).
+#
+# WARNING: Before 8.1.70, *.mag on cmd-line that was only found in cell search path set by .magicrc inits,
+# would FAIL to determine the default tech-file.
+#
+# rb@ef 2015-06-30 author
+# rb 2020-03-11 embed some library functions, to standalone from efabless-opengalaxy env, test via magic-8.2.194
+#
+# magic itself outputs following usage message though -rcfile doesn't appear to work (in some versions):
+#   Usage:  magic [-g gPort] [-d devType] [-m monType] [-i tabletPort] [-D] [-F objFile saveFile]
+#   [-T technology] [-rcfile startupFile | -norcfile][-noconsole] [-nowindow] [-wrapper] [file]
+#
+set Prog "magicDrc"
+
+set argv  [eval "list $env(_M0)"] ;# orig. mix of native plus custom args, for logging all args to script
+
+proc usage {args} {
+    if {[llength $args] > 0} {
+	puts "ERROR: ${::Prog}: [join $args]"
+    }
+    puts {usage: [ -T <techfilePath> ] [-S <drcStyleName>] [-N] [-l FILE_NAME] <magFileName>}
+    puts "  -T name specific techfile, passed to magic itself only, overrides tech implied by magFileName"
+    puts "  -S if given, changes from techfile's default drc style (perhaps \"drc(fast)\") to named style, for example: -S \"drc(full)\""
+    puts "  -l if given, enumerates EVERY individual error bbox to the FILE_NAME"
+    puts "  -N if given, do not use -dereference option of load for topcell (not available in older magics)"
+    puts "  Stdout will log a pareto of error type by count regardless."
+    puts ""
+    puts "  Recommend to run in dir with a ./.magicrc (or ./magic_setup) to configure magic's"
+    puts "  cell search path, thru addpath statements, to locate all cells."
+}
+
+# optionally hardcode library proc-s (part of site-wide extensions - always available - in context of efabless/open-galaxy)
+# This is to make the script more standalone from efabless environment; but these capabilities should be native to magic.
+
+if {[info command scratchWritable] == {}} {
+    puts "${::Prog}: hardcoding library proc-s..."
+# Replacement for 'cellname list exists CELLNAME', to fix ambiguity for cell "0".
+# For cell "0" test for membership in 'cellname list allcells'.
+#
+# Instead of returning 0 for (non-existent) and cellname for exists,
+# returns regular 0/1 instead for non-existent/exists.
+#
+# Therefore NOT direct replacement for uses of 'cellname list exists CELL'.
+# Requires code changes.
+proc cellnameExists {cell} {
+    expr {$cell ne "0" && [cellname list exists $cell] eq $cell ||
+	  $cell eq "0" && [lsearch -exact [cellname list allcells] $cell] > -1}
+}
+
+#
+# scratchWritable [-cleanup] [cellname1 ...] --
+#
+# Turn readonly cells writable in-memory, via redirect to scratch dir.
+# No cellname args: default is to process just all non-writable cells.
+# Explicit cellname arguments: ARE scatchified EVEN if ALREADY writable.
+# Limitation: Explicit named cell created in-mem, never saved, won't scratchify.
+# If just -cleanup: default is to only do cleanup: don't scratchify
+# any cells.
+#
+# -cleanup: Last scratch-dir, if any, and contents are deleted first.
+# No restoring old filepath of cells, save after cleanup will fail.
+#
+# Caller strongly recommended to first do: 'select top cell; expand'
+# to force whole hier. of a topcell to be loaded from disk into memory.
+#
+# This proc does not force expand cells. Before expanded, cells cannot be
+# checked whether writable, and cannot have filepath changed.
+#
+# For batch DRC, for 'drc listall count', every cell in-memory must
+# appear writable.  This is the work-around (caller to 1st ensure
+# hier. is loaded): Reset filepath of readonly cells to a scratch dir,
+# make a dummy/empty .mag in scratch dir for each cell. Change cell's
+# writeable flag.
+#
+# Skipped cells:
+# In all cases, cells are skipped if
+#   'cellname filepath' matches ::scratchWritableDir (already scratchified),
+# This proc does NOT try and force expand; it presumes caller forced an expand
+# thus cells are skipped if:
+#   'cellname filepath' is "default" (can mean not expanded yet, or created never saved),
+#   'cellname filepath' is <CELLNAME>.mag, indicates failed expand (unbound).
+# Note: when filepath gives "default" or <CELLNAME>.mag, the writeable check not meaningful.
+#
+# How to scratchify all in-memory cells (still subject to internal skipping):
+#     scratchWritable {*}[cellname list allcells]
+#
+# TODO: use a combo of filepath & flags likely can detect created in-mem,
+# and could redirect those too scratch dir if named explicitly.
+#
+# Side-effects:
+#   Runs zero or one subprocess, '/bin/mktemp -d' to make a scratch dir.
+#   Redirects where newly modified cells would be saved, if they ever are saved.
+#   Make's a scratch dir that needs to be cleaned-up.
+#   Leaves empty *.mag files in that scratch dir.
+#
+# Uses/requires proc cellnameExists.
+#
+# Same scratch-dir is reused if called multiple times, until next -cleanup.
+#
+# return value: list of cells not processed (skipped) for reasons cited above.
+# Non-existent cells are also skipped but not included in the return list.
+#
+if {![info exists ::scratchWritableDir]} {set ::scratchWritableDir {}}
+if {![info exists ::scratchWritableVerb]} {set ::scratchWritableVerb 0}
+proc scratchWritable {args} {
+    # parse -cleanup option
+    set clean [expr {[lindex $args 0] eq {-cleanup}}]
+    if {$clean} {
+	set args [lrange $args 1 end]
+    }
+
+    # If explicit cells given: don't limit to processing just readOnly cells.
+    set onlyReadonly [expr {$args == {}}]
+
+    # only if no -cleanup, does empty cell list imply all cells
+    set allcell [cellname list allcells]
+    if {!$clean && $args == {}} {
+	set args $allcell
+    }
+
+    # do cleanup
+    if {$clean} {
+	if {$::scratchWritableDir != {} && [file isdir $::scratchWritableDir]} {
+	    set files [glob -dir $::scratchWritableDir -- {*.ext} {*.mag}]
+	    lappend files $::scratchWritableDir
+	    if {$::scratchWritableVerb} {
+		puts "scratchWritable: running, file delete $files"
+	    }
+	    eval {file delete} $files
+	    set ::scratchWritableDir {}
+	}
+    }
+
+    # Filter out non-existent or unbound cells.
+    # Optionally filter already writable cells.
+    #
+    # Unbounds result from placements of cells that now don't exist:
+    # fail to expand.  This proc does not try and force expand; it
+    # presumes a forced expand was already done by caller (if caller
+    # wished).
+    #
+    # Referenced/used cells are initially unexpanded, not yet even located
+    # located in the search path, 'cellname filepath' returns "default".
+    # If expand fails (not found in search path), then 'cellname filepath'
+    # returns <CELLNAME>.mag, if expand worked, the directory containing
+    # the cell.
+    #
+    # If cell was 'cellname create' made, but never saved also "default".
+    # Such a cell is writable. So filter "default" and <CELLNAME>.mag.
+    set skipped {}
+    set ercell1 {}
+    set docells {}
+    foreach cell $args {
+	# filter (without recording as skipped) non-existent cells.
+	if {![cellnameExists $cell]} { continue }
+
+	# filepath = "default": unexpanded (not loaded from disk),
+	# or created in-mem and never saved (is writable already
+	# though flags won't say so): skip both.
+	# TODO: use a combo of filepath & flags likely can detect created in-mem,
+	# and might be able to redirect them too to scratch dir if named explicitly.
+	set tmppath [cellname list filepath $cell]
+	if {$tmppath eq "default"} {
+	    lappend skipped $cell
+	    continue
+	}
+
+	# flags not meaningful, until expanded or expand attempted.
+	# After expand attempt (filepath != "default"), and flags
+	# can now be used to determine cell unbound: not available.
+	set flags   [cellname list flags    $cell]
+	if {[lsearch -exact $flags available] < 0} {
+	    lappend ercell1 $cell
+	    continue
+	}
+
+	if {$onlyReadonly &&
+	    [cellname list writeable $cell] eq "writeable"} {
+	    lappend skipped $cell
+	    continue
+	}
+	lappend docells $cell
+    }
+
+    if {$::scratchWritableVerb} {
+	puts "scratchWritable: skipped cells: $skipped"
+    }
+    
+    # don't make a scratch dir if no work to do
+    if {$docells == {}} {
+	if {$::scratchWritableVerb} {
+	    puts "scratchWritable: scratch-directed 0 cells"
+	}
+	return $skipped
+    }
+
+    # make a scratch dir if needed
+    if {$::scratchWritableDir == {}} {
+	if {[catch {set dir [string trimright [exec /bin/mktemp -d]]} msg]} {
+	    error "ERROR: scratchWritable, '/bin/mktemp -d' failed, $msg"
+	}
+	if {![file isdir $dir] || ![file writable $dir]} {
+	    error "ERROR: scratchWritable, mktemp gave $dir, not a writable dir"
+	}
+	set ::scratchWritableDir $dir
+    }
+
+    set ercell2 {}
+    set okcell {}
+    set madef 0
+    foreach cell $docells {
+	# Relocate if needed: filepath doesn't already point to the scratch dir).
+	# 'cellname list filepath <cellNm>' -> appears to omit .mag extension,
+	# but disk-file needs the .mag in the path.
+	set trgr [file join $::scratchWritableDir "$cell"]      ;# expected "lookup" path
+	set trgw [file join $::scratchWritableDir "$cell.mag"]  ;# true "write" disk path
+	set src [cellname list filepath $cell]
+	if {[cellname list filepath $cell] ne $trgr && [cellname list filepath $cell] ne $trgw} {
+
+	    # make empty .mag for the cell
+	    if {[catch {set outmag [open $trgw w]} msg]} {
+		lappend ercell2 $cell
+		continue
+	    }
+	    incr madef
+	    close $outmag
+
+	    # relocate cell to new file
+	    cellname list filepath $cell $::scratchWritableDir
+	}
+
+	# make cell writable
+	cellname list writeable $cell true
+	lappend okcell $cell
+    }
+
+    if {$::scratchWritableVerb} {
+	puts "scratchWritable: scratch-directed $madef cells"
+    }
+    if {$ercell1 != {} || $ercell2 != {}} {
+	set pre "ERROR: scratchWritable, "
+	set msg {}
+	if {$ercell1 != {}} {
+	    lappend msg "$pre unbound cell(s): $ercell1"
+	}
+	if {$ercell2 != {}} {
+	    lappend msg "$pre failed to make .mag for cell(s): $ercell2"
+	}
+	error [join $msg "\n"]
+    }
+    set skipped
+} ;# end proc scratchWritable
+}
+
+# without top-level proc around bulk of script, intermediate error statements don't abort script.
+proc main {argv} {
+
+# process name-value pair options, if any
+set nbrErr 0
+set ndx 0
+set max [llength $argv]
+set extTechOpt {} ;# -T ...
+set enumFilel  {} ;# -l ... enum output file
+set variant {}    ;# -S ... non-default drc style
+set flatten 0
+set perfN   0     ;# -P <N> do crude DRC perf. test
+set noderef 0     ;# -N disable dereference option of: 'load ... -dereference'
+
+while {$ndx < $max && [string match "-*" [lindex $argv $ndx]]} {
+    set opt [lindex $argv $ndx]
+    incr ndx
+    switch -exact -- $opt {
+	-T {
+	    if {$ndx == $max} {
+		usage "missing tech-file argument for -T option"
+		exit 1
+	    }
+	    set extTechOpt [lindex $argv $ndx]
+	    incr ndx
+	}
+	-S {
+	    if {$ndx == $max} {
+		usage "missing drcStyle argument for -S option"
+		exit 1
+	    }
+	    set variant [lindex $argv $ndx]
+	    incr ndx
+	}
+	-P {
+	    if {$ndx == $max} {
+		usage "missing count argument for -P option"
+		exit 1
+	    }
+	    set perfN [lindex $argv $ndx]
+	    incr ndx
+	}
+	-F {
+	    set flatten 1
+	}
+	-N {
+	    set noderef 1
+	}
+	-l {
+	    if {$ndx == $max} {
+		usage "missing outputFile argument for -l option"
+		exit 1
+	    }
+	    set enumFilel [lindex $argv $ndx]
+	    incr ndx
+	    if {[catch {set enumOut [open $enumFilel w]} msg]} {
+		error "ERROR: ${::Prog}: failed to open-for-write '$enumFilel' threw error, $msg"
+	    }
+	    puts "${::Prog}: enumerating each error bbox to: $enumFilel"
+	}
+	default {
+	    usage "unknown option: $opt"
+	    exit 1
+	}
+    }
+}
+
+if {$ndx == $max} {
+    usage "missing magFileName argument, the topcell"
+    exit 1
+}
+
+# get cmd-line topcell, minus dir-path; and minus extension IFF ext is .mag
+set topc [file tail [lindex $argv $ndx]] ; incr ndx
+if {[file extension $topc] eq ".mag"} {
+    set topc [file rootname $topc]
+}
+set topcStr $topc
+
+# abort if user supplies extra args.
+if {$ndx != $max} {
+    usage "extra/unspported arg past magFileName, '[lindex $argv $ndx]'"
+    exit 1
+}
+
+# load the techfile
+if {$extTechOpt != ""} {
+    if {![file readable $extTechOpt]} {
+	error "ERROR: ${::Prog}: tech-file \"$extTechOpt\" is not readable."
+    }
+
+    tech load $extTechOpt
+    
+    # Verify the cmd-line -T option (if any) is still the current 'tech filename'. If we didn't
+    # explicitly 'tech load' ourselves, the .magicrc or magic.setup might 'tech load' something else.
+    # The 'file join [pwd] ...' makes relative path absolute, but without resolving
+    # all symlinks (which 'file normalize' would do).
+    set techf2 [file join [pwd] [tech filename]]
+    set techf1 [file join [pwd]     $extTechOpt]
+    if {$techf1 != $techf2} {
+	error "ERROR: ${::Prog}: failed tech-load \"$techf1\" (tech-filename=\"$techf2\" not a match)"
+    }
+}
+
+# if mag-cell were passed natively on magic cmd-line, this is too late:
+if {$noderef} {
+    load $topc
+} else {
+    load $topc -dereference
+}
+
+# error checks: ensure (1st) cmd-line cellname now in-memory, and is now the current cell
+
+set topcells [cellname list top]
+# filter (UNNAMED)
+set topcells [lsearch -exact -not -all -inline $topcells "(UNNAMED)"]
+# puts "cellname-list-top is: $topcells"
+
+# could use [cellname list flags $topc] and ensure non-null result (list with available),
+# but if it fails (cell not found), it generates unwanted stdout.
+if {[lsearch -exact [cellname list allcells] $topc] < 0} {
+    error "ERROR: ${::Prog}: cmd-line topcell \"$topc\" not in magic's list of allcells."
+}
+
+if {[lsearch -exact $topcells $topc] < 0} {
+    puts "WARNING: ${::Prog}: cmd-line topcell \"$topc\" not in magic's list of topcells: $topcells"
+}
+
+# crude way even in batch to determine the "current" cell; perhaps not yet the "Edit" cell
+# WARNING, if topcell locked elsewhere or not writable, it can't become the "Edit" cell.
+set topcw [cellname list window]
+if {$topcw ne $topc} {
+    error "ERROR: ${::Prog}: cmd-line topcell, $topc, is not the current cell, 'cellname list window'=$topcw"
+}
+
+# for topcell, filepath==default doesn't change by expand,
+# indicates unknown cell created in-memory by magic's startup sequence.
+if {[cellnameExists         $topc] &&
+    [cellname list filepath $topc] eq "default"} {
+    puts "Search path for cells is \"[path search]\""
+    error "ERROR: ${::Prog}: cmd-line topcell, $topc, auto-created in-memory: not found in cell search path"
+}
+
+if {$flatten} {
+    # delete (UNNAMED) if any.
+    set trg "(UNNAMED)"
+    if {[cellnameExists $trg]} {cellname delete $trg}
+
+    # rename top cell to (UNNAMED)
+    cellname rename $topc $trg
+
+    # now Edit Cell contents are original top cell, but under name (UNNAMED)
+    # flatten Edit-Cell into original top cell name
+    puts "${::Prog}: flattening..."
+    flatten $topc
+
+    # load and edit new version of top cell. This is from in-memory, just making it current-cell.
+    # (So with or without -dereference is expected would have discernable effect by now;
+    # and since it's flattened there are no subcell instances either).
+    if {$noderef} {
+	load $topc
+    } else {
+	load $topc -dereference
+    }
+
+    # crude way even in batch to determine the "current" cell; perhaps not yet the "Edit" cell
+    # WARNING, if topcell locked elsewhere or not writable, it can't become the "Edit" cell.
+    set topcw [cellname list window]
+    if {$topcw ne $topc} {
+	error "ERROR: ${::Prog}: assertion failed, post-flatten, $topc, is not the current cell, 'cellname list window'=$topcw"
+    }
+
+    # should not be necessary:
+    select top cell
+    edit
+
+    # crude way even in batch to determine the "current" cell; perhaps not yet the "Edit" cell
+    # WARNING, if topcell locked elsewhere or not writable, it can't become the "Edit" cell.
+    set topcw [cellname list window]
+    if {$topcw ne $topc} {
+	error "ERROR: ${::Prog}: assertion-2 failed, post-flatten, $topc, is not the current cell, 'cellname list window'=$topcw"
+    }
+}
+
+# todo: Need a check for non-existent topcell (though magic reported not-found and auto-created it).
+# todo: We should locate fullpath to topcell on disk to record this in the log.
+#
+# WARNING, magic junkCell, or magic junkDir/junkCell (passing paths to cells that don't exist),
+# generate startup error messages (could not open cell), but magic creates the new cell in memory.
+# No simple way to detect this after the fact. Can walk the cell search path to verify it's on disk.
+# For the non-existent cell, magic also discards the dirpath from the cmd-line arg.
+# If it did exist at that path, magic opens it successfully, despite that dir not in search path.
+# A proper check for implicit create of non-existent cell should account for this effect too.
+
+# write a line with timestamp and all arguments to stdout (log)
+# (magic renames the TCL clock command)
+set clockp clock
+if {[info command $clockp] == {} && [info command orig_clock] != {}} {
+    set clockp orig_clock
+}
+set nowSec [$clockp seconds]
+set timestamp [$clockp format $nowSec -format "%Y-%m-%d.%T.%Z"]
+# Show quoted logged argv here so it's machine readable for replay purposes.
+puts "${::Prog}: timestamp: $timestamp, arguments: $::env(_M0)"
+
+puts "${::Prog}: running drc on topcell: $topcStr"
+puts "${::Prog}: tech-name: [tech name] -version: [tech version] -filename: [tech filename] -lambda [tech lambda]"
+
+# log the cell search path for this run. Emulates format output by plain "path" (but which prints more than one the cell search path).
+puts "Search path for cells is \"[path search]\""
+
+set res {}
+if {$variant != {}} {
+    if {[catch {set res [drc list style $variant]} msg]} {
+	puts "ERROR: ${::Prog}: but CONTINUING, 'drc style $variant' threw error, $msg"
+    }
+} else {
+    if {[catch {set res [drc list style]} msg]} {
+	puts "ERROR: ${::Prog}: but CONTINUING, 'drc list style' threw error, $msg"
+    }
+}
+if {$res != {}} {
+    puts "drc style reports:\n$res"
+}
+
+# just Manhattan is default, turn on euclidean, and log new mode
+drc euclidean on
+drc euclidean
+
+# 1st "select top cell": without it drc-list-count is blank, and error count reduced.
+# May be unnecessary in some cases.
+# WARNING: if topcell locked by another process, default box is NOT set to full top cell without this (as of 8.1.70 or earlier)
+select top cell
+# expand cell cells: scratchify step requires this up front else can't force all cells writable.
+expand
+
+# The expand triggered load of all subcells. Till then allcells may be incomplete.
+set allcells [cellname list allcells]
+# filter (UNNAMED)
+set allcells [lsearch -exact -not -all -inline $allcells "(UNNAMED)"]
+set nbrAllCells [llength $allcells]
+# puts "DEBUG: cellname-list-allcells are: $allcells"
+
+# TODO: do explicit separate unbound check here (don't rely on scratchWritable for this)
+
+# make allcells writable. Can error out:
+# if are unbounds, or couldn't make scratch dir or .mag files.
+set scratch [expr {!$flatten}]
+if {$scratch && [catch {scratchWritable} msg]} {
+    puts stderr "ERROR: ${::Prog}: aborting at scratchWritable due error(s):"
+    error $msg
+}
+
+# Erase all preexisting *.drtcl first. Else when cell transitions from
+# dirty in previous run (leaving *.drtcl), to clean, the old *.drtcl
+# remains.
+# TODO: only delete *.drtcl of cells in 'cellname list allcells'?
+# TODO: move this up, before scratchWritable?
+set files [glob -nocomplain -types {f} -- ./*.drtcl]
+if {$files != {}} {
+    # TODO: detect/report failure details better here?
+    puts "${::Prog}: deleting preexisting *.drtcl"
+    set msg {}
+    set delfail [catch {eval {file delete} $files} msg]
+    set files [glob -nocomplain -types {f} -- ./*.drtcl]
+    if {$delfail || $files != {}} {
+	puts "ERROR: ${::Prog}: failed to clean old ./*.drtcl files. $msg"
+	incr nbrErr
+    }
+}
+
+edit ;# Fails if topcell not writable, should not be not needed post scratchWritable
+
+set outScale [cif scale out]
+
+# "select top cell" and box [view bbox] should be equivalent in
+# placing a box around whole cell extent.
+# The box cmd ALSO prints lambda and micron user-friendly box data,
+# but it prints microns with not enough resolution,
+# (and no option to disable that flawed print out).
+#
+# todo: emulate box output in full, except for higher resolution,
+# here we only scale/print the overall bbox in microns.
+# select top cell       ;# paranoid, reset the box to data extents post-expand
+# set bbox [view bbox]
+# set bbs {}
+# foreach oord $bbox {
+#     lappend bbs [format "%.3f" [expr {$outScale * $oord}]]
+# }
+# puts "outScale: $outScale, view-bbox: $bbox"
+# puts "Root cell box2: ([lindex $bbs 0]  [lindex $bbs 1]), ([lindex $bbs 2]  [lindex $bbs 3])"
+
+# shouldn't need:
+# drc on
+
+# Want to use 'drc list count' to tell us which cells have errors, so we can
+# run 'drc listall why' on just those cells to enumerate details (which reruns
+# drc again unfortunately).
+
+# For accurate DRC (as of 8.1.70), specifically 'drc list count', need:
+# all-writable cells, then run: 'drc check' & 'drc catchup'.
+# Now we have all writable cells.
+set timeRepeat 1
+if {$perfN > 0} {
+    set timeRepeat $perfN
+}
+set timeres [time {
+    set drcCheckTime1 [time {drc check}]
+    set drcCheckTime2 [time {drc catchup}] } $timeRepeat]
+
+if {$perfN > 0} {
+    puts "perf: ${perfN}X 'drc check','drc catchup': $timeres"
+    puts "perf: last 'drc check' time: $drcCheckTime1"
+    puts "perf: last 'drc catchup' time: $drcCheckTime2"
+    drc statistics
+    drc rulestats
+}
+
+# todo: this 2nd select was in GDS version, test if needed in mag version:
+# 2nd select top cell needed else error count may be reduced (why? bbox does not change due to DRC)
+select top cell
+set outScale [cif scale out]
+set bbox [view bbox]
+set bbs {}
+foreach oord $bbox {
+    lappend bbs [format "%.3f" [expr {$outScale * $oord}]]
+}
+puts "outScale(ostyle=[cif list ostyle]): $outScale, view-bbox: $bbox"
+puts "Root cell box: ([lindex $bbs 0]  [lindex $bbs 1]), ([lindex $bbs 2]  [lindex $bbs 3])"
+# print several native bbox representations:
+box
+
+# listall vs list appear same as of 8.1.70 or earlier.
+# warning: celllist order is not stable, not repeatable; run to run on same data.
+# puts "DEBUG: (drc listall count total) is $drcListCountTot"
+set celllist [drc listall count]
+set celllist [lsearch -not -all -inline -index 0 -exact $celllist "(UNNAMED)"]
+# puts "DEBUG: (drc listall count) is [drc listall count]"
+set drcListCountTot [drc list count total]
+set nbrErrCells [llength $celllist]
+
+# TODO: major problem: 'drc listall why' repeated an every cell, will do subcells
+# multiple times, as many times as their depth in the hier.
+
+# canonicalize order of celllist, move topc to last (if present whatsoever).
+# force our own artificial entry for topc (zero errors) if not present (was clean)
+# puts "DEBUG: celllist before: $celllist"
+set topcPair [lsearch           -inline -index 0 -exact $celllist $topc]
+set celllist [lsearch -not -all -inline -index 0 -exact $celllist $topc]
+set celllist [lsort -index 0 -dictionary $celllist]
+if {$topcPair == {}} {
+    # puts "DEBUG: $topc clean, forcing celllist entry for it"
+    set topcPair [list $topc 0]
+}
+lappend celllist $topcPair
+# puts "DEBUG: celllist after: $celllist"
+# puts "DEBUG: adjusted celllist(drc list count) is $celllist"
+
+# loop over celllist
+set doFeedback 1 ;# TODO: add cmd-line option to control this
+
+# collect 'dry listall why' for the cells in 'cell list count' with non-zero errors
+# If 'drc listall why' does report zero (shouldn't since we're only processing cells
+# with non-zero counts), it unavoidably writes to console a No drc errors found message.
+# We don't want such polluting our list of per-cell pareto's, so don't risk running
+# drc why in-line, in-between per-cell paretos.
+array set cell2why [list $topc {}] ;# default at least empty topcell why list
+foreach pair $celllist {
+    if {[lindex $pair 1] < 1} {continue} ;# only happens for topcell if topcell clean
+    set acell [lindex $pair 0]
+
+    # TODO: magic needs a useful error checkable load command.
+    # The 'load' writes errors to console/stdout, but never throws an error,
+    # nor gives a useful return value. i.e. These catch never catch.
+    if {$noderef} {
+	if {[catch {set res [load $acell]} msg]} {
+	    puts "ERROR: ${::Prog}: 'load $acell' threw error, $msg"
+	    exit 1
+	}
+    } else {
+	if {[catch {set res [load $acell -dereference]} msg]} {
+	    puts "ERROR: ${::Prog}: 'load $acell -dereference' threw error, $msg"
+	    exit 1
+	}
+    }
+    select top cell ;# paranoid, that without it, drc's are reduced
+
+    # optionally do crude DRC perf. analysis here. Only for top-cell, only if -P <N> option given.
+    set timeRepeat 1
+    if {$perfN > 0 && $topc eq $acell} {
+	set timeRepeat $perfN
+    }
+    set timeres [time {set cell2why($acell) [drc listall why]} $timeRepeat]
+    if {$perfN > 0 && $topc eq $acell} {
+	puts "perf: ${::Prog}: for '$acell', ${perfN}X 'drc listall why': $timeres"
+    }
+}
+
+# done with all magic-specifics here. Shouldn't need scratch dir any longer.
+# If this prints something (generally does), don't want it after the pareto table.
+
+# clean/remove the tmp scratch dir and contents
+# TODO: all fatal errors need to call a cleanup proc that includes this before abort
+if {$scratch && [catch {scratchWritable -cleanup} msg]} {
+    puts "ERROR: ${::Prog}: 'scratchWritable -cleanup' threw error, $msg"
+    incr nbrErr
+}
+
+set gtotal 0
+set gcells 0
+foreach pair $celllist {
+    puts ""
+    set acell [lindex $pair 0]
+    if {![info exists cell2why($acell)]} {
+	puts "ERROR: ${::Prog}: cell: $acell, assertion failed, no drc-why list for 'drc list count' pair: $pair"
+	# exit 1
+	continue
+    }
+    set whys $cell2why($acell)
+
+    # enumerate errors under box, plain "drc why" only reports unique types, no quantities
+    # as-yet-undocumented "drc listall why" gives: {errStr1 {errBox1 ...} errStr2 {errBox1 ...} ... }
+    set pareto {}
+    set total 0
+    set enumTotal 0
+    set types 0
+    set typeDup 0
+    set dups 0
+
+    set fbOut {}
+    # file path for feedback, keep in CWD
+    if {$doFeedback && $fbOut == {}} {
+	set fbOut "./$acell.drtcl"
+	if {![file writable $fbOut] &&
+	    ([file exists $fbOut] || ![file writable [file dir $fbOut]])} {
+	    puts stderr "ERROR: ${::Prog}: feedback output not writable, $fbOut"
+	    incr nbrErr
+	    set fbOut {}
+	} elseif {[catch {set outfb [open $fbOut w]} msg]} {
+	    puts stderr "ERROR: ${::Prog}: failed to truncate previous feedback output, $fbOut : $msg"
+	    incr nbrErr
+	    set fbOut {}
+	}
+    }
+    foreach {str boxes} $whys {
+	# sort errors
+	set boxes [lsort -dictionary $boxes]
+
+	# for our pareto, gather data
+	set this [llength $boxes]
+	incr total $this
+	incr types
+	lappend pareto [list $this $str]
+
+	# for enumOut, emulate formatting of $CAD_ROOT/magic/tcl/drc.tcl, which is
+	# not tk pure: fails with complaint about winfo
+	# note: we walk these errors also in order to count/report stats on duplicates, even if not outputing enumerations
+	if {[info exists enumOut]} {
+	    if {$types == 1} {
+		puts $enumOut "[join $pair]\n----------------------------------------"
+	    }
+	    puts $enumOut "${str}\n----------------------------------------"
+	}
+	set lastq {}
+	set thisDup 0
+	foreach quad $boxes {
+	    set quadUM {}
+	    foreach coord $quad {
+		set valum [expr {$coord * $outScale}]
+		set valumf [format "%.3f" $valum]
+		lappend quadUM "${valumf}um"
+	    }
+	    set dup [expr {$quad == $lastq}]
+	    incr thisDup $dup
+	    set line $quadUM
+	    if {[info exists enumOut]} {
+		if {$dup} {
+		    puts $enumOut "[join $line] #dup"
+		} else {
+		    puts $enumOut [join $line]
+		}
+	    }
+	    if {$fbOut != {}} {
+		set line [join $quadUM]
+		regsub -all -- "(\[\[\"\$\\\\])" $str {\\\1} strdq
+		puts $outfb "[concat box $line]"                nonewline
+		puts $outfb " ; feedback add \"$strdq\" medium" nonewline
+		if {$dup} {
+		    puts $outfb " ;#dup"
+		} else {
+		    puts $outfb ""
+		}
+	    }
+
+	    incr enumTotal
+	    set lastq $quad
+	}
+	if {$thisDup} {
+	    incr typeDup
+	    incr dups $thisDup
+	}
+	if {[info exists enumOut]} {
+	    puts $enumOut "----------------------------------------\n"
+	}
+    }
+
+    if {$fbOut != {}} {
+	close $outfb
+	set outfb {}
+    }
+
+    set pareto [lsort -integer -decreasing -index 0 $pareto]
+    if {$total > 0} {
+	puts "--- #err|description, table for cell: $acell"
+    }
+    foreach pair $pareto {
+	puts "[format {%8d} [lindex $pair 0]] [lindex $pair 1]"
+    }
+    if {$typeDup} {
+	puts "[format {%8d} $dups] total duplicate error(s) among $typeDup error type(s), cell: $acell"
+    }
+    puts "[format {%8d} $total] total error(s) among $types error type(s), cell: $acell"
+    # add to grand-totals
+    incr gcells
+    incr gtotal $total
+
+    # always compare the total from the enum to the pareto as error check
+    if {$total != $enumTotal} {
+	puts "ERROR: ${::Prog}: cell: $acell, assertion failed, pareto vs enum count mismatch: $total != $enumTotal"
+	incr nbrErr
+    }
+}
+
+# TODO: in the summary echo also techfile-full-path and drc-style name?
+# grand totals
+puts "[format {%8d} $nbrErrCells] of $nbrAllCells cell(s) report error(s)"
+puts "[format {%8d} $gtotal] grand-total error(s) across $gcells cell(s)"
+
+# wish to compare the drc-list-count-total to the pareto total.
+# Per te 2014-08-27 : it is not an error.
+# if {$total != $drcListCountTot} {
+#   puts "info: ${::Prog}: drc-list-count-total vs drc-listall-why mismatch {drc list count total} gave $drcListCountTot, but {drc listall why} gave $total"
+# }
+
+if {[info exists enumOut]} {
+    close $enumOut
+}
+
+# set celllist4 [drc list count]
+# puts "DEBUG: drc list count0: $celllist0"
+# puts "DEBUG: drc list count1: $celllist1"
+# puts "DEBUG: drc list count2: $celllist2"
+# puts "DEBUG: drc list count3: $celllist3"
+# puts "DEBUG: native (drc list count) is $celllistn"
+# puts "DEBUG: drc list count4: $celllist4"
+
+# todo: implement super-pareto, ranked table of SUM of all DRC errs/counts from ALL cells.
+# (It still would not reflect as-if-flat hierarchical expansion due to repetition of instances).
+
+set nbrErr
+}
+
+# non-zero exit-status on errors, either if thrown by main, or counted and returned by main
+set nbrErr 0
+if {[catch {set nbrErr [main $argv]} msg]} {
+    puts stderr $msg
+    set nbrErr 1
+} elseif {$nbrErr > 0} {
+    puts "ERROR: ${::Prog}: script terminated with errors reported above."
+}
+exit $nbrErr
+
+# for emacs syntax-mode:
+# Local Variables:
+# mode:tcl
+# End:
diff --git a/utils/utils/magicGdrc b/utils/utils/magicGdrc
new file mode 100755
index 0000000..88280ee
--- /dev/null
+++ b/utils/utils/magicGdrc
@@ -0,0 +1,911 @@
+#!/bin/sh
+# SPDX-FileCopyrightText: 2014, 2015, 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (C) 2014, 2015, 2020 efabless Corporation. All Rights Reserved.
+# send a very-first -T FILE to magic's startup, hide all other args from magic-startup
+# for-bash\
+  export _M0= ;\
+  for i in "$@" ; do _M0="$_M0${_M0:+ }\"${i//\"/\\\"}\""; done ;\
+  case "$1" in -T) tch="$2"; shift; shift; _MARGS="$*" exec magic -dnull -noconsole -T "$tch" <"$0" ;; esac
+# hide next line from magic(tclsh):\
+_MARGS="$*" exec magic -dnull -noconsole <"$0"
+#
+# magicDRC: run magic-DRC in batch on a GDS file, tabulate/pareto the error counts.
+# 
+# rb@ef 2014-08-28 author
+# rb 2020-02-19 embed some library functions, to standalone from efabless-opengalaxy env, test via magic-8.2.188
+#
+# todo: support "-" as GDS file arg, to mean GDS from stdin
+#
+
+set ::Prog "magicGdrc"
+set argv  [eval "list $env(_M0)"] ;# orig. mix of native plus custom args, for logging all args to script
+# set argv [split $env(_MARGS)]   ;# (currently unused)
+
+proc usage {args} {
+    if {[llength $args] > 0} {
+	puts "ERROR: ${::Prog}: [join $args]"
+    }
+    puts {usage: [ -T techfilePath ] [-S <drcStyleName>]  [-I <cifIStyleName>] [-km FILE_NAME] [-l FILE_NAME] [-L FILE_NAME] gdsFileName [topCellName]}
+    puts "  -T if given, must be very first"
+    puts "  -S if given, changes from techfile's default/1st drc style (perhaps \"drc(fast)\") to named style, for example: -S \"drc(full)\""
+    puts "  -I if given, changes from techfile's default/1st cifinput style (perhaps \"vendorimport\" or \"import(exact)\") to named style, for example: -I \"import(magic)\""
+    puts "  -path-sub do 'gds path    subcell yes' (default:no). Make unique subcell for each path: cut #tiles cost of angles."
+    puts "  -poly-sub do 'gds polygon subcell yes' (default:no). Make unique subcell for each polygon: cut #tiles cost of angles."
+# gds polygon subcell [yes|no]
+    puts "  -pps  Short hand, equivalent to giving both: -path-sub -poly-sub"
+    puts ""
+    puts "  Error tabulation: By default (slowest, most detail): Report table of counts-by-errorString for all cells."
+    puts "  Stdout logs a pareto of error-type by count unless disabled for some/all cells by below; topcell last."
+    puts "  -tt Table of counts-by-errorString for ONLY topcell; and just lumped total error count per subcell."
+    puts "  -tc Just lumped error counts per cell including topcell (fastest, least detail)."
+    puts "  Cells NOT tabulating count-by-errorString can't appear in other output error files: feedback(*.drtcl), -l, -km."
+    puts "  For lumped error counts, overlapped error shapes from unique error-types are merged further reducing count."
+    puts ""
+    puts "  cell-type +--    (default)     --+--  option -tt      --+--   option -tc"
+    puts "    subcell | count-by-errorString |   lumped-error-count | lumped-error-count"
+    puts "    topcell | count-by-errorString | count-by-errorString | lumped-error-count"
+    puts ""
+    puts "  -km if given, write to FILE_NAME EVERY individual error bbox (MICRONS) in klayout Marker database(XML) format (suggest *.lyrdb)"
+    puts "  -l if given, enumerates EVERY individual error bbox (MICRONS) to FILE_NAME, emulates $::CAD_ROOT/magic/tcl/drc.tcl"
+    puts "  -L same as -l above, but outputs bbox-es in LAMBDA coordinates, not microns"
+    puts "  -nf  Do NOT write *.drtcl per-cell feedback files. Can be source-ed in magic and step thru: feedback find."
+    puts ""
+    puts "  NOTES: Without explicit tech-file option: the ./.magicrc or ./magic_setup and ~/.magicrc may load a default tech-file."
+    puts "  Therefore the tech-file used CAN depend on whether your CWD is ~/design/<CURRENT_DESIGN>/mag when running this script."
+    puts "  Since no *.mag are loaded by this script: the cell search path defined by any init files has no impact."
+    puts "  Since about 8.3.68, magic may generate error-type \"See error definition in the subcell\". There typically are"
+    puts "  redundancies of errors across the hierarchy anyway (but with tech-file err-strings), this seems another form."
+    puts ""
+    puts "example, just list all styles: by causing an error which provokes usage report:"
+    puts "    magicGdrc -T /ef/tech/XFAB/EFXH035B/libs.tech/magic/current/EFXH035B.tech"
+    puts "example, same but run in a ~/design/*/mag/ dir, so techfile set by ./.magicrc (else magic's builtin minimum.tech):"
+    puts "    magicGdrc"
+    puts "example, run GDS drc, explicit: tech, cif-istyle, drc-style:"
+    puts "    magicGdrc -T /ef/tech/SW/EFS8A/libs.tech/magic/current/EFS8A.tech -I vendorimport -S 'drc(full)' /tmp/mytop.gds mytopcell"
+    puts "example, run GDS drc, default tech & styles, write klayout marker database, no per-cell *.drtcl feedback files:"
+    puts "    magicGdrc -km /tmp/mytop.lyrdb -nf /tmp/mytop.gds mytopcell"
+    puts "example, same but make subcells for paths & polygons"
+    puts "    magicGdrc -km /tmp/mytop.lyrdb -nf -pps /tmp/mytop.gds mytopcell"
+    puts "example, run GDS drc, no feedback (*.drtcl), only lumped/merged err-count for all cells"
+    puts "    magicGdrc -tc /tmp/mytop.gds mytopcell"
+    puts "example, run GDS drc, no feedback (*.drtcl), lumped/merged err-count for subcells, detail errors for topcell"
+    puts "    magicGdrc -nf -tt /tmp/mytop.gds mytopcell"
+    puts ""
+
+    reportTechFile
+    reportAllStyles
+    puts ""
+
+    if {[llength $args] > 0} {
+	puts "ERROR: ${::Prog}: [join $args]"
+    }
+}
+proc gdsChk {file} {
+    foreach suffix {"" ".gds" ".gds2" ".strm"} {
+	if {[file readable "${file}${suffix}"]} {return 1}
+    }
+    puts "ERROR: ${::Prog}: Cannot open (as-is or with .gds, .gds2, or .strm) to read GDS-II stream from: $file"
+    exit 1
+}
+
+proc reportTechFile {} {
+    puts "${::Prog}: tech-name: [tech name] -version: [tech version] -filename: [tech filename] -lambda [tech lambda]"
+}
+
+# query currently loaded tech-file for styles the user might need for -I -S options
+# Suggest a bad tech-file if none are found or errors thrown.
+# Used after finding error in -I -S options, and probably should add it to the usage.
+proc reportAllStyles {} {
+    set errs {}
+    if {[catch {set allstyle [cif listall istyle]} msg]} {
+	lappend errs "ERROR: ${::Prog}: bad tech-file? failed to 'cif listall istyle', $msg"
+    } elseif {$allstyle == {}} {
+	lappend errs "ERROR: ${::Prog}: bad tech-file? no cifinput styles found by 'cif listall istyle'"
+    } else {
+	puts "info: ${::Prog}: cifinput styles available: $allstyle"
+    }
+    if {[catch {set allstyle [drc listall style]} msg]} {
+	lappend errs "ERROR: ${::Prog}: bad tech-file? failed to 'drc listall style', $msg"
+    } elseif {$allstyle == {}} {
+	lappend errs "ERROR: ${::Prog}: bad tech-file? no drc styles found by 'drc listall style'"
+    } else {
+	puts "info: ${::Prog}: drc styles available: $allstyle"
+    }
+    if {$errs != {}} {
+
+    }
+    return [llength $errs]
+}
+
+# optionally hardcode library proc-s (part of site-wide extensions - always available - in context of efabless/open-galaxy)
+# This is to make the script more standalone from efabless environment; but these capabilities should be native to magic.
+
+if {[info command unbounds] == {}} {
+    puts "${::Prog}: hardcoding library proc-s..."
+# Replacement for 'cellname list exists CELLNAME', to fix ambiguity for cell "0".
+# For cell "0" test for membership in 'cellname list allcells'.
+#
+# Instead of returning 0 for (non-existent) and cellname for exists,
+# returns regular 0/1 instead for non-existent/exists.
+#
+# Therefore NOT direct replacement for uses of 'cellname list exists CELL'.
+# Requires code changes.
+proc cellnameExists {cell} {
+    expr {$cell ne "0" && [cellname list exists $cell] eq $cell ||
+	  $cell eq "0" && [lsearch -exact [cellname list allcells] $cell] > -1}
+}
+
+# Walk allcells to get/return list of cellNames that are unbound.
+# Only use this after: 'select top cell; expand' to expand whole hierarchy.
+#
+# foreach CELL in 'cellname list allcells':
+#   if flags says available : it's Bound, goto next cell.
+#   if filepath is "default", try to expand the cell.
+#   if still "default"**: cell made by "cellname create", never saved, goto next.
+#   if filepath is CELL.mag, check for "available" flags, if none: Unbound.
+#   else cell is bound.
+#   **: should never get there
+proc unbounds {} {
+    set allcells [cellname list allcells]
+    # filter (UNNAMED)
+    set allcells [lsearch -exact -not -all -inline $allcells "(UNNAMED)"]
+    # set nbrAllCells [llength $allcells]
+    set ercell {}
+    foreach cell $allcells {
+	# filter (without recording as skipped) non-existent cells.
+	if {![cellnameExists $cell]} { continue }
+
+	# filepath = "default": unexpanded (not loaded from disk),
+	# or created in-mem and never saved (is writable already
+	# though flags won't say so): skip both.
+	# TODO: use a combo of filepath & flags likely can detect created in-mem
+	set tmppath [cellname list filepath $cell]
+	if {$tmppath eq "default"} {
+	    lappend skipped $cell
+	    continue
+	}
+
+	# flags not meaningful, until expanded or expand attempted.
+	# After expand attempt (filepath != "default"), and flags
+	# can now be used to determine cell unbound: not available.
+	set flags   [cellname list flags    $cell]
+	if {[lsearch -exact $flags available] < 0} {
+	    lappend ercell $cell
+	    continue
+	}
+    }
+    set ercell ;# return list of unbound cells, if any
+}
+}
+
+# without top-level proc around bulk of script, intermediate error statements don't abort script.
+proc main {argv} {
+
+set mlen [llength $argv]
+
+# process name-value pair options, if any
+set nbrErr 0
+set ndx 0
+set max [llength $argv]
+set extTechOpt {} ;# -T ... but not used here
+set enumFilel  {} ;# -l ... enum output file
+set enumFileL  {} ;# -L ... enum output file
+set enumFileKm {} ;# -km ... enum output file
+set variant {}    ;# -S ... non-default drc style
+set istyle  {}    ;# -I ... non-default cifinput style
+set doFeedback 1  ;# -nf sets to 0: Do not write *.drtcl per-cell feedback files.
+set pathSub 0     ;# -path-sub ... do 'gds path    subcell yes'
+set polySub 0     ;# -poly-sub ... do 'gds polygon subcell yes'
+set subcellTab 1  ;# -tt, -tc both turn OFF subcell count-by-error report
+set topcellTab 1  ;#      -tc     turns OFF topcell count-by-error report
+set flatten 0
+while {$ndx < $max && [string match "-*" [lindex $argv $ndx]]} {
+    set opt [lindex $argv $ndx]
+    incr ndx
+    switch -exact -- $opt {
+	-T {
+	    if {$ndx != 1} {
+		usage "-T option must very 1st (here was #$ndx)"
+		exit 1
+	    }
+	    if {$ndx == $max} {
+		usage "missing tech-file argument for -T option"
+		exit 1
+	    }
+	    set extTechOpt [lindex $argv $ndx] ;# unused
+	    incr ndx
+	}
+	-S {
+	    if {$ndx == $max} {
+		usage "missing drcStyle argument for -S option"
+		exit 1
+	    }
+	    set variant [lindex $argv $ndx]
+	    incr ndx
+	}
+	-I {
+	    if {$ndx == $max} {
+		usage "missing cifinput-style argument for -I option"
+		exit 1
+	    }
+	    set istyle [lindex $argv $ndx]
+	    incr ndx
+	}
+	-F        { set flatten     1}
+	-nf       { set doFeedback 0 }
+	-path-sub { set pathSub     1}
+	-poly-sub { set polySub     1}
+	-pps      { set pathSub     1; set polySub     1}
+	-tt       { set subcellTab 0 ; set topcellTab  1}
+	-tc       { set subcellTab 0 ; set topcellTab 0 }
+	-km {
+	    if {$ndx == $max} {
+		usage "missing outputFile argument for -km option"
+		exit 1
+	    }
+	    set enumFileKm [lindex $argv $ndx]
+	    incr ndx
+	}
+	-l {
+	    if {$ndx == $max} {
+		usage "missing outputFile argument for -l option"
+		exit 1
+	    }
+	    set enumFilel [lindex $argv $ndx]
+	    incr ndx
+	    if {[catch {set enumOut [open $enumFilel w]} msg]} {
+		error "ERROR: ${::Prog}: failed to open-for-write '$enumFilel' threw error, $msg"
+	    }
+	    puts "${::Prog}: enumerating each error bbox to: $enumFilel"
+	}
+	-L {
+	    if {$ndx == $max} {
+		usage "missing outputFile argument for -L option"
+		exit 1
+	    }
+	    set enumFileL [lindex $argv $ndx]
+	    incr ndx
+	    if {[catch {set enumOutL [open $enumFileL w]} msg]} {
+		error "ERROR: ${::Prog}: failed to open-for-write '$enumFileL' threw error, $msg"
+	    }
+	    puts "${::Prog}: enumerating each error bbox to: $enumFileL"
+	}
+	default {
+	    usage "unknown option: $opt"
+	    exit 1
+	}
+    }
+}
+
+if {$ndx == $max} {
+    usage {Insufficient number of arguments, need gdsFileName [topCellName]}
+    exit 1
+}
+
+set gdsf [lindex $argv $ndx] ; incr ndx
+set topc {}
+set topcStr "(AUTO)"
+if {$ndx < $max} {
+    set topc [lindex $argv $ndx] ; incr ndx
+    set topcStr $topc
+}
+# error if extra options (not understood, something is wrong):
+if {$ndx < $max} {
+    error "ERROR: ${::Prog}: after gdsFile=\"$gdsf\", topcell=\"$topc\" found unsupported extra arguments: [lrange $argv $ndx end]"
+}
+# ndx no longer used for argv position from here
+
+gdsChk $gdsf
+
+# warning on combo of -tc & -km. If -km ok, open its output file.
+if {$enumFileKm ne {}} {
+    if {! $topcellTab} {
+	    puts "WARNING: ${::Prog}: with -tc cannot (-km) write klayout-marker-db"
+    } else {	
+	if {[catch {set enumOutKm [open $enumFileKm w]} msg]} {
+	    error "ERROR: ${::Prog}: failed to open-for-write '$enumFileKm' threw error, $msg"
+	}
+	puts "${::Prog}: enumerating each error bbox to: $enumFileKm"
+    }
+}
+
+# write a line with timestamp and all arguments to stdout (log)
+# (magic renames the TCL clock command)
+set clockp clock
+if {[info command $clockp] == {} && [info command orig_clock] != {}} {
+    set clockp orig_clock
+}
+set nowSec [$clockp seconds]
+set timestamp [$clockp format $nowSec -format "%Y-%m-%d.%T.%Z"]
+# TODO: quote logged argv here as needed so it's machine readable for replay purposes.
+puts "${::Prog}: timestamp: $timestamp, arguments: $argv"
+
+# just Manhattan is default, turn on euclidean, and log new mode
+drc euclidean on
+drc euclidean
+
+# 8.1.83 this worked:
+#    drc off; gds drccheck no;  gds read ... ; load topcell; select top cell; expand; drc check; drc update; drc listall count
+# By 8.2.64, that fails, the 'drc listall count' reports errors only in the top-cell, no subcells.
+# 8.1.83 & 8.2.193 this works (gds drccheck defaults to on anyway):
+#    drc off; gds drccheck yes; gds read ... ; load topcell; select top cell; expand; drc check; drc update; drc listall count
+#
+# But are we properly avoiding redundant drc runs?
+#
+# turn off background checker. We'll invoke checks explicitly.
+drc off
+gds drccheck yes
+puts "drc status (whether background checking enabled) is: [drc status]"
+puts "gds drccheck (whether gds-read marks new cells as need-drc) is: [gds drccheck]"
+
+# set user's drc style; set user's cifinput istyle
+# These are back-to-back without intervening status messages.
+# If both wrong their errors are back-to-back.
+set res {}
+set res [drc list style]
+if {$variant != {}} {
+    set allstyle [drc listall style]
+    set ndx [lsearch -exact $allstyle $variant]
+    if {$ndx < 0} {
+	puts "ERROR: ${::Prog}: drc style '$variant' not one of those available: $allstyle"
+	incr nbrErr
+    } else {
+	set res [drc list style $variant]
+    }
+}
+set res2 [cif list istyle]
+if {$istyle != {}} {
+    set allstyle [cif listall istyle]
+    set ndx [lsearch -exact $allstyle $istyle]
+    if {$ndx < 0} {
+	puts "ERROR: ${::Prog}: istyle '$istyle' not one of those available: $allstyle"
+	incr nbrErr
+    } else {
+	set res2 [cif istyle $istyle]
+    }
+}
+if {$res != {}} {
+    puts "drc style reports:\n$res"
+}
+if {$res2 != {}} {
+    puts "cif istyle reports:\n$res2"
+}
+
+# gds {path,polygon} subcell yes
+if         {$pathSub != 0} { gds    path subcells yes }
+puts "gds    path subcells: [gds    path subcells]"
+if      {$polySub != 0}    { gds polygon subcells yes }
+puts "gds polygon subcells: [gds polygon subcells]"
+
+# todo: this catch never happens. Need nicer error check of 'gds read' somehow. Can check for zero-sized file?
+# if use /dev/null for example, it prints its own error message, but no throw, no useful return value.
+puts         "doing: gds read $gdsf ..."
+if {[catch {set res [gds read $gdsf]} msg]} {
+    puts "ERROR: ${::Prog}: 'gds read $gdsf' threw error, $msg"
+    incr nbrErr
+}
+# nothing useful:
+# puts "gds-read res: $res"
+
+set topcells [cellname list top]
+set allcells [cellname list allcells]
+# puts "cellname-list-top from GDS is: $topcells"
+# puts "cellname-list-allcells from GDS are: $allcells"
+# filter (UNNAMED)
+set topcells [lsearch -exact -not -all -inline $topcells "(UNNAMED)"]
+set allcells [lsearch -exact -not -all -inline $allcells "(UNNAMED)"]
+set nbrAllCells [llength $allcells]
+
+if {$topcells == {}} {
+    puts "ERROR: ${::Prog}: GDS-read did not report any useful cell name(s) found."
+    incr nbrErr
+}
+
+if {$nbrErr > 0} {
+    return $nbrErr ;# outside of main, we print termination with errors message
+}
+
+if {$topc == {}} {
+    # try and infer topcell from cellname-list-top.
+    # presume its list of cells not placed anywhere else.
+    # todo: test with "library" GDS having more than one topcell
+    # here we just take the last entry
+    set topc [lindex $topcells end]
+    set topcStr $topc
+    puts "WARNING: auto-picked top-cell \"$topc\"; the topcells inferred from GDS are: $topcells"
+} else {
+    # verify input topc argument exists in GDS read result
+    set ndx [lsearch -exact $allcells $topc]
+    if {$ndx < 0} {
+	puts "ERROR: ${::Prog}: top-cell name: $topc, not found in GDS"
+	puts "info: top cells inferred from GDS are: $topcells"
+	puts "info: all cells inferred from GDS are: $allcells"
+	return [incr nbrErr] ;# outside of main, we print termination with errors message
+    }
+}
+
+puts "${::Prog}: running drc on -gds: $gdsf -topcell: $topcStr"
+reportTechFile
+
+# todo: need to error check load command somehow (no useful return value).
+# it can fail with error message (in log) like:
+#   File dne.mag couldn't be found
+#   Creating new cell
+if {[catch {set res [load $topc]} msg]} {
+    puts "ERROR: ${::Prog}: 'load $topc' threw error (maybe cellName not found in GDS?), $msg"
+    return [incr nbrErr] ;# outside of main, we print termination with errors message
+}
+# nothing useful:
+# puts "load $topc res: $res"
+
+if {$flatten} {
+    # delete (UNNAMED) if any.
+    set trg "(UNNAMED)"
+    if {[cellnameExists $trg]} {cellname delete $trg}
+
+    # rename top cell to (UNNAMED)
+    cellname rename $topc $trg
+
+    # now Edit Cell contents are original top cell, but under name (UNNAMED)
+    # flatten Edit-Cell into original top cell name
+    puts "${::Prog}: flattening..."
+    flatten $topc
+
+    # load and edit new version of top cell
+    load $topc
+
+    # crude way even in batch to determine the "current" cell; perhaps not yet the "Edit" cell
+    # WARNING, if topcell locked elsewhere or not writable, it can't become the "Edit" cell.
+    set topcw [cellname list window]
+    if {$topcw ne $topc} {
+	puts "ERROR: ${::Prog}: assertion failed, post-flatten, $topc, is not the current cell, 'cellname list window'=$topcw"
+	return [incr nbrErr] ;# outside of main, we print termination with errors message
+    }
+
+    # should not be necessary:
+    select top cell
+    edit
+
+    # crude way even in batch to determine the "current" cell; perhaps not yet the "Edit" cell
+    # WARNING, if topcell locked elsewhere or not writable, it can't become the "Edit" cell.
+    set topcw [cellname list window]
+    if {$topcw ne $topc} {
+	puts "ERROR: ${::Prog}: assertion-2 failed, post-flatten, $topc, is not the current cell, 'cellname list window'=$topcw"
+	return [incr nbrErr] ;# outside of main, we print termination with errors message
+    }
+}
+
+# Erase all preexisting *.drtcl first. Else when cell transitions from
+# dirty in previous run (leaving *.drtcl), to clean, the old *.drtcl
+# remains.
+# TODO: only delete *.drtcl of cells in 'cellname list allcells'?
+if {$doFeedback} {
+    set files [glob -nocomplain -types {f} -- ./*.drtcl]
+    if {$flatten} {
+	# only delete topcell's .drtcl in flatten mode, if there is one
+	set files [lsearch -all -inline -exact $files ./$topc.drtcl]
+    }
+    if {$files != {}} {
+	# TODO: detect/report failure details better here?
+	puts "${::Prog}: deleting preexisting *.drtcl"
+	set msg {}
+	set delfail [catch {eval {file delete} $files} msg]
+	set files [glob -nocomplain -types {f} -- ./*.drtcl]
+	if {$delfail || $files != {}} {
+	    puts "ERROR: ${::Prog}: failed to clean old ./*.drtcl files. $msg"
+	    incr nbrErr
+	}
+    }
+}
+
+# 1st "select top cell": without it drc-list-count is blank, and error count reduced.
+select top cell
+
+set bbox0 [view bbox]
+set outScale [cif scale out]
+
+# set bbox1 [view bbox]
+
+# "select top cell" and box [view bbox] should be equivalent in
+# placing a box around whole cell extent.
+# The box cmd ALSO prints lambda and micron user-friendly box data,
+# but it prints microns with not enough resolution,
+# (and no option to disable that flawed print out).
+#
+# todo: emulate box output in full, except for higher resolution,
+# here we only scale/print the overall bbox in microns.
+set bbs {}
+foreach oord $bbox0 {
+    lappend bbs [format "%.3f" [expr {$outScale * $oord}]]
+}
+puts "info: outScale: [format "%.6f" $outScale], view-bbox: $bbox0"
+puts "info: Root cell box: ([lindex $bbs 0]  [lindex $bbs 1]), ([lindex $bbs 2]  [lindex $bbs 3])"
+
+drc check
+drc catchup
+drc statistics
+drc rulestats
+# puts "doing plain: drc count"
+drc count
+
+# 2nd select top cell needed else error count may be reduced (why? bbox does not change due to DRC)
+select top cell
+
+set celllist        [drc listall count]
+set drcListCountTot [drc list count total]
+# puts stdout "(drc listall count)       is << " nonewline; puts stdout [list $celllist]                 nonewline; puts " >>"
+# puts stdout "(drc list count)          is << " nonewline; puts stdout [list [drc list count]]          nonewline; puts " >>"
+# puts stdout "(drc list    count total) is << " nonewline; puts stdout [list $drcListCountTot]          nonewline; puts " >>"
+# puts stdout "(drc listall count total) is << " nonewline; puts stdout [list [drc listall count total]] nonewline; puts " >>"
+# puts stdout "(drc list why)            is << " nonewline; puts stdout [list [drc list why]]            nonewline; puts " >>"
+# puts stdout "(drc listall why)         is << " nonewline; puts stdout [list [drc listall why]]         nonewline; puts " >>"
+
+set bbox2 [view bbox]
+if {$bbox2 != $bbox0} {
+    set bbs {}
+    foreach oord $bbox2 {
+	lappend bbs [format "%.3f" [expr {$outScale * $oord}]]
+    }
+    puts "info: outScale: [format "%.6f" $outScale], view-bbox: $bbox2"
+    puts "info: Root cell box2: ([lindex $bbs 0]  [lindex $bbs 1]), ([lindex $bbs 2]  [lindex $bbs 3])"
+}
+
+
+# canonicalize order of celllist, move topc to last (if present whatsoever).
+# force our own artificial entry for topc (zero errors) if not present (was clean)
+# puts "celllist before: $celllist"
+set nbrErrCells [llength $celllist]
+set topcPair [lsearch           -inline -index 0 -exact $celllist $topc]
+set celllist [lsearch -not -all -inline -index 0 -exact $celllist $topc]
+set celllist [lsort -index 0 -dictionary $celllist]
+if {$topcPair == {}} {
+    # puts "info: ${::Prog}: $topc clean, forcing celllist entry for it"
+    set topcPair [list $topc 0]
+}
+lappend celllist $topcPair
+# puts stdout "adjusted celllist(drc list count) is << " nonewline; puts stdout $celllist nonewline; puts " >>"
+
+array set kmErr2catNm {}
+array set kmErr2catDesc {}
+array set kmCell2item {}
+if {$celllist != {} && [info exists enumOutKm]} {
+    # Header example of .lyrdb klayout Marker format
+    # <?xml version="1.0" encoding="utf-8"?>
+    # <report-database>
+    # <description>Diff of 'x.gds, Cell RINGO' vs. 'x.gds[1], Cell INV2'</description>
+    # <original-file/>
+    # <generator/>
+    # <top-cell>RINGO</top-cell>
+    # <tags>
+    # <tag>
+    # <name>red</name>
+    # <description>Red flag</description>
+    # </tag>
+    # ... 
+    # </tags>
+
+    puts $enumOutKm {<?xml version="1.0" encoding="utf-8"?><report-database>}
+    puts $enumOutKm "<description>$topc DRC timestamp: $timestamp, arguments: $argv</description>"
+    puts $enumOutKm {<original-file/><generator/>}
+    puts $enumOutKm "<top-cell>$topc</top-cell>"
+    puts $enumOutKm {<tags/>}
+    puts $enumOutKm {<cells>}
+
+    # multiple <cells>...</cells> sections do accumulate, but cells and categories need
+    # to be defined before use in an item (specific error), and we know cell names here,
+    # so declare all cells to klayout here.
+    #
+    # Cell-specific header of klayout marker file
+    #  <cell>
+    #   <name>CELLNAME1</name>
+    #   <variant>1</variant>               (don't need)
+    #  </cell>
+    #
+    foreach pair $celllist {
+	set acell [lindex $pair 0]
+
+	# for -tt, no subcell error-detail: don't write subcells in <cells>...</cells> section.
+	if {$acell ne $topc && ! $subcellTab} { continue }
+
+	puts $enumOutKm "  <cell><name>$acell</name></cell>"
+	set kmCell2item($acell) {}
+    }
+    puts $enumOutKm {</cells>}
+}
+
+# loop over celllist
+set gtotal 0
+set gcells 0
+set lumpedHeader 0
+foreach pair $celllist {
+    set acell [lindex $pair 0]
+    set acount [lindex $pair 1]
+
+    if {$acell ne $topc && ! $subcellTab} {
+	if {! $lumpedHeader} {
+	    puts "--- #err|cell, lumped total counts"
+	    set lumpedHeader 1
+	}
+	puts "[format {%8d} $acount] $acell"
+	incr gcells
+	incr gtotal $acount
+	continue
+    }
+    if {$acell eq $topc && ! $topcellTab} {
+	if {! $lumpedHeader} {
+	    puts "--- #err|cell, lumped total counts"
+	    set lumpedHeader 1
+	}
+	puts "[format {%8d} $acount] $acell"
+	incr gcells
+	incr gtotal $acount
+	continue
+    }
+    puts ""
+
+    # todo: need useful error check of load command
+    if {[catch {set res [load $acell]} msg]} {
+	puts "ERROR: ${::Prog}: 'load $acell' threw error, $msg"
+	return [incr nbrErr] ;# outside of main, we print termination with errors message
+    }
+
+    # instead use quiet version for per-cell selects
+    select top cell
+
+    set drcListCountTot [drc listall count total]
+
+    # enumerate errors under box, plain "drc why" only reports unique types, no quantities
+    # as-yet-undocumented "drc listall why" will give: {errStr1 {errBox1 ...} errStr2 {errBox1 ...} ... }
+    set pareto {}
+    set total 0
+    set enumTotal 0
+    set types 0
+    set typeDup 0
+    set dups 0
+
+    set fbOut {}
+    if {$acount != 0} {
+	# file path for feedback, keep in CWD
+	if {$doFeedback && $fbOut == {}} {
+	    set fbOut "./$acell.drtcl"
+	    if {![file writable $fbOut] &&
+		([file exists $fbOut] || ![file writable [file dir $fbOut]])} {
+		puts stderr "ERROR: ${::Prog}: feedback output not writable, $fbOut"
+		incr nbrErr
+		set fbOut {}
+	    } elseif {[catch {set outfb [open $fbOut w]} msg]} {
+		puts stderr "ERROR: ${::Prog}: failed to truncate previous feedback output, $fbOut : $msg"
+		incr nbrErr
+		set fbOut {}
+	    }
+	}
+
+	foreach {str boxes} [drc listall why] {
+	    # sort errors
+	    set boxes [lsort -dictionary $boxes]
+	    # for our pareto, gather data
+	    set this [llength $boxes]
+	    incr total $this
+	    incr types
+	    lappend pareto [list $this $str]
+
+	    # for enumOut, emulate formatting of $CAD_ROOT/magic/tcl/drc.tcl, which is
+	    # not tk pure: fails with complaint about winfo
+	    # note: we walk these errors also in order to count/report stats on duplicates, even if not outputing enumerations
+	    if {[info exists enumOut]} {
+		if {$types == 1} {
+		    puts $enumOut "[join $pair]\n----------------------------------------"
+		}
+		puts $enumOut "${str}\n----------------------------------------"
+	    }
+	    if {[info exists enumOutL]} {
+		if {$types == 1} {
+		    puts $enumOutL "[join $pair]\n----------------------------------------"
+		}
+		puts $enumOutL "${str}\n----------------------------------------"
+	    }
+	    if {[info exists enumOutKm]} {
+		# category names must be declared all together up front before use in items
+		# so we only store their names (error strings) and error detail (items)
+		# to dump after all cells and errors are processed.
+		# TODO: Only quote catName in item if embeds dot, instead of full-time
+		# TODO: test klayout handles literal (non-entity) single-quote in double-quoted name
+		set strKmNm   $str
+		set strKmDesc $str
+		regsub -all -- {&} $strKmDesc {\&amp;} strKmDesc  ;# perhaps not needed; just in case
+		regsub -all -- {<} $strKmDesc {\&lt;}  strKmDesc  ;# description does not have such bug, so use correct entity
+		regsub -all -- {>} $strKmDesc {\&gt;}  strKmDesc  ;# perhaps not needed; just in case
+		regsub -all -- {&}  $strKmNm  {-and-} strKmNm    ;# perhaps not needed; just in case
+		regsub -all -- {>}  $strKmNm  {-gt-}  strKmNm    ;# perhaps not needed; just in case
+		regsub -all -- {<}  $strKmNm  {-lt-}  strKmNm    ;# catName klayout bug: info win truncates at '<' as &lt; entity
+		regsub -all -- "\"" $strKmNm  {'}     strKmNm    ;# we dqoute each catNm in item, so change embedded double to single
+		set kmErr2catNm($str)   $strKmNm
+		set kmErr2catDesc($str) $strKmDesc
+		#
+		# example klayout Marker format, header of one item (one error instance)
+		#  <item>
+		#   <tags/>               (don't need?)
+		#   <image/>               (don't need?)
+		#   <category>'DRC-MSG-STR'</category>       (cat1.cat2 path delimit by dot: names with dot need single|double quotes)
+		#   <cell>RINGO:1</cell>                     (don't need :N variant suffix)
+		#   <visited>false</visited>                  (optional? start with false?)
+		#   <multiplicity>1</multiplicity>           (not boolean, if error "represents" more that are NOT enumerated)
+		#   <values> ... </values>
+		#  </item>
+
+		set itemStr "<item><category>\"$strKmNm\"</category><cell>$acell</cell><values>"
+	    }
+	    set lastq {}
+	    set thisDup 0
+	    foreach quad $boxes {
+		set quadUM {}
+		set kmBoxUM {}
+		foreach coord $quad {
+		    set valum [expr {$coord * $outScale}]
+		    set valumf [format "%.3f" $valum]
+		    lappend quadUM "${valumf}um"
+		    lappend kmBoxUM ${valumf}
+		}
+		set dup [expr {$quad == $lastq}]
+		incr thisDup $dup
+		set line $quadUM
+		if {[info exists enumOut]} {
+		    if {$dup} {
+			puts $enumOut "[join $line] #dup"
+		    } else {
+			puts $enumOut [join $line]
+		    }
+		}
+		if {[info exists enumOutL]} {
+		    if {$dup} {
+			puts $enumOutL "$quad #dup"
+		    } else {
+			puts $enumOutL $quad
+		    }
+		}
+		if {[info exists enumOutKm]} {
+		    #    <value>text: 'item: polygon'</value>                          (text is optional? Repeat the box coordinates here in um?)
+		    #    <value>polygon: (1.4,1.8;-1.4,1.8;-1.4,3.8;1.4,3.8)</value>
+		    #    <value>box: (1.4,1.8;-1.4,3.8)</value>
+		    #   </values>
+		    set kmItem $itemStr
+		    append kmItem " <value>box: ([lindex $kmBoxUM 0],[lindex $kmBoxUM 1];[lindex $kmBoxUM 2],[lindex $kmBoxUM 3])</value>"
+		    if {$dup} {
+			append kmItem " <value>text: 'dup'</value>"
+		    }
+		    append kmItem " </values></item>"
+		    lappend kmCell2item($acell) $kmItem
+		}
+		if {$fbOut != {}} {
+		    set line [join $quadUM]
+		    regsub -all -- "(\[\[\"\$\\\\])" $str {\\\1} strdq
+		    puts $outfb "[concat box $line]"                nonewline
+		    puts $outfb " ; feedback add \"$strdq\" medium" nonewline
+		    if {$dup} {
+			puts $outfb " ;#dup"
+		    } else {
+			puts $outfb ""
+		    }
+		}
+
+		incr enumTotal
+		set lastq $quad
+	    }
+	    if {$thisDup} {
+		incr typeDup
+		incr dups $thisDup
+	    }
+	    if {[info exists enumOut]} {
+		puts $enumOut "----------------------------------------\n"
+	    }
+	    if {[info exists enumOutL]} {
+		puts $enumOutL "----------------------------------------\n"
+	    }
+	}
+    }
+
+    if {$fbOut != {}} {
+	close $outfb
+	set outfb {}
+    }
+
+    set pareto [lsort -integer -decreasing -index 0 $pareto]
+    if {$total > 0} {
+	puts "--- #err|description, table for cell: $acell"
+    }
+    foreach pair $pareto {
+	puts "[format {%8d} [lindex $pair 0]] [lindex $pair 1]"
+    }
+    if {$typeDup} {
+	puts "[format {%8d} $dups] total duplicate error(s) among $typeDup error type(s), cell: $acell"
+    }
+    puts "[format {%8d} $total] total error(s) among $types error type(s), cell: $acell"
+    # add to grand-totals
+    incr gcells
+    incr gtotal $total
+
+    # always compare the total from the enum to the pareto as error check
+    if {$total != $enumTotal} {
+	puts "ERROR: ${::Prog}: cell: $acell, internal error, pareto vs enum count mismatch: $total != $enumTotal"
+	incr nbrErr
+    }
+    # wish to compare the drc-list-count-total to the pareto total.
+    # Per te 2014-08-27 : it is not an error.
+    if {$total != $drcListCountTot} {
+	# puts "info: ${::Prog}: cell: $acell, drc-list-count-total vs drc-listall-why mismatch {drc list count total} gave $drcListCountTot, but {drc listall why} gave $total"
+    }
+}
+
+# grand totals
+puts "[format {%8d} $nbrErrCells] of $nbrAllCells cell(s) report error(s)"
+puts "[format {%8d} $gtotal] grand-total error(s) across $gcells cell(s)"
+
+if {[info exists enumOut]} {
+    close $enumOut
+}
+if {[info exists enumOutL]} {
+    close $enumOutL
+}
+if {[info exists enumOutKm]} {
+    # declare all category names and descriptions, note '<' in name vs description are represented differently
+    #
+    # <categories><category><name>layerN width -lt- 1.0um</name>
+    # <description>layerN width &lt; 1.0um</description></category>
+    # <category> ... </category></categories>
+    #
+    puts $enumOutKm "<categories>"
+    foreach errStr [array names kmErr2catNm] {
+	set nm   $kmErr2catNm($errStr)
+	set desc $kmErr2catDesc($errStr)
+	puts $enumOutKm "  <category><name>$nm</name><description>$desc</description></category>"
+    }
+    puts $enumOutKm "</categories>"
+
+    # dump all items (after all cells and all categories have been defined up front)
+    puts $enumOutKm "<items>"
+    foreach {acell items} [array get kmCell2item] {
+	foreach item $items {
+	    puts $enumOutKm $item
+	}
+    }
+    puts $enumOutKm "</items>"
+
+    # footer example .lyrdb klayout Marker file
+    # </report-database>
+    puts $enumOutKm {</report-database>}
+    close $enumOutKm
+}
+# todo: implement super-pareto, ranked table of SUM of all DRC errs/counts from ALL cells.
+# (It still would not reflect as-if-flat hierarchical expansion due to repetition of instances).
+
+set nbrErr ;# return value
+} ;# end main
+
+# non-zero exit-status on errors, either if thrown by main, or counted and returned by main
+set nbrErr 0
+if {[catch {set nbrErr [main $argv]} msg]} {
+    puts stderr $msg
+    set nbrErr 1
+} elseif {$nbrErr > 0} {
+    puts "ERROR: ${::Prog}: script terminated with errors reported above."
+}
+exit $nbrErr
+
+# for emacs syntax-mode:
+# Local Variables:
+# mode:tcl
+# End:
diff --git a/verilog/dv/caravel/caravel/defs.h b/verilog/dv/caravel/caravel/defs.h
new file mode 100644
index 0000000..6e42c7a
--- /dev/null
+++ b/verilog/dv/caravel/caravel/defs.h
@@ -0,0 +1,203 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef _STRIVE_H_
+#define _STRIVE_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+// a pointer to this is a null pointer, but the compiler does not
+// know that because "sram" is a linker symbol from sections.lds.
+extern uint32_t sram;
+
+// Pointer to firmware flash routines
+extern uint32_t flashio_worker_begin;
+extern uint32_t flashio_worker_end;
+
+// Storage area (MGMT: 0x0100_0000, User: 0x0200_0000)
+#define reg_rw_block0  (*(volatile uint32_t*)0x01000000)
+#define reg_rw_block1  (*(volatile uint32_t*)0x01100000)
+#define reg_ro_block0  (*(volatile uint32_t*)0x02000000)
+
+// UART (0x2000_0000)
+#define reg_uart_clkdiv (*(volatile uint32_t*)0x20000000)
+#define reg_uart_data   (*(volatile uint32_t*)0x20000004)
+#define reg_uart_enable (*(volatile uint32_t*)0x20000008)
+
+// GPIO (0x2100_0000)
+#define reg_gpio_data (*(volatile uint32_t*)0x21000000)
+#define reg_gpio_ena  (*(volatile uint32_t*)0x21000004)
+#define reg_gpio_pu   (*(volatile uint32_t*)0x21000008)
+#define reg_gpio_pd   (*(volatile uint32_t*)0x2100000c)
+
+// Logic Analyzer (0x2200_0000)
+#define reg_la0_data (*(volatile uint32_t*)0x25000000)
+#define reg_la1_data (*(volatile uint32_t*)0x25000004)
+#define reg_la2_data (*(volatile uint32_t*)0x25000008)
+#define reg_la3_data (*(volatile uint32_t*)0x2500000c)
+
+#define reg_la0_ena (*(volatile uint32_t*)0x25000010)
+#define reg_la1_ena (*(volatile uint32_t*)0x25000014)
+#define reg_la2_ena (*(volatile uint32_t*)0x25000018)
+#define reg_la3_ena (*(volatile uint32_t*)0x2500001c)
+
+// User Project Control (0x2300_0000)
+#define reg_mprj_xfer (*(volatile uint32_t*)0x26000000)
+#define reg_mprj_pwr  (*(volatile uint32_t*)0x26000004)
+#define reg_mprj_datal (*(volatile uint32_t*)0x26000008)
+#define reg_mprj_datah (*(volatile uint32_t*)0x2600000c)
+
+#define reg_mprj_io_0 (*(volatile uint32_t*)0x26000020)
+#define reg_mprj_io_1 (*(volatile uint32_t*)0x26000024)
+#define reg_mprj_io_2 (*(volatile uint32_t*)0x26000028)
+#define reg_mprj_io_3 (*(volatile uint32_t*)0x2600002c)
+#define reg_mprj_io_4 (*(volatile uint32_t*)0x26000030)
+#define reg_mprj_io_5 (*(volatile uint32_t*)0x26000034)
+#define reg_mprj_io_6 (*(volatile uint32_t*)0x26000038)
+
+#define reg_mprj_io_7 (*(volatile uint32_t*)0x2600003c)
+#define reg_mprj_io_8 (*(volatile uint32_t*)0x26000040)
+#define reg_mprj_io_9 (*(volatile uint32_t*)0x26000044)
+#define reg_mprj_io_10 (*(volatile uint32_t*)0x26000048)
+
+#define reg_mprj_io_11 (*(volatile uint32_t*)0x2600004c)
+#define reg_mprj_io_12 (*(volatile uint32_t*)0x26000050)
+#define reg_mprj_io_13 (*(volatile uint32_t*)0x26000054)
+#define reg_mprj_io_14 (*(volatile uint32_t*)0x26000058)
+
+#define reg_mprj_io_15 (*(volatile uint32_t*)0x2600005c)
+#define reg_mprj_io_16 (*(volatile uint32_t*)0x26000060)
+#define reg_mprj_io_17 (*(volatile uint32_t*)0x26000064)
+#define reg_mprj_io_18 (*(volatile uint32_t*)0x26000068)
+
+#define reg_mprj_io_19 (*(volatile uint32_t*)0x2600006c)
+#define reg_mprj_io_20 (*(volatile uint32_t*)0x26000070)
+#define reg_mprj_io_21 (*(volatile uint32_t*)0x26000074)
+#define reg_mprj_io_22 (*(volatile uint32_t*)0x26000078)
+
+#define reg_mprj_io_23 (*(volatile uint32_t*)0x2600007c)
+#define reg_mprj_io_24 (*(volatile uint32_t*)0x26000080)
+#define reg_mprj_io_25 (*(volatile uint32_t*)0x26000084)
+#define reg_mprj_io_26 (*(volatile uint32_t*)0x26000088)
+
+#define reg_mprj_io_27 (*(volatile uint32_t*)0x2600008c)
+#define reg_mprj_io_28 (*(volatile uint32_t*)0x26000090)
+#define reg_mprj_io_29 (*(volatile uint32_t*)0x26000094)
+#define reg_mprj_io_30 (*(volatile uint32_t*)0x26000098)
+#define reg_mprj_io_31 (*(volatile uint32_t*)0x2600009c)
+
+#define reg_mprj_io_32 (*(volatile uint32_t*)0x260000a0)
+#define reg_mprj_io_33 (*(volatile uint32_t*)0x260000a4)
+#define reg_mprj_io_34 (*(volatile uint32_t*)0x260000a8)
+#define reg_mprj_io_35 (*(volatile uint32_t*)0x260000ac)
+#define reg_mprj_io_36 (*(volatile uint32_t*)0x260000b0)
+#define reg_mprj_io_37 (*(volatile uint32_t*)0x260000b4)
+
+// User Project Slaves (0x3000_0000)
+#define reg_mprj_slave (*(volatile uint32_t*)0x30000000)
+
+// Flash Control SPI Configuration (2D00_0000)
+#define reg_spictrl (*(volatile uint32_t*)0x2d000000)         
+
+// Bit fields for Flash SPI control
+#define FLASH_BITBANG_IO0	0x00000001
+#define FLASH_BITBANG_IO1	0x00000002
+#define FLASH_BITBANG_CLK	0x00000010
+#define FLASH_BITBANG_CSB	0x00000020
+#define FLASH_BITBANG_OEB0	0x00000100
+#define FLASH_BITBANG_OEB1	0x00000200
+#define FLASH_ENABLE		0x80000000
+
+// Counter-Timer 0 Configuration
+#define reg_timer0_config (*(volatile uint32_t*)0x22000000)
+#define reg_timer0_value  (*(volatile uint32_t*)0x22000004)
+#define reg_timer0_data   (*(volatile uint32_t*)0x22000008)
+
+// Counter-Timer 1 Configuration
+#define reg_timer1_config (*(volatile uint32_t*)0x23000000)
+#define reg_timer1_value  (*(volatile uint32_t*)0x23000004)
+#define reg_timer1_data   (*(volatile uint32_t*)0x23000008)
+
+// Bit fields for Counter-timer configuration
+#define TIMER_ENABLE		0x01
+#define TIMER_ONESHOT		0x02
+#define TIMER_UPCOUNT		0x04
+#define TIMER_CHAIN		0x08
+#define TIMER_IRQ_ENABLE	0x10
+
+// SPI Master Configuration
+#define reg_spimaster_config (*(volatile uint32_t*)0x24000000)
+#define reg_spimaster_data   (*(volatile uint32_t*)0x24000004)
+
+// Bit fields for SPI master configuration
+#define SPI_MASTER_DIV_MASK	0x00ff
+#define SPI_MASTER_MLB		0x0100
+#define SPI_MASTER_INV_CSB	0x0200
+#define SPI_MASTER_INV_CLK	0x0400
+#define SPI_MASTER_MODE_1	0x0800
+#define SPI_MASTER_STREAM	0x1000
+#define SPI_MASTER_ENABLE	0x2000
+#define SPI_MASTER_IRQ_ENABLE	0x4000
+#define SPI_HOUSEKEEPING_CONN	0x8000
+
+// System Area (0x2F00_0000)
+#define reg_power_good    (*(volatile uint32_t*)0x2F000000)
+#define reg_clk_out_dest  (*(volatile uint32_t*)0x2F000004)
+#define reg_trap_out_dest (*(volatile uint32_t*)0x2F000008)
+#define reg_irq_source    (*(volatile uint32_t*)0x2F00000C)
+
+// Bit fields for reg_power_good
+#define USER1_VCCD_POWER_GOOD 0x01
+#define USER2_VCCD_POWER_GOOD 0x02
+#define USER1_VDDA_POWER_GOOD 0x04
+#define USER2_VDDA_POWER_GOOD 0x08
+
+// Bit fields for reg_clk_out_dest
+#define CLOCK1_MONITOR 0x01
+#define CLOCK2_MONITOR 0x02
+
+// Bit fields for reg_irq_source
+#define IRQ7_SOURCE 0x01
+#define IRQ8_SOURCE 0x02
+
+// Individual bit fields for the GPIO pad control
+#define MGMT_ENABLE	  0x0001
+#define OUTPUT_DISABLE	  0x0002
+#define HOLD_OVERRIDE	  0x0004
+#define INPUT_DISABLE	  0x0008
+#define MODE_SELECT	  0x0010
+#define ANALOG_ENABLE	  0x0020
+#define ANALOG_SELECT	  0x0040
+#define ANALOG_POLARITY	  0x0080
+#define SLOW_SLEW_MODE	  0x0100
+#define TRIPPOINT_SEL	  0x0200
+#define DIGITAL_MODE_MASK 0x1c00
+
+// Useful GPIO mode values
+#define GPIO_MODE_MGMT_STD_INPUT_NOPULL    0x0403
+#define GPIO_MODE_MGMT_STD_INPUT_PULLDOWN  0x0803
+#define GPIO_MODE_MGMT_STD_INPUT_PULLUP	   0x0c03
+#define GPIO_MODE_MGMT_STD_OUTPUT	   0x1809
+
+#define GPIO_MODE_USER_STD_INPUT_NOPULL	   0x0402
+#define GPIO_MODE_USER_STD_INPUT_PULLDOWN  0x0802
+#define GPIO_MODE_USER_STD_INPUT_PULLUP	   0x0c02
+#define GPIO_MODE_USER_STD_OUTPUT	   0x1808
+
+// --------------------------------------------------------
+#endif
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/Makefile
new file mode 100644
index 0000000..c7fd2d9
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/Makefile
@@ -0,0 +1,35 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# ---- Test patterns for project striVe ----
+
+.SUFFIXES:
+.SILENT: clean all
+
+PATTERNS = gpio mem uart perf hkspi sysctrl mprj_ctrl pass_thru timer timer2 pll storage
+
+all:  ${PATTERNS}
+	for i in ${PATTERNS}; do \
+		( cd $$i && SIM=RTL make -f Makefile $${i}.vcd &> verify.log && grep Monitor verify.log) ; \
+		( cd $$i && SIM=GL make -f Makefile $${i}.vcd &> verify.log && grep Monitor verify.log) ; \
+	done
+
+clean:  ${PATTERNS}
+	for i in ${PATTERNS}; do \
+		( cd $$i && make clean ) ; \
+	done
+
+.PHONY: clean all
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/gpio/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/gpio/Makefile
new file mode 100644
index 0000000..5724f98
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/gpio/Makefile
@@ -0,0 +1,68 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = gpio
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/gpio/README b/verilog/dv/caravel/caravel/mgmt_soc/gpio/README
new file mode 100644
index 0000000..baadc1f
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/gpio/README
@@ -0,0 +1,44 @@
+<!---
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+-->
+------------------------------------------------
+Caravel
+gpio testbench
+------------------------------------------------
+
+This testbench exercises the fundamental use of the Caravel
+management SoC to drive the I/O in the user area as general
+purpose I/O on startup.
+
+On startup, all GPIO are configured as input to the management
+region (so as to be high impedence to the external world) and
+decoupled from the user project area.
+
+To configure any GPIO as output, the appropriate memory-mapped
+location for the I/O must be properly configured.  Since the
+I/O configuration is stored in two places, in the SoC, but
+also locally at each I/O pad, the "transfer" bit must be
+applied, which initiates a transfer of the configuration data
+around the padframe.
+
+The testbench takes 16 pins from the user area and checks
+functionality by applying input values on 8 of these pins from
+the testbench verilog, detecting them in the C program, then
+copying the values to the other 8 pins, and detecting those
+values in the testbench verilog.
+
+If any of that does not work, then the testbench will fail.
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/gpio/gpio.c b/verilog/dv/caravel/caravel/mgmt_soc/gpio/gpio.c
new file mode 100644
index 0000000..73dd397
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/gpio/gpio.c
@@ -0,0 +1,115 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+/*
+ *	GPIO Test
+ *		Tests PU and PD on the lower 8 pins while being driven from outside
+ *		Tests Writing to the upper 8 pins
+ *		Tests reading from the lower 8 pins
+ */
+
+void main()
+{
+	int i;
+
+	/* Set data out to zero */
+	reg_mprj_datal = 0;
+
+	/* Lower 8 pins are input and upper 8 pins are output */
+	reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+	reg_mprj_io_23 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+	reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
+
+	/* Apply configuration */
+	reg_mprj_xfer = 1;
+	while (reg_mprj_xfer == 1);
+
+	// change the pull up and pull down (checked by the TB)
+	reg_mprj_datal = 0xa0000000;
+
+	reg_mprj_io_23 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+
+	reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+
+	/* Apply configuration */
+	reg_mprj_xfer = 1;
+	while (reg_mprj_xfer == 1);
+
+	reg_mprj_datal = 0x0b000000;
+
+	reg_mprj_io_23 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+
+	reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+
+	/* Apply configuration */
+	reg_mprj_xfer = 1;
+	while (reg_mprj_xfer == 1);
+
+	reg_mprj_io_23 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_22 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_21 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+	reg_mprj_io_20 = GPIO_MODE_MGMT_STD_INPUT_PULLDOWN;
+
+	reg_mprj_io_19 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_18 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_17 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+	reg_mprj_io_16 = GPIO_MODE_MGMT_STD_INPUT_PULLUP;
+
+	/* Apply configuration */
+	reg_mprj_xfer = 1;
+	while (reg_mprj_xfer == 1);
+
+	// read the lower 8 pins, add 1 then output the result
+	// checked by the TB
+	reg_mprj_datal = 0xab000000;
+
+	while (1){
+		int x = (reg_mprj_datal & 0xff0000) >> 16;
+		reg_mprj_datal = (x+1) << 24;
+	}
+}
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/gpio/gpio_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/gpio/gpio_tb.v
new file mode 100644
index 0000000..f46fee9
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/gpio/gpio_tb.v
@@ -0,0 +1,192 @@
+`default_nettype none
+/*
+ *  StriVe - A full example SoC using PicoRV32 in SkyWater s8
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2018  Tim Edwards <tim@efabless.com>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module gpio_tb;
+
+	reg clock;
+	reg power1;
+	reg power2;
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock <= 0;
+	end
+
+	initial begin
+		$dumpfile("gpio.vcd");
+		$dumpvars(0, gpio_tb);
+
+		// Repeat cycles of 1000 clock edges as needed to complete testbench
+		repeat (25) begin
+			repeat (1000) @(posedge clock);
+			$display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		`ifdef GL
+			$display ("Monitor: Timeout, Test GPIO (GL) Failed");
+		`else
+			$display ("Monitor: Timeout, Test GPIO (RTL) Failed");
+		`endif
+		$display("%c[0m",27);
+		$finish;
+	end
+
+	wire [37:0] mprj_io;	// Most of these are no-connects
+	wire [15:0] checkbits;
+	reg  [7:0] checkbits_lo;
+	wire [7:0] checkbits_hi;
+
+	assign mprj_io[23:16] = checkbits_lo;
+	assign checkbits = mprj_io[31:16];
+	assign checkbits_hi = checkbits[15:8];
+	assign mprj_io[3] = 1'b1;       // Force CSB high.
+
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+	wire gpio;
+
+	reg RSTB;
+
+	// Transactor
+	initial begin
+		checkbits_lo <= {8{1'bz}};
+		wait(checkbits_hi == 8'hA0);
+		checkbits_lo <= 8'hF0;
+		wait(checkbits_hi == 8'h0B);
+		checkbits_lo <= 8'h0F;
+		wait(checkbits_hi == 8'hAB);
+		checkbits_lo <= 8'h0;
+		repeat (1000) @(posedge clock);
+		checkbits_lo <= 8'h1;
+		repeat (1000) @(posedge clock);
+		checkbits_lo <= 8'h3;
+	end
+
+	// Monitor
+	initial begin
+		wait(checkbits_hi == 8'hA0);
+		wait(checkbits[7:0]  == 8'hF0);
+		wait(checkbits_hi == 8'h0B);
+		wait(checkbits[7:0]  == 8'h0F);
+		wait(checkbits_hi == 8'hAB);
+		wait(checkbits[7:0]  == 8'h00);
+		wait(checkbits_hi == 8'h01);
+		wait(checkbits[7:0]  == 8'h01);
+		wait(checkbits_hi == 8'h02);
+		wait(checkbits[7:0]  == 8'h03);
+		wait(checkbits_hi == 8'h04);
+		`ifdef GL
+			$display("Monitor: Test GPIO (GL) Passed");
+		`else
+			$display("Monitor: Test GPIO (RTL) Passed");
+		`endif
+		$finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+		#2000;
+	end
+
+	initial begin			// Power-up
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+		
+
+	always @(checkbits) begin
+		#1 $display("GPIO state = %b (%d - %d)", checkbits,
+				checkbits_hi, checkbits_lo);
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+
+	// These are the mappings of mprj_io GPIO pads that are set to
+	// specific functions on startup:
+	//
+	// JTAG      = mgmt_gpio_io[0]              (inout)
+	// SDO       = mgmt_gpio_io[1]              (output)
+	// SDI       = mgmt_gpio_io[2]              (input)
+	// CSB       = mgmt_gpio_io[3]              (input)
+	// SCK       = mgmt_gpio_io[4]              (input)
+	// ser_rx    = mgmt_gpio_io[5]              (input)
+	// ser_tx    = mgmt_gpio_io[6]              (output)
+	// irq       = mgmt_gpio_io[7]              (input)
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("gpio.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/hkspi/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/hkspi/Makefile
new file mode 100644
index 0000000..1695a45
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/hkspi/Makefile
@@ -0,0 +1,69 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# ---- Test patterns for project striVe ----
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = hkspi
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/hkspi/hkspi.c b/verilog/dv/caravel/caravel/mgmt_soc/hkspi/hkspi.c
new file mode 100644
index 0000000..3bfac32
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/hkspi/hkspi.c
@@ -0,0 +1,92 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+void putchar(char c)
+{
+	if (c == '\n')
+		putchar('\r');
+	reg_uart_data = c;
+}
+
+void print(const char *p)
+{
+	while (*p)
+		putchar(*(p++));
+}
+
+// --------------------------------------------------------
+
+void main()
+{
+    // This program is just to keep the processor busy while the
+    // housekeeping SPI is being accessed, to show that the
+    // processor is interrupted only when the reset is applied
+    // through the SPI.
+
+    // Configure I/O:  High 16 bits of user area used for a 16-bit
+    // word to write and be detected by the testbench verilog.
+    // Only serial Tx line is used in this testbench.  It connects
+    // to mprj_io[6].  Since all lines of the chip are input or
+    // high impedence on startup, the I/O has to be configured
+    // for output
+
+    reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    reg_mprj_io_6 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    // Apply configuration
+    reg_mprj_xfer = 1;
+    while (reg_mprj_xfer == 1);
+
+    // Start test
+    reg_mprj_datal = 0xa0000000;
+
+    // Set clock to 64 kbaud and enable the UART
+    reg_uart_clkdiv = 625;
+    reg_uart_enable = 1;
+
+    // Test message
+    print("\n");
+    print("  ____  _          ____         ____\n");
+    print(" |  _ \\(_) ___ ___/ ___|  ___  / ___|\n");
+    print(" | |_) | |/ __/ _ \\___ \\ / _ \\| |\n");
+    print(" |  __/| | (_| (_) |__) | (_) | |___\n");
+    print(" |_|   |_|\\___\\___/____/ \\___/ \\____|\n");
+
+    reg_mprj_datal = 0xab000000;
+}
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/hkspi/hkspi_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/hkspi/hkspi_tb.v
new file mode 100644
index 0000000..50ea981
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/hkspi/hkspi_tb.v
@@ -0,0 +1,430 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+/*	
+	StriVe housekeeping SPI testbench.
+*/
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+`include "tbuart.v"
+
+module hkspi_tb;
+	reg clock;
+	reg SDI, CSB, SCK, RSTB;
+	reg power1, power2;
+
+	wire gpio;
+	wire [15:0] checkbits;
+	wire [37:0] mprj_io;
+	wire uart_tx;
+	wire uart_rx;
+
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+	wire flash_io2;
+	wire flash_io3;
+
+	wire SDO;
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+    // The main testbench is here.  Put the housekeeping SPI into
+    // pass-thru mode and read several bytes from the flash SPI.
+
+    // First define tasks for SPI functions
+
+	task start_csb;
+	    begin
+		SCK <= 1'b0;
+		SDI <= 1'b0;
+		CSB <= 1'b0;
+		#50;
+	    end
+	endtask
+
+	task end_csb;
+	    begin
+		SCK <= 1'b0;
+		SDI <= 1'b0;
+		CSB <= 1'b1;
+		#50;
+	    end
+	endtask
+
+	task write_byte;
+	    input [7:0] odata;
+	    begin
+		SCK <= 1'b0;
+		for (i=7; i >= 0; i--) begin
+		    #50;
+		    SDI <= odata[i];
+                    #50;
+		    SCK <= 1'b1;
+                    #100;
+		    SCK <= 1'b0;
+		end
+	    end
+	endtask
+
+	task read_byte;
+	    output [7:0] idata;
+	    begin
+		SCK <= 1'b0;
+		SDI <= 1'b0;
+		for (i=7; i >= 0; i--) begin
+		    #50;
+                    idata[i] = SDO;
+                    #50;
+		    SCK <= 1'b1;
+                    #100;
+		    SCK <= 1'b0;
+		end
+	    end
+	endtask
+
+	task read_write_byte
+	    (input [7:0] odata,
+	    output [7:0] idata);
+	    begin
+		SCK <= 1'b0;
+		for (i=7; i >= 0; i--) begin
+		    #50;
+		    SDI <= odata[i];
+                    idata[i] = SDO;
+                    #50;
+		    SCK <= 1'b1;
+                    #100;
+		    SCK <= 1'b0;
+		end
+	    end
+	endtask
+	
+	integer i;
+
+    // Now drive the digital signals on the housekeeping SPI
+	reg [7:0] tbdata;
+
+	initial begin
+	    $dumpfile("hkspi.vcd");
+	    $dumpvars(0, hkspi_tb);
+
+	    CSB <= 1'b1;
+	    SCK <= 1'b0;
+	    SDI <= 1'b0;
+	    RSTB <= 1'b0;
+
+	    // Delay, then bring chip out of reset
+	    #1000;
+	    RSTB <= 1'b1;
+	    #2000;
+
+            // First do a normal read from the housekeeping SPI to
+	    // make sure the housekeeping SPI works.
+
+	    start_csb();
+	    write_byte(8'h40);	// Read stream command
+	    write_byte(8'h03);	// Address (register 3 = product ID)
+	    read_byte(tbdata);
+	    end_csb();
+	    #10;
+	    $display("Read data = 0x%02x (should be 0x10)", tbdata);
+
+	    // Toggle external reset
+	    start_csb();
+	    write_byte(8'h80);	// Write stream command
+	    write_byte(8'h07);	// Address (register 7 = external reset)
+	    write_byte(8'h01);	// Data = 0x01 (apply external reset)
+	    end_csb();
+
+	    start_csb();
+	    write_byte(8'h80);	// Write stream command
+	    write_byte(8'h07);	// Address (register 7 = external reset)
+	    write_byte(8'h00);	// Data = 0x00 (release external reset)
+	    end_csb();
+
+	    // Read all registers (0 to 18)
+	    start_csb();
+	    write_byte(8'h40);	// Read stream command
+	    write_byte(8'h00);	// Address (register 3 = product ID)
+	    read_byte(tbdata);
+
+	    $display("Read register 0 = 0x%02x (should be 0x00)", tbdata);
+		if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 1 = 0x%02x (should be 0x04)", tbdata);
+		if(tbdata !== 8'h04) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 2 = 0x%02x (should be 0x56)", tbdata);
+		if(tbdata !== 8'h56) begin
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed, %02x", tbdata); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed, %02x", tbdata); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 3 = 0x%02x (should be 0x10)", tbdata);
+		if(tbdata !== 8'h10) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed, %02x", tbdata); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed, %02x", tbdata); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 4 = 0x%02x (should be 0x00)", tbdata);
+		if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 5 = 0x%02x (should be 0x00)", tbdata);
+		if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 6 = 0x%02x (should be 0x00)", tbdata);
+		if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 7 = 0x%02x (should be 0x00)", tbdata);
+		if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 8 = 0x%02x (should be 0x02)", tbdata);
+		if(tbdata !== 8'h02) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 9 = 0x%02x (should be 0x01)", tbdata);
+		if(tbdata !== 8'h01) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 10 = 0x%02x (should be 0x00)", tbdata);
+		if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 11 = 0x%02x (should be 0x00)", tbdata);
+		if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 12 = 0x%02x (should be 0x00)", tbdata);
+		if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 13 = 0x%02x (should be 0xff)", tbdata);
+		if(tbdata !== 8'hff) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 14 = 0x%02x (should be 0xef)", tbdata);
+		if(tbdata !== 8'hef) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 15 = 0x%02x (should be 0xff)", tbdata);
+		if(tbdata !== 8'hff) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 16 = 0x%02x (should be 0x03)", tbdata);
+		if(tbdata !== 8'h03) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 17 = 0x%02x (should be 0x12)", tbdata);
+		if(tbdata !== 8'h12) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read register 18 = 0x%02x (should be 0x04)", tbdata);
+		if(tbdata !== 8'h04) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI (RTL) Failed"); $finish; 
+			`endif
+		end
+		
+        end_csb();
+
+		`ifdef GL
+			$display("Monitor: Test HK SPI (GL) Passed");
+		`else
+			$display("Monitor: Test HK SPI (RTL) Passed");
+		`endif
+
+	    #10000;
+ 	    $finish;
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+
+	wire hk_sck;
+	wire hk_csb;
+	wire hk_sdi;
+
+	assign hk_sck = SCK;
+	assign hk_csb = CSB;
+	assign hk_sdi = SDI;
+
+	assign checkbits = mprj_io[31:16];
+	assign uart_tx = mprj_io[6];
+	assign mprj_io[5] = uart_rx;
+	assign mprj_io[4] = hk_sck;
+	assign mprj_io[3] = hk_csb;
+	assign mprj_io[2] = hk_sdi;
+	assign SDO = mprj_io[1];
+	
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("hkspi.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+	tbuart tbuart (
+		.ser_rx(uart_tx)
+	);
+		
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/mem/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/mem/Makefile
new file mode 100644
index 0000000..2be8c42
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/mem/Makefile
@@ -0,0 +1,69 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = mem
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@                     
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/mem/mem.c b/verilog/dv/caravel/caravel/mgmt_soc/mem/mem.c
new file mode 100644
index 0000000..a3b6fcc
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/mem/mem.c
@@ -0,0 +1,92 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+/*
+	Memory Test
+	It uses GPIO to flag the success or failure of the test
+*/
+unsigned int ints[10];
+unsigned short shorts[10];
+unsigned char bytes[10];
+
+void main()
+{
+    int i;
+
+    /* Upper 16 user area pins are configured to be GPIO output */
+
+    reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    // Apply configuration
+    reg_mprj_xfer = 1;
+    while (reg_mprj_xfer == 1);
+
+    // start test
+    reg_mprj_datal = 0xA0400000;
+
+    // Test Word R/W
+    for (i=0; i<10; i++)
+	ints[i] = i*5000 + 10000;
+	
+    for (i=0; i<10; i++)
+	if ((i*5000+10000) != ints[i])
+	    reg_mprj_datal = 0xAB400000;
+
+    reg_mprj_datal = 0xAB410000;
+	
+    // Test Half Word R/W
+    reg_mprj_datal = 0xA0200000;
+    for (i=0; i<10; i++)
+	shorts[i] = i*500 + 100;
+	
+    for(i=0; i<10; i++)
+	if((i*500+100) != shorts[i])
+	    reg_mprj_datal = 0xAB200000;
+
+    reg_mprj_datal = 0xAB210000;
+
+    // Test byte R/W
+    reg_mprj_datal = 0xA0100000;
+    for(i=0; i<10; i++)
+	bytes[i] = i*5 + 10;
+	
+    for(i=0; i<10; i++)
+	if((i*5+10) != bytes[i])
+	    reg_mprj_datal = 0xAB100000;
+
+    reg_mprj_datal = 0xAB110000;
+}
\ No newline at end of file
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/mem/mem_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/mem/mem_tb.v
new file mode 100644
index 0000000..a82184c
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/mem/mem_tb.v
@@ -0,0 +1,199 @@
+`default_nettype none
+/*
+ *  StriVe - A full example SoC using PicoRV32 in SkyWater s8
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2018  Tim Edwards <tim@efabless.com>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module mem_tb;
+	reg clock;
+	reg RSTB;
+	reg power1, power2;
+
+	wire gpio;
+        wire [15:0] checkbits;
+	wire [37:0] mprj_io;
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+
+	assign checkbits = mprj_io[31:16];
+
+	// External clock is used by default.  Make this artificially fast for the
+	// simulation.  Normally this would be a slow clock and the digital PLL
+	// would be the fast clock.
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin
+		$dumpfile("mem.vcd");
+		$dumpvars(0, mem_tb);
+
+		// Repeat cycles of 1000 clock edges as needed to complete testbench
+		repeat (100) begin
+			repeat (1000) @(posedge clock);
+			//$display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		`ifdef GL
+			$display ("Monitor: Timeout, Test MEM (GL) Failed");
+		`else
+			$display ("Monitor: Timeout, Test MEM (RTL) Failed");
+		`endif
+		$display("%c[0m",27);
+		$finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+		#2000;
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+	always @(checkbits) begin
+		if(checkbits == 16'hA040) begin
+			$display("Mem Test (word rw) started");
+		end
+		else if(checkbits == 16'hAB40) begin
+			$display("%c[1;31m",27);
+			`ifdef GL
+				$display("Monitor: Test MEM (GL) [word rw] failed");
+			`else
+				$display("Monitor: Test MEM (RTL) [word rw] failed");
+			`endif
+			$display("%c[0m",27);
+			$finish;
+		end
+		else if(checkbits == 16'hAB41) begin
+			`ifdef GL
+				$display("Monitor: Test MEM (GL) [word rw]  passed");
+			`else
+				$display("Monitor: Test MEM (RTL) [word rw]  passed");
+			`endif
+		end
+		else if(checkbits == 16'hA020) begin
+			$display("Mem Test (short rw) started");
+		end
+		else if(checkbits == 16'hAB20) begin
+			$display("%c[1;31m",27);
+			`ifdef GL
+				$display("Monitor: Test MEM (GL) [short rw] failed");
+			`else
+				$display("Monitor: Test MEM (RTL) [short rw] failed");
+			`endif
+			$display("%c[0m",27);
+			$finish;
+		end
+		else if(checkbits == 16'hAB21) begin
+			`ifdef GL
+				$display("Monitor: Test MEM (GL) [short rw]  passed");
+			`else
+				$display("Monitor: Test MEM (RTL) [short rw]  passed");
+			`endif
+		end
+		else if(checkbits == 16'hA010) begin
+			$display("Mem Test (byte rw) started");
+		end
+		else if(checkbits == 16'hAB10) begin
+			$display("%c[1;31m",27);
+			`ifdef GL
+				$display("Monitor: Test MEM (GL) [byte rw] failed");
+			`else
+				$display("Monitor: Test MEM (RTL) [byte rw] failed");
+			`endif
+			$display("%c[0m",27);
+			$finish;
+		end
+		else if(checkbits == 16'hAB11) begin
+			`ifdef GL
+				$display("Monitor: Test MEM (GL) [byte rw] passed");
+			`else
+				$display("Monitor: Test MEM (RTL) [byte rw] passed");
+			`endif
+			$finish;
+		end
+
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+
+	assign VSS = 1'b0;
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+
+	assign mprj_io[3] = 1'b1;       // Force CSB high.
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("mem.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/mprj_ctrl/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/mprj_ctrl/Makefile
new file mode 100644
index 0000000..64e99ed
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/mprj_ctrl/Makefile
@@ -0,0 +1,69 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = mprj_ctrl
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@                     
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/mprj_ctrl/mprj_ctrl.c b/verilog/dv/caravel/caravel/mgmt_soc/mprj_ctrl/mprj_ctrl.c
new file mode 100644
index 0000000..1d7a140
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/mprj_ctrl/mprj_ctrl.c
@@ -0,0 +1,108 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+/*
+ *	User Project IO Control Test
+ */
+
+void main()
+{
+    /* All GPIO pins are configured to be output	*/
+    /* The lower 28 bits are connected to the user	*/
+    /* project to output the counter result, and the	*/
+    /* upper 4 bits are connected to the management	*/
+    /* SoC to apply values that can be flagged by the	*/
+    /* testbench for specific benchmark tests.		*/
+
+    /* GPIOs 31 to 16 are connected to the management SoC */
+    reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    /* GPIOs 27 to 0 are connected to the user area */
+    reg_mprj_io_27 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_26 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_25 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_24 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_23 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_22 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_21 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_20 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_19 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_18 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_17 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_16 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_15 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_14 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_13 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_12 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_11 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_10 = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_9  = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_8  = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_7  = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_6  = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_5  = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_4  = GPIO_MODE_USER_STD_OUTPUT;
+    // reg_mprj_io_3  = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_2  = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_1  = GPIO_MODE_USER_STD_OUTPUT;
+    reg_mprj_io_0  = GPIO_MODE_USER_STD_OUTPUT;
+
+    // Apply configuration
+    reg_mprj_xfer = 1;
+    while (reg_mprj_xfer == 1);
+
+    reg_mprj_datal = 0;
+
+    // start test
+    reg_mprj_datal = 0x50000000;
+
+    // Write to IO Control
+    reg_mprj_io_0 = 0x004F;
+    if (reg_mprj_io_0 != 0x004F)
+	reg_mprj_datal = 0x60000000;
+     else
+	reg_mprj_datal = 0x70000000;
+
+    // Write to IO Control 
+    reg_mprj_io_1 = 0x005F;
+    if (reg_mprj_io_1 != 0x005F)
+	reg_mprj_datal = 0x80000000;
+    else
+	reg_mprj_datal = 0x90000000;
+
+    // Write to IO Control
+    reg_mprj_io_2 = 0x006F;
+    if (reg_mprj_io_2 != 0x006F)
+	reg_mprj_datal = 0xA0000000;
+    else
+	reg_mprj_datal = 0xb0000000;
+
+    // Write to IO Control (NOTE:  Only 13 bits are valid)
+    reg_mprj_io_3 = 0xF0F5;
+    if (reg_mprj_io_3 != 0x10F5)
+	reg_mprj_datal = 0xc0000000;
+    else
+	reg_mprj_datal = 0xd0000000;
+}
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/mprj_ctrl/mprj_ctrl_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/mprj_ctrl/mprj_ctrl_tb.v
new file mode 100644
index 0000000..ae04001
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/mprj_ctrl/mprj_ctrl_tb.v
@@ -0,0 +1,175 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module mprj_ctrl_tb;
+	reg clock;
+	reg RSTB;
+	reg power1, power2;
+
+	wire gpio;
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+	wire [37:0] user_io;
+	wire SDO;
+
+	wire [3:0] checkbits;
+
+	assign checkbits = user_io[31:28];
+
+	// External clock is used by default.  Make this artificially fast for the
+	// simulation.  Normally this would be a slow clock and the digital PLL
+	// would be the fast clock.
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin
+		$dumpfile("mprj_ctrl.vcd");
+		$dumpvars(0, mprj_ctrl_tb);
+		repeat (25) begin
+			repeat (1000) @(posedge clock);
+			$display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		`ifdef GL
+			$display ("Monitor: Timeout, Test User Project (GL) Failed");
+		`else
+			$display ("Monitor: Timeout, Test User Project (RTL) Failed");
+		`endif
+		$display("%c[0m",27);
+		$finish;
+	end
+
+	always @(checkbits) begin
+		if(checkbits == 4'h5) begin
+			$display("User Project control Test started");
+		end else if(checkbits == 4'h6) begin
+			$display("%c[1;31m",27);
+			$display("Monitor: IO control R/W failed (check 6)");
+			$display("%c[0m",27);
+			$finish;
+		end else if(checkbits == 4'h7) begin
+			$display("Monitor: IO control R/W passed (check 7)");
+		end else if(checkbits == 4'h8) begin
+            		$display("%c[1;31m",27);
+			$display("Monitor: power control R/W failed (check 8)");
+			$display("%c[0m",27);
+			$finish;
+        	end else if(checkbits == 4'h9) begin
+			$display("Monitor: power control R/W passed (check 9)");
+		end else if(checkbits == 4'ha) begin
+            		$display("%c[1;31m",27);
+			$display("Monitor: power control R/W failed (check 10)");
+			$display("%c[0m",27);
+			$finish;
+        	end else if(checkbits == 4'hb) begin
+			$display("Monitor: power control R/W passed (check 11)");
+		end else if(checkbits == 4'hc) begin
+            		$display("%c[1;31m",27);
+			$display("Monitor: power control R/W failed (check 12)");
+			$display("%c[0m",27);
+			$finish;
+        	end else if(checkbits == 4'hd) begin
+
+			$display("Monitor: power control R/W passed (check 13)");
+			`ifdef GL
+            	$display("Monitor: User Project control (GL) test passed.");
+			`else
+			    $display("Monitor: User Project control (RTL) test passed.");
+			`endif
+            $finish;
+        	end			
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+		#2000;
+	end
+
+	initial begin
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+	always @(gpio) begin
+		#1 $display("GPIO state = %b ", gpio);
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+	
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+
+	assign user_io[3] = 1'b1;
+	
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	   (clock),
+		.gpio      (gpio),
+		.mprj_io   (user_io),
+		.flash_csb (flash_csb),
+		.flash_clk (flash_clk),
+		.flash_io0 (flash_io0),
+		.flash_io1 (flash_io1),
+		.resetb	   (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("mprj_ctrl.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/pass_thru/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/pass_thru/Makefile
new file mode 100644
index 0000000..2fba759
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/pass_thru/Makefile
@@ -0,0 +1,69 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# ---- Test patterns for project striVe ----
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = pass_thru
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/pass_thru/pass_thru.c b/verilog/dv/caravel/caravel/mgmt_soc/pass_thru/pass_thru.c
new file mode 100644
index 0000000..33a981d
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/pass_thru/pass_thru.c
@@ -0,0 +1,91 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+void putchar(char c)
+{
+	if (c == '\n')
+		putchar('\r');
+	reg_uart_data = c;
+}
+
+void print(const char *p)
+{
+	while (*p)
+		putchar(*(p++));
+}
+
+// --------------------------------------------------------
+
+void main()
+{
+    // This program is just to keep the processor busy while the
+    // housekeeping SPI is being accessed. to show that the
+    // processor is halted while the SPI is accessing the
+    // flash SPI in pass-through mode.
+
+    // Configure I/O:  High 16 bits of user area used for a 16-bit
+    // word to write and be detected by the testbench verilog.
+    // Only serial Tx line is used in this testbench.  It connects
+    // to mprj_io[6].  Since all lines of the chip are input or
+    // high impedence on startup, the I/O has to be configured
+    // for output
+
+    reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    reg_mprj_io_6 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    // Apply configuration
+    reg_mprj_xfer = 1;
+    while (reg_mprj_xfer == 1);
+
+    // Start test
+    reg_mprj_datal = 0xa0000000;
+
+    // Set clock to 64 kbaud and enable the UART
+    reg_uart_clkdiv = 625;
+    reg_uart_enable = 1;
+
+    // Test in progress
+    reg_mprj_datal = 0xa5000000;
+
+    // Test message
+    print("Test message\n");
+
+    // End test
+    reg_mprj_datal = 0xab000000;
+}
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/pass_thru/pass_thru_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/pass_thru/pass_thru_tb.v
new file mode 100644
index 0000000..bb141e1
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/pass_thru/pass_thru_tb.v
@@ -0,0 +1,349 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+/*	
+ *	StriVe housekeeping pass-thru mode SPI testbench.
+ */
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+`include "tbuart.v"
+
+module pass_thru_tb;
+	reg clock;
+	reg SDI, CSB, SCK, RSTB;
+	reg power1, power2;
+
+	wire gpio;
+	wire [15:0] checkbits;
+	wire [37:0] mprj_io;
+	wire uart_tx;
+	wire uart_rx;
+
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+	wire flash_io2;
+	wire flash_io3;
+
+	wire SDO;
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+    // The main testbench is here.  Put the housekeeping SPI into
+    // pass-thru mode and read several bytes from the flash SPI.
+
+    // First define tasks for SPI functions
+
+	task start_csb;
+	    begin
+		SCK <= 1'b0;
+		SDI <= 1'b0;
+		CSB <= 1'b0;
+		#50;
+	    end
+	endtask
+
+	task end_csb;
+	    begin
+		SCK <= 1'b0;
+		SDI <= 1'b0;
+		CSB <= 1'b1;
+		#50;
+	    end
+	endtask
+
+	task write_byte;
+	    input [7:0] odata;
+	    begin
+		SCK <= 1'b0;
+		for (i=7; i >= 0; i--) begin
+		    #50;
+		    SDI <= odata[i];
+                    #50;
+		    SCK <= 1'b1;
+                    #100;
+		    SCK <= 1'b0;
+		end
+	    end
+	endtask
+
+	task read_byte;
+	    output [7:0] idata;
+	    begin
+		SCK <= 1'b0;
+		SDI <= 1'b0;
+		for (i=7; i >= 0; i--) begin
+		    #50;
+                    idata[i] = SDO;
+                    #50;
+		    SCK <= 1'b1;
+                    #100;
+		    SCK <= 1'b0;
+		end
+	    end
+	endtask
+
+	task read_write_byte
+	    (input [7:0] odata,
+	    output [7:0] idata);
+	    begin
+		SCK <= 1'b0;
+		for (i=7; i >= 0; i--) begin
+		    #50;
+		    SDI <= odata[i];
+                    idata[i] = SDO;
+                    #50;
+		    SCK <= 1'b1;
+                    #100;
+		    SCK <= 1'b0;
+		end
+	    end
+	endtask
+	
+	integer i;
+
+    // Now drive the digital signals on the housekeeping SPI
+	reg [7:0] tbdata;
+
+	initial begin
+	    $dumpfile("pass_thru.vcd");
+	    $dumpvars(0, pass_thru_tb);
+
+	    CSB <= 1'b1;
+	    SCK <= 1'b0;
+	    SDI <= 1'b0;
+	    RSTB <= 1'b0;
+
+	    #2000;
+
+	    RSTB <= 1'b1;
+
+	    // Wait on start of program execution
+	    wait(checkbits == 16'hA000);
+
+            // First do a normal read from the housekeeping SPI to
+	    // make sure the housekeeping SPI works.
+
+	    start_csb();
+	    write_byte(8'h40);	// Read stream command
+	    write_byte(8'h03);	// Address (register 3 = product ID)
+	    read_byte(tbdata);
+	    end_csb();
+	    #10;
+	    $display("Read data = 0x%02x (should be 0x10)", tbdata);
+	    if(tbdata !== 8'h10) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI Pass-thru (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI Pass-thru (RTL) Failed"); $finish; 
+			`endif
+		end
+
+	    start_csb();
+	    write_byte(8'hc4);	// Pass-thru mode
+	    write_byte(8'h03);	// Command 03 (read values w/3-byte address
+	    write_byte(8'h00);	// Address is next three bytes (0x000000)
+	    write_byte(8'h00);
+	    write_byte(8'h00);
+
+	    read_byte(tbdata);
+	    $display("Read flash data = 0x%02x (should be 0x93)", tbdata);
+	    if(tbdata !== 8'h93) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI Pass-thru (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI Pass-thru (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read flash data = 0x%02x (should be 0x00)", tbdata);
+	    if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI Pass-thru (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI Pass-thru (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read flash data = 0x%02x (should be 0x00)", tbdata);
+	    if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI Pass-thru (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI Pass-thru (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read flash data = 0x%02x (should be 0x00)", tbdata);
+	    if(tbdata !== 8'h00) begin
+			`ifdef GL
+				$display("Monitor: Test HK SPI Pass-thru (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI Pass-thru (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read flash data = 0x%02x (should be 0x93)", tbdata);
+	    if(tbdata !== 8'h93) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI Pass-thru (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI Pass-thru (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read flash data = 0x%02x (should be 0x01)", tbdata);
+	    if(tbdata !== 8'h01) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI Pass-thru (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI Pass-thru (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read flash data = 0x%02x (should be 0x00)", tbdata);
+	    if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI Pass-thru (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI Pass-thru (RTL) Failed"); $finish; 
+			`endif
+		end
+	    read_byte(tbdata);
+	    $display("Read flash data = 0x%02x (should be 0x00)", tbdata);
+	    if(tbdata !== 8'h00) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI Pass-thru (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI Pass-thru (RTL) Failed"); $finish; 
+			`endif
+		end
+
+	    end_csb();
+
+	    // Wait for processor to restart
+	    wait(checkbits == 16'hA000);
+
+	    // Read product ID register again
+
+	    start_csb();
+	    write_byte(8'h40);	// Read stream command
+	    write_byte(8'h03);	// Address (register 3 = product ID)
+	    read_byte(tbdata);
+	    end_csb();
+	    #10;
+	    $display("Read data = 0x%02x (should be 0x10)", tbdata);
+	    if(tbdata !== 8'h10) begin 
+			`ifdef GL
+				$display("Monitor: Test HK SPI Pass-thru (GL) Failed"); $finish; 
+			`else
+				$display("Monitor: Test HK SPI Pass-thru (RTL) Failed"); $finish; 
+			`endif
+		end
+
+		`ifdef GL
+	    	$display("Monitor: Test HK SPI Pass-thru (GL) Passed");
+		`else
+			$display("Monitor: Test HK SPI Pass-thru (RTL) Passed");
+		`endif
+		
+	    #10000;
+ 	    $finish;
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+
+	wire hk_sck;
+	wire hk_csb;
+	wire hk_sdi;
+
+	assign hk_sck = SCK;
+	assign hk_csb = CSB;
+	assign hk_sdi = SDI;
+
+	assign checkbits = mprj_io[31:16];
+	assign uart_tx = mprj_io[6];
+	assign mprj_io[5] = uart_rx;
+	assign mprj_io[4] = hk_sck;
+	assign mprj_io[3] = hk_csb;
+	assign mprj_io[2] = hk_sdi;
+	assign SDO = mprj_io[1];
+	
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("pass_thru.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+	tbuart tbuart (
+		.ser_rx(uart_tx)
+	);
+		
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/perf/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/perf/Makefile
new file mode 100644
index 0000000..ed26dce
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/perf/Makefile
@@ -0,0 +1,70 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+RTL_PATH = ../../../../rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = perf
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+	
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/perf/perf.c b/verilog/dv/caravel/caravel/mgmt_soc/perf/perf.c
new file mode 100644
index 0000000..5a17ba2
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/perf/perf.c
@@ -0,0 +1,71 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+/*
+	Performance Test
+	It uses GPIO to flag the success or failure of the test
+*/
+unsigned int ints[50];
+unsigned short shorts[50];
+unsigned char bytes[50];
+
+int main()
+{
+    int i;
+    int sum = 0;
+
+    /* Upper 16 user area pins are configured to be GPIO output */
+
+    reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    // Apply configuration
+    reg_mprj_xfer = 1;
+    while (reg_mprj_xfer == 1);
+
+    reg_mprj_datal = 0;
+
+    // start test
+    reg_mprj_datal = 0xA0000000;
+	
+    for (i=0; i<100; i++)
+        sum += (sum + i);
+    
+    reg_mprj_datal = 0xAB000000;
+    
+    return sum;
+}
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/perf/perf_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/perf/perf_tb.v
new file mode 100644
index 0000000..c086226
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/perf/perf_tb.v
@@ -0,0 +1,155 @@
+`default_nettype none
+/*
+ *  StriVe - A full example SoC using PicoRV32 in SkyWater s8
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2018  Tim Edwards <tim@efabless.com>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module perf_tb;
+	reg clock;
+	reg RSTB;
+	reg power1, power2;
+
+	wire gpio;
+	wire [15:0] checkbits;
+	wire [37:0] mprj_io;
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+
+	assign checkbits = mprj_io[31:16];
+
+	// External clock is used by default.  Make this artificially fast for the
+	// simulation.  Normally this would be a slow clock and the digital PLL
+	// would be the fast clock.
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	reg [31:0] kcycles;
+
+	initial begin
+		$dumpfile("perf.vcd");
+		$dumpvars(0, perf_tb);
+
+		kcycles = 0;
+		// Repeat cycles of 1000 clock edges as needed to complete testbench
+		repeat (150) begin
+			repeat (1000) @(posedge clock);
+			//$display("+1000 cycles");
+			kcycles <= kcycles + 1;
+		end
+		$display("%c[1;31m",27);
+		`ifdef GL
+			$display ("Monitor: Timeout, Test Performance (GL) Failed");
+		`else
+			$display ("Monitor: Timeout, Test Performance (RTL) Failed");
+		`endif
+		$display("%c[0m",27);
+		$finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+		#2000;
+	end
+
+	initial begin			// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+	always @(checkbits) begin
+		//#1 $display("GPIO state = %X ", gpio);
+		if(checkbits == 16'hA000) begin
+			kcycles = 0;
+			$display("Performance Test started");
+		end
+		else if(checkbits == 16'hAB00) begin
+			//$display("Monitor: number of cycles/100 iterations: %d KCycles", kcycles);
+			`ifdef GL
+				$display("Monitor: Test Performance (GL) passed [%0d KCycles]", kcycles);
+			`else
+				$display("Monitor: Test Performance (RTL) passed [%0d KCycles]", kcycles);
+			`endif
+			$finish;
+		end
+	end
+	
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+
+	assign mprj_io[3] = 1'b1;       // Force CSB high.
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("perf.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/pll/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/pll/Makefile
new file mode 100644
index 0000000..f1f19aa
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/pll/Makefile
@@ -0,0 +1,68 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = pll
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/pll/pll.c b/verilog/dv/caravel/caravel/mgmt_soc/pll/pll.c
new file mode 100644
index 0000000..81a1fc6
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/pll/pll.c
@@ -0,0 +1,122 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+/*
+ *	PLL Test (self-switching)
+ *	- Enables SPI master
+ *	- Uses SPI master to internally access the housekeeping SPI
+ *      - Switches PLL bypass
+ *	- Changes PLL divider
+ *
+ * 	Tesbench mostly copied from sysctrl
+ */
+void main()
+{
+    int i;
+
+    reg_mprj_datal = 0;
+
+    // Configure upper 16 bits of user GPIO for generating testbench
+    // checkpoints.
+
+    reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    /* Apply configuration */
+    reg_mprj_xfer = 1;
+    while (reg_mprj_xfer == 1);
+
+    // Start test
+    reg_mprj_datal = 0xA0400000;
+
+    // Enable SPI master
+    // SPI master configuration bits:
+    // bits 7-0:	Clock prescaler value (default 2)
+    // bit  8:		MSB/LSB first (0 = MSB first, 1 = LSB first)
+    // bit  9:		CSB sense (0 = inverted, 1 = noninverted)
+    // bit 10:		SCK sense (0 = noninverted, 1 = inverted)
+    // bit 11:		mode (0 = read/write opposite edges, 1 = same edges)
+    // bit 12:		stream (1 = CSB ends transmission)
+    // bit 13:		enable (1 = enabled)
+    // bit 14:		IRQ enable (1 = enabled)
+    // bit 15:		Connect to housekeeping SPI (1 = connected)
+
+    reg_spimaster_config = 0xa002;	// Enable, prescaler = 2,
+					// connect to housekeeping SPI
+
+    // Apply stream read (0x40 + 0x03) and read back one byte 
+
+    reg_spimaster_config = 0xb002;	// Apply stream mode
+    reg_spimaster_data = 0x80;		// Write 0x80 (write mode)
+    reg_spimaster_data = 0x08;		// Write 0x18 (start address)
+    reg_spimaster_data = 0x01;		// Write 0x01 to PLL enable, no DCO mode
+    reg_spimaster_config = 0xa102;	// Release CSB (ends stream mode)
+
+    reg_spimaster_config = 0xb002;	// Apply stream mode
+    reg_spimaster_data = 0x80;		// Write 0x80 (write mode)
+    reg_spimaster_data = 0x11;		// Write 0x11 (start address)
+    reg_spimaster_data = 0x03;		// Write 0x03 to PLL output divider
+    reg_spimaster_config = 0xa102;	// Release CSB (ends stream mode)
+
+    reg_spimaster_config = 0xb002;	// Apply stream mode
+    reg_spimaster_data = 0x80;		// Write 0x80 (write mode)
+    reg_spimaster_data = 0x09;		// Write 0x09 (start address)
+    reg_spimaster_data = 0x00;		// Write 0x00 to clock from PLL (no bypass)
+    reg_spimaster_config = 0xa102;	// Release CSB (ends stream mode)
+
+    // Write checkpoint
+    reg_mprj_datal = 0xA0410000;
+
+    reg_spimaster_config = 0xb002;	// Apply stream mode
+    reg_spimaster_data = 0x80;		// Write 0x80 (write mode)
+    reg_spimaster_data = 0x12;		// Write 0x12 (start address)
+    reg_spimaster_data = 0x03;		// Write 0x03 to feedback divider (was 0x04)
+    reg_spimaster_config = 0xa102;	// Release CSB (ends stream mode)
+
+    // Write checkpoint
+    reg_mprj_datal = 0xA0420000;
+
+    reg_spimaster_config = 0xb002;	// Apply stream mode
+    reg_spimaster_data = 0x80;		// Write 0x80 (write mode)
+    reg_spimaster_data = 0x11;		// Write 0x11 (start address)
+    reg_spimaster_data = 0x04;		// Write 0x04 to PLL output divider
+    reg_spimaster_config = 0xa102;	// Release CSB (ends stream mode)
+
+    reg_spimaster_config = 0x2102;	// Release housekeeping SPI
+
+    // End test
+    reg_mprj_datal = 0xA0900000;
+}
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/pll/pll_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/pll/pll_tb.v
new file mode 100644
index 0000000..fd0f11e
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/pll/pll_tb.v
@@ -0,0 +1,167 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module pll_tb;
+	reg clock;
+	reg power1;
+	reg power2;
+	reg RSTB;
+
+	wire gpio;
+	wire [15:0] checkbits;
+	wire [7:0] spivalue;
+	wire [37:0] mprj_io;
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+	wire SDO;
+
+	assign checkbits = mprj_io[31:16];
+	assign spivalue  = mprj_io[15:8];
+
+	// External clock is used by default.  Make this artificially fast for the
+	// simulation.  Normally this would be a slow clock and the digital PLL
+	// would be the fast clock.
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin
+		$dumpfile("pll.vcd");
+		$dumpvars(0, pll_tb);
+		repeat (25) begin
+			repeat (1000) @(posedge clock);
+			$display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		`ifdef GL
+			$display ("Monitor: Timeout, Test PLL (GL) Failed");
+		`else
+			$display ("Monitor: Timeout, Test PLL (RTL) Failed");
+		`endif
+		 $display("%c[0m",27);
+		$finish;
+	end
+
+	// Monitor
+	initial begin
+	    wait(checkbits == 16'hA040);
+		`ifdef GL
+			$display("Monitor: Test PLL (GL) Started");
+		`else
+			$display("Monitor: Test PLL (RTL) Started");
+		`endif
+
+	    wait(checkbits == 16'hA041);
+            // $display("   SPI value = 0x%x (should be 0x04)", spivalue);
+            // if(spivalue !== 32'h04) begin
+            //     $display("Monitor: Test PLL (RTL) Failed");
+            //     $finish;
+            // end
+	    wait(checkbits == 16'hA042);
+            // $display("   SPI value = 0x%x (should be 0x56)", spivalue);
+            // if(spivalue !== 32'h56) begin
+            //     $display("Monitor: Test PLL (RTL) Failed");
+            //     $finish;
+            // end
+
+	    wait(checkbits == 16'hA090);
+		`ifdef GL
+            $display("Monitor: Test PLL (GL) Passed");
+		`else
+		    $display("Monitor: Test PLL (RTL) Passed");
+		`endif
+            $finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+		#2000;
+	end
+
+	initial begin
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+	always @(checkbits) begin
+		#1 $display("GPIO state = %b ", checkbits);
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+	
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+
+	assign mprj_io[3] = 1'b1;  // Force CSB high.
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock    (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("pll.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/storage/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/storage/Makefile
new file mode 100644
index 0000000..11b0b04
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/storage/Makefile
@@ -0,0 +1,68 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = storage
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/storage/storage.c b/verilog/dv/caravel/caravel/mgmt_soc/storage/storage.c
new file mode 100644
index 0000000..55fdd98
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/storage/storage.c
@@ -0,0 +1,87 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+/*
+	Storage area Test
+	It uses GPIO to flag the success or failure of the test
+*/
+
+void main()
+{
+    int i;
+    volatile uint32_t* ram_addr; 
+    /* Upper 16 user area pins are configured to be GPIO output */
+
+    reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    // Apply configuration
+    reg_mprj_xfer = 1;
+    while (reg_mprj_xfer == 1);
+
+    // start test
+    reg_mprj_datal = 0xA0400000;
+
+    // Test Management R/W block0
+    for (i=0; i<10; i++){
+        ram_addr = &reg_rw_block0 + i;
+        *ram_addr = i*5000 + 10000;
+    }
+	
+    for (i=0; i<10; i++){
+        ram_addr = &reg_rw_block0 + i;
+        if ((i*5000+10000) != *ram_addr) 
+	    reg_mprj_datal = 0xAB400000;
+    }
+	
+    reg_mprj_datal = 0xAB410000;
+	
+    // Test Management R/W block1
+    reg_mprj_datal = 0xA0200000;
+    for (i=0; i<10; i++){
+        ram_addr = &reg_rw_block1 + i;
+        *ram_addr = i*5000 + 10000;
+    }
+	
+    for (i=0; i<10; i++){
+        ram_addr = &reg_rw_block1 + i;
+        if ((i*5000+10000) != *ram_addr) 
+	    reg_mprj_datal = 0xAB200000;
+    }
+    
+    reg_mprj_datal = 0xAB210000;
+}
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/storage/storage_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/storage/storage_tb.v
new file mode 100644
index 0000000..cfbe150
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/storage/storage_tb.v
@@ -0,0 +1,186 @@
+`default_nettype none
+/*
+ *  StriVe - A full example SoC using PicoRV32 in SkyWater s8
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2018  Tim Edwards <tim@efabless.com>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module storage_tb;
+	reg clock;
+	reg RSTB;
+	reg power1, power2;
+
+	wire gpio;
+    wire [15:0] checkbits;
+	wire [37:0] mprj_io;
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+
+	assign checkbits = mprj_io[31:16];
+
+	// External clock is used by default.  Make this artificially fast for the
+	// simulation.  Normally this would be a slow clock and the digital PLL
+	// would be the fast clock.
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin
+		$dumpfile("storage.vcd");
+		$dumpvars(0, storage_tb);
+
+		// Repeat cycles of 1000 clock edges as needed to complete testbench
+		repeat (100) begin
+			repeat (1000) @(posedge clock);
+			//$display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		`ifdef GL
+			$display ("Monitor: Timeout, Test Storage (GL) Failed");
+		`else
+			$display ("Monitor: Timeout, Test Storage (RTL) Failed");
+		`endif
+		$display("%c[0m",27);
+		$finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+		#2000;
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+	always @(checkbits) begin
+		if(checkbits == 16'hA040) begin
+			`ifdef GL
+				$display("Mem Test storage MGMT block0 (GL) [word rw] started");
+			`else
+				$display("Mem Test storage MGMT block0 (RTL) [word rw] started");
+			`endif
+		end
+		else if(checkbits == 16'hAB40) begin
+			$display("%c[1;31m",27);
+			`ifdef GL
+				$display("Monitor: Test storage MGMT block0 (GL) [word rw] failed");
+			`else
+				$display("Monitor: Test storage MGMT block0 (RTL) [word rw] failed");
+			`endif
+			$display("%c[0m",27);
+			$finish;
+		end
+		else if(checkbits == 16'hAB41) begin
+			`ifdef GL
+				$display("Monitor: Test storage MGMT block0 (GL) [word rw]  passed");
+			`else
+				$display("Monitor: Test storage MGMT block0 (RTL) [word rw]  passed");
+			`endif
+		end
+		else if(checkbits == 16'hA020) begin
+			`ifdef GL
+				$display("Mem Test storage MGMT block1 (GL) [word rw] started");
+			`else
+				$display("Mem Test storage MGMT block1 (RTL) [word rw] started");
+			`endif
+		end
+		else if(checkbits == 16'hAB20) begin
+			$display("%c[1;31m",27);
+			`ifdef GL
+				$display("Monitor: Test storage MGMT block1 (GL) [word rw] failed");
+			`else
+				$display("Monitor: Test storage MGMT block1 (RTL) [word rw] failed");
+			`endif
+			$display("%c[0m",27);
+			$finish;
+		end
+		else if(checkbits == 16'hAB21) begin
+			`ifdef GL
+				$display("Monitor: Test storage MGMT block1 (GL) [word rw]  passed");
+			`else
+				$display("Monitor: Test storage MGMT block1 (RTL) [word rw]  passed");
+			`endif
+            $finish;
+		end
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+
+	assign VSS = 1'b0;
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+
+	assign mprj_io[3] = 1'b1;  // Force CSB high.
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("storage.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/sysctrl/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/sysctrl/Makefile
new file mode 100644
index 0000000..4816f03
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/sysctrl/Makefile
@@ -0,0 +1,68 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = sysctrl
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/sysctrl/sysctrl.c b/verilog/dv/caravel/caravel/mgmt_soc/sysctrl/sysctrl.c
new file mode 100644
index 0000000..0f5d56d
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/sysctrl/sysctrl.c
@@ -0,0 +1,165 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+/*
+ *	System Control Test
+ *	- Enables SPI master
+ *	- Uses SPI master to internally access the housekeeping SPI
+ *      - Reads default value of SPI-Controlled registers
+ *      - Flags failure/success using mprj_io
+ */
+void main()
+{
+    int i;
+    uint32_t value;
+
+    reg_mprj_datal = 0;
+
+    // Configure upper 16 bits of user GPIO for generating testbench
+    // checkpoints.
+
+    reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    // Configure next 8 bits for writing the SPI value read on GPIO
+    reg_mprj_io_15 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_14 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_13 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_12 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_11 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_10 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_9  = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_8  = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    /* Apply configuration */
+    reg_mprj_xfer = 1;
+    while (reg_mprj_xfer == 1);
+
+    // Start test
+    reg_mprj_datal = 0xA0400000;
+
+    // Enable SPI master
+    // SPI master configuration bits:
+    // bits 7-0:	Clock prescaler value (default 2)
+    // bit  8:		MSB/LSB first (0 = MSB first, 1 = LSB first)
+    // bit  9:		CSB sense (0 = inverted, 1 = noninverted)
+    // bit 10:		SCK sense (0 = noninverted, 1 = inverted)
+    // bit 11:		mode (0 = read/write opposite edges, 1 = same edges)
+    // bit 12:		stream (1 = CSB ends transmission)
+    // bit 13:		enable (1 = enabled)
+    // bit 14:		IRQ enable (1 = enabled)
+    // bit 15:		Connect to housekeeping SPI (1 = connected)
+
+    reg_spimaster_config = 0xa002;	// Enable, prescaler = 2,
+					// connect to housekeeping SPI
+
+    // Apply stream read (0x40 + 0x03) and read back one byte 
+
+    reg_spimaster_config = 0xb002;	// Apply stream mode
+    reg_spimaster_data = 0x40;		// Write 0x40 (read mode)
+    reg_spimaster_data = 0x01;		// Write 0x01 (start address)
+
+    reg_spimaster_data = 0x00;		// Write 0x00 for read
+    value = reg_spimaster_data;		// Read back byte
+    // Write checkpoint
+    reg_mprj_datal = 0xA0410000 | (value << 8);	// Mfgr ID (high)
+
+    reg_spimaster_data = 0x00;		// Write 0x00 for read
+    value = reg_spimaster_data;		// Read back byte
+    // Write checkpoint
+    reg_mprj_datal = 0xA0420000 | (value << 8);	// Mfgr ID (low)
+
+    reg_spimaster_data = 0x00;		// Write 0x00 for read
+    value = reg_spimaster_data;		// Read back byte
+    // Write checkpoint
+    reg_mprj_datal = 0xA0430000 | (value << 8);	// Prod ID
+
+    reg_spimaster_config = 0xa102;	// Release CSB (ends stream mode)
+    reg_spimaster_config = 0xb002;	// Apply stream mode
+    reg_spimaster_data = 0x40;		// Write 0x40 (read mode)
+    reg_spimaster_data = 0x08;		// Write 0x08 (start address)
+
+    reg_spimaster_data = 0x00;		// Write 0x00 for read
+    value = reg_spimaster_data;		// Read back byte
+    // Write checkpoint
+    reg_mprj_datal = 0xA0440000 | (value << 8);	// PLL enable
+
+    reg_spimaster_data = 0x00;		// Write 0x00 for read
+    value = reg_spimaster_data;		// Read back byte
+    // Write checkpoint
+    reg_mprj_datal = 0xA0450000 | (value << 8);	// PLL bypass
+
+    reg_spimaster_config = 0xa102;	// Release CSB (ends stream mode)
+    reg_spimaster_config = 0xb002;	// Apply stream mode
+    reg_spimaster_data = 0x40;		// Write 0x40 (read mode)
+    reg_spimaster_data = 0x0d;		// Write 0x0d (start address)
+
+    reg_spimaster_data = 0x00;		// Write 0x00 for read
+    value = reg_spimaster_data;		// Read back byte
+    // Write checkpoint
+    reg_mprj_datal = 0xA0460000 | (value << 8);	// PLL trim (2 high bits)
+
+    reg_spimaster_data = 0x00;		// Write 0x00 for read
+    value = reg_spimaster_data;		// Read back byte
+    // Write checkpoint
+    reg_mprj_datal = 0xA0470000 | (value << 8);	// PLL trim (2nd byte)
+
+    reg_spimaster_data = 0x00;		// Write 0x00 for read
+    value = reg_spimaster_data;		// Read back byte
+    // Write checkpoint
+    reg_mprj_datal = 0xA0480000 | (value << 8);	// PLL trim (3rd byte)
+
+    reg_spimaster_data = 0x00;		// Write 0x00 for read
+    value = reg_spimaster_data;		// Read back byte
+    // Write checkpoint
+    reg_mprj_datal = 0xA0490000 | (value << 8);	// PLL trim (low byte)
+
+    reg_spimaster_data = 0x00;		// Write 0x00 for read
+    value = reg_spimaster_data;		// Read back byte
+    // Write checkpoint
+    reg_mprj_datal = 0xA04a0000 | (value << 8);	// PLL select (3 lowest bits)
+
+    reg_spimaster_data = 0x00;		// Write 0x00 for read
+    value = reg_spimaster_data;		// Read back byte
+    // Write checkpoint
+    reg_mprj_datal = 0xA04b0000 | (value << 8);	// PLL divider (5 lowest bits)
+
+    reg_spimaster_config = 0xa102;	// Release CSB (ends stream mode)
+    reg_spimaster_config = 0x2102;	// Release housekeeping SPI
+
+    // End test
+    reg_mprj_datal = 0xA0900000;
+}
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/sysctrl/sysctrl_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/sysctrl/sysctrl_tb.v
new file mode 100644
index 0000000..b2e6b49
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/sysctrl/sysctrl_tb.v
@@ -0,0 +1,219 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module sysctrl_tb;
+	reg clock;
+	reg RSTB;
+	reg power1, power2;
+
+	wire gpio;
+	wire [15:0] checkbits;
+	wire [7:0] spivalue;
+	wire [37:0] mprj_io;
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+	wire SDO;
+
+	assign checkbits = mprj_io[31:16];
+	assign spivalue  = mprj_io[15:8];
+
+	// External clock is used by default.  Make this artificially fast for the
+	// simulation.  Normally this would be a slow clock and the digital PLL
+	// would be the fast clock.
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin
+		$dumpfile("sysctrl.vcd");
+		$dumpvars(0, sysctrl_tb);
+		repeat (25) begin
+			repeat (1000) @(posedge clock);
+			$display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		`ifdef GL
+			$display ("Monitor: Timeout, Test Sysctrl (GL) Failed");
+		`else
+			$display ("Monitor: Timeout, Test Sysctrl (RTL) Failed");
+		`endif
+		 $display("%c[0m",27);
+		$finish;
+	end
+
+	// Monitor
+	initial begin
+	    wait(checkbits == 16'hA040);
+			`ifdef GL
+            	$display("Monitor: Test Sysctrl (GL) Started");
+			`else
+			    $display("Monitor: Test Sysctrl (RTL) Started");
+			`endif
+	    wait(checkbits == 16'hA041);
+            $display("   SPI value = 0x%x (should be 0x04)", spivalue);
+            if(spivalue !== 32'h04) begin
+                $display("Monitor: Test Sysctrl Failed");
+                $finish;
+            end
+	    wait(checkbits == 16'hA042);
+            $display("   SPI value = 0x%x (should be 0x56)", spivalue);
+            if(spivalue !== 32'h56) begin
+                $display("Monitor: Test Sysctrl Failed");
+                $finish;
+            end
+	    wait(checkbits == 16'hA043);
+            $display("   SPI value = 0x%x (should be 0x10)", spivalue);
+            if(spivalue !== 32'h10) begin
+                $display("Monitor: Test Sysctrl Failed");
+                $finish;
+            end
+	    wait(checkbits == 16'hA044);
+            $display("   SPI value = 0x%x (should be 0x02)", spivalue);
+            if(spivalue !== 32'h02) begin
+                $display("Monitor: Test Sysctrl Failed");
+                $finish;
+            end
+	    wait(checkbits == 16'hA045);
+            $display("   SPI value = 0x%x (should be 0x01)", spivalue);
+            if(spivalue !== 32'h01) begin
+                $display("Monitor: Test Sysctrl Failed");
+                $finish;
+            end
+	    wait(checkbits == 16'hA046);
+            $display("   SPI value = 0x%x (should be 0xff)", spivalue);
+            if(spivalue !== 32'hff) begin
+                $display("Monitor: Test Sysctrl Failed");
+                $finish;
+            end
+	    wait(checkbits == 16'hA047);
+            $display("   SPI value = 0x%x (should be 0xef)", spivalue);
+            if(spivalue !== 32'hef) begin
+                $display("Monitor: Test Sysctrl Failed");
+                $finish;
+            end
+	    wait(checkbits == 16'hA048);
+            $display("   SPI value = 0x%x (should be 0xff)", spivalue);
+            if(spivalue !== 32'hff) begin
+                $display("Monitor: Test Sysctrl Failed");
+                $finish;
+            end
+	    wait(checkbits == 16'hA049);
+            $display("   SPI value = 0x%x (should be 0x03)", spivalue);
+            if(spivalue !== 32'h03) begin
+                $display("Monitor: Test Sysctrl Failed");
+                $finish;
+            end
+	    wait(checkbits == 16'hA04a);
+            $display("   SPI value = 0x%x (should be 0x12)", spivalue);
+            if(spivalue !== 32'h12) begin
+                $display("Monitor: Test Sysctrl Failed");
+                $finish;
+            end
+	    wait(checkbits == 16'hA04b);
+            $display("   SPI value = 0x%x (should be 0x04)", spivalue);
+            if(spivalue !== 32'h04) begin
+                $display("Monitor: Test Sysctrl Failed");
+                $finish;
+            end
+
+	    wait(checkbits == 16'hA090);
+		 	`ifdef GL
+            	$display("Monitor: Test Sysctrl (GL) Passed");
+			`else
+		        $display("Monitor: Test Sysctrl (RTL) Passed");
+			`endif
+            $finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+		#2000;
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+	always @(checkbits) begin
+		#1 $display("GPIO state = %b ", checkbits);
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+	
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+
+	assign mprj_io[3] = 1'b1;
+	
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock    (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("sysctrl.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/timer/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/timer/Makefile
new file mode 100644
index 0000000..d7b66b8
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/timer/Makefile
@@ -0,0 +1,68 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = timer
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/timer/timer.c b/verilog/dv/caravel/caravel/mgmt_soc/timer/timer.c
new file mode 100644
index 0000000..e01ed7f
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/timer/timer.c
@@ -0,0 +1,141 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+/*
+ *	Timer Test
+ */
+
+void main()
+{
+	int i;
+	uint32_t value;
+
+	/* Initialize output data vector to zero */
+	reg_mprj_datah = 0x00000000;
+	reg_mprj_datal = 0x00000000;
+
+	/* Apply all 38 bits to management standard output.	*/
+
+	/* The lower 32 will be used to output the count value	*/
+	/* from the timer.  The top 5 bits will be used	to mark	*/
+	/* specific checkpoints for the testbench simulation.	*/
+
+	reg_mprj_io_37 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_36 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_35 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_34 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_33 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_32 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_15 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_14 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_13 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_12 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_11 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_10 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_9  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_8  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_7  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_6  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_5  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_4  = GPIO_MODE_MGMT_STD_OUTPUT;
+	// reg_mprj_io_3  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_2  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_1  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_0  = GPIO_MODE_MGMT_STD_OUTPUT;
+
+	/* Apply configuration */
+	reg_mprj_xfer = 1;
+	while (reg_mprj_xfer == 1);
+
+	/* Present start marker (see testbench verilog) */
+	reg_mprj_datah = 0x0a;
+
+	/* Configure timer for a single-shot countdown */
+	reg_timer0_value = 0xdcba9876;
+
+	/* Timer configuration bits:				*/
+	/* 0 = timer enable (1 = enabled, 0 = disabled)		*/
+	/* 1 = one-shot mode (1 = oneshot, 0 = continuous)	*/
+	/* 2 = up/down (1 = count up, 0 = count down)		*/
+	/* 3 = chain (1 = enabled, 0 = disabled)		*/
+	/* 4 = IRQ enable (1 = enabled, 0 = disabled)		*/
+
+	reg_timer0_config = 3;	/* Enabled, one-shot, down count */
+
+	for (i = 0; i < 8; i++) {
+	    value = reg_timer0_data;
+	    reg_mprj_datal = value;	// Put count value on GPIO
+	}
+
+	reg_timer0_config = 0;	/* Disabled */
+
+	reg_mprj_datah = 0x01;	/* Check value in testbench */
+
+	reg_timer0_value = 0x00000011;
+	reg_timer0_config = 7;	/* Enabled, one-shot, count up */
+	
+	for (i = 0; i < 3; i++) {
+	    value = reg_timer0_data;
+	    reg_mprj_datal = value;	// Put count value on GPIO
+	}
+
+	reg_mprj_datah = 0x02;	/* Check value in testbench */
+	
+	reg_timer0_data = 0x00000101;	// Set value (will be reset)
+	reg_timer0_config = 2;	/* Disabled, one-shot, count up */
+	reg_timer0_config = 5;	/* Enabled, continuous, count down */
+	
+	for (i = 0; i < 5; i++) {
+	    value = reg_timer0_data;
+	    reg_mprj_datal = value;	// Put count value on GPIO
+	}
+
+	reg_mprj_datah = 0x03;	/* Check value in testbench */
+
+	reg_timer0_data = 0x00000145;	// Force new value
+
+	reg_mprj_datah = 0x04;	/* Check value in testbench */
+	
+	for (i = 0; i < 5; i++) {
+	    value = reg_timer0_data;
+	    reg_mprj_datal = value;	// Put count value on GPIO
+	}
+	
+	/* Present end marker (see testbench verilog) */
+	reg_mprj_datah = 0x05;
+}
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/timer/timer_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/timer/timer_tb.v
new file mode 100644
index 0000000..64cf850
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/timer/timer_tb.v
@@ -0,0 +1,197 @@
+`default_nettype none
+/*
+ *  StriVe - A full example SoC using PicoRV32 in SkyWater s8
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2018  Tim Edwards <tim@efabless.com>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module timer_tb;
+
+	reg RSTB;
+	reg clock;
+	reg power1, power2;
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock <= 0;
+	end
+
+	initial begin
+		$dumpfile("timer.vcd");
+		$dumpvars(0, timer_tb);
+
+		// Repeat cycles of 1000 clock edges as needed to complete testbench
+		repeat (50) begin
+			repeat (1000) @(posedge clock);
+			$display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		`ifdef GL
+			$display ("Monitor: Timeout, Test GPIO (GL) Failed");
+		`else
+			$display ("Monitor: Timeout, Test GPIO (RTL) Failed");
+		`endif
+		 $display("%c[0m",27);
+		$finish;
+	end
+
+	wire [37:0] mprj_io;	// Most of these are no-connects
+	wire [5:0] checkbits;
+	wire [31:0] countbits;
+
+	assign checkbits = mprj_io[37:32];
+	assign countbits = mprj_io[31:0];
+
+	assign mprj_io[3] = 1'b1;  // Force CSB high.
+
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+	wire gpio;
+
+	// Monitor
+	initial begin
+		wait(checkbits == 6'h0a);
+		`ifdef GL
+			$display("Monitor: Test Timer (GL) Started");
+		`else 
+			$display("Monitor: Test Timer (RTL) Started");
+		`endif
+		/* Add checks here */
+		wait(checkbits == 6'h01);
+		$display("   countbits = 0x%x (should be 0xdcba7cfb)", countbits);
+		if(countbits !== 32'hdcba7cfb) begin
+		    $display("Monitor: Test Timer Failed");
+		    $finish;
+		end
+		wait(checkbits == 6'h02);
+		$display("   countbits = 0x%x (should be 0x19)", countbits);
+		if(countbits !== 32'h19) begin
+		    $display("Monitor: Test Timer Failed");
+		    $finish;
+		end
+		wait(checkbits == 6'h03);
+		$display("   countbits = %x (should be 0x0f)", countbits);
+		if(countbits !== ((32'h0f) | (3'b100))) begin
+		    $display("Monitor: Test Timer Failed");
+		    $finish;
+		end
+		wait(checkbits == 6'h04);
+		$display("   countbits = %x (should be 0x0f)", countbits);
+		if(countbits !== ((32'h0f) | (3'b100))) begin
+		    $display("Monitor: Test Timer Failed");
+		    $finish;
+		end
+		wait(checkbits == 6'h05);
+		$display("   countbits = %x (should be 0x12bc)", countbits);
+		if(countbits !== 32'h12bc) begin
+		    $display("Monitor: Test Timer Failed");
+		    $finish;
+		end
+		
+		`ifdef GL
+			$display("Monitor: Test Timer (GL) Passed");
+		`else
+			$display("Monitor: Test Timer (RTL) Passed");
+		`endif
+		$finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+	always @(checkbits) begin
+		#1 $display("Timer state = %b (%d)", countbits, countbits);
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+
+	// These are the mappings of mprj_io GPIO pads that are set to
+	// specific functions on startup:
+	//
+	// JTAG      = mgmt_gpio_io[0]              (inout)
+	// SDO       = mgmt_gpio_io[1]              (output)
+	// SDI       = mgmt_gpio_io[2]              (input)
+	// CSB       = mgmt_gpio_io[3]              (input)
+	// SCK       = mgmt_gpio_io[4]              (input)
+	// ser_rx    = mgmt_gpio_io[5]              (input)
+	// ser_tx    = mgmt_gpio_io[6]              (output)
+	// irq       = mgmt_gpio_io[7]              (input)
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("timer.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/timer2/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/timer2/Makefile
new file mode 100644
index 0000000..0be97ef
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/timer2/Makefile
@@ -0,0 +1,68 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = timer2
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/timer2/timer2.c b/verilog/dv/caravel/caravel/mgmt_soc/timer2/timer2.c
new file mode 100644
index 0000000..6d598ac
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/timer2/timer2.c
@@ -0,0 +1,214 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+/*
+ *	Timer2 Test --- This runs the same testbench as the
+ *	other timer, on the 2nd counter/timer module instance.
+ */
+
+void main()
+{
+	int i;
+	uint32_t value;
+
+	/* Initialize output data vector to zero */
+	reg_mprj_datah = 0x00000000;
+	reg_mprj_datal = 0x00000000;
+
+	/* Apply all 38 bits to management standard output.	*/
+
+	/* The lower 32 will be used to output the count value	*/
+	/* from the timer.  The top 5 bits will be used	to mark	*/
+	/* specific checkpoints for the testbench simulation.	*/
+
+	reg_mprj_io_37 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_36 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_35 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_34 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_33 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_32 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_15 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_14 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_13 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_12 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_11 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_10 = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_9  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_8  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_7  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_6  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_5  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_4  = GPIO_MODE_MGMT_STD_OUTPUT;
+	// reg_mprj_io_3  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_2  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_1  = GPIO_MODE_MGMT_STD_OUTPUT;
+	reg_mprj_io_0  = GPIO_MODE_MGMT_STD_OUTPUT;
+
+	/* Apply configuration */
+	reg_mprj_xfer = 1;
+	while (reg_mprj_xfer == 1);
+
+	/* Present start marker (see testbench verilog) */
+	reg_mprj_datah = 0x0a;
+
+	/* Configure timer for a single-shot countdown */
+	reg_timer1_value = 0xdcba9876;
+
+	/* Timer configuration bits:				*/
+	/* 0 = timer enable (1 = enabled, 0 = disabled)		*/
+	/* 1 = one-shot mode (1 = oneshot, 0 = continuous)	*/
+	/* 2 = up/down (1 = count up, 0 = count down)		*/
+	/* 3 = IRQ enable (1 = enabled, 0 = disabled)		*/
+
+	reg_timer1_config = 3;	/* Enabled, one-shot, down count */
+
+	for (i = 0; i < 8; i++) {
+	    value = reg_timer1_data;
+	    reg_mprj_datal = value;	// Put count value on GPIO
+	}
+
+	reg_timer1_config = 0;	/* Disabled */
+
+	reg_mprj_datah = 0x01;	/* Check value in testbench */
+
+	reg_timer1_value = 0x00000011;
+	reg_timer1_config = 7;	/* Enabled, one-shot, count up */
+	
+	for (i = 0; i < 3; i++) {
+	    value = reg_timer1_data;
+	    reg_mprj_datal = value;	// Put count value on GPIO
+	}
+
+	reg_mprj_datah = 0x02;	/* Check value in testbench */
+	
+	reg_timer1_data = 0x00000101;	// Set value (will be reset)
+	reg_timer1_config = 2;	/* Disabled, one-shot, count up */
+	reg_timer1_config = 5;	/* Enabled, continuous, count down */
+	
+	for (i = 0; i < 5; i++) {
+	    value = reg_timer1_data;
+	    reg_mprj_datal = value;	// Put count value on GPIO
+	}
+
+	reg_mprj_datah = 0x03;	/* Check value in testbench */
+
+	reg_timer1_data = 0x00000145;	// Force new value
+
+	reg_mprj_datah = 0x04;	/* Check value in testbench */
+	
+	for (i = 0; i < 5; i++) {
+	    value = reg_timer1_data;
+	    reg_mprj_datal = value;	// Put count value on GPIO
+	}
+
+	reg_mprj_datah = 0x05;	/* Check value in testbench */
+
+	/* Now, set up chained 64 bit timer.  Check count-up	*/
+	/* value and count-down value crossing the 32-bit	*/
+	/* boundary.						*/
+
+	/* First disable both counters, and set the "chained"	*/
+	/* property so that enable/disable will be synchronized	*/
+
+	reg_timer1_config = 8;	/* Disabled, chained */
+	reg_timer0_config = 8;	/* Disabled, chained */
+
+	/* Configure timer for a chained single-shot countdown. */
+	/* Count start = 0x0000000100001000, end = 0x0		*/
+
+	reg_timer1_value = 0x00000055;
+	reg_timer0_value = 0x00001000;
+
+	/* Timer configuration bits:				*/
+	/* 0 = timer enable (1 = enabled, 0 = disabled)		*/
+	/* 1 = one-shot mode (1 = oneshot, 0 = continuous)	*/
+	/* 2 = up/down (1 = count up, 0 = count down)		*/
+	/* 3 = chain (1 = enabled, 0 = disabled)		*/
+	/* 4 = IRQ enable (1 = enabled, 0 = disabled)		*/
+
+	reg_timer1_config = 11;	/* Enabled, one-shot, down count, chained */
+	reg_timer0_config = 11;	/* Enabled, one-shot, down count, chained */
+
+	for (i = 0; i < 1; i++) {
+	    value = reg_timer1_data;
+	    reg_mprj_datal = value;	// Put count value on GPIO
+	}
+
+	reg_mprj_datah = 0x06;	/* Check value in testbench */
+
+	// Skip to the end. . .
+	reg_timer1_data = 0x00000000;
+	reg_timer0_data = 0x00000200;
+
+	for (i = 0; i < 4; i++) {
+	    value = reg_timer0_data;
+	    reg_mprj_datal = value;	// Put count value on GPIO
+	}
+
+	reg_mprj_datah = 0x07;	/* Check value in testbench */
+
+	reg_timer1_config = 14;	/* Disabled, one-shot, up count, chained */
+	reg_timer0_config = 14;	/* Disabled, one-shot, up count, chained */
+
+	reg_timer1_value = 0x00000002;
+	reg_timer0_value = 0x00000000;
+
+	reg_timer1_config = 15;	/* Enabled, one-shot, up count, chained */
+	reg_timer0_config = 15;	/* Enabled, one-shot, up count, chained */
+
+	for (i = 0; i < 1; i++) {
+	    value = reg_timer0_data;
+	    reg_mprj_datal = value;	// Put count value on GPIO
+	}
+
+	reg_mprj_datah = 0x08;	/* Check value in testbench */
+
+	// Skip to the end. . . 
+	/* Count 0x00000001ffffff00 to 0x0000000200000000 and stop */
+
+	reg_timer1_data = 0x00000001;	// Set value (will be reset)
+	reg_timer0_data = 0xffffff00;	// Set value (will be reset)
+
+	for (i = 0; i < 4; i++) {
+	    value = reg_timer1_data;
+	    reg_mprj_datal = value;	// Put timer1 count value on GPIO
+	}
+
+	/* Present end marker (see testbench verilog) */
+	reg_mprj_datah = 0x10;
+}
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/timer2/timer2_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/timer2/timer2_tb.v
new file mode 100644
index 0000000..96aab4e
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/timer2/timer2_tb.v
@@ -0,0 +1,225 @@
+`default_nettype none
+/*
+ *  StriVe - A full example SoC using PicoRV32 in SkyWater s8
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2018  Tim Edwards <tim@efabless.com>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module timer2_tb;
+
+	reg clock;
+	reg RSTB;
+	reg power1, power2;
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock <= 0;
+	end
+
+	initial begin
+		$dumpfile("timer2.vcd");
+		$dumpvars(0, timer2_tb);
+
+		// Repeat cycles of 1000 clock edges as needed to complete testbench
+		repeat (60) begin
+			repeat (1000) @(posedge clock);
+			$display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		`ifdef GL
+			$display ("Monitor: Timeout, Test Timer2 (GL) Failed");
+		`else
+			$display ("Monitor: Timeout, Test Timer2 (RTL) Failed");
+		`endif
+		$display("%c[0m",27);
+		$finish;
+	end
+
+	wire [37:0] mprj_io;	// Most of these are no-connects
+	wire [5:0] checkbits;
+	wire [31:0] countbits;
+
+	assign checkbits = mprj_io[37:32];
+	assign countbits = mprj_io[31:0];
+
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+	wire gpio;
+
+	// Monitor
+	initial begin
+		wait(checkbits == 6'h0a);
+		`ifdef GL
+			$display("Monitor: Test Timer2 (GL) Started");
+		`else
+			$display("Monitor: Test Timer2 (RTL) Started");
+		`endif
+		/* Add checks here */
+		wait(checkbits == 6'h01);
+		$display("   countbits = 0x%x (should be 0xdcba7cfb)", countbits);
+		if(countbits !== 32'hdcba7cfb) begin
+		    $display("Monitor: Test Timer2 (RTL) Failed");
+		    $finish;
+		end
+		wait(checkbits == 6'h02);
+		$display("   countbits = 0x%x (should be 0x19)", countbits);
+		if(countbits !== 32'h19) begin
+		    $display("Monitor: Test Timer2 (RTL) Failed");
+		    $finish;
+		end
+		wait(checkbits == 6'h03);
+		$display("   countbits = %x (should be 0x0f)", countbits);
+		if(countbits !== 32'h0f) begin
+		    $display("Monitor: Test Timer (RTL) Failed");
+		    $finish;
+		end
+		wait(checkbits == 6'h04);
+		$display("   countbits = %x (should be 0x0f)", countbits);
+		if(countbits !== 32'h0f) begin
+		    $display("Monitor: Test Timer2 (RTL) Failed");
+		    $finish;
+		end
+		wait(checkbits == 6'h05);
+		$display("   countbits = %x (should be 0x12bc)", countbits);
+		if(countbits !== 32'h12bc) begin
+		    $display("Monitor: Test Timer2 (RTL) Failed");
+		    $finish;
+		end
+
+		wait(checkbits == 6'h06);
+		$display("   countbits = %x (should be 0x005d)", countbits);
+		if(countbits !== 32'h005d) begin
+		    $display("Monitor: Test Timer2 (RTL) Failed");
+		    $finish;
+		end
+
+		wait(checkbits == 6'h07);
+		$display("   countbits = %x (should be 0x0008)", countbits);
+		if(countbits !== 32'h0008) begin
+		    $display("Monitor: Test Timer2 (RTL) Failed");
+		    $finish;
+		end
+
+		wait(checkbits == 6'h08);
+		$display("   countbits = %x (should be 0x0259)", countbits);
+		if(countbits !== 32'h0259) begin
+		    $display("Monitor: Test Timer2 (RTL) Failed");
+		    $finish;
+		end
+
+		wait(checkbits == 6'h10);
+		$display("   countbits = %x (should be 0x000a)", countbits);
+		if(countbits !== 32'h000a) begin
+		    $display("Monitor: Test Timer2 (RTL) Failed");
+		    $finish;
+		end
+
+		`ifdef GL
+			$display("Monitor: Test Timer2 (GL) Passed");
+		`else
+			$display("Monitor: Test Timer2 (RTL) Passed");
+		`endif
+		$finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+	always @(checkbits) begin
+		#1 $display("Timer state = %b (%d)", countbits, countbits);
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+	
+	assign mprj_io[3] = 1'b1;  // Force CSB high.
+
+	// These are the mappings of mprj_io GPIO pads that are set to
+	// specific functions on startup:
+	//
+	// JTAG      = mgmt_gpio_io[0]              (inout)
+	// SDO       = mgmt_gpio_io[1]              (output)
+	// SDI       = mgmt_gpio_io[2]              (input)
+	// CSB       = mgmt_gpio_io[3]              (input)
+	// SCK       = mgmt_gpio_io[4]              (input)
+	// ser_rx    = mgmt_gpio_io[5]              (input)
+	// ser_tx    = mgmt_gpio_io[6]              (output)
+	// irq       = mgmt_gpio_io[7]              (input)
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("timer2.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/uart/Makefile b/verilog/dv/caravel/caravel/mgmt_soc/uart/Makefile
new file mode 100644
index 0000000..e446947
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/uart/Makefile
@@ -0,0 +1,69 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# ---- Test patterns for project striVe ----
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = uart
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+else  
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(VERILOG_PATH) -I $(RTL_PATH) \
+	$< -o $@ 
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/uart/uart.c b/verilog/dv/caravel/caravel/mgmt_soc/uart/uart.c
new file mode 100644
index 0000000..13cee0f
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/uart/uart.c
@@ -0,0 +1,76 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+#include "../../stub.c"
+
+// --------------------------------------------------------
+
+void main()
+{
+    int j;
+
+    // Configure I/O:  High 16 bits of user area used for a 16-bit
+    // word to write and be detected by the testbench verilog.
+    // Only serial Tx line is used in this testbench.  It connects
+    // to mprj_io[6].  Since all lines of the chip are input or
+    // high impedence on startup, the I/O has to be configured
+    // for output
+
+    reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+    reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    reg_mprj_io_6 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+    // Set clock to 64 kbaud and enable the UART.  It is important to do this
+    // before applying the configuration, or else the Tx line initializes as
+    // zero, which indicates the start of a byte to the receiver.
+
+    reg_uart_clkdiv = 625;
+    reg_uart_enable = 1;
+
+    // Now, apply the configuration
+    reg_mprj_xfer = 1;
+    while (reg_mprj_xfer == 1);
+
+    // Start test
+    reg_mprj_datal = 0xa0000000;
+
+    // This should appear at the output, received by the testbench UART.
+    // (Makes simulation time long.)
+    print("Monitor: Test UART (RTL) passed\n");
+
+    // Allow transmission to complete before signalling that the program
+    // has ended.
+    for (j = 0; j < 20; j++);
+    reg_mprj_datal = 0xab000000;
+}
diff --git a/verilog/dv/caravel/caravel/mgmt_soc/uart/uart_tb.v b/verilog/dv/caravel/caravel/mgmt_soc/uart/uart_tb.v
new file mode 100644
index 0000000..298e882
--- /dev/null
+++ b/verilog/dv/caravel/caravel/mgmt_soc/uart/uart_tb.v
@@ -0,0 +1,146 @@
+`default_nettype none
+/*
+ *  StriVe - A full example SoC using PicoRV32 in SkyWater s8
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2018  Tim Edwards <tim@efabless.com>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+`include "tbuart.v"
+
+module uart_tb;
+	reg clock;
+	reg RSTB;
+	reg power1, power2;
+
+	wire gpio;
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+	wire [37:0] mprj_io;
+	wire [15:0] checkbits;
+	wire uart_tx;
+	wire SDO;
+
+	assign checkbits = mprj_io[31:16];
+	assign uart_tx = mprj_io[6];
+
+	always #12.5 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin
+		$dumpfile("uart.vcd");
+		$dumpvars(0, uart_tb);
+
+		$display("Wait for UART o/p");
+		repeat (150) begin
+			repeat (10000) @(posedge clock);
+			// Diagnostic. . . interrupts output pattern.
+		end
+		$finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+		#2000;
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+	always @(checkbits) begin
+		if(checkbits == 16'hA000) begin
+			$display("UART Test started");
+		end
+		else if(checkbits == 16'hAB00) begin
+			`ifdef GL
+				$display("UART Test (GL) passed");
+			`else
+				$display("UART Test (RTL) passed");
+			`endif
+			$finish;
+		end
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+	
+	assign mprj_io[3] = 1'b1;  // Force CSB high.
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("uart.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+	// Testbench UART
+	tbuart tbuart (
+		.ser_rx(uart_tx)
+	);
+		
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/sections.lds b/verilog/dv/caravel/caravel/sections.lds
new file mode 100644
index 0000000..8da9aae
--- /dev/null
+++ b/verilog/dv/caravel/caravel/sections.lds
@@ -0,0 +1,58 @@
+MEMORY {
+	FLASH (rx)	: ORIGIN = 0x10000000, LENGTH = 0x400000 	/* 4MB */
+	RAM(xrw)	: ORIGIN = 0x00000000, LENGTH = 0x0400		/* 256 words (1 KB) */ 
+}
+
+SECTIONS {
+	/* The program code and other data goes into FLASH */
+	.text :
+	{
+		. = ALIGN(4);
+		*(.text)	/* .text sections (code) */
+		*(.text*)	/* .text* sections (code) */
+		*(.rodata)	/* .rodata sections (constants, strings, etc.) */
+		*(.rodata*)	/* .rodata* sections (constants, strings, etc.) */
+		*(.srodata)	/* .srodata sections (constants, strings, etc.) */
+		*(.srodata*)	/* .srodata*sections (constants, strings, etc.) */
+		. = ALIGN(4);
+		_etext = .;		/* define a global symbol at end of code */
+		_sidata = _etext;	/* This is used by the startup to initialize data */
+	} >FLASH
+
+	/* Initialized data section */
+	.data : AT ( _sidata )
+	{
+		. = ALIGN(4);
+		_sdata = .;
+		_ram_start = .;
+		. = ALIGN(4);
+		*(.data)
+		*(.data*)
+		*(.sdata)
+		*(.sdata*)
+		. = ALIGN(4);
+		_edata = .;
+	} >RAM
+
+	/* Uninitialized data section */
+	.bss :
+	{
+		. = ALIGN(4);
+		_sbss = .;
+		*(.bss)
+		*(.bss*)
+		*(.sbss)
+		*(.sbss*)
+		*(COMMON)
+
+		. = ALIGN(4);
+		_ebss = .;
+	} >RAM
+
+	/* Define the start of the heap */
+	.heap :
+	{
+		. = ALIGN(4);
+		_heap_start = .;
+	} >RAM
+}
diff --git a/verilog/dv/caravel/caravel/spiflash.v b/verilog/dv/caravel/caravel/spiflash.v
new file mode 100644
index 0000000..d4a82d9
--- /dev/null
+++ b/verilog/dv/caravel/caravel/spiflash.v
@@ -0,0 +1,414 @@
+`default_nettype none
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+//
+// Simple SPI flash simulation model
+//
+// This model samples io input signals 1ns before the SPI clock edge and
+// updates output signals 1ns after the SPI clock edge.
+//
+// Supported commands:
+//    AB, B9, FF, 03, BB, EB, ED
+//
+// Well written SPI flash data sheets:
+//    Cypress S25FL064L http://www.cypress.com/file/316661/download
+//    Cypress S25FL128L http://www.cypress.com/file/316171/download
+//
+
+module spiflash #(
+	parameter FILENAME = "firmware.hex"
+)(
+	input csb,
+	input clk,
+	inout io0, // MOSI
+	inout io1, // MISO
+	inout io2,
+	inout io3
+);
+	localparam verbose = 0;
+	localparam integer latency = 8;
+	
+	reg [7:0] buffer;
+	integer bitcount = 0;
+	integer bytecount = 0;
+	integer dummycount = 0;
+
+	reg [7:0] spi_cmd;
+	reg [7:0] xip_cmd = 0;
+	reg [23:0] spi_addr;
+
+	reg [7:0] spi_in;
+	reg [7:0] spi_out;
+	reg spi_io_vld;
+
+	reg powered_up = 0;
+
+	localparam [3:0] mode_spi         = 1;
+	localparam [3:0] mode_dspi_rd     = 2;
+	localparam [3:0] mode_dspi_wr     = 3;
+	localparam [3:0] mode_qspi_rd     = 4;
+	localparam [3:0] mode_qspi_wr     = 5;
+	localparam [3:0] mode_qspi_ddr_rd = 6;
+	localparam [3:0] mode_qspi_ddr_wr = 7;
+
+	reg [3:0] mode = 0;
+	reg [3:0] next_mode = 0;
+
+	reg io0_oe = 0;
+	reg io1_oe = 0;
+	reg io2_oe = 0;
+	reg io3_oe = 0;
+
+	reg io0_dout = 0;
+	reg io1_dout = 0;
+	reg io2_dout = 0;
+	reg io3_dout = 0;
+
+	assign #1 io0 = io0_oe ? io0_dout : 1'bz;
+	assign #1 io1 = io1_oe ? io1_dout : 1'bz;
+	assign #1 io2 = io2_oe ? io2_dout : 1'bz;
+	assign #1 io3 = io3_oe ? io3_dout : 1'bz;
+
+	wire io0_delayed;
+	wire io1_delayed;
+	wire io2_delayed;
+	wire io3_delayed;
+
+	assign #1 io0_delayed = io0;
+	assign #1 io1_delayed = io1;
+	assign #1 io2_delayed = io2;
+	assign #1 io3_delayed = io3;
+
+	// 16 MB (128Mb) Flash
+	reg [7:0] memory [0:16*1024*1024-1];
+
+	initial begin
+		$display("Memory 5 bytes = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
+			memory[1048576], memory[1048577], memory[1048578],
+			memory[1048579], memory[1048580]);
+		$display("Reading %s",  FILENAME);
+		$readmemh(FILENAME, memory);
+		$display("%s loaded into memory", FILENAME);
+		$display("Memory 5 bytes = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
+			memory[1048576], memory[1048577], memory[1048578],
+			memory[1048579], memory[1048580]);
+	end
+
+	task spi_action;
+		begin
+			spi_in = buffer;
+
+			if (bytecount == 1) begin
+				spi_cmd = buffer;
+
+				if (spi_cmd == 8'h ab)
+					powered_up = 1;
+
+				if (spi_cmd == 8'h b9)
+					powered_up = 0;
+
+				if (spi_cmd == 8'h ff)
+					xip_cmd = 0;
+			end
+
+			if (powered_up && spi_cmd == 'h 03) begin
+				if (bytecount == 2)
+					spi_addr[23:16] = buffer;
+
+				if (bytecount == 3)
+					spi_addr[15:8] = buffer;
+
+				if (bytecount == 4)
+					spi_addr[7:0] = buffer;
+
+				if (bytecount >= 4) begin
+					buffer = memory[spi_addr];
+					spi_addr = spi_addr + 1;
+				end
+			end
+
+			if (powered_up && spi_cmd == 'h bb) begin
+				if (bytecount == 1)
+					mode = mode_dspi_rd;
+
+				if (bytecount == 2)
+					spi_addr[23:16] = buffer;
+
+				if (bytecount == 3)
+					spi_addr[15:8] = buffer;
+
+				if (bytecount == 4)
+					spi_addr[7:0] = buffer;
+
+				if (bytecount == 5) begin
+					xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
+					mode = mode_dspi_wr;
+					dummycount = latency;
+				end
+
+				if (bytecount >= 5) begin
+					buffer = memory[spi_addr];
+					spi_addr = spi_addr + 1;
+				end
+			end
+
+			if (powered_up && spi_cmd == 'h eb) begin
+				if (bytecount == 1)
+					mode = mode_qspi_rd;
+
+				if (bytecount == 2)
+					spi_addr[23:16] = buffer;
+
+				if (bytecount == 3)
+					spi_addr[15:8] = buffer;
+
+				if (bytecount == 4)
+					spi_addr[7:0] = buffer;
+
+				if (bytecount == 5) begin
+					xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
+					mode = mode_qspi_wr;
+					dummycount = latency;
+				end
+
+				if (bytecount >= 5) begin
+					buffer = memory[spi_addr];
+					spi_addr = spi_addr + 1;
+				end
+			end
+
+			if (powered_up && spi_cmd == 'h ed) begin
+				if (bytecount == 1)
+					next_mode = mode_qspi_ddr_rd;
+
+				if (bytecount == 2)
+					spi_addr[23:16] = buffer;
+
+				if (bytecount == 3)
+					spi_addr[15:8] = buffer;
+
+				if (bytecount == 4)
+					spi_addr[7:0] = buffer;
+
+				if (bytecount == 5) begin
+					xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
+					mode = mode_qspi_ddr_wr;
+					dummycount = latency;
+				end
+
+				if (bytecount >= 5) begin
+					buffer = memory[spi_addr];
+					spi_addr = spi_addr + 1;
+				end
+			end
+
+			spi_out = buffer;
+			spi_io_vld = 1;
+
+			if (verbose) begin
+				if (bytecount == 1)
+					$write("<SPI-START>");
+				$write("<SPI:%02x:%02x>", spi_in, spi_out);
+			end
+
+		end
+	endtask
+
+	task ddr_rd_edge;
+		begin
+			buffer = {buffer, io3_delayed, io2_delayed, io1_delayed, io0_delayed};
+			bitcount = bitcount + 4;
+			if (bitcount == 8) begin
+				bitcount = 0;
+				bytecount = bytecount + 1;
+				spi_action;
+			end
+		end
+	endtask
+
+	task ddr_wr_edge;
+		begin
+			io0_oe = 1;
+			io1_oe = 1;
+			io2_oe = 1;
+			io3_oe = 1;
+
+			io0_dout = buffer[4];
+			io1_dout = buffer[5];
+			io2_dout = buffer[6];
+			io3_dout = buffer[7];
+
+			buffer = {buffer, 4'h 0};
+			bitcount = bitcount + 4;
+			if (bitcount == 8) begin
+				bitcount = 0;
+				bytecount = bytecount + 1;
+				spi_action;
+			end
+		end
+	endtask
+
+	always @(csb) begin
+		if (csb) begin
+			if (verbose) begin
+				$display("");
+				$fflush;
+			end
+			buffer = 0;
+			bitcount = 0;
+			bytecount = 0;
+			mode = mode_spi;
+			io0_oe = 0;
+			io1_oe = 0;
+			io2_oe = 0;
+			io3_oe = 0;
+		end else
+		if (xip_cmd) begin
+			buffer = xip_cmd;
+			bitcount = 0;
+			bytecount = 1;
+			spi_action;
+		end
+	end
+
+	always @(csb, clk) begin
+		spi_io_vld = 0;
+		if (!csb && !clk) begin
+			if (dummycount > 0) begin
+				io0_oe = 0;
+				io1_oe = 0;
+				io2_oe = 0;
+				io3_oe = 0;
+			end else
+			case (mode)
+				mode_spi: begin
+					io0_oe = 0;
+					io1_oe = 1;
+					io2_oe = 0;
+					io3_oe = 0;
+					io1_dout = buffer[7];
+				end
+				mode_dspi_rd: begin
+					io0_oe = 0;
+					io1_oe = 0;
+					io2_oe = 0;
+					io3_oe = 0;
+				end
+				mode_dspi_wr: begin
+					io0_oe = 1;
+					io1_oe = 1;
+					io2_oe = 0;
+					io3_oe = 0;
+					io0_dout = buffer[6];
+					io1_dout = buffer[7];
+				end
+				mode_qspi_rd: begin
+					io0_oe = 0;
+					io1_oe = 0;
+					io2_oe = 0;
+					io3_oe = 0;
+				end
+				mode_qspi_wr: begin
+					io0_oe = 1;
+					io1_oe = 1;
+					io2_oe = 1;
+					io3_oe = 1;
+					io0_dout = buffer[4];
+					io1_dout = buffer[5];
+					io2_dout = buffer[6];
+					io3_dout = buffer[7];
+				end
+				mode_qspi_ddr_rd: begin
+					ddr_rd_edge;
+				end
+				mode_qspi_ddr_wr: begin
+					ddr_wr_edge;
+				end
+			endcase
+			if (next_mode) begin
+				case (next_mode)
+					mode_qspi_ddr_rd: begin
+						io0_oe = 0;
+						io1_oe = 0;
+						io2_oe = 0;
+						io3_oe = 0;
+					end
+					mode_qspi_ddr_wr: begin
+						io0_oe = 1;
+						io1_oe = 1;
+						io2_oe = 1;
+						io3_oe = 1;
+						io0_dout = buffer[4];
+						io1_dout = buffer[5];
+						io2_dout = buffer[6];
+						io3_dout = buffer[7];
+					end
+				endcase
+				mode = next_mode;
+				next_mode = 0;
+			end
+		end
+	end
+
+	always @(posedge clk) begin
+		if (!csb) begin
+			if (dummycount > 0) begin
+				dummycount = dummycount - 1;
+			end else
+			case (mode)
+				mode_spi: begin
+					buffer = {buffer, io0};
+					bitcount = bitcount + 1;
+					if (bitcount == 8) begin
+						bitcount = 0;
+						bytecount = bytecount + 1;
+						spi_action;
+					end
+				end
+				mode_dspi_rd, mode_dspi_wr: begin
+					buffer = {buffer, io1, io0};
+					bitcount = bitcount + 2;
+					if (bitcount == 8) begin
+						bitcount = 0;
+						bytecount = bytecount + 1;
+						spi_action;
+					end
+				end
+				mode_qspi_rd, mode_qspi_wr: begin
+					buffer = {buffer, io3, io2, io1, io0};
+					bitcount = bitcount + 4;
+					if (bitcount == 8) begin
+						bitcount = 0;
+						bytecount = bytecount + 1;
+						spi_action;
+					end
+				end
+				mode_qspi_ddr_rd: begin
+					ddr_rd_edge;
+				end
+				mode_qspi_ddr_wr: begin
+					ddr_wr_edge;
+				end
+			endcase
+		end
+	end
+endmodule
diff --git a/verilog/dv/caravel/caravel/start.s b/verilog/dv/caravel/caravel/start.s
new file mode 100644
index 0000000..62a6f42
--- /dev/null
+++ b/verilog/dv/caravel/caravel/start.s
@@ -0,0 +1,159 @@
+.section .text
+
+start:
+
+# zero-initialize register file
+addi x1, zero, 0
+# x2 (sp) is initialized by reset
+addi x3, zero, 0
+addi x4, zero, 0
+addi x5, zero, 0
+addi x6, zero, 0
+addi x7, zero, 0
+addi x8, zero, 0
+addi x9, zero, 0
+addi x10, zero, 0
+addi x11, zero, 0
+addi x12, zero, 0
+addi x13, zero, 0
+addi x14, zero, 0
+addi x15, zero, 0
+addi x16, zero, 0
+addi x17, zero, 0
+addi x18, zero, 0
+addi x19, zero, 0
+addi x20, zero, 0
+addi x21, zero, 0
+addi x22, zero, 0
+addi x23, zero, 0
+addi x24, zero, 0
+addi x25, zero, 0
+addi x26, zero, 0
+addi x27, zero, 0
+addi x28, zero, 0
+addi x29, zero, 0
+addi x30, zero, 0
+addi x31, zero, 0
+
+# zero initialize scratchpad memory
+# setmemloop:
+# sw zero, 0(x1)
+# addi x1, x1, 4
+# blt x1, sp, setmemloop
+
+# copy data section
+la a0, _sidata
+la a1, _sdata
+la a2, _edata
+bge a1, a2, end_init_data
+loop_init_data:
+lw a3, 0(a0)
+sw a3, 0(a1)
+addi a0, a0, 4
+addi a1, a1, 4
+blt a1, a2, loop_init_data
+end_init_data:
+
+# zero-init bss section
+la a0, _sbss
+la a1, _ebss
+bge a0, a1, end_init_bss
+loop_init_bss:
+sw zero, 0(a0)
+addi a0, a0, 4
+blt a0, a1, loop_init_bss
+end_init_bss:
+
+# call main
+call main
+loop:
+j loop
+
+.global flashio_worker_begin
+.global flashio_worker_end
+
+.balign 4
+
+flashio_worker_begin:
+# a0 ... data pointer
+# a1 ... data length
+# a2 ... optional WREN cmd (0 = disable)
+
+# address of SPI ctrl reg
+li   t0, 0x28000000
+
+# Set CS high, IO0 is output
+li   t1, 0x120
+sh   t1, 0(t0)
+
+# Enable Manual SPI Ctrl
+sb   zero, 3(t0)
+
+# Send optional WREN cmd
+beqz a2, flashio_worker_L1
+li   t5, 8
+andi t2, a2, 0xff
+flashio_worker_L4:
+srli t4, t2, 7
+sb   t4, 0(t0)
+ori  t4, t4, 0x10
+sb   t4, 0(t0)
+slli t2, t2, 1
+andi t2, t2, 0xff
+addi t5, t5, -1
+bnez t5, flashio_worker_L4
+sb   t1, 0(t0)
+
+# SPI transfer
+flashio_worker_L1:
+
+# If byte count is zero, we're done
+beqz a1, flashio_worker_L3
+
+# Set t5 to count down 32 bits
+li   t5, 32
+# Load t2 from address a0 (4 bytes)
+lw   t2, 0(a0)
+
+flashio_worker_LY:
+# Set t6 to count down 8 bits
+li   t6, 8
+
+flashio_worker_L2:
+# Clock out the bit (msb first) on IO0 and read bit in from IO1
+srli t4, t2, 31
+sb   t4, 0(t0)
+ori  t4, t4, 0x10
+sb   t4, 0(t0)
+lbu  t4, 0(t0)
+andi t4, t4, 2
+srli t4, t4, 1
+slli t2, t2, 1
+or   t2, t2, t4
+
+# Decrement 32 bit count
+addi t5, t5, -1
+bnez t5, flashio_worker_LX
+
+sw   t2, 0(a0)
+addi a0, a0, 4
+lw   t2, 0(a0)
+
+flashio_worker_LX:
+addi t6, t6, -1
+bnez t6, flashio_worker_L2
+addi a1, a1, -1
+bnez a1, flashio_worker_LY
+
+beqz t5, flashio_worker_L3
+sw   t2, 0(a0)
+
+flashio_worker_L3:
+# Back to MEMIO mode
+li   t1, 0x80
+sb   t1, 3(t0)
+
+ret
+.balign 4
+flashio_worker_end:
+
diff --git a/verilog/dv/caravel/caravel/stub.c b/verilog/dv/caravel/caravel/stub.c
new file mode 100644
index 0000000..575cfc3
--- /dev/null
+++ b/verilog/dv/caravel/caravel/stub.c
@@ -0,0 +1,29 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+void putchar(char c)
+{
+	if (c == '\n')
+		putchar('\r');
+	reg_uart_data = c;
+}
+
+void print(const char *p)
+{
+	while (*p)
+		putchar(*(p++));
+}
\ No newline at end of file
diff --git a/verilog/dv/caravel/caravel/tbuart.v b/verilog/dv/caravel/caravel/tbuart.v
new file mode 100644
index 0000000..f623a60
--- /dev/null
+++ b/verilog/dv/caravel/caravel/tbuart.v
@@ -0,0 +1,90 @@
+`default_nettype none
+/*
+ *  PicoSoC - A simple example SoC using PicoRV32
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+/* tbuart --- mimic an external UART display, operating at 9600 baud	*/
+/* and accepting ASCII characters for display.				*/
+
+/* To do:  Match a known UART 3.3V 16x2 LCD display.  However, it	*/
+/* should be possible on a testing system to interface to the UART	*/
+/* pins on a Raspberry Pi, also running at 3.3V.			*/
+
+module tbuart (
+	input  ser_rx
+);
+	reg [3:0] recv_state;
+	reg [2:0] recv_divcnt;
+	reg [7:0] recv_pattern;
+	reg [8*50-1:0] recv_buf_data;	// 50 characters.  Increase as needed for tests.
+
+	reg clk;
+
+	initial begin
+		clk <= 1'b0;
+		recv_state <= 0;
+		recv_divcnt <= 0;
+		recv_pattern <= 0;
+		recv_buf_data <= 0;
+	end
+
+	// NOTE:  Running at 3.0us clock period @ 5 clocks per bit = 15.0us per
+	// bit ~= 64 kbaud. Not tuned to any particular UART.  Most run at
+	// 9600 baud default and will bounce up to higher baud rates when
+	// passed specific command words.
+
+	always #1500 clk <= (clk === 1'b0);
+
+	always @(posedge clk) begin
+		recv_divcnt <= recv_divcnt + 1;
+		case (recv_state)
+			0: begin
+				if (!ser_rx)
+					recv_state <= 1;
+				recv_divcnt <= 0;
+			end
+			1: begin
+				if (2*recv_divcnt > 3'd3) begin
+					recv_state <= 2;
+					recv_divcnt <= 0;
+				end
+			end
+			10: begin
+				if (recv_divcnt > 3'd3) begin
+					// 0x0a = '\n'
+					if (recv_pattern == 8'h0a) begin
+						$display("output: %s", recv_buf_data);
+					end else begin
+						recv_buf_data <= {recv_buf_data, recv_pattern};
+					end
+					recv_state <= 0;
+				end
+			end
+			default: begin
+				if (recv_divcnt > 3'd3) begin
+					recv_pattern <= {ser_rx, recv_pattern[7:1]};
+					recv_state <= recv_state + 1;
+					recv_divcnt <= 0;
+				end
+			end
+		endcase
+	end
+
+endmodule
diff --git a/verilog/dv/caravel/caravel/user_proj_example/Makefile b/verilog/dv/caravel/caravel/user_proj_example/Makefile
new file mode 100644
index 0000000..7e37e02
--- /dev/null
+++ b/verilog/dv/caravel/caravel/user_proj_example/Makefile
@@ -0,0 +1,34 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# ---- Test patterns for project striVe ----
+
+.SUFFIXES:
+.SILENT: clean all
+
+PATTERNS = io_ports la_test1 la_test2
+
+all:  ${PATTERNS}
+	for i in ${PATTERNS}; do \
+		( cd $$i && make -f Makefile $${i}.vcd &> verify.log && grep Monitor verify.log) ; \
+	done
+
+clean:  ${PATTERNS}
+	for i in ${PATTERNS}; do \
+		( cd $$i && make clean ) ; \
+	done
+
+.PHONY: clean all
diff --git a/verilog/dv/caravel/caravel/user_proj_example/README.md b/verilog/dv/caravel/caravel/user_proj_example/README.md
new file mode 100644
index 0000000..503b8f4
--- /dev/null
+++ b/verilog/dv/caravel/caravel/user_proj_example/README.md
@@ -0,0 +1,37 @@
+<!---
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+-->
+# Mega-Project Counter Tests
+
+The directory includes three tests for the counter mega-project example: 
+
+1) IO Ports Test: 
+
+	* Configures the user space lower 8 IO pins as outputs
+	* Observes the counter value through the configured pins in the testbench
+
+ 2) Logic Analyzer Test 1:
+ 
+	* Configures LA probes [31:0] as inputs to the management SoC to monitor the counter value 
+	* Configures LA probes [63:32] as outputs from the management SoC to set the counter initial value 
+	* Flags when counter value exceeds 500 through the management SoC gpio
+	* Outputs message to the UART when the test concludes successfuly
+  
+ 3) Logic Analyzer Test 2:
+ 
+	* Configures LA probes [64] and [65] as outputs from the management SoC to set counter clock and reset values
+	* Provides counter clock and monitors the counter value after five clock cycles
diff --git a/verilog/dv/caravel/caravel/user_proj_example/io_ports/Makefile b/verilog/dv/caravel/caravel/user_proj_example/io_ports/Makefile
new file mode 100644
index 0000000..d6c2bf6
--- /dev/null
+++ b/verilog/dv/caravel/caravel/user_proj_example/io_ports/Makefile
@@ -0,0 +1,67 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+FIRMWARE_PATH = ../..
+VERILOG_PATH = ../../../..
+RTL_PATH = $(VERILOG_PATH)/rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = io_ports
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@
+else
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
diff --git a/verilog/dv/caravel/caravel/user_proj_example/io_ports/io_ports.c b/verilog/dv/caravel/caravel/user_proj_example/io_ports/io_ports.c
new file mode 100644
index 0000000..a159f0a
--- /dev/null
+++ b/verilog/dv/caravel/caravel/user_proj_example/io_ports/io_ports.c
@@ -0,0 +1,60 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+
+/*
+	IO Test:
+		- Configures MPRJ lower 8-IO pins as outputs
+		- Observes counter value through the MPRJ lower 8 IO pins (in the testbench)
+*/
+
+void main()
+{
+	/* 
+	IO Control Registers
+	| DM     | VTRIP | SLOW  | AN_POL | AN_SEL | AN_EN | MOD_SEL | INP_DIS | HOLDH | OEB_N | MGMT_EN |
+	| 3-bits | 1-bit | 1-bit | 1-bit  | 1-bit  | 1-bit | 1-bit   | 1-bit   | 1-bit | 1-bit | 1-bit   |
+
+	Output: 0000_0110_0000_1110  (0x1808) = GPIO_MODE_USER_STD_OUTPUT
+	| DM     | VTRIP | SLOW  | AN_POL | AN_SEL | AN_EN | MOD_SEL | INP_DIS | HOLDH | OEB_N | MGMT_EN |
+	| 110    | 0     | 0     | 0      | 0      | 0     | 0       | 1       | 0     | 0     | 0       |
+	
+	 
+	Input: 0000_0001_0000_1111 (0x0402) = GPIO_MODE_USER_STD_INPUT_NOPULL
+	| DM     | VTRIP | SLOW  | AN_POL | AN_SEL | AN_EN | MOD_SEL | INP_DIS | HOLDH | OEB_N | MGMT_EN |
+	| 001    | 0     | 0     | 0      | 0      | 0     | 0       | 0       | 0     | 1     | 0       |
+
+	*/
+
+	// Configure lower 8-IOs as user output
+	// Observe counter value in the testbench
+	reg_mprj_io_0 =  GPIO_MODE_USER_STD_OUTPUT;
+	reg_mprj_io_1 =  GPIO_MODE_USER_STD_OUTPUT;
+	reg_mprj_io_2 =  GPIO_MODE_USER_STD_OUTPUT;
+	reg_mprj_io_3 =  GPIO_MODE_USER_STD_OUTPUT;
+	reg_mprj_io_4 =  GPIO_MODE_USER_STD_OUTPUT;
+	reg_mprj_io_5 =  GPIO_MODE_USER_STD_OUTPUT;
+	reg_mprj_io_6 =  GPIO_MODE_USER_STD_OUTPUT;
+	reg_mprj_io_7 =  GPIO_MODE_USER_STD_OUTPUT;
+
+        /* Apply configuration */
+        reg_mprj_xfer = 1;
+        while (reg_mprj_xfer == 1);
+
+}
+
diff --git a/verilog/dv/caravel/caravel/user_proj_example/io_ports/io_ports_tb.v b/verilog/dv/caravel/caravel/user_proj_example/io_ports/io_ports_tb.v
new file mode 100644
index 0000000..c680a0b
--- /dev/null
+++ b/verilog/dv/caravel/caravel/user_proj_example/io_ports/io_ports_tb.v
@@ -0,0 +1,152 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module io_ports_tb;
+	reg clock;
+    	reg RSTB;
+	reg power1, power2;
+	reg power3, power4;
+
+    	wire gpio;
+    	wire [37:0] mprj_io;
+	wire [7:0] mprj_io_0;
+
+	assign mprj_io_0 = mprj_io[7:0];
+
+	// External clock is used by default.  Make this artificially fast for the
+	// simulation.  Normally this would be a slow clock and the digital PLL
+	// would be the fast clock.
+
+	always #12.5 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin
+		$dumpfile("io_ports.vcd");
+		$dumpvars(0, io_ports_tb);
+
+		// Repeat cycles of 1000 clock edges as needed to complete testbench
+		repeat (25) begin
+			repeat (1000) @(posedge clock);
+			// $display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		$display ("Monitor: Timeout, Test Mega-Project IO Ports (RTL) Failed");
+		$display("%c[0m",27);
+		$finish;
+	end
+
+	initial begin
+	    // Observe Output pins [7:0]
+	    wait(mprj_io_0 == 8'h01);
+	    wait(mprj_io_0 == 8'h02);
+	    wait(mprj_io_0 == 8'h03);
+    	    wait(mprj_io_0 == 8'h04);
+	    wait(mprj_io_0 == 8'h05);
+            wait(mprj_io_0 == 8'h06);
+	    wait(mprj_io_0 == 8'h07);
+            wait(mprj_io_0 == 8'h08);
+	    wait(mprj_io_0 == 8'h09);
+            wait(mprj_io_0 == 8'h0A);   
+	    wait(mprj_io_0 == 8'hFF);
+	    wait(mprj_io_0 == 8'h00);
+
+	    $display("Monitor: Test 1 Mega-Project IO (RTL) Passed");
+	    $finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#2000;
+		RSTB <= 1'b1;	    // Release reset
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		power3 <= 1'b0;
+		power4 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+		#200;
+		power3 <= 1'b1;
+		#200;
+		power4 <= 1'b1;
+	end
+
+	always @(mprj_io) begin
+		#1 $display("MPRJ-IO state = %b ", mprj_io[7:0]);
+	end
+
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+
+	wire VDD3V3 = power1;
+	wire VDD1V8 = power2;
+	wire USER_VDD3V3 = power3;
+	wire USER_VDD1V8 = power4;
+	wire VSS = 1'b0;
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (USER_VDD3V3),
+		.vdda2    (USER_VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (USER_VDD1V8),
+		.vccd2	  (USER_VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+        	.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("io_ports.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/user_proj_example/la_test1/Makefile b/verilog/dv/caravel/caravel/user_proj_example/la_test1/Makefile
new file mode 100644
index 0000000..968a74b
--- /dev/null
+++ b/verilog/dv/caravel/caravel/user_proj_example/la_test1/Makefile
@@ -0,0 +1,66 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+FIRMWARE_PATH = ../..
+RTL_PATH = ../../../../rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = la_test1
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@
+else
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
diff --git a/verilog/dv/caravel/caravel/user_proj_example/la_test1/la_test1.c b/verilog/dv/caravel/caravel/user_proj_example/la_test1/la_test1.c
new file mode 100644
index 0000000..9759ed7
--- /dev/null
+++ b/verilog/dv/caravel/caravel/user_proj_example/la_test1/la_test1.c
@@ -0,0 +1,112 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+#include "../../stub.c"
+
+// --------------------------------------------------------
+
+/*
+	MPRJ Logic Analyzer Test:
+		- Observes counter value through LA probes [31:0] 
+		- Sets counter initial value through LA probes [63:32]
+		- Flags when counter value exceeds 500 through the management SoC gpio
+		- Outputs message to the UART when the test concludes successfuly
+*/
+
+void main()
+{
+	// The upper GPIO pins are configured to be output
+	// and accessble to the management SoC.
+	// Used to flad the start/end of a test 
+	// The lower GPIO pins are configured to be output
+	// and accessible to the user project.  They show
+	// the project count value, although this test is
+	// designed to read the project count through the
+	// logic analyzer probes.
+	// I/O 6 is configured for the UART Tx line
+
+        reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+        reg_mprj_io_15 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_14 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_13 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_12 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_11 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_10 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_9  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_8  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_7  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_5  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_4  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_3  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_2  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_1  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_0  = GPIO_MODE_USER_STD_OUTPUT;
+
+        reg_mprj_io_6  = GPIO_MODE_MGMT_STD_OUTPUT;
+
+	// Set UART clock to 64 kbaud (enable before I/O configuration)
+	reg_uart_clkdiv = 625;
+	reg_uart_enable = 1;
+
+        /* Apply configuration */
+        reg_mprj_xfer = 1;
+        while (reg_mprj_xfer == 1);
+
+	// Configure LA probes [31:0], [127:64] as inputs to the cpu 
+	// Configure LA probes [63:32] as outputs from the cpu
+	reg_la0_ena = 0xFFFFFFFF;    // [31:0]
+	reg_la1_ena = 0x00000000;    // [63:32]
+	reg_la2_ena = 0xFFFFFFFF;    // [95:64]
+	reg_la3_ena = 0xFFFFFFFF;    // [127:96]
+
+	// Flag start of the test 
+	reg_mprj_datal = 0xAB400000;
+
+	// Set Counter value to zero through LA probes [63:32]
+	reg_la1_data = 0x00000000;
+
+	// Configure LA probes from [63:32] as inputs to disable counter write
+	reg_la1_ena  = 0xFFFFFFFF;    
+
+	while (1) {
+		if (reg_la0_data > 0x1F4) {
+			reg_mprj_datal = 0xAB410000;
+			break;
+		}
+	}
+	print("\n");
+	print("Monitor: Test 2 Passed\n\n");	// Makes simulation very long!
+	reg_mprj_datal = 0xAB510000;
+}
+
diff --git a/verilog/dv/caravel/caravel/user_proj_example/la_test1/la_test1_tb.v b/verilog/dv/caravel/caravel/user_proj_example/la_test1/la_test1_tb.v
new file mode 100644
index 0000000..210098f
--- /dev/null
+++ b/verilog/dv/caravel/caravel/user_proj_example/la_test1/la_test1_tb.v
@@ -0,0 +1,138 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+`include "tbuart.v"
+
+module la_test1_tb;
+	reg clock;
+    	reg RSTB;
+	reg power1, power2;
+
+    	wire gpio;
+	wire uart_tx;
+    	wire [37:0] mprj_io;
+	wire [15:0] checkbits;
+
+	assign checkbits  = mprj_io[31:16];
+	assign uart_tx = mprj_io[6];
+
+	always #12.5 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin
+		$dumpfile("la_test1.vcd");
+		$dumpvars(0, la_test1_tb);
+
+		// Repeat cycles of 1000 clock edges as needed to complete testbench
+		repeat (200) begin
+			repeat (1000) @(posedge clock);
+			// $display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		$display ("Monitor: Timeout, Test Mega-Project IO (RTL) Failed");
+		$display("%c[0m",27);
+		$finish;
+	end
+
+	initial begin
+		wait(checkbits == 16'hAB40);
+		$display("LA Test 1 started");
+		wait(checkbits == 16'hAB41);
+		wait(checkbits == 16'hAB51);
+		#10000;
+		$finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+		#2000;
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+    	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+
+	wire VDD1V8;
+    	wire VDD3V3;
+	wire VSS;
+    
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+        	.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("la_test1.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+	// Testbench UART
+	tbuart tbuart (
+		.ser_rx(uart_tx)
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/caravel/caravel/user_proj_example/la_test2/Makefile b/verilog/dv/caravel/caravel/user_proj_example/la_test2/Makefile
new file mode 100644
index 0000000..4980a08
--- /dev/null
+++ b/verilog/dv/caravel/caravel/user_proj_example/la_test2/Makefile
@@ -0,0 +1,66 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+FIRMWARE_PATH = ../..
+RTL_PATH = ../../../../rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+GCC_PREFIX?=riscv32-unknown-elf
+PDK_PATH?=/ef/tech/SW/sky130A
+
+SIM?=RTL
+
+.SUFFIXES:
+
+PATTERN = la_test2
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+ifeq ($(SIM),RTL)
+	iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@
+else
+	iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
+	-I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@
+endif
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/${GCC_PREFIX}-gcc -march=rv32imc -mabi=ilp32 -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
diff --git a/verilog/dv/caravel/caravel/user_proj_example/la_test2/la_test2.c b/verilog/dv/caravel/caravel/user_proj_example/la_test2/la_test2.c
new file mode 100644
index 0000000..0267d25
--- /dev/null
+++ b/verilog/dv/caravel/caravel/user_proj_example/la_test2/la_test2.c
@@ -0,0 +1,99 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Efabless Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "../../defs.h"
+#include "../../stub.c"
+
+/*
+	MPRJ LA Test:
+		- Sets counter clk through LA[64]
+		- Sets counter rst through LA[65] 
+		- Observes count value for five clk cycle through LA[31:0]
+*/
+
+int clk = 0;
+int i;
+
+void main()
+{
+	// All GPIO pins are configured to be output
+	// Used to flad the start/end of a test 
+
+        reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
+        reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
+
+        reg_mprj_io_15 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_14 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_13 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_12 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_11 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_10 = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_9  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_8  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_7  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_5  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_4  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_3  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_2  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_1  = GPIO_MODE_USER_STD_OUTPUT;
+        reg_mprj_io_0  = GPIO_MODE_USER_STD_OUTPUT;
+
+        /* Apply configuration */
+        reg_mprj_xfer = 1;
+        while (reg_mprj_xfer == 1);
+
+	// Configure All LA probes as inputs to the cpu 
+	reg_la0_ena = 0xFFFFFFFF;    // [31:0]
+	reg_la1_ena = 0xFFFFFFFF;    // [63:32]
+	reg_la2_ena = 0xFFFFFFFF;    // [95:64]
+	reg_la3_ena = 0xFFFFFFFF;    // [127:96]
+
+	// Flag start of the test
+	reg_mprj_datal = 0xAB600000;
+
+	// Configure LA[64] LA[65] as outputs from the cpu
+	reg_la2_ena  = 0xFFFFFFFC; 
+
+	// Set clk & reset to one
+	reg_la2_data = 0x00000003;
+
+	// Toggle clk & de-assert reset
+	for (i=0; i<11; i=i+1) {
+		clk = !clk;
+		reg_la2_data = 0x00000000 | clk;
+	}
+
+	if (reg_la0_data == 0x05) {
+		reg_mprj_datal = 0xAB610000;
+	}
+
+}
+
diff --git a/verilog/dv/caravel/caravel/user_proj_example/la_test2/la_test2_tb.v b/verilog/dv/caravel/caravel/user_proj_example/la_test2/la_test2_tb.v
new file mode 100644
index 0000000..b9e5c80
--- /dev/null
+++ b/verilog/dv/caravel/caravel/user_proj_example/la_test2/la_test2_tb.v
@@ -0,0 +1,129 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module la_test2_tb;
+	reg clock;
+    	reg RSTB;
+	reg power1, power2;
+
+    	wire gpio;
+    	wire [37:0] mprj_io;
+	wire [15:0] checkbits;
+
+	assign checkbits = mprj_io[31:16];
+
+	always #12.5 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin
+		$dumpfile("la_test2.vcd");
+		$dumpvars(0, la_test2_tb);
+
+		// Repeat cycles of 1000 clock edges as needed to complete testbench
+		repeat (30) begin
+			repeat (1000) @(posedge clock);
+			// $display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		$display ("Monitor: Timeout, Test Mega-Project IO (RTL) Failed");
+		$display("%c[0m",27);
+		$finish;
+	end
+
+	initial begin
+		wait(checkbits == 16'h AB60);
+		$display("Monitor: Test 2 MPRJ-Logic Analyzer Started");
+		wait(checkbits == 16'h AB61);
+		$display("Monitor: Test 2 MPRJ-Logic Analyzer Passed");
+		$finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+		#2000;
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+    	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+
+	wire VDD1V8;
+    	wire VDD3V3;
+	wire VSS;
+    
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+	assign VSS = 1'b0;
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+        	.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("la_test2.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),
+		.io3()
+	);
+
+endmodule
+`default_nettype wire
diff --git a/verilog/dv/wb_utests/wb_utests/Makefile b/verilog/dv/wb_utests/wb_utests/Makefile
new file mode 100644
index 0000000..9684dfc
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/Makefile
@@ -0,0 +1,34 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# ---- Test patterns for project striVe ----
+
+.SUFFIXES:
+.SILENT: clean all
+
+PATTERNS = gpio_wb intercon_wb la_wb mem_wb mprj_ctrl spi_sysctrl_wb spimemio_wb uart_wb    
+
+all:  ${PATTERNS}
+	for i in ${PATTERNS}; do \
+		( cd $$i && make -f Makefile $${i}.vcd &> verify.log && grep Monitor verify.log) ; \
+	done
+
+clean:  ${PATTERNS}
+	for i in ${PATTERNS}; do \
+		( cd $$i && make clean ) ; \
+	done
+
+.PHONY: clean all
diff --git a/verilog/dv/wb_utests/wb_utests/gpio_wb/Makefile b/verilog/dv/wb_utests/wb_utests/gpio_wb/Makefile
new file mode 100644
index 0000000..a42f609
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/gpio_wb/Makefile
@@ -0,0 +1,33 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+.SUFFIXES:
+
+PATTERN = gpio_wb
+
+all:  ${PATTERN:=.vcd}
+
+%.vvp: %_tb.v
+	iverilog -I .. -I ../../../rtl \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+clean:
+	rm -f *.vvp *.vcd
+
+.PHONY: clean all
diff --git a/verilog/dv/wb_utests/wb_utests/gpio_wb/gpio_wb_tb.v b/verilog/dv/wb_utests/wb_utests/gpio_wb/gpio_wb_tb.v
new file mode 100644
index 0000000..6ff214c
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/gpio_wb/gpio_wb_tb.v
@@ -0,0 +1,198 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+
+`timescale 1 ns / 1 ps
+
+`include "gpio_wb.v"
+
+module gpio_wb_tb;
+
+    reg wb_clk_i;
+    reg wb_rst_i;
+
+    reg wb_stb_i;
+    reg wb_cyc_i;
+    reg wb_we_i;
+    reg [3:0] wb_sel_i;
+
+    reg [31:0] wb_dat_i;
+    reg [31:0] wb_adr_i;
+    reg [15:0] gpio_in_pad;
+
+    wire wb_ack_o;
+    wire [31:0] wb_dat_o;
+
+    initial begin
+        wb_clk_i = 0; 
+        wb_rst_i = 0;
+        wb_stb_i = 0; 
+        wb_cyc_i = 0;  
+        wb_sel_i = 0;  
+        wb_we_i  = 0;  
+        wb_dat_i = 0; 
+        wb_adr_i = 0;  
+        gpio_in_pad = 0;
+    end
+
+    always #1 wb_clk_i = ~wb_clk_i;
+
+    initial begin
+        $dumpfile("gpio_wb_tb.vcd");
+        $dumpvars(0, gpio_wb_tb);
+        repeat (50) begin
+            repeat (1000) @(posedge wb_clk_i);
+        end
+        $display("%c[1;31m",27);
+        $display ("Monitor: Timeout, Test GPIO Wishbone Failed");
+        $display("%c[0m",27);
+        $finish;
+    end
+
+    integer i;
+    
+    // GPIO Internal Register Addresses
+    wire [31:0] gpio_adr     = uut.BASE_ADR | uut.GPIO_DATA;
+    wire [31:0] gpio_oeb_adr = uut.BASE_ADR | uut.GPIO_ENA;
+    wire [31:0] gpio_pu_adr  = uut.BASE_ADR | uut.GPIO_PU;
+    wire [31:0] gpio_pd_adr  = uut.BASE_ADR | uut.GPIO_PD;
+
+    reg [15:0] gpio_data;
+    reg [15:0] gpio_pu; 
+    reg [15:0] gpio_pd; 
+    reg [15:0] gpio_oeb;  
+
+    initial begin
+        // Reset Operation
+        wb_rst_i = 1;
+        #2;
+        wb_rst_i = 0; 
+        #2;
+
+        // Write to gpio_data reg
+        gpio_in_pad = 16'h FFFF;
+        gpio_data = 16'h A000;
+        write(gpio_adr, gpio_data);
+       
+        #2;
+        // Read from gpio_data reg
+        read(gpio_adr);
+        if (wb_dat_o !== {gpio_data, gpio_in_pad}) begin
+            $display("Monitor: Error reading from gpio reg");
+            $finish;
+        end
+        
+        #2;
+        // Write to pull-up reg
+        gpio_pu = 16'h 000f;
+        write(gpio_pu_adr, gpio_pu);
+        
+        #2;
+        // Read from pull-up reg
+        read(gpio_pu_adr);
+        if (wb_dat_o !== {16'd0, gpio_pu}) begin
+            $display("Monitor: Error reading from gpio pull-up reg");
+            $finish;
+        end
+
+        #2;
+        // Write to pull-down reg
+        gpio_pd = 16'h 00f0;
+        write(gpio_pd_adr, gpio_pd);
+        
+        #2;
+        // Read from pull-down reg
+        read(gpio_pd_adr);
+        if (wb_dat_o !== {16'd0, gpio_pd}) begin
+            $display("Monitor: Error reading from gpio pull-down reg");
+            $finish;
+        end
+
+        #2;
+        // Write to gpio enable reg
+        gpio_oeb = 16'h 00ff;
+        write(gpio_oeb_adr, gpio_oeb);
+        
+        #2;
+        // Read from gpio enable reg
+        read(gpio_oeb_adr);
+        if (wb_dat_o !== {16'd0, gpio_oeb}) begin
+            $display("Monitor: Error reading from gpio output enable reg");
+            $finish;
+        end
+        
+        #6;
+        $display("Monitor: GPIO WB Success!");
+        $finish;
+    end
+    
+    task write;
+        input [32:0] addr;
+        input [32:0] data;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_sel_i = 4'hF; 
+                wb_we_i = 1;     
+                wb_adr_i = addr;
+                wb_dat_i = data;
+                $display("Write Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Write Cycle Ended.");
+        end
+    endtask
+    
+    task read;
+        input [32:0] addr;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_we_i = 0;
+                wb_adr_i = addr;
+                $display("Read Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Read Cycle Ended.");
+        end
+    endtask
+    
+    gpio_wb uut(
+        .wb_clk_i(wb_clk_i),
+	.wb_rst_i(wb_rst_i),
+        .wb_stb_i(wb_stb_i),
+	.wb_cyc_i(wb_cyc_i),
+	.wb_sel_i(wb_sel_i),
+	.wb_we_i(wb_we_i),
+	.wb_dat_i(wb_dat_i),
+	.wb_adr_i(wb_adr_i), 
+        .wb_ack_o(wb_ack_o),
+	.wb_dat_o(wb_dat_o),
+        .gpio_in_pad(gpio_in_pad)
+    );
+    
+endmodule
diff --git a/verilog/dv/wb_utests/wb_utests/intercon_wb/Makefile b/verilog/dv/wb_utests/wb_utests/intercon_wb/Makefile
new file mode 100644
index 0000000..294cf17
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/intercon_wb/Makefile
@@ -0,0 +1,33 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+.SUFFIXES:
+
+PATTERN = intercon_wb
+
+all:  ${PATTERN:=.vcd}
+
+%.vvp: %_tb.v
+	iverilog -I .. -I ../../ -I ../../../rtl \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+clean:
+	rm -f *.vvp *.vcd *.log
+
+.PHONY: clean all
diff --git a/verilog/dv/wb_utests/wb_utests/intercon_wb/intercon_wb_tb.v b/verilog/dv/wb_utests/wb_utests/intercon_wb/intercon_wb_tb.v
new file mode 100644
index 0000000..5d91efa
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/intercon_wb/intercon_wb_tb.v
@@ -0,0 +1,203 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+
+`timescale 1 ns / 1 ps
+
+`include "wb_intercon.v"
+`include "dummy_slave.v"
+
+`define AW 32
+`define DW 32
+`define NS 6
+
+`define SLAVE_ADR { \
+    {8'h28, {24{1'b0}} }, \   
+    {8'h23, {24{1'b0}} }, \     
+    {8'h21, {24{1'b0}} }, \    
+    {8'h20, {24{1'b0}} }, \    
+    {8'h10, {24{1'b0}} }, \    
+    {8'h00, {24{1'b0}} }  \
+}\
+
+`define ADR_MASK { \
+    {8'hFF, {24{1'b0}} }, \
+    {8'hFF, {24{1'b0}} }, \
+    {8'hFF, {24{1'b0}} }, \
+    {8'hFF, {24{1'b0}} }, \
+    {8'hFF, {24{1'b0}} }, \
+    {8'hFF, {24{1'b0}} }  \
+}\
+
+module intercon_wb_tb;
+
+    localparam SEL = `DW / 8;
+
+    reg wb_clk_i;
+	reg wb_rst_i;
+
+    // Master Interface
+    reg wbm_stb_i;
+    reg wbm_cyc_i;
+    reg wbm_we_i;
+    reg [SEL-1:0] wbm_sel_i;
+    reg [`AW-1:0] wbm_adr_i;
+    reg [`DW-1:0] wbm_dat_i;
+
+    wire [`DW-1:0] wbm_dat_o;
+    wire wbm_ack_o;
+
+    // Wishbone Slave Interface
+    wire [`NS-1:0] wbs_stb_i;
+    wire [`NS-1:0] wbs_ack_o;
+    wire [(`NS*`DW)-1:0] wbs_adr_i;
+    wire [(`NS*`AW)-1:0] wbs_dat_i;
+    wire [(`NS*`DW)-1:0] wbs_dat_o;
+
+    initial begin
+        wb_clk_i = 0; 
+        wb_rst_i = 0;
+        wbm_adr_i = 0;  
+        wbm_dat_i = 0;  
+        wbm_sel_i = 0;   
+        wbm_we_i  = 0;    
+        wbm_cyc_i = 0;   
+        wbm_stb_i = 0;  
+    end
+
+    always #1 wb_clk_i = ~wb_clk_i;
+
+    initial begin
+        $dumpfile("intercon_wb_tb.vcd");
+        $dumpvars(0, intercon_wb_tb);
+        repeat (50) begin
+            repeat (1000) @(posedge wb_clk_i);
+        end
+        $display("%c[1;31m",27);
+        $display ("Monitor: Timeout, Test Wishbone Interconnect Failed");
+        $display("%c[0m",27);
+        $finish;
+    end
+
+    integer i;
+
+    reg [`AW*`NS-1: 0] addr = `SLAVE_ADR;
+    reg [`DW:0] slave_data;
+    reg [`AW:0] slave_addr;
+
+    initial begin
+        // Reset Operation
+        wb_rst_i = 1;
+        #2;
+        wb_rst_i = 0; 
+        #2;
+
+        // W/R from all slaves
+        for (i=0; i<`NS; i=i+1) begin
+            slave_addr = addr[i*`AW +: `AW];
+            slave_data = $urandom_range(0, 2**32);
+            write(slave_addr, slave_data);
+            #2;
+            read(slave_addr);
+            if (wbm_dat_o !== slave_data) begin
+                $display("%c[1;31m",27);
+                $display ("Monitor: Reading from slave %0d failed", i);
+                $display("Monitor: Test Wishbone Interconnect failed");
+                $display("%c[0m",27);
+                $finish;
+            end
+        end
+        $display("Monitor: Test Wishbone Interconnect Success!");
+        $finish;
+    end
+    
+    task write;
+        input [`AW-1:0] addr;
+        input [`AW-1:0] data;
+        begin 
+            @(posedge wb_clk_i) begin
+                wbm_stb_i = 1;
+                wbm_cyc_i = 1;
+                wbm_sel_i = {SEL{1'b1}}; 
+                wbm_we_i = 1;    
+                wbm_adr_i = addr;
+                wbm_dat_i = data;
+                $display("Write Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wbm_ack_o == 1);
+            wait(wbm_ack_o == 0);
+            wbm_cyc_i = 0;
+            wbm_stb_i = 0;
+            $display("Write Cycle Ended.");
+        end
+    endtask
+    
+    task read;
+        input [`AW-1:0] addr;
+        begin 
+            @(posedge wb_clk_i) begin
+                wbm_stb_i = 1;
+                wbm_cyc_i = 1;
+                wbm_adr_i = addr;
+                wbm_we_i =  0;     
+                $display("Read Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wbm_ack_o == 1);
+            wait(wbm_ack_o == 0);
+            wbm_cyc_i = 0;
+            wbm_stb_i = 0;
+            $display("Read Cycle Ended.");
+        
+        end
+    endtask
+
+    wb_intercon #(
+        .AW(`AW),
+        .DW(`DW),
+        .NS(`NS),
+        .ADR_MASK(`ADR_MASK),
+        .SLAVE_ADR(`SLAVE_ADR)
+    ) uut(
+        // Master Interface
+        .wbm_adr_i(wbm_adr_i),
+        .wbm_stb_i(wbm_stb_i),
+        .wbm_dat_o(wbm_dat_o),
+        .wbm_ack_o(wbm_ack_o), 
+    
+        // Slave Interface
+        .wbs_stb_o(wbs_stb_i),
+        .wbs_dat_i(wbs_dat_o), 
+        .wbs_ack_i(wbs_ack_o)
+    );
+    
+    // Instantiate five dummy slaves for testing
+    dummy_slave dummy_slaves [`NS-1:0](
+        .wb_clk_i({`NS{wb_clk_i}}),
+        .wb_rst_i({`NS{wb_rst_i}}),
+        .wb_stb_i(wbs_stb_i),
+        .wb_cyc_i(wbm_cyc_i),
+        .wb_we_i(wbm_we_i),
+        .wb_sel_i(wbm_sel_i),
+        .wb_adr_i(wbm_adr_i),
+        .wb_dat_i(wbm_dat_i),
+        .wb_dat_o(wbs_dat_o),
+        .wb_ack_o(wbs_ack_o)
+    );
+
+endmodule
\ No newline at end of file
diff --git a/verilog/dv/wb_utests/wb_utests/la_wb/Makefile b/verilog/dv/wb_utests/wb_utests/la_wb/Makefile
new file mode 100644
index 0000000..1b76d6b
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/la_wb/Makefile
@@ -0,0 +1,33 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+.SUFFIXES:
+
+PATTERN = la_wb
+
+all:  ${PATTERN:=.vcd}
+
+%.vvp: %_tb.v
+	iverilog -I .. -I ../../../rtl \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+clean:
+	rm -f *.vvp *.vcd
+
+.PHONY: clean all
diff --git a/verilog/dv/wb_utests/wb_utests/la_wb/la_wb_tb.v b/verilog/dv/wb_utests/wb_utests/la_wb/la_wb_tb.v
new file mode 100644
index 0000000..c1548c9
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/la_wb/la_wb_tb.v
@@ -0,0 +1,224 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+`timescale 1 ns / 1 ps
+
+`include "la_wb.v"
+
+module la_wb_tb;
+
+    reg wb_clk_i;
+	reg wb_rst_i;
+
+    reg wb_stb_i;
+    reg wb_cyc_i;
+	reg wb_we_i;
+	reg [3:0] wb_sel_i;
+
+	reg [31:0] wb_dat_i;
+	reg [31:0] wb_adr_i;
+
+	wire wb_ack_o;
+	wire [31:0] wb_dat_o;
+
+    initial begin
+        wb_clk_i = 0; 
+        wb_rst_i = 0;
+        wb_stb_i = 0; 
+        wb_cyc_i = 0;  
+        wb_sel_i = 0;  
+        wb_we_i  = 0;  
+        wb_dat_i = 0; 
+        wb_adr_i = 0;  
+    end
+
+    always #1 wb_clk_i = ~wb_clk_i;
+    
+    initial begin
+        $dumpfile("la_wb_tb.vcd");
+        $dumpvars(0, la_wb_tb);
+        repeat (50) begin
+            repeat (1000) @(posedge wb_clk_i);
+        end
+        $display("%c[1;31m",27);
+        $display ("Monitor: Timeout, Test Wishbone LA Failed");
+        $display("%c[0m",27);
+        $finish;
+    end
+
+    integer i;
+    
+    // LA Wishbone Internal Register Addresses
+    wire [31:0] la_data_adr_0   = uut.BASE_ADR | uut.LA_DATA_0;
+    wire [31:0] la_data_adr_1   = uut.BASE_ADR | uut.LA_DATA_1;
+    wire [31:0] la_data_adr_2   = uut.BASE_ADR | uut.LA_DATA_2;
+    wire [31:0] la_data_adr_3   = uut.BASE_ADR | uut.LA_DATA_3;
+    
+    wire [31:0] la_ena_adr_0 = uut.BASE_ADR | uut.LA_ENA_0;
+    wire [31:0] la_ena_adr_1 = uut.BASE_ADR | uut.LA_ENA_1;
+    wire [31:0] la_ena_adr_2 = uut.BASE_ADR | uut.LA_ENA_2;
+    wire [31:0] la_ena_adr_3 = uut.BASE_ADR | uut.LA_ENA_3;
+
+    reg [31:0] la_data_0;
+    reg [31:0] la_data_1; 
+    reg [31:0] la_data_2;
+    reg [31:0] la_data_3; 
+
+    reg [31:0] la_ena_0;
+    reg [31:0] la_ena_1; 
+    reg [31:0] la_ena_2;
+    reg [31:0] la_ena_3; 
+
+    initial begin
+        // Reset Operation
+        wb_rst_i = 1;
+        #2;
+        wb_rst_i = 0; 
+        #2;
+
+        // Write to la data registers
+        la_data_0 = $urandom_range(0, 2**32);
+        la_data_1 = $urandom_range(0, 2**32);
+        la_data_2 = $urandom_range(0, 2**32);
+        la_data_3 = $urandom_range(0, 2**32);
+
+        write(la_data_adr_0, la_data_0);
+        write(la_data_adr_1, la_data_1);
+        write(la_data_adr_2, la_data_2);
+        write(la_data_adr_3, la_data_3);
+
+        #2;
+        // Read from la data registers
+        read(la_data_adr_0);
+        if (wb_dat_o !== la_data_0) begin
+            $display("Monitor: Error reading from la data_0 reg");
+            $finish;
+        end
+        
+        read(la_data_adr_1);
+        if (wb_dat_o !== la_data_1) begin
+            $display("Monitor: Error reading from la data_0 reg");
+            $finish;
+        end
+        
+        read(la_data_adr_2);
+        if (wb_dat_o !== la_data_1) begin
+            $display("Monitor: Error reading from la data_0 reg");
+            $finish;
+        end
+
+        read(la_data_adr_3);
+        if (wb_dat_o !== la_data_3) begin
+            $display("Monitor: Error reading from la data_0 reg");
+            $finish;
+        end
+
+        // Write to la emable registers
+        la_ena_0 = $urandom_range(0, 2**32);
+        la_ena_1 = $urandom_range(0, 2**32);
+        la_ena_2 = $urandom_range(0, 2**32);
+        la_ena_3 = $urandom_range(0, 2**32);
+
+        write(la_ena_adr_0, la_ena_0);
+        write(la_ena_adr_1, la_ena_1);
+        write(la_ena_adr_2, la_ena_2);
+        write(la_ena_adr_3, la_ena_3);
+
+        #2;
+        // Read from la data registers
+        read(la_ena_adr_0);
+        if (wb_dat_o !== la_ena_0) begin
+            $display("Monitor: Error reading from la data_0 reg");
+            $finish;
+        end
+        
+        read(la_ena_adr_1);
+        if (wb_dat_o !== la_ena_1) begin
+            $display("Monitor: Error reading from la data_0 reg");
+            $finish;
+        end
+        
+        read(la_ena_adr_2);
+        if (wb_dat_o !== la_ena_1) begin
+            $display("Monitor: Error reading from la data_0 reg");
+            $finish;
+        end
+
+        read(la_ena_adr_3);
+        if (wb_dat_o !== la_ena_3) begin
+            $display("Monitor: Error reading from la data_0 reg");
+            $finish;
+        end
+        #6;
+        $display("Monitor: Test LA Wishbone Success!");
+        $finish;
+    end
+    
+    task write;
+        input [32:0] addr;
+        input [32:0] data;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_sel_i = 4'hF; 
+                wb_we_i = 1;     
+                wb_adr_i = addr;
+                wb_dat_i = data;
+                $display("Write Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Write Cycle Ended.");
+        end
+    endtask
+    
+    task read;
+        input [32:0] addr;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_we_i = 0;
+                wb_adr_i = addr;
+                $display("Read Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Read Cycle Ended.");
+        end
+    endtask
+
+    la_wb uut(
+        .wb_clk_i(wb_clk_i),
+	    .wb_rst_i(wb_rst_i),
+        .wb_stb_i(wb_stb_i),
+	    .wb_cyc_i(wb_cyc_i),
+	    .wb_sel_i(wb_sel_i),
+	    .wb_we_i(wb_we_i),
+	    .wb_dat_i(wb_dat_i),
+	    .wb_adr_i(wb_adr_i), 
+        .wb_ack_o(wb_ack_o),
+	    .wb_dat_o(wb_dat_o)
+    );
+
+endmodule
\ No newline at end of file
diff --git a/verilog/dv/wb_utests/wb_utests/mem_wb/Makefile b/verilog/dv/wb_utests/wb_utests/mem_wb/Makefile
new file mode 100644
index 0000000..4ed37bf
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/mem_wb/Makefile
@@ -0,0 +1,33 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+.SUFFIXES:
+
+PATTERN = mem_wb
+
+all:  ${PATTERN:=.vcd}
+
+%.vvp: %_tb.v
+	iverilog -I .. -I ../../../rtl \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+clean:
+	rm -f *.vvp *.vcd
+
+.PHONY: clean all
diff --git a/verilog/dv/wb_utests/wb_utests/mem_wb/mem_wb_tb.v b/verilog/dv/wb_utests/wb_utests/mem_wb/mem_wb_tb.v
new file mode 100644
index 0000000..549f904
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/mem_wb/mem_wb_tb.v
@@ -0,0 +1,159 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+
+`timescale 1 ns / 1 ps
+
+`define USE_OPENRAM
+
+`include "sram_1rw1r_32_8192_8_sky130.v"
+`include "mem_wb.v"
+
+module mem_wb_tb;
+
+    reg wb_clk_i;
+    reg wb_rst_i;
+
+    reg [31:0] wb_adr_i;
+    reg [31:0] wb_dat_i;
+    reg [3:0]  wb_sel_i;
+    reg wb_we_i;
+    reg wb_cyc_i;
+    reg wb_stb_i;
+
+    wire wb_ack_o;
+    wire [31:0] wb_dat_o;
+
+    initial begin
+        wb_clk_i = 0; 
+        wb_rst_i = 0;
+
+        wb_stb_i = 0;  // master select-signal for the slave
+        wb_we_i  = 0;  // R = 0 , W = 1
+        wb_cyc_i = 0;  // master is transferring
+        wb_adr_i = 0;  // input addr 32-bits
+        wb_dat_i = 0;  // input data 32-bits
+        wb_sel_i = 0;  // where data is available on data_i 4-bits
+    end
+
+    always #1 wb_clk_i = ~wb_clk_i;
+
+    initial begin
+        $dumpfile("mem_wb_tb.vcd");
+        $dumpvars(0, mem_wb_tb);
+        repeat (50) begin
+            repeat (1000) @(posedge wb_clk_i);
+        end
+        $display("%c[1;31m",27);
+        $display ("Monitor: Timeout, Test Wishbone Memory Failed");
+        $display("%c[0m",27);
+        $finish;
+    end
+
+    integer i;
+
+    reg [31:0] ref_data [255: 0];
+    reg [31: 0] read_data;
+
+    initial begin
+        // Reset Operation
+        wb_rst_i = 1;
+        #2;
+        wb_rst_i = 0; 
+        #2;
+
+        // Randomly Write to memory array
+        for ( i = 0; i < 1; i = i + 1) begin 
+            ref_data[i] = $urandom_range(0, 2**30);
+            write(i, ref_data[i]);
+            #2;
+        end
+
+        #6;
+        for ( i = 0; i < 1; i = i + 1) begin 
+            read(i);
+            if (wb_dat_o !== ref_data[i]) begin
+                $display("%c[1;31m",27);
+                $display("Expected %0b, but Got %0b ", ref_data[i], wb_dat_o);
+                $display("Monitor: Wishbone Memory Failed");
+                $display("%c[0m",27);
+                $finish;
+            end
+            #2;
+        end
+        #6;
+        $display("Success!");
+        $finish;
+    end
+     
+    task write;
+        input [32:0] addr;
+        input [32:0] data;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_sel_i = 4'hF; 
+                wb_we_i = 1;     
+                wb_adr_i = addr;
+                wb_dat_i = data;
+                $display("Write Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Write Cycle Ended.");
+        end
+    endtask
+    
+    task read;
+        input [32:0] addr;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_we_i = 0;
+                wb_adr_i = addr;
+                $display("Read Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Read Cycle Ended.");
+        end
+    endtask
+    
+    mem_wb uut(
+        .wb_clk_i(wb_clk_i),
+        .wb_rst_i(wb_rst_i),
+
+        .wb_adr_i(wb_adr_i), 
+        .wb_dat_i(wb_dat_i),
+        .wb_sel_i(wb_sel_i),
+        .wb_we_i(wb_we_i),
+        .wb_cyc_i(wb_cyc_i),
+        .wb_stb_i(wb_stb_i),
+
+        .wb_ack_o(wb_ack_o), 
+        .wb_dat_o(wb_dat_o)
+    );
+
+endmodule
\ No newline at end of file
diff --git a/verilog/dv/wb_utests/wb_utests/mprj_ctrl/Makefile b/verilog/dv/wb_utests/wb_utests/mprj_ctrl/Makefile
new file mode 100644
index 0000000..f354018
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/mprj_ctrl/Makefile
@@ -0,0 +1,33 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+.SUFFIXES:
+
+PATTERN = mprj_ctrl
+
+all:  ${PATTERN:=.vcd}
+
+%.vvp: %_tb.v
+	iverilog  -I ../../../rtl \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+clean:
+	rm -f *.vvp *.vcd *.log
+
+.PHONY: clean all
\ No newline at end of file
diff --git a/verilog/dv/wb_utests/wb_utests/mprj_ctrl/mprj_ctrl_tb.v b/verilog/dv/wb_utests/wb_utests/mprj_ctrl/mprj_ctrl_tb.v
new file mode 100644
index 0000000..5d86450
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/mprj_ctrl/mprj_ctrl_tb.v
@@ -0,0 +1,158 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+
+`timescale 1 ns / 1 ps
+
+`include "mprj_ctrl.v"
+
+module mprj_ctrl_tb;
+
+    reg wb_clk_i;
+	reg wb_rst_i;
+
+    reg wb_stb_i;
+    reg wb_cyc_i;
+	reg wb_we_i;
+	reg [3:0] wb_sel_i;
+	reg [31:0] wb_dat_i;
+	reg [31:0] wb_adr_i;
+
+	wire wb_ack_o;
+	wire [31:0] wb_dat_o;
+
+    initial begin
+        wb_clk_i = 0; 
+        wb_rst_i = 0;
+        wb_stb_i = 0; 
+        wb_cyc_i = 0;  
+        wb_sel_i = 0;  
+        wb_we_i  = 0;  
+        wb_dat_i = 0; 
+        wb_adr_i = 0; 
+    end
+
+    always #1 wb_clk_i = ~wb_clk_i;
+
+    // Mega Project Control Registers 
+    wire [31:0] mprj_ctrl = uut.BASE_ADR;
+    wire [31:0] pwr_ctrl  = uut.BASE_ADR + uut.IO_PADS*4;
+
+    initial begin
+        $dumpfile("mprj_ctrl_tb.vcd");
+        $dumpvars(0, mprj_ctrl_tb);
+        repeat (50) begin
+            repeat (1000) @(posedge wb_clk_i);
+        end
+        $display("%c[1;31m",27);
+        $display ("Monitor: Timeout, Test Mega-Project Control Failed");
+        $display("%c[0m",27);
+        $finish;
+    end
+
+    integer i;
+
+    reg [31:0] data;
+
+    initial begin   
+        // Reset Operation
+        wb_rst_i = 1;
+        #2;
+        wb_rst_i = 0;
+        #2;
+
+        for (i=0; i<uut.IO_PADS; i=i+1) begin
+            data = $urandom_range(0, 2**(7));
+            write(mprj_ctrl+i*4, data);
+            #2;
+            read(mprj_ctrl+i*4);
+            if (wb_dat_o !== data) begin
+                $display("Monitor: R/W from IO-CTRL Failed.");
+                $finish;
+            end
+        end
+
+        for (i=0; i<uut.PWR_CTRL; i=i+1) begin
+            data = $urandom_range(0, 2**(7));
+            write(pwr_ctrl+i*4, data);
+            #2;
+            read(pwr_ctrl+i*4);
+            if (wb_dat_o !== data) begin
+                $display("Monitor: R/W from POWER-CTRL Failed.");
+                $finish;
+            end
+        end
+        
+        $display("Success!");
+        $finish;
+    end
+
+    task write;
+        input [32:0] addr;
+        input [32:0] data;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_sel_i = 4'hF; 
+                wb_we_i = 1;     
+                wb_adr_i = addr;
+                wb_dat_i = data;
+                $display("Write Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Write Cycle Ended.");
+        end
+    endtask
+    
+    task read;
+        input [32:0] addr;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_we_i = 0;
+                wb_adr_i = addr;
+                $display("Read Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Read Cycle Ended.");
+        end
+    endtask
+
+    mprj_ctrl_wb uut(
+        .wb_clk_i(wb_clk_i),
+	    .wb_rst_i(wb_rst_i),
+        .wb_stb_i(wb_stb_i),
+	    .wb_cyc_i(wb_cyc_i),
+	    .wb_sel_i(wb_sel_i),
+	    .wb_we_i(wb_we_i),
+	    .wb_dat_i(wb_dat_i),
+	    .wb_adr_i(wb_adr_i), 
+        .wb_ack_o(wb_ack_o),
+	    .wb_dat_o(wb_dat_o)
+    );
+
+endmodule
\ No newline at end of file
diff --git a/verilog/dv/wb_utests/wb_utests/spi_sysctrl_wb/Makefile b/verilog/dv/wb_utests/wb_utests/spi_sysctrl_wb/Makefile
new file mode 100644
index 0000000..8bf03c7
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/spi_sysctrl_wb/Makefile
@@ -0,0 +1,34 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+.SUFFIXES:
+
+PATTERN = spi_sysctrl_wb
+
+all:  ${PATTERN:=.vcd}
+
+%.vvp: %_tb.v
+	iverilog  -I ../../../rtl \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+clean:
+	rm -f *.vvp *.vcd *.log
+
+.PHONY: clean all
+
diff --git a/verilog/dv/wb_utests/wb_utests/spi_sysctrl_wb/spi_sysctrl_wb_tb.v b/verilog/dv/wb_utests/wb_utests/spi_sysctrl_wb/spi_sysctrl_wb_tb.v
new file mode 100644
index 0000000..a5baf05
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/spi_sysctrl_wb/spi_sysctrl_wb_tb.v
@@ -0,0 +1,242 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+
+`timescale 1 ns / 1 ps
+
+`include "spi_sysctrl.v"
+`include "striVe_spi.v"
+
+module spi_sysctrl_wb_tb;
+
+    reg wb_clk_i;
+	reg wb_rst_i;
+
+    reg wb_stb_i;
+    reg wb_cyc_i;
+	reg wb_we_i;
+	reg [3:0] wb_sel_i;
+	reg [31:0] wb_dat_i;
+	reg [31:0] wb_adr_i;
+
+	wire wb_ack_o;
+	wire [31:0] wb_dat_o;
+
+    wire [7:0] spi_ro_config; // (verify) wire input to the core not connected to HKSPI, what should it be connected to ? 
+    wire [4:0] spi_ro_pll_div; 
+    wire [2:0] spi_ro_pll_sel;
+    wire spi_ro_xtal_ena;
+    wire spi_ro_reg_ena; 
+    wire [25:0] spi_ro_pll_trim;
+    wire spi_ro_pll_dco_ena;
+    wire [11:0] spi_ro_mfgr_id;
+    wire [7:0] spi_ro_prod_id;
+    wire [3:0] spi_ro_mask_rev;
+    wire spi_ro_pll_bypass;
+   
+    // HKSPI
+    reg RSTB;	    
+    reg SCK;	   
+    reg SDI;	    
+    reg CSB;	    
+    reg trap;
+    reg [3:0] mask_rev_in;	
+
+    wire SDO;	  
+    wire sdo_enb;
+    wire xtal_ena;
+    wire reg_ena;
+    wire pll_dco_ena;
+    wire [25:0] pll_trim;
+    wire [2:0] pll_sel;
+    wire [4:0] pll_div;
+    wire pll_bypass;
+    wire irq;
+    wire reset;
+    wire RST;
+    wire [11:0] mfgr_id;
+    wire [7:0] prod_id;
+    wire [3:0] mask_rev;
+
+    initial begin
+        wb_clk_i = 0; 
+        wb_rst_i = 0;
+        wb_stb_i = 0; 
+        wb_cyc_i = 0;  
+        wb_sel_i = 0;  
+        wb_we_i  = 0;  
+        wb_dat_i = 0; 
+        wb_adr_i = 0; 
+        CSB = 1;
+        SCK = 0;
+        SDI = 0;
+        RSTB = 0; 
+    end
+
+    always #1 wb_clk_i = ~wb_clk_i;
+
+    // System Control Default Register Addresses (Read-only reg)
+    wire [31:0] spi_cfg         = uut.BASE_ADR | uut.SPI_CFG; // unused & reserved ? 
+    wire [31:0] spi_ena         = uut.BASE_ADR | uut.SPI_ENA;
+    wire [31:0] spi_pll_cfg     = uut.BASE_ADR | uut.SPI_PLL_CFG;
+    wire [31:0] spi_mfgr_id     = uut.BASE_ADR | uut.SPI_MFGR_ID;
+    wire [31:0] spi_prod_id     = uut.BASE_ADR | uut.SPI_PROD_ID;
+    wire [31:0] spi_mask_rev    = uut.BASE_ADR | uut.SPI_MASK_REV;
+    wire [31:0] spi_pll_bypass  = uut.BASE_ADR | uut.SPI_PLL_BYPASS;
+
+    initial begin
+        $dumpfile("spi_sysctrl_wb_tb.vcd");
+        $dumpvars(0, spi_sysctrl_wb_tb);
+        repeat (50) begin
+            repeat (1000) @(posedge wb_clk_i);
+        end
+        $display("%c[1;31m",27);
+        $display ("Monitor: Timeout, Test SPI System Control Failed");
+        $display("%c[0m",27);
+        $finish;
+    end
+
+    integer i;
+
+    initial begin   
+        // Reset Operation
+        wb_rst_i = 1;
+        RSTB = 0;       // active low reset
+        #2;
+        wb_rst_i = 0;
+        RSTB = 1; 
+        #2;
+
+        // Read mask_rev register
+        mask_rev_in = 4'hF;
+        read(spi_mask_rev);
+        if (wb_dat_o !== {28'd0, mask_rev_in}) begin
+            $display("Error reading mask_rev reg");
+            $finish;
+        end
+
+        // Read manufacture id register
+        read(spi_mfgr_id);
+        if (wb_dat_o !== {20'd0, 12'h456}) begin
+            $display("Error reading manufacture id reg");
+            $finish;
+        end
+
+        // Read product id register
+        read(spi_prod_id);
+        if (wb_dat_o !== {24'd0, 8'h05}) begin
+            $display("Error reading product id reg");
+            $finish;
+        end
+
+        // Read PLL-Bypass register
+        read(spi_pll_bypass);
+        if (wb_dat_o !== {31'd0, 1'b1}) begin
+            $display("Error reading pll bypass id reg");
+            $finish;
+        end
+
+        // Read PLL-Configuration register
+        read(spi_pll_cfg);
+        if (wb_dat_o !== {5'd0, spi_ro_pll_trim, spi_ro_pll_dco_ena}) begin
+            $display("Error reading pll bypass id reg");
+            $finish;
+        end
+
+        // Read SPI Enables register
+        read(spi_ena);
+        if (wb_dat_o !== {22'd0, spi_ro_pll_div, spi_ro_pll_sel, spi_ro_xtal_ena, spi_ro_reg_ena}) begin
+            $display("Error reading pll bypass id reg");
+            $finish;
+        end                
+        $display("Success!");
+        $finish;
+    end
+
+    task read;
+        input [32:0] addr;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_we_i = 0;
+                wb_adr_i = addr;
+                $display("Monitor: Read Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Monitor: Read Cycle Ended.");
+        end
+    endtask
+
+    spi_sysctrl_wb uut(
+        .wb_clk_i(wb_clk_i),
+	    .wb_rst_i(wb_rst_i),
+
+        .wb_stb_i(wb_stb_i),
+	    .wb_cyc_i(wb_cyc_i),
+	    .wb_sel_i(wb_sel_i),
+	    .wb_we_i(wb_we_i),
+	    .wb_dat_i(wb_dat_i),
+	    .wb_adr_i(wb_adr_i), 
+        .wb_ack_o(wb_ack_o),
+	    .wb_dat_o(wb_dat_o),
+        
+        .spi_ro_config(spi_ro_config), // (verify) wire input to the core not connected to HKSPI, what should it be connected to ? 
+        .spi_ro_pll_div(spi_ro_pll_div), 
+        .spi_ro_pll_sel(spi_ro_pll_sel),
+        .spi_ro_xtal_ena(spi_ro_xtal_ena),
+        .spi_ro_reg_ena(spi_ro_reg_ena), 
+    
+        .spi_ro_pll_trim(spi_ro_pll_trim),
+        .spi_ro_pll_dco_ena(spi_ro_pll_dco_ena),  
+
+        .spi_ro_mfgr_id(spi_ro_mfgr_id),
+        .spi_ro_prod_id(spi_ro_prod_id), 
+        .spi_ro_mask_rev(spi_ro_mask_rev), 
+        .pll_bypass(spi_ro_pll_bypass)
+    );
+
+    striVe_spi hkspi (
+		.RSTB(RSTB),
+		.SCK(SCK),
+		.SDI(SDI),
+		.CSB(CSB),
+
+		.SDO(SDO),
+		.sdo_enb(SDO_enb),
+		.xtal_ena(spi_ro_xtal_ena),
+		.reg_ena(spi_ro_reg_ena),
+		.pll_dco_ena(spi_ro_pll_dco_ena),
+		.pll_sel(spi_ro_pll_sel),
+		.pll_div(spi_ro_pll_div),
+		.pll_trim(spi_ro_pll_trim),
+		.pll_bypass(spi_ro_pll_bypass),
+		.irq(irq_spi),
+		.RST(por),
+		.reset(ext_reset),
+		.trap(trap),
+		.mfgr_id(spi_ro_mfgr_id),
+		.prod_id(spi_ro_prod_id),
+		.mask_rev_in(mask_rev_in),
+		.mask_rev(spi_ro_mask_rev)
+    );
+
+endmodule
\ No newline at end of file
diff --git a/verilog/dv/wb_utests/wb_utests/spimemio_wb/Makefile b/verilog/dv/wb_utests/wb_utests/spimemio_wb/Makefile
new file mode 100644
index 0000000..d145f04
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/spimemio_wb/Makefile
@@ -0,0 +1,34 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+.SUFFIXES:
+
+PATTERN = spimemio_wb
+
+all:  ${PATTERN:=.vcd}
+
+%.vvp: %_tb.v
+	iverilog -I ../ -I ../../  -I ../../../rtl \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+clean:
+	rm -f *.vvp *.vcd *.log
+
+.PHONY: clean all
+
diff --git a/verilog/dv/wb_utests/wb_utests/spimemio_wb/flash.hex b/verilog/dv/wb_utests/wb_utests/spimemio_wb/flash.hex
new file mode 100644
index 0000000..23bd76d
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/spimemio_wb/flash.hex
@@ -0,0 +1,6 @@
+@10000000
+a1
+b1
+c1
+d1
+f1
\ No newline at end of file
diff --git a/verilog/dv/wb_utests/wb_utests/spimemio_wb/spimemio_wb_tb.v b/verilog/dv/wb_utests/wb_utests/spimemio_wb/spimemio_wb_tb.v
new file mode 100644
index 0000000..febc124
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/spimemio_wb/spimemio_wb_tb.v
@@ -0,0 +1,233 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+
+`timescale 1 ns / 1 ps
+
+`define FLASH_BASE  32'h 1000_000
+
+`include "spimemio.v"
+// `include "spiflash.v"
+
+module spimemio_wb_tb;
+
+    reg wb_clk_i;
+	reg wb_rst_i;
+
+    reg wb_flash_stb_i;
+	reg wb_cfg_stb_i;
+	reg wb_cyc_i;
+	reg wb_we_i;
+	reg [3:0]  wb_sel_i;
+	reg [31:0] wb_adr_i;
+	reg [31:0] wb_dat_i;
+
+	wire wb_flash_ack_o;
+    wire wb_cfg_ack_o;
+	wire [31:0] wb_flash_dat_o;
+	wire [31:0] wb_cfg_dat_o;
+
+    wire flash_csb;
+    wire flash_clk;
+
+    wire flash_io0_oeb;
+    wire flash_io1_oeb;
+    wire flash_io2_oeb;
+    wire flash_io3_oeb;
+
+    wire flash_io0_di = 1'b 1;
+    wire flash_io1_di = 1'b 1;
+    wire flash_io2_di = 1'b 1;
+    wire flash_io3_di = 1'b 1;
+
+    initial begin
+        wb_clk_i = 0; 
+        wb_rst_i = 0;
+        wb_flash_stb_i = 0;  
+        wb_cfg_stb_i = 0; 
+        wb_cyc_i = 0;   
+        wb_we_i  = 0;
+        wb_sel_i = 0;    
+        wb_adr_i = 0;  
+        wb_dat_i = 0;  
+    end
+
+    always #1 wb_clk_i = ~wb_clk_i;
+
+    spimemio_wb uut(
+        .wb_clk_i(wb_clk_i),
+	    .wb_rst_i(wb_rst_i),
+        
+        .wb_flash_stb_i(wb_flash_stb_i),
+	    .wb_cfg_stb_i(wb_cfg_stb_i),
+	    .wb_cyc_i(wb_cyc_i),
+    	.wb_we_i(wb_we_i),
+	    .wb_sel_i(wb_sel_i),
+	    .wb_adr_i(wb_adr_i), 
+	    .wb_dat_i(wb_dat_i),
+	    .wb_flash_ack_o(wb_flash_ack_o),
+        .wb_cfg_ack_o(wb_cfg_ack_o),
+	    .wb_flash_dat_o(wb_flash_dat_o),
+	    .wb_cfg_dat_o(wb_cfg_dat_o),
+
+        .flash_clk(flash_clk),
+        .flash_csb(flash_csb),
+
+        .flash_io0_oeb(flash_io0_oeb),
+        .flash_io1_oeb(flash_io1_oeb),
+        .flash_io2_oeb(flash_io2_oeb),
+        .flash_io3_oeb(flash_io3_oeb),
+
+        .flash_io0_di(flash_io0_di),
+        .flash_io1_di(flash_io1_di),
+	    .flash_io2_di(flash_io2_di),
+	    .flash_io3_di(flash_io3_di)       
+    );
+
+    initial begin
+        $dumpfile("spimemio_wb_tb.vcd");
+        $dumpvars(0, spimemio_wb_tb);
+        repeat (50) begin
+            repeat (1000) @(posedge wb_clk_i);
+        end
+        $display("%c[1;31m",27);
+        $display ("Monitor: Timeout, Test spimmemio Failed");
+        $display("%c[0m",27);
+        $finish;
+    end
+
+    integer i;
+        
+    wire [31:0] cfgreg_data;
+    assign cfgreg_data = {
+        1'b 1,
+        8'b 0,
+        3'b 111,
+        4'b 1010,
+        4'b 0,             // make sure is it tied to zero in the module itself
+        {~flash_io3_oeb, ~flash_io2_oeb, ~flash_io1_oeb, ~flash_io0_oeb},
+        2'b 0,
+        flash_csb,
+        flash_clk,
+        {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}
+    };
+
+    initial begin
+        // Reset Operation
+        wb_rst_i = 1;
+        #2;
+        wb_rst_i = 0; 
+        #2;
+
+        // Read from flash
+        for (i = `FLASH_BASE; i < `FLASH_BASE + 100 ; i = i + 4) begin
+            read(i, 1, 0);
+            if (wb_flash_dat_o !== 32'hFFFF_FFFF) begin
+                $display("%c[1;31m",27);
+                $display("Expected %0b, but Got %0b ",  32'hFFFF_FFFF, wb_flash_dat_o);
+                $display("Monitor: Wishbone spimemio Failed");
+            	$display("%c[0m",27);
+                $finish;
+            end
+            #2;
+        end 
+
+        #6;
+        // Write to Configuration register
+        write(cfgreg_data, 0);
+        #2;
+        read(0, 0, 1);
+        if (wb_cfg_dat_o !== cfgreg_data) begin
+            $display("%c[1;31m",27);
+            $display("Expected %0b, but Got %0b ",  cfgreg_data, wb_cfg_dat_o);
+            $display("Monitor: Wishbone spimemio Failed");
+            $display("%c[0m",27);
+            $finish;
+        end
+        
+        $display("Success!");
+        $finish;
+    end
+    
+    task write;
+        input [32:0] data;
+        input [31:0] addr;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_cfg_stb_i = 1'b 1;
+                wb_flash_stb_i = 1'b 0;
+                wb_cyc_i = 1'b 1;
+                wb_sel_i = 4'b 1111; // complete word
+                wb_we_i = 1'b 1;     // write enable
+                wb_adr_i = addr;
+                wb_dat_i = data;
+            end
+
+            wait_ack();
+        end
+    endtask
+    
+    task read;
+        input [32:0] addr;
+        input flash_stb;
+        input cfg_stb;
+        begin 
+            wb_flash_stb_i = flash_stb;
+            wb_cfg_stb_i = cfg_stb;
+
+            wb_cyc_i = 1'b 1;
+            wb_adr_i = addr;
+            wb_dat_i = 24;
+            wb_sel_i = 4'b 1111; // complete word
+            wb_we_i = 1'b 0;     // read
+            $display("Initiated Read transaction...");
+            wait_ack();
+        end
+    endtask
+
+    task wait_ack;
+        // Wait for an ACK
+        if (wb_cfg_stb_i == 1) begin
+            @(posedge wb_cfg_ack_o) begin
+                #2;  // To end the transaction on the falling edge of ack 
+                wb_cyc_i = 1'b 0;
+                wb_cfg_stb_i = 1'b 0;
+                $display("Monitor: Received an ACK from slave");
+            end
+        end
+        else begin
+            @(posedge wb_flash_ack_o) begin
+                #2;  // To end the transaction on the falling edge of ack 
+                wb_cyc_i = 1'b 0;
+                wb_flash_stb_i = 1'b 0;
+                $display("Monitor: Received an ACK from slave");
+            end
+        end
+    endtask
+
+    // spiflash #(
+	// 	.FILENAME("flash.hex")
+	// ) spiflash (
+	// 	.csb(flash_csb),
+	// 	.clk(flash_clk),
+	// 	.io0(flash_io0),
+	// 	.io1(flash_io1),
+	// 	.io2(flash_io2),
+	// 	.io3(flash_io3)
+	// );
+    
+endmodule
\ No newline at end of file
diff --git a/verilog/dv/wb_utests/wb_utests/storage_wb/Makefile b/verilog/dv/wb_utests/wb_utests/storage_wb/Makefile
new file mode 100644
index 0000000..d080bcf
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/storage_wb/Makefile
@@ -0,0 +1,33 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+.SUFFIXES:
+
+PATTERN = storage_wb
+
+all:  ${PATTERN:=.vcd}
+
+%.vvp: %_tb.v
+	iverilog  -I ../../../rtl \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+clean:
+	rm -f *.vvp *.vcd *.log
+
+.PHONY: clean all
\ No newline at end of file
diff --git a/verilog/dv/wb_utests/wb_utests/storage_wb/storage_wb_tb.v b/verilog/dv/wb_utests/wb_utests/storage_wb/storage_wb_tb.v
new file mode 100644
index 0000000..0cc6b78
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/storage_wb/storage_wb_tb.v
@@ -0,0 +1,228 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+// `define DBG
+
+`define STORAGE_BASE_ADR  32'h0100_0000
+
+`include "defines.v"
+`include "sram_1rw1r_32_256_8_sky130.v"
+`include "storage.v"
+`include "storage_bridge_wb.v"
+
+module storage_tb;
+
+    localparam [(`RAM_BLOCKS*24)-1:0] STORAGE_RW_ADR = {
+        {24'h 10_0000},
+        {24'h 00_0000}
+    };
+
+    localparam [23:0] STORAGE_RO_ADR = {
+        {24'h 20_0000}
+    };
+
+    reg wb_clk_i;
+    reg wb_rst_i;
+
+    reg [31:0] wb_adr_i;
+    reg [31:0] wb_dat_i;
+    reg [3:0]  wb_sel_i;
+    reg wb_we_i;
+    reg wb_cyc_i;
+    reg  [1:0] wb_stb_i;
+    wire [1:0] wb_ack_o;
+    wire [31:0] wb_rw_dat_o;
+
+    // MGMT_AREA RO WB Interface  
+    wire [31:0] wb_ro_dat_o;
+
+    wire [`RAM_BLOCKS-1:0] mgmt_ena;
+    wire [(`RAM_BLOCKS*4)-1:0] mgmt_wen_mask;
+    wire [`RAM_BLOCKS-1:0] mgmt_wen;
+    wire [31:0] mgmt_wdata;
+    wire [7:0] mgmt_addr;
+    wire [(`RAM_BLOCKS*32)-1:0] mgmt_rdata;
+    wire ro_ena;
+    wire [7:0] ro_addr;
+    wire [31:0] ro_rdata;
+
+    initial begin
+        wb_clk_i = 0;
+        wb_rst_i = 0;
+        wb_stb_i = 0; 
+        wb_cyc_i = 0;  
+        wb_sel_i = 0;  
+        wb_we_i  = 0;  
+        wb_dat_i = 0; 
+        wb_adr_i = 0; 
+    end
+
+    always #1 wb_clk_i = ~wb_clk_i;
+
+    initial begin
+        $dumpfile("storage.vcd");
+        $dumpvars(0, storage_tb);
+        repeat (100) begin
+            repeat (1000) @(posedge wb_clk_i);
+        end
+        $display("%c[1;31m",27);
+        $display ("Monitor: Timeout, Test Storage Area Failed");
+        $display("%c[0m",27);
+        $finish;
+    end
+
+    reg [31:0] ref_data [255: 0];
+    reg [(24*`RAM_BLOCKS)-1:0] storage_rw_adr = STORAGE_RW_ADR;
+    reg [23:0] storage_ro_adr = STORAGE_RO_ADR;
+    reg [31:0] block_adr;
+
+    integer i,j;
+
+    initial begin
+        // Reset Operation
+        wb_rst_i = 1;
+        #2;
+        wb_rst_i = 0;
+        #2;
+
+        // Test MGMT R/W port and user RO port
+        for (i = 0; i<`RAM_BLOCKS; i = i +1) begin
+            for ( j = 0; j < 100; j = j + 1) begin 
+                if (i == 0) begin
+                    ref_data[j] = $urandom_range(0, 2**30);
+                end
+                block_adr = (storage_rw_adr[24*i+:24] + (j << 2))  | `STORAGE_BASE_ADR;
+                write(block_adr, ref_data[j]);
+                #2;
+            end
+        end
+        
+        for (i = 0; i<`RAM_BLOCKS; i = i +1) begin
+            for ( j = 0; j < 100; j = j + 1) begin 
+                block_adr = (storage_rw_adr[24*i+:24] + (j << 2))  | `STORAGE_BASE_ADR;
+                read(block_adr, 0);
+                if (wb_rw_dat_o !== ref_data[j]) begin
+                    $display("Got %0h, Expected %0h from addr %0h: ",wb_rw_dat_o,ref_data[j], block_adr);
+                    $display("Monitor: MGMT R/W Operation Failed");
+                    $finish;
+                end
+                
+                if (i == 0) begin
+                    block_adr = (storage_ro_adr + (j << 2))  | `STORAGE_BASE_ADR;
+                    read(block_adr, 1);
+                    if (wb_ro_dat_o !== ref_data[j]) begin
+                        $display("Monitor: MGMT RO Operation Failed");
+                        $finish;
+                    end
+                end
+                #2;
+            end
+        end
+
+        $display("Success");
+        $finish;
+    end
+    
+    task write;
+        input [32:0] addr;
+        input [32:0] data;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i[0] = 1;
+                wb_cyc_i = 1;
+                wb_sel_i = 4'hF; 
+                wb_we_i = 1;     
+                wb_adr_i = addr;
+                wb_dat_i = data;
+                $display("Write Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o[0] == 1);
+            wait(wb_ack_o[0] == 0);
+            wb_cyc_i = 0;
+            wb_stb_i[0] = 0;
+            $display("Write Cycle Ended.");
+        end
+    endtask
+    
+    task read;
+        input [32:0] addr;
+        input integer interface;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i[interface] = 1;
+                wb_cyc_i = 1;
+                wb_we_i = 0;
+                wb_adr_i = addr;
+                $display("Read Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o[interface] == 1);
+            wait(wb_ack_o[interface] == 0);
+            wb_cyc_i = 0;
+            wb_stb_i[interface] = 0;
+            $display("Read Cycle Ended.");
+        end
+    endtask
+
+    storage_bridge_wb #(
+        .RW_BLOCKS_ADR(STORAGE_RW_ADR),
+        .RO_BLOCKS_ADR(STORAGE_RO_ADR)
+    ) wb_bridge (
+        .wb_clk_i(wb_clk_i),
+        .wb_rst_i(wb_rst_i),
+
+        .wb_adr_i(wb_adr_i),
+        .wb_dat_i(wb_dat_i),
+        .wb_sel_i(wb_sel_i),
+        .wb_we_i(wb_we_i),
+        .wb_cyc_i(wb_cyc_i),
+        .wb_stb_i(wb_stb_i),
+        .wb_ack_o(wb_ack_o),
+        .wb_rw_dat_o(wb_rw_dat_o),
+
+    // MGMT_AREA RO WB Interface  
+        .wb_ro_dat_o(wb_ro_dat_o),
+
+    // MGMT Area native memory interface
+        .mgmt_ena(mgmt_ena), 
+        .mgmt_wen_mask(mgmt_wen_mask),
+        .mgmt_wen(mgmt_wen),
+        .mgmt_addr(mgmt_addr),
+        .mgmt_wdata(mgmt_wdata),
+        .mgmt_rdata(mgmt_rdata),
+    // MGMT_AREA RO Interface
+        .mgmt_ena_ro(ro_ena),
+        .mgmt_addr_ro(ro_addr),
+        .mgmt_rdata_ro(ro_rdata)
+    );
+
+    storage uut (
+        // Management R/W WB interface
+        .mgmt_clk(wb_clk_i),
+        .mgmt_ena(mgmt_ena),
+        .mgmt_wen(mgmt_wen),
+        .mgmt_wen_mask(mgmt_wen_mask),
+        .mgmt_addr(mgmt_addr),
+        .mgmt_wdata(mgmt_wdata),
+        .mgmt_rdata(mgmt_rdata),
+        // Management RO interface  
+        .mgmt_ena_ro(ro_ena),
+        .mgmt_addr_ro(ro_addr),
+        .mgmt_rdata_ro(ro_rdata)
+    );
+
+endmodule
\ No newline at end of file
diff --git a/verilog/dv/wb_utests/wb_utests/sysctrl_wb/Makefile b/verilog/dv/wb_utests/wb_utests/sysctrl_wb/Makefile
new file mode 100644
index 0000000..89aa77b
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/sysctrl_wb/Makefile
@@ -0,0 +1,34 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+.SUFFIXES:
+
+PATTERN = sysctrl_wb
+
+all:  ${PATTERN:=.vcd}
+
+%.vvp: %_tb.v
+	iverilog  -I ../../../rtl \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+clean:
+	rm -f *.vvp *.vcd *.log
+
+.PHONY: clean all
+
diff --git a/verilog/dv/wb_utests/wb_utests/sysctrl_wb/sysctrl_wb_tb.v b/verilog/dv/wb_utests/wb_utests/sysctrl_wb/sysctrl_wb_tb.v
new file mode 100644
index 0000000..cf80e03
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/sysctrl_wb/sysctrl_wb_tb.v
@@ -0,0 +1,185 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+`timescale 1 ns / 1 ps
+
+`include "sysctrl.v"
+
+module sysctrl_wb_tb;
+
+    reg wb_clk_i;
+	reg wb_rst_i;
+
+    reg wb_stb_i;
+    reg wb_cyc_i;
+	reg wb_we_i;
+	reg [3:0] wb_sel_i;
+	reg [31:0] wb_dat_i;
+	reg [31:0] wb_adr_i;
+
+	wire wb_ack_o;
+	wire [31:0] wb_dat_o;
+    
+    initial begin
+        wb_clk_i = 0; 
+        wb_rst_i = 0;
+        wb_stb_i = 0; 
+        wb_cyc_i = 0;  
+        wb_sel_i = 0;  
+        wb_we_i  = 0;  
+        wb_dat_i = 0; 
+        wb_adr_i = 0; 
+    end
+
+    always #1 wb_clk_i = ~wb_clk_i;
+    
+    initial begin
+        $dumpfile("sysctrl_wb_tb.vcd");
+        $dumpvars(0, sysctrl_wb_tb);
+        repeat (50) begin
+            repeat (1000) @(posedge wb_clk_i);
+        end
+        $display("%c[1;31m",27);
+        $display ("Monitor: Timeout, Test System Control Failed");
+        $display("%c[0m",27);
+        $finish;
+    end
+
+    integer i;
+    
+    // System Control Default Register Addresses 
+    wire [31:0] clk1_out_adr   = uut.BASE_ADR | uut.CLK1_OUT;  
+    wire [31:0] clk2_out_adr   = uut.BASE_ADR | uut.CLK2_OUT;  
+    wire [31:0] trap_out_adr  = uut.BASE_ADR | uut.TRAP_OUT;
+    wire [31:0] irq7_src_adr  = uut.BASE_ADR | uut.IRQ7_SRC;
+    wire [31:0] irq8_src_adr  = uut.BASE_ADR | uut.IRQ8_SRC;
+
+    reg clk1_output_dest;
+    reg clk2_output_dest;
+    reg trap_output_dest;
+    reg irq_7_inputsrc;
+    reg irq_8_inputsrc;
+   
+    initial begin
+        // Reset Operation
+        wb_rst_i = 1;
+        #2;
+        wb_rst_i = 0;
+        #2;
+        
+        clk1_output_dest   = 1'b1;
+        clk2_output_dest   = 1'b1;
+        trap_output_dest  = 1'b1;
+        irq_7_inputsrc    = 1'b1;
+        irq_8_inputsrc    = 1'b1;
+
+        // Write to System Control Registers
+        write(clk1_out_adr, clk1_output_dest);
+        write(clk2_out_adr, clk2_output_dest);
+        write(trap_out_adr, trap_output_dest);
+        write(irq7_src_adr, irq_7_inputsrc);
+        write(irq8_src_adr, irq_8_inputsrc);
+        #2;
+        read(clk1_out_adr);
+        if (wb_dat_o !== clk1_output_dest) begin
+            $display("Error reading CLK1 output destination register.");
+            $finish;
+        end
+
+        read(clk2_out_adr);
+        if (wb_dat_o !== clk2_output_dest) begin
+            $display("Error reading CLK2 output destination register.");
+            $finish;
+        end
+
+        read(trap_out_adr);
+        if (wb_dat_o !== trap_output_dest) begin
+            $display("Error reading trap output destination register.");
+            $finish;
+        end
+
+        read(irq7_src_adr);
+        if (wb_dat_o !== irq_7_inputsrc) begin
+            $display("Error reading IRQ7 input source register.");
+            $finish;
+        end
+
+        read(irq8_src_adr);
+        if (wb_dat_o !== irq_8_inputsrc) begin
+            $display("Error reading IRQ8 input source register.");
+            $finish;
+        end
+
+        $display("Success!");
+        $finish;
+    end
+    
+    task write;
+        input [32:0] addr;
+        input [32:0] data;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_sel_i = 4'hF; 
+                wb_we_i = 1;     
+                wb_adr_i = addr;
+                wb_dat_i = data;
+                $display("Monitor: Write Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Monitor: Write Cycle Ended.");
+        end
+    endtask
+    
+    task read;
+        input [32:0] addr;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_we_i = 0;
+                wb_adr_i = addr;
+                $display("Monitor: Read Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Monitor: Read Cycle Ended.");
+        end
+    endtask
+
+    sysctrl_wb uut(
+        .wb_clk_i(wb_clk_i),
+	    .wb_rst_i(wb_rst_i),
+        .wb_stb_i(wb_stb_i),
+	    .wb_cyc_i(wb_cyc_i),
+	    .wb_sel_i(wb_sel_i),
+	    .wb_we_i(wb_we_i),
+	    .wb_dat_i(wb_dat_i),
+	    .wb_adr_i(wb_adr_i), 
+        .wb_ack_o(wb_ack_o),
+	    .wb_dat_o(wb_dat_o)
+    );
+    
+endmodule
diff --git a/verilog/dv/wb_utests/wb_utests/uart_wb/Makefile b/verilog/dv/wb_utests/wb_utests/uart_wb/Makefile
new file mode 100644
index 0000000..d1c587f
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/uart_wb/Makefile
@@ -0,0 +1,33 @@
+# SPDX-FileCopyrightText: 2020 Efabless Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+.SUFFIXES:
+
+PATTERN = uart_wb
+
+all:  ${PATTERN:=.vcd}
+
+%.vvp: %_tb.v
+	iverilog -I .. -I ../../ -I ../../../rtl \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+clean:
+	rm -f *.vvp *.vcd *.log
+
+.PHONY: clean all
diff --git a/verilog/dv/wb_utests/wb_utests/uart_wb/uart_wb_tb.v b/verilog/dv/wb_utests/wb_utests/uart_wb/uart_wb_tb.v
new file mode 100644
index 0000000..0bbefdf
--- /dev/null
+++ b/verilog/dv/wb_utests/wb_utests/uart_wb/uart_wb_tb.v
@@ -0,0 +1,168 @@
+// SPDX-FileCopyrightText: 2020 Efabless Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+
+`default_nettype none
+
+
+`timescale 1 ns / 1 ps
+
+`include "simpleuart.v"
+
+module uart_wb_tb;
+    
+    reg wb_clk_i;
+	reg wb_rst_i;
+
+    reg wb_stb_i;
+	reg wb_cyc_i;
+	reg wb_we_i;
+	reg [3:0] wb_sel_i;
+	reg [31:0] wb_adr_i;
+	reg [31:0] wb_dat_i;
+
+	wire wb_ack_o;
+	wire [31:0] wb_dat_o;
+
+    wire tbuart_rx;
+	wire ser_rx;
+  
+    initial begin
+        wb_clk_i = 0; 
+        wb_rst_i = 0;
+        wb_stb_i = 0; 
+        wb_we_i  = 0;  
+        wb_cyc_i = 0;  
+        wb_adr_i = 0; 
+        wb_dat_i = 0; 
+        wb_sel_i = 0;  
+    end
+
+    always #1 wb_clk_i = ~wb_clk_i;
+
+    initial begin
+        $dumpfile("uart_wb_tb.vcd");
+        $dumpvars(0, uart_wb_tb);
+        repeat (500) begin
+            repeat (10000) @(posedge wb_clk_i);
+        end
+        $display("%c[1;31m",27);
+        $display("Monitor: Timeout, Test UART Failed");
+        $display("%c[0m",27);
+        $finish;
+    end
+
+    integer i;
+
+    wire [31:0] div_reg_addr = uut.BASE_ADR | uut.CLK_DIV;
+    wire [31:0] div_reg_data = 32'h FFFF_FFFF;
+    
+    wire [31:0] dat_reg_addr = uut.BASE_ADR | uut.DATA;
+    wire [31:0] dat_reg_data = 32'h FFFF_FFFF;
+
+    initial begin
+        // Reset Operation
+        wb_rst_i = 1;
+        #2;
+        wb_rst_i = 0; 
+        #2;
+
+        // Write to div register
+        write(div_reg_addr, div_reg_data);
+        #2;
+        read(div_reg_addr);
+        if (wb_dat_o !== div_reg_data) begin
+            $display("%c[1;31m",27);
+            $display("Expected %0b, but Got %0b ", div_reg_data, wb_dat_o);
+            $display("Monitor: Wishbone UART Failed");
+            $display("%c[0m",27);
+            $finish;
+        end
+        #6;
+
+        // Write Operation: writes to data register
+        write(dat_reg_addr, dat_reg_data);
+        #2;
+        read(dat_reg_addr);
+        if (wb_dat_o !== dat_reg_data) begin
+            $display("%c[1;31m",27);
+            $display("Expected %0b, but Got %0b ", dat_reg_data, wb_dat_o);
+            $display("Monitor: Wishbone UART Failed");
+            $display("%c[0m",27);
+            $finish;
+        end
+        $display("Success!");
+        $finish;
+    end
+    
+    task write;
+        input [32:0] addr;
+        input [32:0] data;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_sel_i = 4'hF; 
+                wb_we_i = 1;     
+                wb_adr_i = addr;
+                wb_dat_i = data;
+                $display("Write Cycle Started.");
+            end
+            #2;
+            wb_we_i = 0;     
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            #2;
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Write Cycle Ended.");
+        end
+    endtask
+    
+    task read;
+        input [32:0] addr;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i = 1;
+                wb_cyc_i = 1;
+                wb_we_i = 0;
+                wb_adr_i = addr;
+                $display("Read Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o == 1);
+            #2;
+            // wait(wb_ack_o == 0);
+            wb_cyc_i = 0;
+            wb_stb_i = 0;
+            $display("Read Cycle Ended.");
+        end
+    endtask
+    
+    simpleuart_wb uut (
+		.wb_clk_i(wb_clk_i),
+		.wb_rst_i(wb_rst_i),
+    	.wb_stb_i(wb_stb_i),
+    	.wb_cyc_i(wb_cyc_i),
+    	.wb_sel_i(wb_sel_i),
+    	.wb_we_i(wb_we_i),
+        .wb_adr_i(wb_adr_i),      
+	    .wb_dat_i(wb_dat_i),
+	    .wb_ack_o(wb_ack_o),
+	    .wb_dat_o(wb_dat_o),
+        .ser_tx(tbuart_rx),
+		.ser_rx(ser_rx)
+	);
+
+endmodule