lint
diff --git a/configure.py b/configure.py
index cc0ce65..28479fb 100755
--- a/configure.py
+++ b/configure.py
@@ -6,7 +6,6 @@
 from signal import signal, SIGPIPE, SIG_DFL
 signal(SIGPIPE, SIG_DFL)
 
-filler_project_url = 'https://github.com/mattvenn/wokwi_filler'
 tmp_dir = '/tmp/tt'
 DEFAULT_NUM_PROJECTS = 498
 
@@ -15,8 +14,9 @@
 
     projects_db = "projects.pkl"
 
-    def __init__(self, update_cache=False, update_single=None):
+    def __init__(self, update_cache=False, update_single=None, test=False):
         self.default_project = 0
+        self.test = test
         if update_cache:
             self.update_cache(update_single)
         else:
@@ -92,12 +92,22 @@
     def get_wokwi_ids(self):
         return self.wokwi_ids
 
+    def get_giturl(self, id):
+        try:
+            return self.get_project_urls()[id]
+        except IndexError:
+            return self.get_project_urls()[self.default_project]
+
     @classmethod
     def build_wokwi_url(Project, wokwi_id):
         return "https://wokwi.com/projects/{}".format(wokwi_id)
 
     def get_project_urls(self):
-        from project_urls import project_urls
+        if self.test:
+            from project_urls_test import project_urls, filler_project_url
+        else:
+            from project_urls import project_urls, filler_project_url
+
         return [filler_project_url] + project_urls
 
     # the latest artifact isn't necessarily the one related to the latest commit, as github
@@ -149,7 +159,7 @@
             exit(1)
         else:
             # only get artifacts called GDS
-            artifacts = [ a for a in data['artifacts'] if a['name'] == 'GDS']
+            artifacts = [a for a in data['artifacts'] if a['name'] == 'GDS']
             logging.debug("found {} artifacts".format(len(artifacts)))
 
         download_url = Projects.get_most_recent_action_url(commits, artifacts)
@@ -294,13 +304,14 @@
             .slow_clk               (io_out[10]),
             .set_clk_div            (io_in[11]),
 
-            .scan_clk               (clk[0]),
+            .scan_clk_out           (clk[0]),
+            .scan_clk_in            (clk[NUM_MACROS]),
             .scan_data_out          (data[0]),
             .scan_data_in           (data[NUM_MACROS]),
             .scan_select            (scan[0]),
             .scan_latch_en          (latch[0]),
 
-            .la_scan_clk            (la_data_in[0]),
+            .la_scan_clk_in         (la_data_in[0]),
             .la_scan_data_in        (la_data_in[1]),
             .la_scan_data_out       (la_data_out[0]),
             .la_scan_select         (la_data_in[2]),
@@ -313,6 +324,7 @@
 
         """
         lesson_template = """
+        // {giturl}
         {name} #(.NUM_IOS(8)) {instance} (
             .clk_in          (clk  [{id}]),
             .data_in         (data [{id}]),
@@ -337,7 +349,7 @@
             for i in range(self.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)
+                instance = lesson_template.format(giturl=self.projects.get_giturl(i), instance=self.projects.get_macro_instance(i), name=self.projects.get_macro_name(i), id=i, next_id=i + 1)
                 fh.write(instance)
             fh.write(post)
 
@@ -382,6 +394,7 @@
     parser.add_argument('--update-single', help='only fetch a single repo for debug')
     parser.add_argument('--update-caravel', help='configure caravel for build', action='store_const', const=True)
     parser.add_argument('--limit-num-projects', help='only configure for the first n projects', type=int, default=DEFAULT_NUM_PROJECTS)
+    parser.add_argument('--test', help='use test projects', action='store_const', const=True)
     parser.add_argument('--debug', help="debug logging", action="store_const", dest="loglevel", const=logging.DEBUG, default=logging.INFO)
 
     args = parser.parse_args()
@@ -402,7 +415,7 @@
     ch.setFormatter(log_format)
     log.addHandler(ch)
 
-    projects = Projects(update_cache=args.update_projects, update_single=args.update_single)
+    projects = Projects(update_cache=args.update_projects, test=args.test, update_single=args.update_single)
     caravel = CaravelConfig(projects, num_projects=args.limit_num_projects)
 
     if args.update_caravel:
