From 72d19420fa77353dd0e7cf7e0a7284311c79e6fc Mon Sep 17 00:00:00 2001 From: Kia <kia@special-circumstanc.es> Date: Wed, 3 Mar 2021 19:52:59 -0700 Subject: [PATCH] first draft of flowcontroller --- gearbox.py | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/gearbox.py b/gearbox.py index cebcfe3..b190ca3 100755 --- a/gearbox.py +++ b/gearbox.py @@ -75,6 +75,7 @@ class GearboxFlowControl(Elaboratable): def elaborate(self, platform): m = Module() + internalfault = Signal() # The top-level flow control logic works as follows. # First, we determine which operations are *possible* based on the read/write indices @@ -87,11 +88,23 @@ class GearboxFlowControl(Elaboratable): # If so, we set valid_out to signal to downstream we're ready to produce can_read_this_cycle = Signal(1) # Then, we look at the flow-control signals from upstream/downstream to see which - # transactions will happen, and set the following two internal signals, which are + # transactions will happen, and set the following two bus signals, which are # used to gate the read/write index updates: + # write_happens_this_cycle + # read_happens_this_cycle - write_happens_this_cycle = Signal(1) - read_happens_this_cycle = Signal(1) + + # We replicate signals to avoid repeating "self.bus." + + read_ptr = Signal(range(self.len_storage)) + m.d.comb += read_ptr.eq(self.bus.read_ptr) + + write_ptr = Signal(range(self.len_storage)) + m.d.comb += write_ptr.eq(self.bus.write_ptr) + + len_storage = self.len_storage + + disambiguator = Signal(IndexDisambiguator, reset=IndexDisambiguator.LAST_OP_WAS_READ) with m.If(read_ptr == write_ptr): # the special case first @@ -99,7 +112,7 @@ class GearboxFlowControl(Elaboratable): with m.Case(IndexDisambiguator.LAST_OP_UNKNOWN): # fault m.d.comb += can_read_this_cycle.eq(0) m.d.comb += can_write_this_cycle.eq(0) - m.d.comb += self.bus.fault.eq(1) + m.d.sync += internalfault.eq(1) with m.Case(IndexDisambiguator.LAST_OP_WAS_WRITE): # completely full m.d.comb += can_read_this_cycle.eq(1) m.d.comb += can_write_this_cycle.eq(0) @@ -128,8 +141,29 @@ class GearboxFlowControl(Elaboratable): with m.If(numinvalid >= self.in_width): m.d.comb += can_write_this_cycle.eq(1) + with m.Elif(read_ptr > write_ptr): + # write_ptr < read_ptr. Here, the valid bits wrap, and the invalid bits do not wrap. + # The valid bits are: inclusive [read_ptr, K] inclusive, union with inclusive [0, write_ptr) exclusive + # the invalid bits are inclusive [write_ptr, read_ptr) exclusive + # We first calculate the number of valid bits: + numvalid = Signal(range(len_storage)) + m.d.comb += numvalid.eq(len_storage - read_ptr + write_ptr) + + with m.If(numvalid >= self.out_width): + m.d.comb += can_read_this_cycle.eq(1) + + # We calculate the number of invalid bits: + numinvalid = Signal(range(len_storage)) + + m.d.comb += numinvalid.eq(read_ptr - write_ptr) + + with m.If(numinvalid >= self.in_width): + m.d.comb += can_write_this_cycle.eq(1) + with m.Else(): # should never happen + m.d.sync += internalfault.eq(1) + return m class ArbitraryGearbox(Elaboratable): @@ -154,7 +188,6 @@ class ArbitraryGearbox(Elaboratable): write_ptr = Signal(range(len_storage)) read_ptr = Signal(range(len_storage)) - disambiguator = Signal(IndexDisambiguator, reset=IndexDisambiguator.LAST_OP_WAS_READ) # The buffer is composed of two different flavor of bits: @@ -176,9 +209,7 @@ class ArbitraryGearbox(Elaboratable): # There are multiple cases for read_ptr and write_ptr: - # write_ptr < read_ptr. Here, the valid bits wrap, and the invalid bits do not wrap. - # The valid bits are: inclusive [read_ptr, K] inclusive, union with inclusive [0, write_ptr) exclusive - # the invalid bits are inclusive [write_ptr, read_ptr) exclusive + # Naturally, there is a tricky edge case which requires an extra bit (literally) of disambiguation. # If write_ptr == read_ptr we don't know if the buffer is entirely full or entirely empty. -- GitLab