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 1bbb8b6..0aa0e18 100644 --- a/litedram/frontend/adapter.py +++ b/litedram/frontend/adapter.py @@ -186,6 +186,7 @@ class LiteDRAMNativePortUpConverter(Module): 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 @@ class LiteDRAMNativePortUpConverter(Module): ) ) 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 @@ class LiteDRAMNativePortUpConverter(Module): ) ) ) + + # 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 @@ class LiteDRAMNativePortUpConverter(Module): 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 @@ class LiteDRAMNativePortUpConverter(Module): ] 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 @@ class LiteDRAMNativePortUpConverter(Module): 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 @@ class LiteDRAMNativePortUpConverter(Module): 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 e7a2d51..f5fe93d 100644 --- a/test/test_wishbone.py +++ b/test/test_wishbone.py @@ -14,7 +14,7 @@ from litex.soc.interconnect import wishbone 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 @@ class TestWishbone(MemoryTestDataMixin, unittest.TestCase): 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)