frontend/fifo: Revisit DRAM state to avoid deadlock situations when port_data_width != port_address_width.

This commit is contained in:
Florent Kermarrec 2021-10-06 18:05:48 +02:00
parent 1598b2733a
commit 136be83749
2 changed files with 32 additions and 19 deletions

View file

@ -219,7 +219,8 @@ class LiteDRAMFIFO(Module):
# Parameters. # Parameters.
# ----------- # -----------
assert write_port.data_width == read_port.data_width assert write_port.data_width == read_port.data_width
port_data_width = write_port.data_width port_data_width = write_port.data_width
port_address_width = write_port.address_width
assert data_width <= port_data_width assert data_width <= port_data_width
data_width_ratio = port_data_width//data_width data_width_ratio = port_data_width//data_width
if not with_bypass: if not with_bypass:
@ -261,9 +262,9 @@ class LiteDRAMFIFO(Module):
# Sink --> Pre-FIFO. # Sink --> Pre-FIFO.
self.sink.connect(pre_fifo.sink), self.sink.connect(pre_fifo.sink),
# DRAM Threshold. We can only enable path to DRAAM when we have enough data for a full # DRAM Threshold. We can only enable path to DRAM when we have enough data for a full
# DRAM word. # DRAM word.
dram_store_threshold.eq(pre_fifo.level > data_width_ratio), dram_store_threshold.eq(pre_fifo.level >= data_width_ratio),
# Bypass / DRAM. # Bypass / DRAM.
If(with_bypass & dram_bypass, If(with_bypass & dram_bypass,
@ -291,36 +292,46 @@ class LiteDRAMFIFO(Module):
# FSM. # FSM.
# ---- # ----
if with_bypass: if with_bypass:
dram_first = Signal()
dram_inc = Signal()
dram_dec = Signal()
dram_cnt = Signal(port_address_width)
dram_inc_mod = Signal(int(math.log2(data_width_ratio)))
dram_dec_mod = Signal(int(math.log2(data_width_ratio)))
self.submodules.fsm = fsm = FSM(reset_state="BYPASS") self.submodules.fsm = fsm = FSM(reset_state="BYPASS")
fsm.act("BYPASS", fsm.act("BYPASS",
dram_bypass.eq(1), dram_bypass.eq(1),
# Switch to DRAM mode when enough data to store a DRAM word. # Switch to DRAM mode when enough data to store a DRAM word.
If(dram_store_threshold, If(dram_store_threshold,
NextValue(dram_store, 1), NextValue(dram_first, 1),
NextValue(dram_cnt, 0),
NextState("DRAM") NextState("DRAM")
) )
) )
dram_cnt_inc = Signal()
dram_cnt_dec = Signal()
dram_cnt = Signal(int(math.log2(fifo_depth + pre_fifo_depth + post_fifo_depth) + 2))
self.sync += dram_cnt.eq(dram_cnt + dram_cnt_inc - dram_cnt_dec)
fsm.act("DRAM", fsm.act("DRAM",
# Store in DRAM.
dram_store.eq(1),
# Increment DRAM Data Count on Pre-Converter's Sink cycle. # Increment DRAM Data Count on Pre-Converter's Sink cycle.
dram_cnt_inc.eq(pre_converter.sink.valid & pre_converter.sink.ready), If(pre_converter.sink.valid & pre_converter.sink.ready,
dram_inc.eq(1),
NextValue(dram_first, 0),
NextValue(dram_inc_mod, dram_inc_mod + 1),
),
# Decrement DRAM Data Count on Post-Converter's Source cycle. # Decrement DRAM Data Count on Post-Converter's Source cycle.
dram_cnt_dec.eq(post_converter.source.valid & post_converter.source.ready), If(post_converter.source.valid & post_converter.source.ready,
dram_dec.eq(1),
# Update DRAM store.. NextValue(dram_dec_mod, dram_dec_mod + 1),
If(pre_converter.source.valid,
NextValue(dram_store, dram_store_threshold),
), ),
# Maintain DRAM Data Count. # Maintain DRAM Data Count.
NextValue(dram_cnt, dram_cnt + dram_cnt_inc - dram_cnt_dec), NextValue(dram_cnt, dram_cnt + dram_inc - dram_dec),
# Switch back to Bypass mode when DRAM Data count # Switch back to Bypass mode when no remaining DRAM word.
If((dram_store_threshold == 0) & (dram_cnt == 0), If((dram_first == 0) & (dram_cnt == 0) & (dram_inc_mod == 0) & (dram_dec_mod == 0),
dram_store.eq(0),
NextState("BYPASS") NextState("BYPASS")
) )
) )

View file

@ -235,8 +235,9 @@ class TestFIFO(unittest.TestCase):
def fifo_continuous_stream_short_test(self, with_bypass): def fifo_continuous_stream_short_test(self, with_bypass):
# Verify FIFO operation with continuous writes and reads without wrapping # Verify FIFO operation with continuous writes and reads without wrapping
@passive
def generator(dut): def generator(dut):
for i in range(64): for i in range(2*64):
yield from dut.write(10 + i) yield from dut.write(10 + i)
def checker(dut): def checker(dut):
@ -262,8 +263,9 @@ class TestFIFO(unittest.TestCase):
def fifo_continuous_stream_long_test(self, with_bypass): def fifo_continuous_stream_long_test(self, with_bypass):
# Verify FIFO operation with continuous writes and reads with wrapping # Verify FIFO operation with continuous writes and reads with wrapping
@passive
def generator(dut): def generator(dut):
for i in range(64): for i in range(2*64):
yield from dut.write(10 + i) yield from dut.write(10 + i)
def checker(dut): def checker(dut):