From 82537ca0ebc459807dac2c05453b14ebbbd9caa1 Mon Sep 17 00:00:00 2001 From: Kia <kia@special-circumstanc.es> Date: Sun, 14 Mar 2021 20:25:19 -0600 Subject: [PATCH] start work on golden model --- rtl_lib/gearbox.py | 101 +++++++++++++++------------------------------ 1 file changed, 34 insertions(+), 67 deletions(-) diff --git a/rtl_lib/gearbox.py b/rtl_lib/gearbox.py index 66d370d..8868141 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 -- GitLab