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 <mdudek@antmicro.com>
This commit is contained in:
Maciej Dudek 2021-02-19 15:14:49 +01:00 committed by Robert Szczepanski
parent 7b3c6abd50
commit c54fc4af82
2 changed files with 29 additions and 9 deletions

View File

@ -186,6 +186,7 @@ class LiteDRAMNativePortUpConverter(Module):
send_inner_cmd_addr = Signal.like(port_to.cmd.addr) send_inner_cmd_addr = Signal.like(port_to.cmd.addr)
send_inner_cmd_we = Signal.like(port_to.cmd.we) 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), self.cmd_buffer = cmd_buffer = stream.SyncFIFO([ ("cmd_addr", send_cmd_addr.nbits),
("cmd_we", send_cmd_we.nbits)], ("cmd_we", send_cmd_we.nbits)],
cmd_buffer_depth) cmd_buffer_depth)
@ -207,10 +208,10 @@ class LiteDRAMNativePortUpConverter(Module):
) )
) )
send_fsm.act("SEND", 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.addr.eq(send_inner_cmd_addr),
port_to.cmd.we.eq(send_inner_cmd_we), 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, If(cmd_buffer.source.valid,
cmd_buffer.source.ready.eq(1), cmd_buffer.source.ready.eq(1),
NextValue(send_inner_cmd_addr, cmd_buffer.source.cmd_addr), 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, # Command flow is quite complicate, nonlinear and it depends on type read/write,
# so here is summary: # so here is summary:
# This FSM receives commands from `port_from` and pushes them to `cmd_buffer` queue, # 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", fsm.act("WAIT-FOR-CMD",
If(port_from.cmd.valid, If(port_from.cmd.valid,
NextValue(counter, 0), NextValue(counter, 0),
NextValue(cmd_last, 0),
NextValue(cmd_addr, port_from.cmd.addr[log2_int(ratio):]), NextValue(cmd_addr, port_from.cmd.addr[log2_int(ratio):]),
NextValue(cmd_we, port_from.cmd.we), NextValue(cmd_we, port_from.cmd.we),
If(port_from.cmd.we, If(port_from.cmd.we,
@ -485,14 +499,12 @@ class LiteDRAMNativePortUpConverter(Module):
] ]
self.sync += [ self.sync += [
If(wdata_fifo.source.valid & wdata_fifo.source.ready,
Case(write_chunk, cases)
),
If(wdata_finished, If(wdata_finished,
write_inner_counter.eq(0), write_inner_counter.eq(0),
wdata_buffer.we.eq(0), wdata_buffer.we.eq(0),
).Elif(wdata_fifo.source.valid & wdata_fifo.source.ready, ).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, If(self.send_cmd_busy,
NextState("WAIT-TO-SEND") NextState("WAIT-TO-SEND")
).Else( ).Else(
If(port_from.cmd.valid & port_from.cmd.we,
NextValue(counter, 0), NextValue(counter, 0),
NextValue(cmd_last, 0),
If(port_from.cmd.valid & port_from.cmd.we,
NextValue(cmd_addr, port_from.cmd.addr[log2_int(self.ratio):]), NextValue(cmd_addr, port_from.cmd.addr[log2_int(self.ratio):]),
NextValue(cmd_we, port_from.cmd.we), 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") NextState("FILL")
).Else( ).Else(
NextState("WAIT-FOR-CMD") NextState("WAIT-FOR-CMD")
@ -536,8 +554,9 @@ class LiteDRAMNativePortUpConverter(Module):
self.send_cmd_we.eq(port_from.cmd.we), self.send_cmd_we.eq(port_from.cmd.we),
NextValue(cmd_addr, port_from.cmd.addr[log2_int(self.ratio):]), NextValue(cmd_addr, port_from.cmd.addr[log2_int(self.ratio):]),
NextValue(cmd_we, port_from.cmd.we), NextValue(cmd_we, port_from.cmd.we),
If(self.send_cmd_busy,
NextValue(counter, 0), NextValue(counter, 0),
NextValue(cmd_last, 0),
If(self.send_cmd_busy,
NextState("WAIT-TO-SEND") NextState("WAIT-TO-SEND")
).Else( ).Else(
port_from.cmd.ready.eq(1), port_from.cmd.ready.eq(1),

View File

@ -14,7 +14,7 @@ from litex.soc.interconnect import wishbone
from litedram.frontend.wishbone import LiteDRAMWishbone2Native from litedram.frontend.wishbone import LiteDRAMWishbone2Native
from litedram.common import LiteDRAMNativePort from litedram.common import LiteDRAMNativePort
from test.common import DRAMMemory, MemoryTestDataMixin from test.common import *
class TestWishbone(MemoryTestDataMixin, unittest.TestCase): class TestWishbone(MemoryTestDataMixin, unittest.TestCase):
@ -40,6 +40,7 @@ class TestWishbone(MemoryTestDataMixin, unittest.TestCase):
main_generator(dut), main_generator(dut),
dut.mem.write_handler(dut.port), dut.mem.write_handler(dut.port),
dut.mem.read_handler(dut.port), dut.mem.read_handler(dut.port),
timeout_generator(10000)
] ]
run_simulation(dut, generators, vcd_name='sim.vcd') run_simulation(dut, generators, vcd_name='sim.vcd')
self.assertEqual(dut.mem.mem, mem_expected) self.assertEqual(dut.mem.mem, mem_expected)