From c54fc4af82bfce7efb30a4d5999e9eb42a309bca Mon Sep 17 00:00:00 2001 From: Maciej Dudek Date: Fri, 19 Feb 2021 15:14:49 +0100 Subject: [PATCH] Fix UpConverter write path not working as intended LiteDRAM controler does not check if wdata stream has valid signal set, it assumes that wdata has valid data when cmd is send. Signed-off-by: Maciej Dudek --- litedram/frontend/adapter.py | 35 +++++++++++++++++++++++++++-------- test/test_wishbone.py | 3 ++- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/litedram/frontend/adapter.py b/litedram/frontend/adapter.py index 1bbb8b6ed..0aa0e1830 100644 --- a/litedram/frontend/adapter.py +++ b/litedram/frontend/adapter.py @@ -186,6 +186,7 @@ def __init__(self, port_from, port_to, reverse=False, send_inner_cmd_addr = Signal.like(port_to.cmd.addr) send_inner_cmd_we = Signal.like(port_to.cmd.we) + send_wdata_latch = Signal(reset=1) self.cmd_buffer = cmd_buffer = stream.SyncFIFO([ ("cmd_addr", send_cmd_addr.nbits), ("cmd_we", send_cmd_we.nbits)], cmd_buffer_depth) @@ -207,10 +208,10 @@ def __init__(self, port_from, port_to, reverse=False, ) ) send_fsm.act("SEND", - port_to.cmd.valid.eq(1), + port_to.cmd.valid.eq(~send_inner_cmd_we | (port_to.wdata.valid & send_wdata_latch)), port_to.cmd.addr.eq(send_inner_cmd_addr), port_to.cmd.we.eq(send_inner_cmd_we), - If(port_to.cmd.ready, + If(port_to.cmd.ready & port_to.cmd.valid, If(cmd_buffer.source.valid, cmd_buffer.source.ready.eq(1), NextValue(send_inner_cmd_addr, cmd_buffer.source.cmd_addr), @@ -221,6 +222,18 @@ def __init__(self, port_from, port_to, reverse=False, ) ) ) + + # send_latch keeps track if we have already send write command to valid wdata + self.sync += [ + If(port_to.cmd.ready & port_to.cmd.valid & send_inner_cmd_we & ~wdata_finished, + # we have avlid cmd and wdata, but port_to is not ready to recive data, send cmd + # and lock out further write commands until we send our wdata + send_wdata_latch.eq(0), + ).Elif(wdata_finished, + # we have send our wdata, unlock send + send_wdata_latch.eq(1), + ) + ] # Command flow is quite complicate, nonlinear and it depends on type read/write, # so here is summary: # This FSM receives commands from `port_from` and pushes them to `cmd_buffer` queue, @@ -293,6 +306,7 @@ def __init__(self, port_from, port_to, reverse=False, fsm.act("WAIT-FOR-CMD", If(port_from.cmd.valid, NextValue(counter, 0), + NextValue(cmd_last, 0), NextValue(cmd_addr, port_from.cmd.addr[log2_int(ratio):]), NextValue(cmd_we, port_from.cmd.we), If(port_from.cmd.we, @@ -485,14 +499,12 @@ def __init__(self, port_from, port_to, reverse=False, ] self.sync += [ - If(wdata_fifo.source.valid & wdata_fifo.source.ready, - Case(write_chunk, cases) - ), If(wdata_finished, write_inner_counter.eq(0), wdata_buffer.we.eq(0), ).Elif(wdata_fifo.source.valid & wdata_fifo.source.ready, - write_inner_counter.eq(write_inner_counter + 1) + write_inner_counter.eq(write_inner_counter + 1), + Case(write_chunk, cases) ) ] @@ -509,10 +521,16 @@ def tx_commit (self, cmd_addr, cmd_we, cmd_last, port_from, counter, ordering): If(self.send_cmd_busy, NextState("WAIT-TO-SEND") ).Else( + NextValue(counter, 0), + NextValue(cmd_last, 0), If(port_from.cmd.valid & port_from.cmd.we, - NextValue(counter, 0), NextValue(cmd_addr, port_from.cmd.addr[log2_int(self.ratio):]), NextValue(cmd_we, port_from.cmd.we), + port_from.cmd.ready.eq(1), + NextValue(counter, 1), + NextValue(ordering[:1 * log2_int(self.ratio)], + port_from.cmd.addr[:log2_int(self.ratio)]), + NextValue(cmd_last, port_from.cmd.last), NextState("FILL") ).Else( NextState("WAIT-FOR-CMD") @@ -536,8 +554,9 @@ def rx_commit (self, cmd_addr, cmd_we, cmd_last, port_from, counter, ordering): self.send_cmd_we.eq(port_from.cmd.we), NextValue(cmd_addr, port_from.cmd.addr[log2_int(self.ratio):]), NextValue(cmd_we, port_from.cmd.we), + NextValue(counter, 0), + NextValue(cmd_last, 0), If(self.send_cmd_busy, - NextValue(counter, 0), NextState("WAIT-TO-SEND") ).Else( port_from.cmd.ready.eq(1), diff --git a/test/test_wishbone.py b/test/test_wishbone.py index e7a2d5107..f5fe93d12 100644 --- a/test/test_wishbone.py +++ b/test/test_wishbone.py @@ -14,7 +14,7 @@ from litedram.frontend.wishbone import LiteDRAMWishbone2Native from litedram.common import LiteDRAMNativePort -from test.common import DRAMMemory, MemoryTestDataMixin +from test.common import * class TestWishbone(MemoryTestDataMixin, unittest.TestCase): @@ -40,6 +40,7 @@ def main_generator(dut): main_generator(dut), dut.mem.write_handler(dut.port), dut.mem.read_handler(dut.port), + timeout_generator(10000) ] run_simulation(dut, generators, vcd_name='sim.vcd') self.assertEqual(dut.mem.mem, mem_expected)