mirror of
https://github.com/enjoy-digital/litedram.git
synced 2025-01-04 09:52:25 -05:00
test/test_bist: add generator test, remove async test
This commit is contained in:
parent
7677a853f1
commit
6a46ea3052
4 changed files with 102 additions and 168 deletions
|
@ -72,26 +72,3 @@ class DRAMMemory:
|
||||||
yield
|
yield
|
||||||
yield dram_port.cmd.ready.eq(0)
|
yield dram_port.cmd.ready.eq(0)
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
class BISTDriver:
|
|
||||||
def __init__(self, module):
|
|
||||||
self.module = module
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
yield self.module.reset.eq(1)
|
|
||||||
yield
|
|
||||||
yield self.module.reset.eq(0)
|
|
||||||
yield
|
|
||||||
|
|
||||||
def run(self, base, length):
|
|
||||||
yield self.module.base.eq(base)
|
|
||||||
yield self.module.length.eq(length)
|
|
||||||
yield self.module.start.eq(1)
|
|
||||||
yield
|
|
||||||
yield self.module.start.eq(0)
|
|
||||||
yield
|
|
||||||
while((yield self.module.done) == 0):
|
|
||||||
yield
|
|
||||||
if hasattr(self.module, "errors"):
|
|
||||||
self.errors = (yield self.module.errors)
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ class TestAXI(unittest.TestCase):
|
||||||
if ax_addr != beat.addr:
|
if ax_addr != beat.addr:
|
||||||
self.errors += 1
|
self.errors += 1
|
||||||
yield
|
yield
|
||||||
|
|
||||||
# dut
|
# dut
|
||||||
ax_burst = stream.Endpoint(ax_description(32, 32))
|
ax_burst = stream.Endpoint(ax_description(32, 32))
|
||||||
ax_beat = stream.Endpoint(ax_description(32, 32))
|
ax_beat = stream.Endpoint(ax_description(32, 32))
|
||||||
|
@ -135,7 +135,7 @@ class TestAXI(unittest.TestCase):
|
||||||
for i in range(32):
|
for i in range(32):
|
||||||
bursts.append(Burst(burst_types["fixed"], prng.randrange(2**32), prng.randrange(256), log2_int(32//8)))
|
bursts.append(Burst(burst_types["fixed"], prng.randrange(2**32), prng.randrange(256), log2_int(32//8)))
|
||||||
bursts.append(Burst(burst_types["incr"], prng.randrange(2**32), prng.randrange(256), log2_int(32//8)))
|
bursts.append(Burst(burst_types["incr"], prng.randrange(2**32), prng.randrange(256), log2_int(32//8)))
|
||||||
|
|
||||||
# generate expexted dut output (beats for reference)
|
# generate expexted dut output (beats for reference)
|
||||||
beats = []
|
beats = []
|
||||||
for burst in bursts:
|
for burst in bursts:
|
||||||
|
|
|
@ -5,7 +5,8 @@ from migen import *
|
||||||
|
|
||||||
from litex.soc.interconnect.stream import *
|
from litex.soc.interconnect.stream import *
|
||||||
|
|
||||||
from litedram.common import LiteDRAMWritePort, LiteDRAMReadPort
|
from litedram.common import *
|
||||||
|
from litedram.frontend.bist import *
|
||||||
from litedram.frontend.bist import _LiteDRAMBISTGenerator
|
from litedram.frontend.bist import _LiteDRAMBISTGenerator
|
||||||
from litedram.frontend.bist import _LiteDRAMBISTChecker
|
from litedram.frontend.bist import _LiteDRAMBISTChecker
|
||||||
|
|
||||||
|
@ -14,52 +15,108 @@ from test.common import *
|
||||||
from litex.gen.sim import *
|
from litex.gen.sim import *
|
||||||
|
|
||||||
|
|
||||||
class DUT(Module):
|
class GenCheckDriver:
|
||||||
def __init__(self):
|
def __init__(self, module):
|
||||||
self.write_port = LiteDRAMWritePort(aw=32, dw=32)
|
self.module = module
|
||||||
self.read_port = LiteDRAMReadPort(aw=32, dw=32)
|
|
||||||
self.submodules.generator = _LiteDRAMBISTGenerator(self.write_port, True)
|
|
||||||
self.submodules.checker = _LiteDRAMBISTChecker(self.read_port, True)
|
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
yield self.module.reset.eq(1)
|
||||||
|
yield
|
||||||
|
yield self.module.reset.eq(0)
|
||||||
|
yield
|
||||||
|
|
||||||
def main_generator(dut, mem):
|
def run(self, base, length):
|
||||||
generator = BISTDriver(dut.generator)
|
yield self.module.base.eq(base)
|
||||||
checker = BISTDriver(dut.checker)
|
yield self.module.length.eq(length)
|
||||||
|
yield self.module.start.eq(1)
|
||||||
# write
|
yield
|
||||||
yield from generator.reset()
|
yield self.module.start.eq(0)
|
||||||
yield from generator.run(16, 64)
|
yield
|
||||||
|
while((yield self.module.done) == 0):
|
||||||
# read (no errors)
|
yield
|
||||||
yield from checker.reset()
|
if hasattr(self.module, "errors"):
|
||||||
yield from checker.run(16, 64)
|
self.errors = (yield self.module.errors)
|
||||||
assert checker.errors == 0
|
|
||||||
|
|
||||||
# corrupt memory (using generator)
|
|
||||||
yield from generator.reset()
|
|
||||||
yield from generator.run(16 + 60, 64)
|
|
||||||
|
|
||||||
# read (4 errors)
|
|
||||||
yield from checker.reset()
|
|
||||||
yield from checker.run(16, 64)
|
|
||||||
assert checker.errors != 0
|
|
||||||
|
|
||||||
# read (no errors)
|
|
||||||
yield from checker.reset()
|
|
||||||
yield from checker.run(16 + 60, 64)
|
|
||||||
assert checker.errors == 0
|
|
||||||
|
|
||||||
|
|
||||||
class TestBIST(unittest.TestCase):
|
class TestBIST(unittest.TestCase):
|
||||||
def test(self):
|
def test_generator(self):
|
||||||
|
port = LiteDRAMNativeWritePort(address_width=32, data_width=32)
|
||||||
|
|
||||||
|
def main_generator(dut):
|
||||||
|
self.errors = 0
|
||||||
|
|
||||||
|
# test incr
|
||||||
|
yield dut.ce.eq(1)
|
||||||
|
yield dut.random_enable.eq(0)
|
||||||
|
yield
|
||||||
|
for i in range(1024):
|
||||||
|
data = (yield dut.o)
|
||||||
|
if data != i:
|
||||||
|
self.errors += 1
|
||||||
|
yield
|
||||||
|
|
||||||
|
# test random
|
||||||
|
datas = []
|
||||||
|
yield dut.ce.eq(1)
|
||||||
|
yield dut.random_enable.eq(1)
|
||||||
|
for i in range(1024):
|
||||||
|
data = (yield dut.o)
|
||||||
|
if data in datas:
|
||||||
|
self.errors += 1
|
||||||
|
datas.append(data)
|
||||||
|
yield
|
||||||
|
|
||||||
|
# dut
|
||||||
|
dut = Generator(23, n_state=23, taps=[17, 22])
|
||||||
|
|
||||||
|
# simulation
|
||||||
|
generators = [main_generator(dut)]
|
||||||
|
run_simulation(dut, main_generator(dut), vcd_name="generator.vcd")
|
||||||
|
self.assertEqual(self.errors, 0)
|
||||||
|
|
||||||
|
def test_bist(self):
|
||||||
|
class DUT(Module):
|
||||||
|
def __init__(self):
|
||||||
|
self.write_port = LiteDRAMNativeWritePort(address_width=32, data_width=32)
|
||||||
|
self.read_port = LiteDRAMNativeReadPort(address_width=32, data_width=32)
|
||||||
|
self.submodules.generator = _LiteDRAMBISTGenerator(self.write_port)
|
||||||
|
self.submodules.checker = _LiteDRAMBISTChecker(self.read_port)
|
||||||
|
|
||||||
|
def main_generator(dut, mem):
|
||||||
|
generator = GenCheckDriver(dut.generator)
|
||||||
|
checker = GenCheckDriver(dut.checker)
|
||||||
|
|
||||||
|
# write
|
||||||
|
yield from generator.reset()
|
||||||
|
yield from generator.run(16, 64)
|
||||||
|
|
||||||
|
# read (no errors)
|
||||||
|
yield from checker.reset()
|
||||||
|
yield from checker.run(16, 64)
|
||||||
|
assert checker.errors == 0
|
||||||
|
|
||||||
|
# corrupt memory (using generator)
|
||||||
|
yield from generator.reset()
|
||||||
|
yield from generator.run(16 + 60, 64)
|
||||||
|
|
||||||
|
# read (4 errors)
|
||||||
|
yield from checker.reset()
|
||||||
|
yield from checker.run(16, 64)
|
||||||
|
assert checker.errors != 0
|
||||||
|
|
||||||
|
# read (no errors)
|
||||||
|
yield from checker.reset()
|
||||||
|
yield from checker.run(16 + 60, 64)
|
||||||
|
assert checker.errors == 0
|
||||||
|
|
||||||
|
# dut
|
||||||
dut = DUT()
|
dut = DUT()
|
||||||
mem = DRAMMemory(32, 128)
|
mem = DRAMMemory(32, 128)
|
||||||
generators = {
|
|
||||||
"sys" : [
|
# simulation
|
||||||
main_generator(dut, mem),
|
generators = [
|
||||||
mem.write_generator(dut.write_port),
|
main_generator(dut, mem),
|
||||||
mem.read_generator(dut.read_port)
|
mem.write_generator(dut.write_port),
|
||||||
]
|
mem.read_generator(dut.read_port)
|
||||||
}
|
]
|
||||||
clocks = {"sys": 10}
|
run_simulation(dut, generators, vcd_name="bist.vcd")
|
||||||
run_simulation(dut, generators, clocks, vcd_name="sim.vcd")
|
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
from migen import *
|
|
||||||
|
|
||||||
from litex.soc.interconnect.stream import *
|
|
||||||
|
|
||||||
from litedram.common import PhySettings, LiteDRAMNativePort
|
|
||||||
from litedram.core import *
|
|
||||||
from litedram.modules import SDRAMModule
|
|
||||||
from litedram.frontend.crossbar import LiteDRAMCrossbar
|
|
||||||
from litedram.frontend.bist import _LiteDRAMBISTGenerator
|
|
||||||
from litedram.frontend.bist import _LiteDRAMBISTChecker
|
|
||||||
from litedram.frontend.adaptation import LiteDRAMNativePortCDC
|
|
||||||
|
|
||||||
from litedram.phy.model import SDRAMPHYModel
|
|
||||||
|
|
||||||
from test.common import *
|
|
||||||
|
|
||||||
from litex.gen.sim import *
|
|
||||||
|
|
||||||
|
|
||||||
class SimModule(SDRAMModule):
|
|
||||||
# geometry
|
|
||||||
nbanks = 2
|
|
||||||
nrows = 2048
|
|
||||||
ncols = 2
|
|
||||||
# timings
|
|
||||||
tRP = 1
|
|
||||||
tRCD = 1
|
|
||||||
tWR = 1
|
|
||||||
tWTR = (1, None)
|
|
||||||
tREFI = 1
|
|
||||||
tRFC = 1
|
|
||||||
|
|
||||||
|
|
||||||
class TB(Module):
|
|
||||||
def __init__(self):
|
|
||||||
# phy
|
|
||||||
sdram_module = SimModule(1000, "1:1")
|
|
||||||
phy_settings = PhySettings(
|
|
||||||
memtype="SDR",
|
|
||||||
dfi_databits=1*16,
|
|
||||||
nphases=1,
|
|
||||||
rdphase=0,
|
|
||||||
wrphase=0,
|
|
||||||
rdcmdphase=0,
|
|
||||||
wrcmdphase=0,
|
|
||||||
cl=2,
|
|
||||||
read_latency=4,
|
|
||||||
write_latency=0
|
|
||||||
)
|
|
||||||
self.submodules.sdrphy = SDRAMPHYModel(sdram_module,
|
|
||||||
phy_settings,
|
|
||||||
we_granularity=0)
|
|
||||||
|
|
||||||
# controller
|
|
||||||
self.submodules.controller = LiteDRAMController(
|
|
||||||
phy_settings,
|
|
||||||
sdram_module.geom_settings,
|
|
||||||
sdram_module.timing_settings,
|
|
||||||
ControllerSettings(with_refresh=False))
|
|
||||||
self.comb += self.controller.dfi.connect(self.sdrphy.dfi)
|
|
||||||
self.submodules.crossbar = LiteDRAMCrossbar(self.controller.interface,
|
|
||||||
self.controller.nrowbits)
|
|
||||||
|
|
||||||
# ports
|
|
||||||
write_user_port = self.crossbar.get_port("write", cd="write")
|
|
||||||
read_user_port = self.crossbar.get_port("read", cd="read")
|
|
||||||
|
|
||||||
# generator / checker
|
|
||||||
self.submodules.generator = _LiteDRAMBISTGenerator(write_user_port, True)
|
|
||||||
self.submodules.checker = _LiteDRAMBISTChecker(read_user_port, True)
|
|
||||||
|
|
||||||
|
|
||||||
def main_generator(dut):
|
|
||||||
generator = BISTDriver(dut.generator)
|
|
||||||
checker = BISTDriver(dut.checker)
|
|
||||||
|
|
||||||
for i in range(16):
|
|
||||||
yield
|
|
||||||
|
|
||||||
# write
|
|
||||||
yield from generator.reset()
|
|
||||||
yield from generator.run(16, 16)
|
|
||||||
|
|
||||||
# read (no errors)
|
|
||||||
yield from checker.reset()
|
|
||||||
yield from checker.run(16, 16)
|
|
||||||
assert checker.errors == 0
|
|
||||||
|
|
||||||
|
|
||||||
class TestBISTAsync(unittest.TestCase):
|
|
||||||
def test(self):
|
|
||||||
tb = TB()
|
|
||||||
generators = {"sys" : [main_generator(tb)]}
|
|
||||||
clocks = {"sys": 10,
|
|
||||||
"write": 12,
|
|
||||||
"read": 8}
|
|
||||||
run_simulation(tb, generators, clocks, vcd_name="sim.vcd")
|
|
||||||
self.assertEqual(dut.checker.error_count.status, 0)
|
|
Loading…
Reference in a new issue