working tb, very slow but ok for 20 designs
diff --git a/configure.py b/configure.py
index e0b2308..41c0f61 100755
--- a/configure.py
+++ b/configure.py
@@ -44,6 +44,12 @@
         except IndexError:
             return "scan_wrapper_{}_{}".format(self.wokwi_ids[self.default_project], id)
 
+    def get_wokwi_id(self, id):
+        try:
+            return self.wokwi_ids[id]
+        except IndexError:
+            return self.wokwi_ids[self.default_project]
+
     def get_macro_gds_name(self, id):
         try:
             return "scan_wrapper_{}.gds".format(self.wokwi_ids[id])
@@ -301,6 +307,7 @@
             fh.write(assigns.format(NUM_PROJECTS))
             fh.write(scan_controller_template)
             for i in range(NUM_PROJECTS):
+                logging.debug("instance {} {}".format(i, self.projects.get_macro_name(i)))
                 # instantiate template
                 instance = lesson_template.format(instance=self.projects.get_macro_instance(i), name=self.projects.get_macro_name(i), id=i, next_id=i + 1)
                 fh.write(instance)
diff --git a/verilog/dv/scan_controller/scan_wrapper.py b/verilog/dv/scan_controller/scan_wrapper.py
deleted file mode 100644
index 8e9ecce..0000000
--- a/verilog/dv/scan_controller/scan_wrapper.py
+++ /dev/null
@@ -1,68 +0,0 @@
-import cocotb
-from cocotb.clock import Clock
-from cocotb.triggers import RisingEdge, FallingEdge, ClockCycles, Timer
-clock_period_ns = 10
-
-def convert_to_int(data):
-    num = 0
-    for i in range(8):
-        if data[7-i]:
-            num += (1 << i)
-    return num
-
-async def scan_clock(dut, cycles=1):
-    for i in range(cycles):
-        dut.clk_in.value = 1
-        await Timer(clock_period_ns, units='ns')
-        dut.clk_in.value = 0
-        await Timer(clock_period_ns, units='ns')
-
-async def preload(dut):
-    # prepare for loading the scan chain
-    dut.scan_select_in.value = 0
-    dut.latch_enable_in.value = 0
-    #dut.data_in.value = 0
-    await scan_clock(dut, 1) 
-
-async def latch(dut):
-    # latch the data from the chain into the module
-    dut.latch_enable_in.value = 1
-    await Timer(clock_period_ns, units='ns')
-    dut.latch_enable_in.value = 0
-
-async def capture_data(dut):
-    # capture the module's output into the scan chain
-    data = []
-    dut.scan_select_in.value = 1
-    await scan_clock(dut, 1) 
-
-    # dump the data out of the chain
-    dut.scan_select_in.value = 0
-    for i in range(8):
-        await scan_clock(dut, 1) 
-        data.append(dut.data_out.value)
-    return data
-
-async def reset(dut):
-    data = [0, 0, 0, 0, 0, 0, 1, 0]
-    await load_data(dut, data)
-    data = [0, 0, 0, 0, 0, 0, 1, 1]
-    await load_data(dut, data)
-    data = [0, 0, 0, 0, 0, 0, 0, 0]
-    await load_data(dut, data)
-
-async def single_cycle(dut):
-    data = [0, 0, 0, 0, 0, 0, 0, 1]
-    await load_data(dut, data)
-    data = [0, 0, 0, 0, 0, 0, 0, 0]
-    await load_data(dut, data)
-
-async def load_data(dut, data):
-    await preload(dut)
-    for i in range(8):
-        dut.data_in.value = data[i]
-        await scan_clock(dut, 1) 
-    # TODO why have to wait an extra cycle here?
-    await scan_clock(dut, 1) 
-    await latch(dut)
-
diff --git a/verilog/dv/scan_controller/test_scan_controller.gtkw b/verilog/dv/scan_controller/test_scan_controller.gtkw
index 425db70..13e729c 100644
--- a/verilog/dv/scan_controller/test_scan_controller.gtkw
+++ b/verilog/dv/scan_controller/test_scan_controller.gtkw
@@ -1,9 +1,9 @@
 [*]
 [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI
-[*] Fri Aug 26 14:01:08 2022
+[*] Fri Aug 26 16:35:14 2022
 [*]
 [dumpfile] "/home/matt/work/asic-workshop/shuttle7/tinytapeout-mpw7/verilog/dv/scan_controller/test_scan_controller.vcd"
-[dumpfile_mtime] "Fri Aug 26 13:59:55 2022"
+[dumpfile_mtime] "Fri Aug 26 16:31:15 2022"
 [dumpfile_size] 9424599
 [savefile] "/home/matt/work/asic-workshop/shuttle7/tinytapeout-mpw7/verilog/dv/scan_controller/test_scan_controller.gtkw"
 [timestart] 0
@@ -13,8 +13,6 @@
 [treeopen] test_scan_controller_tb.
 [treeopen] test_scan_controller_tb.user_project_wrapper.
 [treeopen] test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.
-[treeopen] test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.
-[treeopen] test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.user_module.
 [sst_width] 507
 [signals_width] 265
 [sst_expanded] 1
@@ -24,9 +22,9 @@
 test_scan_controller_tb.reset
 @24
 test_scan_controller_tb.user_project_wrapper.active_select[8:0]
-@c00022
+@800023
 test_scan_controller_tb.user_project_wrapper.inputs[7:0]
-@28
+@29
 (0)test_scan_controller_tb.user_project_wrapper.inputs[7:0]
 (1)test_scan_controller_tb.user_project_wrapper.inputs[7:0]
 (2)test_scan_controller_tb.user_project_wrapper.inputs[7:0]
@@ -35,7 +33,7 @@
 (5)test_scan_controller_tb.user_project_wrapper.inputs[7:0]
 (6)test_scan_controller_tb.user_project_wrapper.inputs[7:0]
 (7)test_scan_controller_tb.user_project_wrapper.inputs[7:0]
-@1401200
+@1001201
 -group_end
 @800022
 test_scan_controller_tb.user_project_wrapper.outputs[7:0]
@@ -81,29 +79,5 @@
 -group_end
 @1401200
 -module 0
-@800200
--module 12
-@28
-test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.data_out
-@c00022
-test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.user_module.io_in[7:0]
-@28
-(0)test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.user_module.io_in[7:0]
-(1)test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.user_module.io_in[7:0]
-(2)test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.user_module.io_in[7:0]
-(3)test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.user_module.io_in[7:0]
-(4)test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.user_module.io_in[7:0]
-(5)test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.user_module.io_in[7:0]
-(6)test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.user_module.io_in[7:0]
-(7)test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.user_module.io_in[7:0]
-@1401200
--group_end
-@22
-test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.user_module.io_out[7:0]
-@28
-test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.scan_select_in
-test_scan_controller_tb.user_project_wrapper.scan_wrapper_340805072482992722_12.latch_enable_in
-@1000200
--module 12
 [pattern_trace] 1
 [pattern_trace] 0
diff --git a/verilog/dv/scan_controller/test_scan_controller.py b/verilog/dv/scan_controller/test_scan_controller.py
index 311a276..a53f624 100644
--- a/verilog/dv/scan_controller/test_scan_controller.py
+++ b/verilog/dv/scan_controller/test_scan_controller.py
@@ -1,11 +1,12 @@
 import cocotb
 from cocotb.clock import Clock
 from cocotb.triggers import RisingEdge, FallingEdge, ClockCycles
-from scan_wrapper import *
+#from scan_wrapper import *
 
 # utility functions. using 2nd bit as reset and 1st bit as clock for synchronous design examples
 async def reset(dut):
     for i in range(2):
+        print("reset cycle {}".format(i))
         await RisingEdge(dut.ready);
         dut.inputs.value = 0b10
         await RisingEdge(dut.ready);
diff --git a/verilog/rtl/scan_cells.v b/verilog/rtl/scan_cells.v
new file mode 100644
index 0000000..227a452
--- /dev/null
+++ b/verilog/rtl/scan_cells.v
@@ -0,0 +1,115 @@
+`define default_netname none
+
+module buffer_cell (
+    input wire in,
+    output wire out
+    );
+    assign out = in;
+endmodule
+
+module and_cell (
+    input wire a,
+    input wire b,
+    output wire out
+    );
+
+    assign out = a & b;
+endmodule
+
+module or_cell (
+    input wire a,
+    input wire b,
+    output wire out
+    );
+
+    assign out = a | b;
+endmodule
+
+module xor_cell (
+    input wire a,
+    input wire b,
+    output wire out
+    );
+
+    assign out = a ^ b;
+endmodule
+
+module nand_cell (
+    input wire a,
+    input wire b,
+    output wire out
+    );
+
+    assign out = !(a&b);
+endmodule
+
+module not_cell (
+    input wire in,
+    output wire out
+    );
+
+    assign out = !in;
+endmodule
+
+module mux_cell (
+    input wire a,
+    input wire b,
+    input wire sel,
+    output wire out
+    );
+
+    assign out = sel ? b : a;
+endmodule
+
+module dff_cell (
+    input wire clk,
+    input wire d,
+    output reg q,
+    output wire notq
+    );
+
+    assign notq = !q;
+    always @(posedge clk)
+        q <= d;
+
+endmodule
+
+module dffsr_cell (
+    input wire clk,
+    input wire d,
+    input wire s,
+    input wire r,
+    output reg q,
+    output wire notq
+    );
+
+    assign notq = !q;
+
+    always @(posedge clk or posedge s or posedge r) begin
+        if (r)
+            q <= '0;
+        else if (s)
+            q <= '1;
+        else
+            q <= d;
+    end
+endmodule
+
+// for scan wrapper
+module latch (GATE, D, Q);
+   input  GATE, D;
+   output Q;
+   reg    Q;
+   always @ (GATE or D)
+      if (GATE)
+         Q <= D;
+endmodule
+
+module scan_flop(CLK, D, SCD, SCE, Q);
+    input CLK, D, SCD, SCE;
+    output Q;
+    reg Q;
+
+    always @(posedge CLK)
+        Q <= SCE ? SCD : D;
+endmodule