Merge pull request #169 from antmicro/jboc/unit-tests

Add LiteDRAMWishbone2Native tests
This commit is contained in:
enjoy-digital 2020-03-21 19:12:45 +01:00 committed by GitHub
commit ebdbcacc1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 203 additions and 5 deletions

View File

@ -3,7 +3,9 @@
# This file is Copyright (c) 2020 Antmicro <www.antmicro.com>
# 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
@ -221,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

View File

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

View File

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

View File

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

103
test/test_wishbone.py Normal file
View File

@ -0,0 +1,103 @@
# This file is Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
# 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, MemoryTestDataMixin
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, 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,
base_address=base_address)
self.mem = DRAMMemory(port.data_width, len(mem_expected))
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)
self.assertEqual(dut.mem.mem, mem_expected)
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(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)