mirror of
https://github.com/enjoy-digital/litedram.git
synced 2025-01-04 09:52:25 -05:00
frontend/adaptation: fix error when read follows write to the same address
This commit is contained in:
parent
1587ee3611
commit
2f35e9714d
2 changed files with 30 additions and 30 deletions
|
@ -164,25 +164,27 @@ class LiteDRAMNativePortUpConverter(Module):
|
|||
cmd_last = Signal()
|
||||
# indicates that we need to proceed to the next port_to command
|
||||
next_cmd = Signal()
|
||||
addr_changed = Signal()
|
||||
# signals that indicate that write/read convertion has finished
|
||||
wdata_finished = Signal()
|
||||
rdata_finished = Signal()
|
||||
# used to prevent reading old memory value if previous command has written the same address
|
||||
read_lock = Signal()
|
||||
rw_collision = Signal()
|
||||
|
||||
self.comb += [
|
||||
addr_changed.eq(cmd_addr[log2_int(ratio):] != port_from.cmd.addr[log2_int(ratio):]),
|
||||
# collision happens on write to read transition when address does not change
|
||||
rw_collision.eq(cmd_we & (port_from.cmd.valid & ~port_from.cmd.we) & ~addr_changed),
|
||||
# go to the next command if one of the following happens:
|
||||
# * port_to address changes
|
||||
# * cmd type changes
|
||||
# * we received all the `ratio` commands
|
||||
# * this is the last command in a sequence
|
||||
next_cmd.eq(
|
||||
(cmd_addr[log2_int(ratio):] != port_from.cmd.addr[log2_int(ratio):])
|
||||
| (cmd_we != port_from.cmd.we)
|
||||
| (sel == 2**ratio - 1)
|
||||
| cmd_last
|
||||
),
|
||||
next_cmd.eq(addr_changed | (cmd_we != port_from.cmd.we) | (sel == 2**ratio - 1) | cmd_last),
|
||||
# when the first command is received, send it immediatelly
|
||||
If(sel == 0,
|
||||
If(port_from.cmd.valid,
|
||||
If(port_from.cmd.valid & ~read_lock,
|
||||
port_to.cmd.valid.eq(1),
|
||||
port_to.cmd.we.eq(port_from.cmd.we),
|
||||
port_to.cmd.addr.eq(port_from.cmd.addr[log2_int(ratio):]),
|
||||
|
@ -214,6 +216,12 @@ class LiteDRAMNativePortUpConverter(Module):
|
|||
If(cmd_buffer.sink.valid & cmd_buffer.sink.ready,
|
||||
sel.eq(0),
|
||||
),
|
||||
# block sending read command if we have just written to that address
|
||||
If(wdata_finished,
|
||||
read_lock.eq(0),
|
||||
).Elif(rw_collision & ~port_to.cmd.valid,
|
||||
read_lock.eq(1)
|
||||
)
|
||||
]
|
||||
|
||||
# Read Datapath ----------------------------------------------------------------------------
|
||||
|
|
|
@ -269,24 +269,15 @@ class TestAdaptation(MemoryTestDataMixin, unittest.TestCase):
|
|||
self.converter_readback_test(dut, pattern=[], mem_expected=mem_expected,
|
||||
main_generator=main_generator)
|
||||
|
||||
@unittest.skip("Read after write not yet synchronised enough")
|
||||
def test_up_converter_auto_flush_on_cmd_we_change(self):
|
||||
# Verify that up-conversion automatically flushes the cmd when command type (write/read) changes
|
||||
def main_generator(dut):
|
||||
yield from dut.write(0x00, 0x11, wait_data=False)
|
||||
yield from dut.write(0x01, 0x22, wait_data=False)
|
||||
yield from dut.write(0x02, 0x33, wait_data=False)
|
||||
yield from dut.write(0x03, 0x44, wait_data=False)
|
||||
yield from dut.write(0x04, 0x55, wait_data=False)
|
||||
yield from dut.write(0x05, 0x66, wait_data=False)
|
||||
yield from dut.read (0x00)
|
||||
yield from dut.read (0x01)
|
||||
yield from dut.read (0x02)
|
||||
yield from dut.read (0x03)
|
||||
yield from dut.read (0x04)
|
||||
yield from dut.read (0x05)
|
||||
yield from dut.read (0x06)
|
||||
yield from dut.read (0x07)
|
||||
yield from dut.read(0x00, wait_data=False)
|
||||
yield from dut.read(0x01, wait_data=False)
|
||||
yield from dut.read(0x02, wait_data=False)
|
||||
yield from dut.read(0x03, wait_data=False)
|
||||
|
||||
yield from dut.write_driver.wait_all()
|
||||
yield from dut.read_driver.wait_all()
|
||||
|
@ -295,22 +286,23 @@ class TestAdaptation(MemoryTestDataMixin, unittest.TestCase):
|
|||
|
||||
mem_expected = [
|
||||
# data address
|
||||
0x44332211, # 0x00
|
||||
0x00006655, # 0x04
|
||||
0x00002211, # 0x00
|
||||
0x00000000, # 0x04
|
||||
0x00000000, # 0x08
|
||||
0x00000000, # 0x0c
|
||||
]
|
||||
pattern = [
|
||||
(0x00, mem_expected[0]),
|
||||
(0x01, mem_expected[1]),
|
||||
(0x00, 0x11),
|
||||
(0x01, 0x22),
|
||||
(0x02, 0x00),
|
||||
(0x03, 0x00),
|
||||
]
|
||||
|
||||
for separate_rw in [True, False]:
|
||||
with self.subTest(separate_rw=separate_rw):
|
||||
dut = ConverterDUT(user_data_width=8, native_data_width=32,
|
||||
mem_depth=len(mem_expected), separate_rw=separate_rw)
|
||||
self.converter_readback_test(dut, pattern=pattern, mem_expected=mem_expected,
|
||||
main_generator=main_generator)
|
||||
# with separate_rw=True we will fail because read will happen before write completes
|
||||
dut = ConverterDUT(user_data_width=8, native_data_width=32,
|
||||
mem_depth=len(mem_expected), separate_rw=False)
|
||||
self.converter_readback_test(dut, pattern=pattern, mem_expected=mem_expected,
|
||||
main_generator=main_generator)
|
||||
|
||||
def test_up_converter_write_with_gap(self):
|
||||
# Verify that the up-converter can mask data properly when sending non-sequential writes
|
||||
|
|
Loading…
Reference in a new issue