diff --git a/openlane/scan_controller/base.sdc b/openlane/scan_controller/base.sdc
new file mode 100644
index 0000000..7324dd0
--- /dev/null
+++ b/openlane/scan_controller/base.sdc
@@ -0,0 +1,70 @@
+# SDC file, in TCL
+# declare clocks and relationships between them
+# Create main clock of the scan controller, locally named the same clock
+create_clock [get_ports $::env(CLOCK_PORT)]  -name $::env(CLOCK_PORT)  -period $::env(CLOCK_PERIOD)
+
+# Create our generated clock that drives the scan chain
+# derived from clk, present on edge 3 5 7 
+# multicycle path, only data transition on falling edge of scan clock
+create_generated_clock -edges {3 5 7} -source $::env(CLOCK_PORT) -name clk_scan_out [get_ports scan_clk_out]
+set_multicycle_path -start -hold -from [get_clocks $::env(CLOCK_PORT)] -to [get_clocks clk_scan_out] 1
+
+# Create feedback clock - scan_clk_in. we don't know what it will arrive, but we know the period 
+create_clock [get_ports scan_clk_in] -name clk_scan_in -period [expr {$::env(CLOCK_PERIOD) * 2}]
+
+# CDC
+# receiving data into shift register and clocked by clk_scan_in
+# constrain to a reasonable range
+set_min_delay 0.25                              -from [get_clocks clk_scan_in] -to [get_clocks $::env(CLOCK_PORT)]
+set_max_delay [expr {$::env(CLOCK_PERIOD) / 2}] -from [get_clocks clk_scan_in] -to [get_clocks $::env(CLOCK_PORT)]
+
+# IO delays
+# Scan chain input  0.5 ns setup time, 0.5 ns hold time
+set_input_delay  -min  0.5 -clock [get_clocks clk_scan_in]  [get_ports {scan_data_in}]
+set_input_delay  -max  0.5 -clock [get_clocks clk_scan_in]  [get_ports {scan_data_in}]
+
+# Scan chain output 1.5 ns setup time, 1.5 ns hold time
+# scan_data_out cannot change in this window around clk_scan_out rising edge
+set_output_delay -min -1.5 -clock [get_clocks clk_scan_out] [get_ports {scan_data_out}]
+set_output_delay -max  1.5 -clock [get_clocks clk_scan_out] [get_ports {scan_data_out}]
+
+# Limit the max output delay on other outputs
+# Probably not important, but useful because then these paths will be reported
+set_output_delay -max  1.5 -clock [get_clocks $::env(CLOCK_PORT)] [get_ports {scan_select scan_latch_en}]
+
+# All the other IOs we consider asynchronous so ... no point in constraining
+# https://open-source-silicon.slack.com/archives/C02K4RD241Y/p1661983399157329?thread_ts=1661978191.926169&cid=C02K4RD241Y
+set_false_path -from [get_ports {active_select inputs set_clk_div la_* driver_sel}]
+
+
+# Misc
+# most copied from default OpenLane SDC 
+set_max_fanout $::env(SYNTH_MAX_FANOUT) [current_design]
+
+if { ![info exists ::env(SYNTH_CLK_DRIVING_CELL)] } {
+    set ::env(SYNTH_CLK_DRIVING_CELL) $::env(SYNTH_DRIVING_CELL)
+}
+
+if { ![info exists ::env(SYNTH_CLK_DRIVING_CELL_PIN)] } {
+    set ::env(SYNTH_CLK_DRIVING_CELL_PIN) $::env(SYNTH_DRIVING_CELL_PIN)
+}
+
+set_driving_cell -lib_cell $::env(SYNTH_DRIVING_CELL) -pin $::env(SYNTH_DRIVING_CELL_PIN) [get_ports {scan_data_in}]
+set_driving_cell -lib_cell $::env(SYNTH_CLK_DRIVING_CELL) -pin $::env(SYNTH_CLK_DRIVING_CELL_PIN) [get_ports "$::env(CLOCK_PORT) scan_clk_in"]
+
+set cap_load [expr $::env(SYNTH_CAP_LOAD) / 1000.0]
+puts "\[INFO\]: Setting load to: $cap_load"
+set_load  $cap_load [all_outputs]
+
+# clock jitter
+puts "\[INFO\]: Setting clock uncertainity to: $::env(SYNTH_CLOCK_UNCERTAINITY)"
+set_clock_uncertainty $::env(SYNTH_CLOCK_UNCERTAINITY) [get_clocks "$::env(CLOCK_PORT) clk_scan_in clk_scan_out"]
+
+# clock slew
+puts "\[INFO\]: Setting clock transition to: $::env(SYNTH_CLOCK_TRANSITION)"
+set_clock_transition $::env(SYNTH_CLOCK_TRANSITION) [get_clocks "$::env(CLOCK_PORT) clk_scan_in clk_scan_out"]
+
+# make everything worse by SYNTH_TIMING_DERATE
+puts "\[INFO\]: Setting timing derate to: [expr {$::env(SYNTH_TIMING_DERATE) * 100}] %"
+set_timing_derate -early [expr {1-$::env(SYNTH_TIMING_DERATE)}]
+set_timing_derate -late [expr {1+$::env(SYNTH_TIMING_DERATE)}]
diff --git a/openlane/scan_controller/config.tcl b/openlane/scan_controller/config.tcl
index b51552f..c52bd12 100644
--- a/openlane/scan_controller/config.tcl
+++ b/openlane/scan_controller/config.tcl
@@ -31,6 +31,11 @@
 set ::env(CLOCK_PERIOD) "10"
 set ::env(CLOCK_PORT) "clk"
 
+set ::env(BASE_SDC_FILE) $::env(DESIGN_DIR)/base.sdc
+
+set ::env(SYNTH_CLOCK_UNCERTAINITY) 0.20
+set ::env(SYNTH_CLOCK_TRANSITION)   0.15
+
 # macro needs to work inside Caravel, so can't be core and can't use metal 5
 set ::env(DESIGN_IS_CORE) 0
 set ::env(RT_MAX_LAYER) {met4}
