frontend/adaptation: fix error when read follows write to the same address

This commit is contained in:
Jędrzej Boczar 2020-05-11 16:11:40 +02:00
parent 1587ee3611
commit 2f35e9714d
2 changed files with 30 additions and 30 deletions
litedram/frontend
test

View file

@ -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 ----------------------------------------------------------------------------

View file

@ -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