diff --git a/rtl_lib/gearbox.py b/rtl_lib/gearbox.py
index 66d370d70ae12e082050fcf17553c3b3f7e41fc5..88681413da7ead5f872a071dd12ccce4035f9186 100644
--- a/rtl_lib/gearbox.py
+++ b/rtl_lib/gearbox.py
@@ -3,7 +3,7 @@ from nmigen import *
 from nmigen.hdl.rec import *
 from nmigen.asserts import *
 from nmigen.cli import main
-
+from pipe_stage import PipeStage
 
 # NEXT TASKS (IMMEDIATE)
 # finish fleshing out code, attach buses from the Flow controller to the gearbox
@@ -15,11 +15,6 @@ from nmigen.cli import main
 
 # REMAINING WORK
 #
-# make a quick-and-dirty testbench that selects a random inwidth, random outwidth, and randomly
-# starts/stops the input/output and verifies that the sequence of bits coming out is the same
-# as that coming in (can do with PRBS) and that bus interface constraints are not violated
-
-
 # can make a testbench only operating on the indices and the flowcontrol signals that keeps a
 # model of the valid/invalid bits and verifies that when a transaction happens, the right bits
 # get read/written and the right indices get moved in the right ways
@@ -291,64 +286,25 @@ class ArbitraryGearbox(Elaboratable):
 
 
 class IdempotentGearbox(Elaboratable):
-        def __init__(self, *, in_width, out_width):
-            self.in_width = in_width
-            self.out_width = out_width
-            assert(in_width == out_width)
+        def __init__(self, *, width):
+            self.width = width
 
-            self.bus = GearboxBus(in_width=in_width, out_width=out_width)
+            self.bus = GearboxBus(in_width=width, out_width=width)
 
         def elaborate(self, platform):
             m = Module()
-            skid_buffer = Signal(self.in_width)
-            skid_buffer_frozen = Signal(1)
-
-            # we signal ready to upstream if and only if the skid buffer is empty
-            m.d.comb += self.bus.ready_out.eq(~skid_buffer_frozen)
-
-
-            # should we capture a value in the skid buffer?
-            # we should if upstream has data for us *and* downstream cannot accept
-
-            # If we want to fill our skid buffer, we need:
-            # 1. valid input data       (bus.valid_in   == 1)
-            # 2. a buffer that is empty (skid_buffer_frozen  == 0)
-            # 3. stalled downstream     (bus.ready_in == 0) & (bus.valid_out == 1)
 
-            with m.If(self.bus.valid_in & (~skid_buffer_frozen)  & (~self.bus.ready_in) & (self.bus.valid_out)):
-                m.d.sync += skid_buffer_frozen.eq(1)
+            m.submodules.pipe = pipe = PipeStage(width=self.width, registered_ready=True)
 
-            # if downstream is accepting data again, we will flush our skid buffer
-            with m.If(self.bus.ready_in == 1):
-                m.d.sync += skid_buffer_frozen.eq(0)
+            m.d.comb += pipe.upstream_valid_in.eq(self.bus.valid_in)
+            m.d.comb += pipe.downstream_ready_in.eq(self.bus.ready_in)
+            m.d.comb += pipe.upstream_data_in.eq(self.bus.data_in)
 
+            m.d.comb += self.bus.valid_out.eq(pipe.downstream_valid_out)
+            m.d.comb += self.bus.data_out.eq(pipe.downstream_data_out)
+            m.d.comb += self.bus.ready_out.eq(pipe.upstream_ready_out)
 
-            # Stalled == (bus.ready_in == 0 & bus.valid_out == 1)
-            # so not stalled = !(bus.ready_in == 0 & bus.valid_out == 1)
-            #    = bus.ready_in == 1 | bus.valid_out == 0
-            # by de Morgan
 
-            with m.If((self.bus.ready_in) | (~self.bus.valid_out)):
-                m.d.sync += self.bus.valid_out.eq(self.bus.valid_in | skid_buffer_frozen)
-
-            # data path
-
-            # always clock data into the skid buffer as long as the buffer isn't filled
-
-            with m.If(skid_buffer_frozen == 0):
-                m.d.sync += skid_buffer.eq(self.bus.data_in)
-
-            # not stalled condition
-            with m.If((self.bus.ready_in) | (~self.bus.valid_out)):
-                with m.If(skid_buffer_frozen == 1):
-                    m.d.sync += self.bus.data_out.eq(skid_buffer)
-                with m.Elif(self.bus.valid_in == 1):
-                    m.d.sync += self.bus.data_out.eq(self.bus.data_in)
-
-
-            with m.If(Past(ResetSignal()) == 0):
-                with m.If((self.bus.valid_in == 1) & (Past(self.bus.valid_in) == 1)):
-                    m.d.comb += Assert(Rose(self.bus.valid_out))
             return m
 
 
@@ -361,20 +317,29 @@ class GoldenGearboxModel(Elaboratable):
         def __init__(self, *, in_width, out_width, sim_memory_size):
             self.in_width = in_width
             self.out_width = out_width
-            assert(in_width == out_width)
+            self.sim_memory_size = sim_memory_size
 
             self.memory = Signal(sim_memory_size)
 
             self.bus = GearboxBus(in_width=in_width, out_width=out_width)
 
         def elaborate(self, platform):
+            m = Module()
+            write_ptr = Signal(range(self.sim_memory_size))
+            read_ptr = Signal(range(self.sim_memory_size))
 
+            with m.If(self.bus.valid_in == 1):
+                m.d.sync += write_ptr.eq(write_ptr + self.in_width)
+                with m.Switch(write_ptr):
+                        for cand_wptr in range(0, self.sim_memory_size):
+                            with m.Case(cand_wptr):
 
-            write_ptr = Signal(range(sim_memory_size))
-            read_ptr = Signal(range(sim_memory_size))
+                                m.d.sync += self.memory.eq(
+
+                                    Cat(self.memory.bit_select(0, cand_wptr),
+                                        self.bus.data_in))
 
 
-            m = Module()
             return m
 
 
@@ -388,16 +353,18 @@ class DummyPlug(Elaboratable):
     def elaborate(self, platform):
         m = Module()
 
-        m.submodules.gearbox = gearbox = IdempotentGearbox(in_width=(3), out_width=3)
-        #counter = Signal(8)
-        #m.d.sync += counter.eq(counter+1)
+        #m.d.comb += gearbox.bus.data_in.eq(AnySeq(3))
+        #m.d.comb += gearbox.bus.ready_in.eq(AnySeq(1))
+        #m.d.comb += gearbox.bus.valid_in.eq(AnySeq(1))
+
+        m.submodules.gearbox = gearbox = GoldenGearboxModel(in_width=3, out_width=6, sim_memory_size=16)
+        counter = Signal(8)
+        m.d.sync += counter.eq(counter+1)
 
-#        with m.If(counter == 3):
-#            m.d.comb += gearbox.bus.valid_in.eq(1)
-        m.d.comb += gearbox.bus.data_in.eq(AnySeq(3))
-        m.d.comb += gearbox.bus.ready_in.eq(AnySeq(1))
-        m.d.comb += gearbox.bus.valid_in.eq(AnySeq(1))
+        with m.If(counter%2 == 0):
+            m.d.comb += gearbox.bus.valid_in.eq(1)
 
+        m.d.comb += gearbox.bus.data_in.eq(0xf)
 
         return m