diff --git a/project_urls.py b/project_urls.py
index 5853b70..b1bc202 100644
--- a/project_urls.py
+++ b/project_urls.py
@@ -1,4 +1,4 @@
-# name must be valid verilog module name set in scan_wrapper.v
+filler_project_url = 'https://github.com/mattvenn/wokwi_filler'
 project_urls = [
             'https://github.com/mattvenn/wokwi-verilog-gds-test',
             'https://github.com/mattvenn/animation_tinytapeout_demo',
diff --git a/project_urls_test.py b/project_urls_test.py
new file mode 100644
index 0000000..a10723a
--- /dev/null
+++ b/project_urls_test.py
@@ -0,0 +1,5 @@
+filler_project_url = 'https://github.com/mattvenn/tinytapeout-test-straight'
+project_urls = [
+    'https://github.com/mattvenn/tinytapeout-7seg-seconds-counter',
+    'https://github.com/mattvenn/tinytapeout-test-invert',
+    ]
diff --git a/verilog/dv/scan_controller/test_scan_controller.gtkw b/verilog/dv/scan_controller/test_scan_controller.gtkw
index f4509d8..c90cbc9 100644
--- a/verilog/dv/scan_controller/test_scan_controller.gtkw
+++ b/verilog/dv/scan_controller/test_scan_controller.gtkw
@@ -1,19 +1,18 @@
 [*]
 [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI
-[*] Sat Aug 27 16:09:50 2022
+[*] Wed Aug 31 19:31:00 2022
 [*]
 [dumpfile] "/home/matt/work/asic-workshop/shuttle7/tinytapeout-mpw7/verilog/dv/scan_controller/test_scan_controller.vcd"
-[dumpfile_mtime] "Sat Aug 27 16:09:19 2022"
-[dumpfile_size] 86352838
+[dumpfile_mtime] "Wed Aug 31 19:30:43 2022"
+[dumpfile_size] 14402588
 [savefile] "/home/matt/work/asic-workshop/shuttle7/tinytapeout-mpw7/verilog/dv/scan_controller/test_scan_controller.gtkw"
 [timestart] 0
 [size] 1848 1016
 [pos] -1 -1
-*-27.000000 91200000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+*-30.000000 3209000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
 [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.
 [sst_width] 507
 [signals_width] 265
 [sst_expanded] 1
@@ -21,76 +20,19 @@
 @28
 test_scan_controller_tb.clk
 test_scan_controller_tb.reset
-@24
-test_scan_controller_tb.user_project_wrapper.active_select[8:0]
-@c00022
-test_scan_controller_tb.user_project_wrapper.inputs[7:0]
-@28
-(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]
-(3)test_scan_controller_tb.user_project_wrapper.inputs[7:0]
-(4)test_scan_controller_tb.user_project_wrapper.inputs[7:0]
-(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
--group_end
-@c00022
-test_scan_controller_tb.user_project_wrapper.outputs[7:0]
-@28
-(0)test_scan_controller_tb.user_project_wrapper.outputs[7:0]
-(1)test_scan_controller_tb.user_project_wrapper.outputs[7:0]
-(2)test_scan_controller_tb.user_project_wrapper.outputs[7:0]
-(3)test_scan_controller_tb.user_project_wrapper.outputs[7:0]
-(4)test_scan_controller_tb.user_project_wrapper.outputs[7:0]
-(5)test_scan_controller_tb.user_project_wrapper.outputs[7:0]
-(6)test_scan_controller_tb.user_project_wrapper.outputs[7:0]
-(7)test_scan_controller_tb.user_project_wrapper.outputs[7:0]
-@1401200
--group_end
-@28
-test_scan_controller_tb.user_project_wrapper.ready
-@800200
--scan controller
-@28
-test_scan_controller_tb.user_project_wrapper.scan_controller.scan_clk
-test_scan_controller_tb.user_project_wrapper.scan_controller.state[2:0]
-@22
-test_scan_controller_tb.user_project_wrapper.scan_controller.current_design[8:0]
-@1000200
--scan controller
-@c00200
--module 0
-@28
-test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.data_in
-test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.data_out
-@800022
-test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.scan_data_in[7:0]
-@28
-(0)test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.scan_data_in[7:0]
-(1)test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.scan_data_in[7:0]
-(2)test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.scan_data_in[7:0]
-(3)test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.scan_data_in[7:0]
-(4)test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.scan_data_in[7:0]
-(5)test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.scan_data_in[7:0]
-(6)test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.scan_data_in[7:0]
-(7)test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.scan_data_in[7:0]
-test_scan_controller_tb.user_project_wrapper.scan_wrapper_339501025136214612_0.scan_select_in
-@1001200
--group_end
-@1401200
--module 0
-@800200
--scan chain
-@28
-test_scan_controller_tb.user_project_wrapper.scan_controller.clk
-test_scan_controller_tb.user_project_wrapper.scan_controller.scan_clk
+test_scan_controller_tb.user_project_wrapper.scan_controller.scan_clk_in
+test_scan_controller_tb.user_project_wrapper.scan_controller.scan_clk_out
 test_scan_controller_tb.user_project_wrapper.scan_controller.scan_data_in
 test_scan_controller_tb.user_project_wrapper.scan_controller.scan_data_out
-test_scan_controller_tb.user_project_wrapper.scan_controller.scan_latch_enable
+test_scan_controller_tb.user_project_wrapper.scan_controller.scan_latch_en
 test_scan_controller_tb.user_project_wrapper.scan_controller.scan_select
-@1000200
--scan chain
+@22
+test_scan_controller_tb.user_project_wrapper.scan_controller.inputs[7:0]
+test_scan_controller_tb.user_project_wrapper.scan_controller.outputs[7:0]
+test_scan_controller_tb.user_project_wrapper.scan_controller.active_select[8:0]
+@28
+test_scan_controller_tb.user_project_wrapper.scan_controller.ready
+@29
+test_scan_controller_tb.user_project_wrapper.scan_controller.proj_done
 [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 ba1da90..3cfe4da 100644
--- a/verilog/dv/scan_controller/test_scan_controller.py
+++ b/verilog/dv/scan_controller/test_scan_controller.py
@@ -39,14 +39,13 @@
 
     dut.reset.value = 1
     dut.set_clk_div.value = 0
-    dut.driver_sel.value = 0b01   # internal controller
-    dut.active_select.value = 12 # 7 seg seconds
+    dut.driver_sel.value = 0b10   # internal controller
+    dut.active_select.value = 1 # 7 seg seconds
     await ClockCycles(dut.clk, 10)
     dut.reset.value = 0
     dut.inputs.value = 0
     dut.set_clk_div.value = 1   # lock in the new clock divider value
     await ClockCycles(dut.clk, 1)
-#    dut.set_clk_div.value = 0
     dut.inputs.value = 0
 
     # reset: set bit 1 high, wait for one cycle of slow_clk, then set bit 1 low
@@ -60,7 +59,40 @@
     await FallingEdge(dut.slow_clk)
     for i in range(2):
         print("clock {:2} 7seg {}".format(i, decode_seg(dut.seven_seg.value)))
-        #assert decode_seg(dut.seven_seg.value) == i
-        #await single_cycle(dut)
+        assert decode_seg(dut.seven_seg.value) == i
         await FallingEdge(dut.slow_clk)
 
+    print("straight test")
+    dut.set_clk_div.value = 0   # no clock div
+    dut.active_select.value = 0 # straight
+    await FallingEdge(dut.ready)
+    for i in range(11):
+        dut.inputs.value = i
+        await FallingEdge(dut.ready)
+        print(i, int(dut.outputs))
+        if i > 0:
+            assert i == int(dut.outputs) + 1
+
+    print("invert test")
+    dut.active_select.value = 2 # invert
+    dut.inputs.value = 0
+    await FallingEdge(dut.ready)
+    await FallingEdge(dut.ready)
+    for i in range(11):
+        dut.inputs.value = i
+        await FallingEdge(dut.ready)
+        print(i, int(dut.outputs))
+        if i > 0:
+            assert 256 - i == int(dut.outputs)
+
+    for design in range(10): # next 10 designs are all straight
+        print("straight test at pos {}".format(design))
+        dut.active_select.value = 3 + design 
+        await FallingEdge(dut.ready)
+        for i in range(11):
+            dut.inputs.value = i
+            await FallingEdge(dut.ready)
+            print(i, int(dut.outputs))
+            if i > 0:
+                assert i == int(dut.outputs) + 1
+    
diff --git a/verilog/dv/scan_controller_int/scan_controller_int.gtkw b/verilog/dv/scan_controller_int/scan_controller_int.gtkw
index 30bde20..2007495 100644
--- a/verilog/dv/scan_controller_int/scan_controller_int.gtkw
+++ b/verilog/dv/scan_controller_int/scan_controller_int.gtkw
@@ -1,23 +1,23 @@
 [*]
 [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI
-[*] Sun Aug 28 04:38:22 2022
+[*] Wed Aug 31 20:59:40 2022
 [*]
 [dumpfile] "/home/matt/work/asic-workshop/shuttle7/tinytapeout-mpw7/verilog/dv/scan_controller_int/scan_controller_tb.vcd"
-[dumpfile_mtime] "Sun Aug 28 04:37:55 2022"
-[dumpfile_size] 1813865
+[dumpfile_mtime] "Wed Aug 31 20:58:10 2022"
+[dumpfile_size] 830785
 [savefile] "/home/matt/work/asic-workshop/shuttle7/tinytapeout-mpw7/verilog/dv/scan_controller_int/scan_controller_int.gtkw"
 [timestart] 0
 [size] 1848 1016
 [pos] -1 -1
-*-29.000000 696514800 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+*-28.000000 744000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
 [treeopen] scan_controller_tb.
 [treeopen] scan_controller_tb.uut.
 [treeopen] scan_controller_tb.uut.mprj.
 [treeopen] scan_controller_tb.uut.mprj.scan_controller.
-[sst_width] 423
-[signals_width] 261
+[sst_width] 708
+[signals_width] 329
 [sst_expanded] 1
-[sst_vpaned_height] 254
+[sst_vpaned_height] 646
 @28
 scan_controller_tb.clk
 @22
@@ -32,10 +32,14 @@
 @28
 scan_controller_tb.set_clk_div
 scan_controller_tb.slow_clk
+scan_controller_tb.uut.mprj.scan_controller.slow_clk
+scan_controller_tb.uut.mprj.scan_controller.slow_clk_ena
+scan_controller_tb.uut.mprj.scan_controller.reset
+scan_controller_tb.uut.mprj.scan_controller.clk_divider_I.reset
+scan_controller_tb.uut.mprj.scan_controller.clk_divider_I.clk
 @800200
 -scan chain
 @28
-scan_controller_tb.uut.mprj.scan_controller.scan_clk
 scan_controller_tb.uut.mprj.scan_controller.scan_data_in
 scan_controller_tb.uut.mprj.scan_controller.scan_data_out
 scan_controller_tb.uut.mprj.scan_controller.scan_latch_en
@@ -46,13 +50,16 @@
 scan_controller_tb.uut.mprj.scan_controller.active_select[8:0]
 scan_controller_tb.uut.mprj.scan_controller.inputs[7:0]
 scan_controller_tb.uut.mprj.scan_controller.outputs[7:0]
-@28
-scan_controller_tb.uut.mprj.scan_controller.clk_divider.last_set
-@22
-scan_controller_tb.uut.mprj.scan_controller.clk_divider.compare[7:0]
-@8024
-scan_controller_tb.uut.mprj.scan_controller.clk_divider.counter[21:0]
 @20000
 -
+@28
+scan_controller_tb.uut.mprj.scan_wrapper_339501025136214612_0.data_in
+scan_controller_tb.uut.mprj.scan_controller.clk_divider_I.slow_clk
+>-4100000
+scan_controller_tb.uut.mprj.scan_controller.clk_divider_I.match
+@22
+>0
+scan_controller_tb.uut.mprj.scan_controller.clk_divider_I.compare[7:0]
+scan_controller_tb.uut.mprj.scan_controller.clk_divider_I.counter[7:0]
 [pattern_trace] 1
 [pattern_trace] 0
diff --git a/verilog/dv/scan_controller_int/test_scan_controller.py b/verilog/dv/scan_controller_int/test_scan_controller.py
index 1dcdf71..9c87630 100644
--- a/verilog/dv/scan_controller_int/test_scan_controller.py
+++ b/verilog/dv/scan_controller_int/test_scan_controller.py
@@ -7,7 +7,7 @@
     clock = Clock(dut.clk, 25, units="ns") # 40M
     cocotb.fork(clock.start())
    
-    dut.driver_sel.value = 0b01 # internal
+    dut.driver_sel.value = 0b10 # internal
     dut.set_clk_div.value = 0
     dut.inputs.value = 0
     dut.active_sel.value = 0
@@ -43,13 +43,18 @@
     assert dut.outputs.value == 0xAA
 
     # use the clock divider
+    await ClockCycles(dut.clk, 100)
     print("checking clock divider")
+    dut.RSTB.value = 0
     await RisingEdge(dut.clk)
     dut.inputs.value = 1
     dut.set_clk_div.value = 1
+    await ClockCycles(dut.clk, 100)
+    dut.RSTB.value = 1
     await ClockCycles(dut.clk, 2)
     dut.inputs.value = 0
 
+    print("waiting for slow clock")
     # check slow clock output
     for i in range(2):
         await RisingEdge(dut.slow_clk)
diff --git a/verilog/dv/scan_controller_la/test_scan_controller.py b/verilog/dv/scan_controller_la/test_scan_controller.py
index 9d7907e..6eadd7e 100644
--- a/verilog/dv/scan_controller_la/test_scan_controller.py
+++ b/verilog/dv/scan_controller_la/test_scan_controller.py
@@ -7,7 +7,7 @@
     clock = Clock(dut.clk, 25, units="ns") # 40M
     cocotb.fork(clock.start())
    
-    dut.driver_sel.value = 0b10 # logic analyser
+    dut.driver_sel.value = 0b01 # logic analyser
     dut.RSTB.value = 0
     dut.power1.value = 0
     dut.power2.value = 0
diff --git a/verilog/rtl/scan_controller/properties.v b/verilog/rtl/scan_controller/properties.v
index c104f6a..a14d115 100644
--- a/verilog/rtl/scan_controller/properties.v
+++ b/verilog/rtl/scan_controller/properties.v
@@ -1,22 +1,24 @@
 always @(*) begin
     if(driver_sel == 2'b00) begin // external driver
-        assert(outputs[0]    == scan_data_in);
-        assert(scan_clk      == ext_scan_clk);
+        assert(outputs[0]    == scan_clk_in);
+        assert(outputs[1]    == scan_data_in);
+        assert(scan_clk_out  == inputs[0]);
         assert(scan_data_out == inputs[1]);
         assert(scan_select   == inputs[2]);
         assert(scan_latch_en == inputs[3]);
     end else
-    if(driver_sel == 2'b10) begin // external driver
+    if(driver_sel == 2'b01) begin // la
         assert(la_scan_data_out == scan_data_in);
-        assert(scan_clk      == la_scan_clk);
+        assert(scan_clk_out  == la_scan_clk_in);
         assert(scan_data_out == la_scan_data_in);
         assert(scan_select   == la_scan_select);
         assert(scan_latch_en == la_scan_latch_en);
     end else
-    if(driver_sel == 2'b01) begin // internal driver
+    if(driver_sel == 2'b10) begin // internal driver
         assert(int_scan_data_out == scan_data_out);
-        assert(scan_clk      == int_scan_clk);
+        assert(scan_clk_out  == int_scan_clk_out);
         assert(scan_data_in  == int_scan_data_in);
+        assert(scan_clk_in   == int_scan_clk_in);
         assert(scan_select   == int_scan_select);
         assert(scan_latch_en == int_scan_latch_en);
     end
diff --git a/verilog/rtl/scan_controller/scan_controller.v b/verilog/rtl/scan_controller/scan_controller.v
index 1591991..e1d75a8 100644
--- a/verilog/rtl/scan_controller/scan_controller.v
+++ b/verilog/rtl/scan_controller/scan_controller.v
@@ -1,226 +1,451 @@
+`timescale 1ns / 100ps
 `default_nettype none
 
-module scan_controller (
+module scan_controller #(
+    parameter integer NUM_DESIGNS = 8,
+    parameter integer NUM_IOS     = 8,
+
+    // auto-set
+    parameter integer PL = NUM_IOS - 1
+)(
     input  wire clk,
     input  wire reset,
 
     input  wire [8:0] active_select,    // which design is connected to the inputs and outputs
-    input  wire [7:0] inputs,           // inputs to the design (or external scan chain)
+    input  wire [PL:0] inputs,           // inputs to the design (or external scan chain)
     input  wire set_clk_div,            // set clock divider. See module below
-    output wire [7:0] outputs,          // outputs from the design (or external scan chain)
+    output wire [PL:0] outputs,          // outputs from the design (or external scan chain)
     output wire ready,                  // debug output that goes high once per refresh
     output wire slow_clk,               // debug clock divider output
 
-    output wire scan_clk,               // scan chain interface for the tiny designs, from perspective of this module
-    output wire scan_data_out,          // see diagrams below for how the scan chain works
+    output reg  scan_clk_out,           // scan chain interface for the tiny designs, from perspective of this module
+    output reg  scan_data_out,          // see diagrams below for how the scan chain works
+    input  wire scan_clk_in,            // feedback clock after having done the whole round
     input  wire scan_data_in,           // will be driven by internal driver, external gpio pins, or Caravel logic analyser
-    output wire scan_select,            // external scan chain driver muxes with ins/outs, eg microcontroller outside the ASIC
-    output wire scan_latch_en,
+    output reg  scan_select,            // external scan chain driver muxes with ins/outs, eg microcontroller outside the ASIC
+    output reg  scan_latch_en,
 
-    input  wire la_scan_clk,            // logic analyser scan chain driver, driven by firmware running on Caravel's VexRisc 
-    input  wire la_scan_data_in,        // signal names from perspective of this module
+    input  wire la_scan_clk_in,         // logic analyser scan chain driver, driven by firmware running on Caravel's VexRisc
+    input  wire la_scan_data_in,        // signal names from perspective of this module toward scan chain
     output wire la_scan_data_out,
     input  wire la_scan_select,
     input  wire la_scan_latch_en,
 
-    input  wire [1:0] driver_sel,       // 00 = external, 01 = internal, 10 = logic analyser
+    input  wire [1:0] driver_sel,       // 00 = external, 01 = logic analyzer, 1x = internal
 
     output wire [`MPRJ_IO_PADS-1:0] oeb // caravel harness needs output enable bar set low to enable outputs
-    );
+);
 
+    // Signals
+    // -------
+    assign ready = active && state == ST_IDLE;
+
+    // Reset
+    reg  [2:0]  rst_shift;
+    wire        rst_i;
+
+    // Muxing
+        // _in / _out are from the perspecitve of this module toward the scan
+        // chain. So all _in are FROM the scan chain (and either input to this
+        // module from there, or output from this module to LA / External)
+
+    wire        ext_scan_clk_in;
+    wire        ext_scan_data_in;
+    wire        ext_scan_clk_out;
+    wire        ext_scan_data_out;
+    wire        ext_scan_select;
+    wire        ext_scan_latch_en;
+
+    wire        int_scan_clk_in;
+    wire        int_scan_data_in;
+    reg         int_scan_clk_out;
+    reg         int_scan_data_out;
+    reg         int_scan_select;
+    reg         int_scan_latch_en;
+
+    // FSM
+    localparam [3:0]
+        ST_IDLE             = 0,    // Idle
+        ST_IN_LOAD          = 1,    // Capture input
+        ST_IN_SHIFT_LO      = 2,    // Shift input to design: lo-clk
+        ST_IN_SHIFT_HI      = 3,    // Shift input to design: hi-clk
+        ST_IN_LATCH_WAIT    = 4,    // Wait before latching
+        ST_IN_LATCH         = 5,    // Latch
+        ST_OUT_LOAD_PRE     = 6,    // Prepare load
+        ST_OUT_LOAD         = 7,    // Clock once to load
+        ST_OUT_LOAD_POST    = 8,    // Wait for load to be done
+        ST_OUT_LOAD_CLR     = 9,    // Restore chain to shift mode
+        ST_OUT_SHIFT_LO     = 10,   // Shift output to us: lo-clk
+        ST_OUT_SHIFT_HI     = 11,   // Shift output to us: hi-clk
+        ST_OUT_CAP_WAIT     = 12,   // Wait for capture
+        ST_OUT_CAP          = 13;   // Capture to out local register
+
+    reg       active;
+
+    reg [3:0] state;
+    reg [3:0] state_nxt;
+
+    // Scan progress
+    reg [$clog2(NUM_IOS)-1:0] bit_cnt;
+    wire                      bit_last;
+
+    reg   [8:0] proj_cnt;
+    wire        proj_sel;
+    wire        proj_done;
+
+    // Auto IO
+    reg  [PL:0] aio_input_sync;
+    reg  [PL:0] aio_input_reg;
+    reg  [PL:0] aio_input_shift;
+
+    reg  [PL:0] aio_output_shift;
+    reg  [PL:0] aio_output_reg;
+
+    wire        aio_input_sh;
+    wire        aio_input_ld;
+    wire        aio_output_cap;
+
+    // Wait state config
+    reg   [7:0] ws_cnt;
+    wire        ws_cnt_done;
+    wire        ws_cnt_run;
+
+    // Wait state config
+    reg  [2:0]  ws_set_sync;
+    reg         ws_set_now;
+    reg  [7:0]  ws_cfg;
+
+    // Clock divider
+    wire        slow_clk_ena;
+
+
+    // Misc
+    // ----
+
+    // Generate internal ties for the IO blocks
     assign oeb = {`MPRJ_IO_PADS{1'b0}};
 
-    parameter NUM_DESIGNS = 8; 
-    parameter NUM_IOS     = 8;
-
-    localparam START = 0;
-    localparam LOAD = 1;
-    localparam READ = 2;
-    localparam CAPTURE_STATE = 3;
-    localparam LATCH = 4;
-                    
-    // scan chain muxing
-    // signal names in perspective of this module
-    wire ext_scan_clk       = inputs[0];
-    wire ext_scan_data_in   = inputs[1];
-    wire ext_scan_data_out  = scan_data_in;
-    wire ext_scan_select    = inputs[2];   
-    wire ext_scan_latch_en  = inputs[3];
-
-    assign scan_clk         = driver_sel == 2'b00 ? ext_scan_clk      : driver_sel == 2'b01 ? int_scan_clk      : la_scan_clk;
-    assign scan_data_out    = driver_sel == 2'b00 ? ext_scan_data_in  : driver_sel == 2'b01 ? int_scan_data_out : la_scan_data_in;
-    assign scan_select      = driver_sel == 2'b00 ? ext_scan_select   : driver_sel == 2'b01 ? int_scan_select   : la_scan_select;
-    assign scan_latch_en    = driver_sel == 2'b00 ? ext_scan_latch_en : driver_sel == 2'b01 ? int_scan_latch_en : la_scan_latch_en;
-
-    wire int_scan_data_in   = scan_data_in;
-    assign la_scan_data_out = scan_data_in;
-    assign outputs          = driver_sel == 2'b01 ? outputs_r : {7'b0, ext_scan_data_out};
-
     `ifdef FORMAL
         `include "properties.v"
     `endif
 
-    // reg
-    reg [8:0] current_design;
-    reg [2:0] state;
-    reg [3:0] num_io;
-    reg scan_clk_r;
-    reg scan_select_out_r;
+    // Generate our own reset, with de-assertion
+    // synchronized to clock
+    always @(negedge clk or posedge reset)
+        if (reset)
+            rst_shift <= 3'b111;
+        else
+            rst_shift <= { rst_shift[1:0], 1'b0 };
 
-    reg [7:0] inputs_r;
-    reg [7:0] outputs_r;
-    reg [7:0] output_buf;
-
-    // wires
-    wire [8:0] active_select_rev = NUM_DESIGNS - 1 - active_select;
-    assign ready = state == START;
-    wire int_scan_latch_en = state == LATCH;
-    wire int_scan_clk = scan_clk_r;
-    wire int_scan_data_out = (state == LOAD && current_design == active_select_rev ) ? inputs_r[NUM_IOS-1-num_io] : 0;
-    wire int_scan_select = scan_select_out_r;
-
-    // clock divider
-    clk_divider clk_divider (
-        .clk            (clk),
-        .set            (set_clk_div),
-        .reset          (reset),
-        .divider        (inputs),
-        .slow_clk       (slow_clk)
-    );
-    wire [7:0] inputs_and_clk = set_clk_div ? { inputs[7:1], slow_clk } : inputs;
-
-    /*
-
-    LOAD
-
-             ┌──┐  ┌──┐  ┌──┐  ┌──┐              
-    clk    : ┘  └──┘  └──┘  └──┘  └──────────────
-             ┐                                   
-    scan en: └───────────────────────────────────
-             ┐                       ┌─────┐     
-    latch  : └───────────────────────┘     └─────
-             ┐     ┌─────┐     ┌─────┐           
-    data o : └─────┘     └─────┘     └───────────
-             xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-    data i : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+    assign rst_i = rst_shift[2];
 
 
-    READ
+    // Scan chain and IO muxing
+    // ------------------------
 
-             ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐  
-    clk    : ┘  └──┘  └──┘  └──┘  └──┘  └──┘  └──
-             ┐     ┌─────┐                       
-    scan en: └─────┘     └───────────────────────
-             ┐                                   
-    latch  : └───────────────────────────────────
-             xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-    data o : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-             ┐           ┌─────┐     ┌─────┐     
-    data i : └───────────┘     └─────┘     └─────
+        // To ensure we get something working, the scan chain can be driven
+        // three different ways. Automatic, from caravel LA and fully
+        // externally (see driver_sel input)
 
-    */
+    // External interface
+    assign ext_scan_clk_out   = inputs[0];
+    assign ext_scan_data_out  = inputs[1];
+    assign ext_scan_select    = inputs[2];
+    assign ext_scan_latch_en  = inputs[3];
 
-    // FSM, only run it if driver_sel is set to internal
-    always @(posedge clk) begin
-        if(reset) begin
-            current_design <= 0;
-            state <= START; 
-            inputs_r <= 0;
-            outputs_r <= 0;
-            scan_clk_r <= 0;
-            num_io <= 0;
-            output_buf <= 0;
-        end else if (driver_sel == 2'b01) begin
-            case(state)
-                START: begin
-                    state <= LOAD;
-                    inputs_r <= inputs_and_clk;
-                    outputs_r <= output_buf;
-                    current_design <= 0;
-                    scan_select_out_r <= 0;
-                end
+    assign ext_scan_clk_in    = scan_clk_in;
+    assign ext_scan_data_in   = scan_data_in;
 
-                LOAD: begin
-                    scan_clk_r <= ~scan_clk_r;
-                    if(scan_clk_r) begin
-                        num_io <= num_io + 1;
+    // Internal interface
+    assign int_scan_clk_in    = scan_clk_in;
+    assign int_scan_data_in   = scan_data_in;
 
-                        if(num_io == NUM_IOS - 1) begin
-                            num_io <= 0;
-                            current_design <= current_design + 1;
-                        
-                            if(current_design == NUM_DESIGNS - 1)
-                                state <= LATCH;
-                        end
+    // LA interface
+    assign la_scan_data_out   = scan_data_in;
 
-                    end
-
-                end
-                LATCH: begin
-                    state <= READ;
-                    current_design <= 0;
-                    scan_select_out_r <= 1;
-                end
-            
-                READ: begin
-                    scan_select_out_r <= 0;
-                    scan_clk_r <= ~scan_clk_r;
-                    if(scan_clk_r) begin
-                        num_io <= num_io + 1;
-                        if(current_design == active_select_rev)
-                            output_buf[NUM_IOS-1-num_io] <= int_scan_data_in;
-
-                        if(num_io == NUM_IOS - 1) begin
-                            num_io <= 0;
-                            current_design <= current_design + 1;
-
-
-                            if(current_design == NUM_DESIGNS - 1) begin
-                                state <= START;
-                            end
-                        end
-                    end
-                end
-            endcase
-        end
-    end
-
-endmodule
-
-module clk_divider (
-    input clk,
-    input reset,
-    input set,
-    input [DIV_WIDTH-1:0] divider,
-    output slow_clk
-    );
-    
-    // fastest useful clock period must be < max refresh rate: 750Hz
-    // 10M with 14bit divider (min) gives ~610Hz
-    // 10M with 22bit divider (max) gives ~2.4Hz
-    localparam MIN_WIDTH = 13;
-    localparam DIV_WIDTH = 8;
-
-    reg [MIN_WIDTH+8:0] counter;
-    reg [DIV_WIDTH-1:0] compare;
-    reg last_set;
-
-    assign slow_clk = counter[MIN_WIDTH + compare];
-
-    always @(posedge clk) begin
-        if(reset) begin
-            counter <= 0;
-            compare <= 0;
-            last_set <= 0;
-        end
-        else begin
-            // update divider on positive edge of set
-            if(set && !last_set) begin
-                compare <= divider;
+    // Mux toward scan-schain
+    always @(*)
+    begin
+        casez (driver_sel)
+            // External
+            2'b00: begin
+                scan_clk_out  = ext_scan_clk_out;
+                scan_data_out = ext_scan_data_out;
+                scan_select   = ext_scan_select;
+                scan_latch_en = ext_scan_latch_en;
             end
-            counter <= counter + 1'b1;
-            last_set <= set;
-        end
+
+            // Caravel LA
+            2'b01: begin
+                scan_clk_out  = la_scan_clk_in;
+                scan_data_out = la_scan_data_in;
+                scan_select   = la_scan_select;
+                scan_latch_en = la_scan_latch_en;
+            end
+
+            // Internal
+            2'b1z: begin
+                scan_clk_out  = int_scan_clk_out;
+                scan_data_out = int_scan_data_out;
+                scan_select   = int_scan_select;
+                scan_latch_en = int_scan_latch_en;
+            end
+        endcase
     end
 
-endmodule
+    // Synchronizer for inputs
+    always @(posedge clk)
+    begin
+        aio_input_sync <= inputs;
+        aio_input_reg  <= driver_sel[1] ? aio_input_sync : 0;
+    end
+
+    // Mux for outputs
+    assign outputs = driver_sel[1] ? aio_output_reg : {6'b0, ext_scan_data_in, ext_scan_clk_in};
+
+
+    // FSM & control
+    // -------------
+
+    // Check if we're active
+    always @(posedge clk or posedge rst_i)
+        if (rst_i)
+            active <= 1'b0;
+        else
+            active <= driver_sel[1];
+
+    // State register
+    always @(posedge clk or posedge rst_i)
+        if (rst_i)
+            state <= ST_IDLE;
+        else
+            state <= state_nxt;
+
+    // State transitions
+    always @(*)
+    begin
+        // Defaults
+        state_nxt = state;
+
+        // Transitions
+        case (state)
+            ST_IDLE:
+                if (active)
+                    state_nxt = ST_IN_LOAD;
+
+            ST_IN_LOAD:
+                state_nxt = ST_IN_SHIFT_LO;
+
+            ST_IN_SHIFT_LO:
+                state_nxt = ST_IN_SHIFT_HI;
+
+            ST_IN_SHIFT_HI:
+                state_nxt = (proj_sel & bit_last) ? ST_IN_LATCH_WAIT : ST_IN_SHIFT_LO;
+
+            ST_IN_LATCH_WAIT:
+                if (ws_cnt_done)
+                    state_nxt = ST_IN_LATCH;
+
+            ST_IN_LATCH:
+                state_nxt = ST_OUT_LOAD_PRE;
+
+            ST_OUT_LOAD_PRE:
+                if (ws_cnt_done)
+                    state_nxt = ST_OUT_LOAD;
+
+            ST_OUT_LOAD:
+                state_nxt = ST_OUT_LOAD_POST;
+
+            ST_OUT_LOAD_POST:
+                if (ws_cnt_done)
+                    state_nxt = ST_OUT_LOAD_CLR;
+
+            ST_OUT_LOAD_CLR:
+                if (ws_cnt_done)
+                    state_nxt = ST_OUT_SHIFT_LO;
+
+            ST_OUT_SHIFT_LO:
+                state_nxt = ST_OUT_SHIFT_HI;
+
+            ST_OUT_SHIFT_HI:
+                state_nxt = (proj_done & bit_last) ? ST_OUT_CAP_WAIT : ST_OUT_SHIFT_LO;
+
+            ST_OUT_CAP_WAIT:
+                if (ws_cnt_done)
+                    state_nxt = ST_OUT_CAP;
+
+            ST_OUT_CAP:
+                state_nxt = ST_IDLE;
+        endcase
+    end
+
+
+    // Scan progress tracking
+    // ----------------------
+
+    // Keep track of IO number
+    always @(posedge clk)
+        if (state == ST_IDLE)
+            bit_cnt <= 0;
+        else if ((state == ST_IN_SHIFT_HI) | (state == ST_OUT_SHIFT_HI))
+            bit_cnt <= bit_last ? 0 : (bit_cnt + 1);
+
+    assign bit_last = (bit_cnt == (NUM_IOS - 1));
+
+    // Keep track of project number
+    always @(posedge clk)
+        if (state == ST_IDLE)
+            proj_cnt <= 0;
+        else if (((state == ST_IN_SHIFT_HI) | (state == ST_OUT_SHIFT_HI)) & bit_last)
+            proj_cnt <= proj_cnt + 1;
+
+    assign proj_sel  = (proj_cnt == active_select);
+    assign proj_done = (proj_cnt == NUM_DESIGNS);
+
+
+    // Scan chain control
+    // ------------------
+
+    always @(posedge clk)
+    begin
+        int_scan_clk_out  <= (state == ST_IN_SHIFT_HI)  | (state == ST_OUT_LOAD) | (state == ST_OUT_SHIFT_HI);
+        int_scan_data_out <= aio_input_shift[PL];
+        int_scan_select   <= (state == ST_OUT_LOAD_PRE) | (state == ST_OUT_LOAD) | (state == ST_OUT_LOAD_POST);
+        int_scan_latch_en <= (state == ST_IN_LATCH);
+    end
+
+
+    // Shift registers
+    // ---------------
+
+    // Local control from FSM
+    assign aio_input_sh   = (state == ST_IN_SHIFT_HI);
+    assign aio_input_ld   = (state == ST_IN_LOAD);
+    assign aio_output_cap = (state == ST_OUT_CAP);
+
+    // Input
+    always @(posedge clk)
+        if (aio_input_ld)
+            aio_input_shift <= slow_clk_ena ? { aio_input_reg[PL-1:1], slow_clk } : aio_input_reg;
+        else if (aio_input_sh)
+            aio_input_shift <= { aio_input_shift[PL-1:0], 1'b0 };
+
+    // Output
+    always @(posedge int_scan_clk_in)
+        aio_output_shift <= { aio_output_shift[PL-1:0], int_scan_data_in };
+
+    always @(posedge clk)
+        if (aio_output_cap)
+            aio_output_reg <= aio_output_shift;
+
+
+    // Wait state counter
+    // ------------------
+
+    always @(posedge clk)
+        if (~ws_cnt_run | ws_cnt_done)
+            ws_cnt <= 0;
+        else
+            ws_cnt <= ws_cnt + 1;
+
+    assign ws_cnt_done = (ws_cnt == ws_cfg);
+
+    assign ws_cnt_run = (
+        (state == ST_IN_LATCH_WAIT) |
+        (state == ST_OUT_LOAD_PRE) |
+        (state == ST_OUT_LOAD_POST) |
+        (state == ST_OUT_LOAD_CLR)  |
+        (state == ST_OUT_CAP_WAIT)
+    );
+
+
+    // Wait state config
+    // -----------------
+
+        // This dictates how many wait cycle we insert in various state
+        // of the load process. We have a sane default, but also allow
+        // override externally.
+
+    always @(posedge clk or posedge rst_i)
+        if (rst_i)
+            ws_set_sync <= 3'b000;
+        else
+            ws_set_sync <= { ws_set_sync[1:0], (driver_sel == 2'b11) };
+
+    always @(posedge clk)
+        ws_set_now <= ~ws_set_sync[2] & ws_set_sync[1];
+
+    always @(posedge clk or posedge rst_i)
+        if (rst_i)
+            ws_cfg <= 8'd10;
+        else if (ws_set_now)
+            ws_cfg <= inputs;
+
+
+    // Clock Divider
+    // -------------
+
+    clk_divider clk_divider_I (
+        .clk      (clk),
+        .ce       (aio_input_ld),
+        .set      (set_clk_div),
+        .reset    (rst_i),
+        .divider  (inputs),
+        .active   (slow_clk_ena),
+        .slow_clk (slow_clk)
+    );
+
+endmodule // scan_controller
+
+
+module clk_divider #(
+    parameter integer DIV_WIDTH = 8
+)(
+    input  wire clk,
+    input  wire ce,
+    input  wire reset,
+    input  wire set,
+    input  wire [DIV_WIDTH-1:0] divider,
+    output wire active,
+    output reg  slow_clk
+);
+
+    reg [DIV_WIDTH-1:0] counter;
+    reg [DIV_WIDTH-1:0] compare;
+    wire                match;
+
+    reg [2:0] set_sync;
+    reg       set_now;
+
+    // Detect rising edge (with synchronizer)
+    always @(posedge clk)
+    begin
+        set_sync <= { set_sync[1:0], set };
+        set_now  <= ~set_sync[2] & set_sync[1];
+    end
+
+    assign active = set_sync[2];
+
+    // Latch divider
+    always @(posedge clk)
+        if (set_now)
+            compare <= divider;
+
+    // Compare
+    assign match = (counter == compare);
+
+    // Counter
+    always @(posedge clk or posedge reset)
+        if (reset)
+            counter <= 0;
+        else if (ce)
+            counter <= match ? 0 : (counter + 1);
+
+    // Clock gen
+    always @(posedge clk or posedge reset)
+        if (reset)
+            slow_clk <= 1'b0;
+        else if (ce)
+            slow_clk <= slow_clk ^ match;
+
+endmodule // clk_divider
diff --git a/verilog/rtl/user_project_wrapper.v b/verilog/rtl/user_project_wrapper.v
index 7ea4afa..2079594 100644
--- a/verilog/rtl/user_project_wrapper.v
+++ b/verilog/rtl/user_project_wrapper.v
@@ -96,13 +96,14 @@
             .slow_clk               (io_out[10]),
             .set_clk_div            (io_in[11]),
 
-            .scan_clk               (clk[0]),
+            .scan_clk_out           (clk[0]),
+            .scan_clk_in            (clk[NUM_MACROS]),
             .scan_data_out          (data[0]),
             .scan_data_in           (data[NUM_MACROS]),
             .scan_select            (scan[0]),
             .scan_latch_en          (latch[0]),
 
-            .la_scan_clk            (la_data_in[0]),
+            .la_scan_clk_in         (la_data_in[0]),
             .la_scan_data_in        (la_data_in[1]),
             .la_scan_data_out       (la_data_out[0]),
             .la_scan_select         (la_data_in[2]),