From 7593b2d9b9d9cb4b724325d23d3b4e147b3f4361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Thu, 19 Mar 2020 15:59:39 +0100 Subject: [PATCH 1/5] test: add basic wishbone test --- test/test_wishbone.py | 54 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 test/test_wishbone.py diff --git a/test/test_wishbone.py b/test/test_wishbone.py new file mode 100644 index 0000000..33528fa --- /dev/null +++ b/test/test_wishbone.py @@ -0,0 +1,54 @@ +# This file is Copyright (c) 2018-2019 Florent Kermarrec +# License: BSD + +import unittest + +from migen import * +from litex.gen.sim import run_simulation +from litex.soc.interconnect import wishbone + +from litedram.frontend.wishbone import LiteDRAMWishbone2Native +from litedram.common import LiteDRAMNativePort + +from test.common import DRAMMemory, seed_to_data + + +class TestWishbone(unittest.TestCase): + def test_wishbone_data_width_not_smaller(self): + with self.assertRaises(AssertionError): + wb = wishbone.Interface(data_width=32) + port = LiteDRAMNativePort("both", address_width=32, data_width=wb.data_width * 2) + LiteDRAMWishbone2Native(wb, port) + + def wishbone_readback_test(self, pattern, wishbone, port, mem_depth=64, **kwargs): + class DUT(Module): + def __init__(self): + self.port = port + self.wb = wishbone + self.submodules += LiteDRAMWishbone2Native(self.wb, self.port, **kwargs) + self.mem = DRAMMemory(port.data_width, mem_depth) + + def main_generator(dut): + for adr, data in pattern: + yield from dut.wb.write(adr, data) + data_r = (yield from dut.wb.read(adr)) + self.assertEqual(data_r, data) + + dut = DUT() + generators = [ + main_generator(dut), + dut.mem.write_handler(dut.port), + dut.mem.read_handler(dut.port), + ] + run_simulation(dut, generators) + + mem_expected = [0] * mem_depth + for adr, data in pattern: + mem_expected[adr] = data + self.assertEqual(dut.mem.mem, mem_expected) + + def test_wishbone(self): + pattern = [(adr, seed_to_data(adr, nbits=32)) for adr in range(16)] + wb = wishbone.Interface(data_width=32, adr_width=30) + port = LiteDRAMNativePort("both", address_width=30, data_width=32) + self.wishbone_readback_test(pattern, wb, port) From e8558f6f9fd6b20364e904151ec149df4f5d0999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Fri, 20 Mar 2020 13:18:24 +0100 Subject: [PATCH 2/5] test: fix bits formatting --- test/test_ecc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test_ecc.py b/test/test_ecc.py index 24d96e3..5b5bcef 100644 --- a/test/test_ecc.py +++ b/test/test_ecc.py @@ -25,10 +25,12 @@ def frombits(bits): return int(bits[::-1], 2) def bits_pp(value, width=32): - # pretty print binary value, with 0b, groupped by nibbles + # pretty print binary value, groupped by bytes if isinstance(value, str): value = frombits(value) - return f"{value:#0{width}_b}" + s = f"{value:0{width}b}" + byte_chunks = [s[i:i+8] for i in range(0, len(s), 8)] + return "0b " + " ".join(byte_chunks) def extract_ecc_data(data_width, codeword_width, codeword_bits): From 3c0fdf07104c30cc961f89e97fd5462c4a82638c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Fri, 20 Mar 2020 13:19:16 +0100 Subject: [PATCH 3/5] test: handle 'we' in DRAMMemory, add memory debug messages --- test/common.py | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/test/common.py b/test/common.py index 9fd8630..37eaa81 100644 --- a/test/common.py +++ b/test/common.py @@ -3,7 +3,9 @@ # This file is Copyright (c) 2020 Antmicro # License: BSD +import os import random +from operator import or_ from migen import * @@ -32,9 +34,34 @@ class DRAMMemory: for _ in range(depth-len(init)): self.mem.append(0) + # "W" enables write msgs, "R" - read msgs and "1" both + self._debug = os.environ.get("DRAM_MEM_DEBUG", "0") + def show_content(self): for addr in range(self.depth): - print("0x{:08x}: 0x{:08x}".format(addr, self.mem[addr])) + print("0x{:08x}: 0x{:0{dwidth}x}".format(addr, self.mem[addr], dwidth=self.width//4)) + + def _warn(self, address): + if address > self.depth * self.width: + print("! adr > 0x{:08x}".format( + self.depth * self.width)) + + def _write(self, address, data, we): + mask = reduce(or_, [0xff << (8 * bit) for bit in range(self.width//8) + if (we & (1 << bit)) != 0], 0) + data = data & mask + self.mem[address%self.depth] = data + if self._debug in ["1", "W"]: + print("W 0x{:08x}: 0x{:0{dwidth}x}".format(address, self.mem[address%self.depth], + dwidth=self.width//4)) + self._warn(address) + + def _read(self, address): + if self._debug in ["1", "R"]: + print("R 0x{:08x}: 0x{:0{dwidth}x}".format(address, self.mem[address%self.depth], + dwidth=self.width//4)) + self._warn(address) + return self.mem[address%self.depth] @passive def read_handler(self, dram_port, rdata_valid_random=0): @@ -48,7 +75,7 @@ class DRAMMemory: while prng.randrange(100) < rdata_valid_random: yield yield dram_port.rdata.valid.eq(1) - yield dram_port.rdata.data.eq(self.mem[address%self.depth]) + yield dram_port.rdata.data.eq(self._read(address)) yield yield dram_port.rdata.valid.eq(0) yield dram_port.rdata.data.eq(0) @@ -77,7 +104,7 @@ class DRAMMemory: yield yield dram_port.wdata.ready.eq(1) yield - self.mem[address%self.depth] = (yield dram_port.wdata.data) # TODO manage we + self._write(address, (yield dram_port.wdata.data), (yield dram_port.wdata.we)) yield dram_port.wdata.ready.eq(0) yield pending = 0 From 7996ee514379789ebaadfa3030ca4274c0d3d943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Fri, 20 Mar 2020 14:46:18 +0100 Subject: [PATCH 4/5] test: add missing write-enable handling --- test/test_adaptation.py | 2 ++ test/test_axi.py | 1 + 2 files changed, 3 insertions(+) diff --git a/test/test_adaptation.py b/test/test_adaptation.py index 4b70b6c..4a41419 100644 --- a/test/test_adaptation.py +++ b/test/test_adaptation.py @@ -62,6 +62,7 @@ class TestAdaptation(unittest.TestCase): yield yield write_port.wdata.valid.eq(1) yield write_port.wdata.data.eq(write_data[i]) + yield write_port.wdata.we.eq(0b1111) yield while (yield write_port.wdata.ready) == 0: yield @@ -113,6 +114,7 @@ class TestAdaptation(unittest.TestCase): yield write_port.cmd.addr.eq(i) yield write_port.wdata.valid.eq(1) yield write_port.wdata.data.eq(write_data[i]) + yield write_port.wdata.we.eq(0xff) yield while (yield write_port.cmd.ready) == 0: yield diff --git a/test/test_axi.py b/test/test_axi.py index 91215a5..1f141f8 100644 --- a/test/test_axi.py +++ b/test/test_axi.py @@ -104,6 +104,7 @@ class TestAXI(unittest.TestCase): else: yield axi_port.w.last.eq(0) yield axi_port.w.data.eq(data) + yield axi_port.w.strb.eq(2**axi_port.w.strb.nbits - 1) yield while (yield axi_port.w.ready) == 0: yield From f19d92b67f3426608a698d3fd6407720147bf7d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Fri, 20 Mar 2020 14:15:33 +0100 Subject: [PATCH 5/5] test: add wishbone tests with data width mismatch --- test/common.py | 63 ++++++++++++++++++++++++++++++++++++ test/test_wishbone.py | 75 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 125 insertions(+), 13 deletions(-) diff --git a/test/common.py b/test/common.py index 37eaa81..fab3a70 100644 --- a/test/common.py +++ b/test/common.py @@ -248,6 +248,69 @@ class MemoryTestDataMixin: 0xdeadc0debaadbeef, # 0x38 ], ), + "64bit_to_32bit": dict( + pattern=[ + # address, data + (0x00, 0x0d15ea5e00facade), + (0x05, 0xabadcafe8badf00d), + (0x01, 0xcafefeedbaadf00d), + (0x02, 0xfee1deaddeadc0de), + ], + expected=[ + # data, word, address + 0x00facade, # 0 0x00 + 0x0d15ea5e, # 1 0x04 + 0xbaadf00d, # 2 0x08 + 0xcafefeed, # 3 0x0c + 0xdeadc0de, # 4 0x10 + 0xfee1dead, # 5 0x14 + 0x00000000, # 6 0x18 + 0x00000000, # 7 0x1c + 0x00000000, # 8 0x20 + 0x00000000, # 9 0x24 + 0x8badf00d, # 10 0x28 + 0xabadcafe, # 11 0x2c + 0x00000000, # 12 0x30 + ] + ), + "32bit_to_8bit": dict( + pattern=[ + # address, data + (0x00, 0x00112233), + (0x05, 0x44556677), + (0x01, 0x8899aabb), + (0x02, 0xccddeeff), + ], + expected=[ + # data, address + 0x33, # 0x00 + 0x22, # 0x01 + 0x11, # 0x02 + 0x00, # 0x03 + 0xbb, # 0x04 + 0xaa, # 0x05 + 0x99, # 0x06 + 0x88, # 0x07 + 0xff, # 0x08 + 0xee, # 0x09 + 0xdd, # 0x0a + 0xcc, # 0x0b + 0x00, # 0x0c + 0x00, # 0x0d + 0x00, # 0x0e + 0x00, # 0x0f + 0x00, # 0x10 + 0x00, # 0x11 + 0x00, # 0x12 + 0x00, # 0x13 + 0x77, # 0x14 + 0x66, # 0x15 + 0x55, # 0x16 + 0x44, # 0x17 + 0x00, # 0x18 + 0x00, # 0x19 + ] + ), "32bit_not_aligned": dict( pattern=[ # address, data diff --git a/test/test_wishbone.py b/test/test_wishbone.py index 33528fa..f8df2e6 100644 --- a/test/test_wishbone.py +++ b/test/test_wishbone.py @@ -10,23 +10,24 @@ from litex.soc.interconnect import wishbone from litedram.frontend.wishbone import LiteDRAMWishbone2Native from litedram.common import LiteDRAMNativePort -from test.common import DRAMMemory, seed_to_data +from test.common import DRAMMemory, MemoryTestDataMixin -class TestWishbone(unittest.TestCase): +class TestWishbone(MemoryTestDataMixin, unittest.TestCase): def test_wishbone_data_width_not_smaller(self): with self.assertRaises(AssertionError): wb = wishbone.Interface(data_width=32) port = LiteDRAMNativePort("both", address_width=32, data_width=wb.data_width * 2) LiteDRAMWishbone2Native(wb, port) - def wishbone_readback_test(self, pattern, wishbone, port, mem_depth=64, **kwargs): + def wishbone_readback_test(self, pattern, mem_expected, wishbone, port, base_address=0): class DUT(Module): def __init__(self): self.port = port self.wb = wishbone - self.submodules += LiteDRAMWishbone2Native(self.wb, self.port, **kwargs) - self.mem = DRAMMemory(port.data_width, mem_depth) + self.submodules += LiteDRAMWishbone2Native(self.wb, self.port, + base_address=base_address) + self.mem = DRAMMemory(port.data_width, len(mem_expected)) def main_generator(dut): for adr, data in pattern: @@ -41,14 +42,62 @@ class TestWishbone(unittest.TestCase): dut.mem.read_handler(dut.port), ] run_simulation(dut, generators) - - mem_expected = [0] * mem_depth - for adr, data in pattern: - mem_expected[adr] = data self.assertEqual(dut.mem.mem, mem_expected) - def test_wishbone(self): - pattern = [(adr, seed_to_data(adr, nbits=32)) for adr in range(16)] - wb = wishbone.Interface(data_width=32, adr_width=30) + def test_wishbone_8bit(self): + data = self.pattern_test_data["8bit"] + wb = wishbone.Interface(adr_width=30, data_width=8) + port = LiteDRAMNativePort("both", address_width=30, data_width=8) + self.wishbone_readback_test(data["pattern"], data["expected"], wb, port) + + def test_wishbone_32bit(self): + data = self.pattern_test_data["32bit"] + wb = wishbone.Interface(adr_width=30, data_width=32) port = LiteDRAMNativePort("both", address_width=30, data_width=32) - self.wishbone_readback_test(pattern, wb, port) + self.wishbone_readback_test(data["pattern"], data["expected"], wb, port) + + def test_wishbone_64bit(self): + data = self.pattern_test_data["64bit"] + wb = wishbone.Interface(adr_width=30, data_width=64) + port = LiteDRAMNativePort("both", address_width=30, data_width=64) + self.wishbone_readback_test(data["pattern"], data["expected"], wb, port) + + def test_wishbone_64bit_to_32bit(self): + data = self.pattern_test_data["64bit_to_32bit"] + wb = wishbone.Interface(adr_width=30, data_width=64) + port = LiteDRAMNativePort("both", address_width=30, data_width=32) + self.wishbone_readback_test(data["pattern"], data["expected"], wb, port) + + def test_wishbone_32bit_to_8bit(self): + data = self.pattern_test_data["32bit_to_8bit"] + wb = wishbone.Interface(adr_width=30, data_width=32) + port = LiteDRAMNativePort("both", address_width=30, data_width=8) + self.wishbone_readback_test(data["pattern"], data["expected"], wb, port) + + def test_wishbone_32bit_base_address(self): + data = self.pattern_test_data["32bit"] + wb = wishbone.Interface(adr_width=30, data_width=32) + port = LiteDRAMNativePort("both", address_width=30, data_width=32) + origin = 0x10000000 + # add offset (in data words) + pattern = [(adr + origin//(32//8), data) for adr, data in data["pattern"]] + self.wishbone_readback_test(pattern, data["expected"], wb, port, + base_address=origin) + + def test_wishbone_64bit_to_32bit_base_address(self): + data = self.pattern_test_data["64bit_to_32bit"] + wb = wishbone.Interface(adr_width=30, data_width=64) + port = LiteDRAMNativePort("both", address_width=30, data_width=32) + origin = 0x10000000 + pattern = [(adr + origin//(64//8), data) for adr, data in data["pattern"]] + self.wishbone_readback_test(pattern, data["expected"], wb, port, + base_address=origin) + + def test_wishbone_32bit_to_8bit_base_address(self): + data = self.pattern_test_data["32bit_to_8bit"] + wb = wishbone.Interface(adr_width=30, data_width=32) + port = LiteDRAMNativePort("both", address_width=30, data_width=8) + origin = 0x10000000 + pattern = [(adr + origin//(32//8), data) for adr, data in data["pattern"]] + self.wishbone_readback_test(pattern, data["expected"], wb, port, + base_address=origin)