test: add option to benchmark predefined access patterns
This commit is contained in:
parent
4a3ad56146
commit
fcbcd4d3fe
|
@ -185,6 +185,60 @@ class _LiteDRAMBISTGenerator(Module):
|
|||
raise NotImplementedError
|
||||
self.comb += dma.sink.data.eq(data_gen.o)
|
||||
|
||||
@ResetInserter()
|
||||
class _LiteDRAMPatternGenerator(Module):
|
||||
def __init__(self, dram_port, init=[]):
|
||||
ashift, awidth = get_ashift_awidth(dram_port)
|
||||
self.start = Signal()
|
||||
self.done = Signal()
|
||||
self.ticks = Signal(32)
|
||||
|
||||
# # #
|
||||
|
||||
# DMA --------------------------------------------------------------------------------------
|
||||
dma = LiteDRAMDMAWriter(dram_port)
|
||||
self.submodules += dma
|
||||
|
||||
cmd_counter = Signal(dram_port.address_width, reset_less=True)
|
||||
|
||||
# Data / Address FSM -----------------------------------------------------------------------
|
||||
fsm = FSM(reset_state="IDLE")
|
||||
self.submodules += fsm
|
||||
fsm.act("IDLE",
|
||||
If(self.start,
|
||||
NextValue(cmd_counter, 0),
|
||||
NextState("RUN")
|
||||
),
|
||||
NextValue(self.ticks, 0)
|
||||
)
|
||||
fsm.act("RUN",
|
||||
dma.sink.valid.eq(1),
|
||||
If(dma.sink.ready,
|
||||
NextValue(cmd_counter, cmd_counter + 1),
|
||||
If(cmd_counter == (len(init) - 1),
|
||||
NextState("DONE")
|
||||
)
|
||||
),
|
||||
NextValue(self.ticks, self.ticks + 1)
|
||||
)
|
||||
fsm.act("DONE",
|
||||
self.done.eq(1)
|
||||
)
|
||||
|
||||
if isinstance(dram_port, LiteDRAMNativePort): # addressing in dwords
|
||||
dma_sink_addr = dma.sink.address
|
||||
elif isinstance(dram_port, LiteDRAMAXIPort): # addressing in bytes
|
||||
dma_sink_addr = dma.sink.address[ashift:]
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
addr_cases = {i: dma_sink_addr.eq(addr) for i, (addr, data) in enumerate(init)}
|
||||
data_cases = {i: dma.sink.data.eq(data) for i, (addr, data) in enumerate(init)}
|
||||
self.comb += [
|
||||
Case(cmd_counter, addr_cases),
|
||||
Case(cmd_counter, data_cases),
|
||||
]
|
||||
|
||||
# LiteDRAMBISTGenerator ----------------------------------------------------------------------------
|
||||
|
||||
class LiteDRAMBISTGenerator(Module, AutoCSR):
|
||||
|
@ -367,6 +421,88 @@ class _LiteDRAMBISTChecker(Module, AutoCSR):
|
|||
self.done.eq(1)
|
||||
)
|
||||
|
||||
@ResetInserter()
|
||||
class _LiteDRAMPatternChecker(Module, AutoCSR):
|
||||
def __init__(self, dram_port, init=[]):
|
||||
ashift, awidth = get_ashift_awidth(dram_port)
|
||||
self.start = Signal()
|
||||
self.done = Signal()
|
||||
self.ticks = Signal(32)
|
||||
self.errors = Signal(32)
|
||||
|
||||
# # #
|
||||
|
||||
# DMA --------------------------------------------------------------------------------------
|
||||
dma = LiteDRAMDMAReader(dram_port)
|
||||
self.submodules += dma
|
||||
|
||||
# Address FSM ------------------------------------------------------------------------------
|
||||
cmd_counter = Signal(dram_port.address_width, reset_less=True)
|
||||
|
||||
cmd_fsm = FSM(reset_state="IDLE")
|
||||
self.submodules += cmd_fsm
|
||||
cmd_fsm.act("IDLE",
|
||||
If(self.start,
|
||||
NextValue(cmd_counter, 0),
|
||||
NextState("RUN")
|
||||
)
|
||||
)
|
||||
cmd_fsm.act("RUN",
|
||||
dma.sink.valid.eq(1),
|
||||
If(dma.sink.ready,
|
||||
NextValue(cmd_counter, cmd_counter + 1),
|
||||
If(cmd_counter == (len(init) - 1),
|
||||
NextState("DONE")
|
||||
)
|
||||
)
|
||||
)
|
||||
cmd_fsm.act("DONE")
|
||||
|
||||
if isinstance(dram_port, LiteDRAMNativePort): # addressing in dwords
|
||||
dma_addr_sink = dma.sink.address
|
||||
elif isinstance(dram_port, LiteDRAMAXIPort): # addressing in bytes
|
||||
dma_addr_sink = dma.sink.address[ashift:]
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
addr_cases = {i: dma_addr_sink.eq(addr) for i, (addr, data) in enumerate(init)}
|
||||
self.comb += Case(cmd_counter, addr_cases)
|
||||
|
||||
# Data FSM ---------------------------------------------------------------------------------
|
||||
data_counter = Signal(dram_port.address_width, reset_less=True)
|
||||
|
||||
expected_data = Signal.like(dma.source.data)
|
||||
data_cases = {i: expected_data.eq(data) for i, (addr, data) in enumerate(init)}
|
||||
self.comb += Case(data_counter, data_cases)
|
||||
|
||||
data_fsm = FSM(reset_state="IDLE")
|
||||
self.submodules += data_fsm
|
||||
data_fsm.act("IDLE",
|
||||
If(self.start,
|
||||
NextValue(data_counter, 0),
|
||||
NextValue(self.errors, 0),
|
||||
NextState("RUN")
|
||||
),
|
||||
NextValue(self.ticks, 0)
|
||||
)
|
||||
|
||||
data_fsm.act("RUN",
|
||||
dma.source.ready.eq(1),
|
||||
If(dma.source.valid,
|
||||
NextValue(data_counter, data_counter + 1),
|
||||
If(dma.source.data != expected_data,
|
||||
NextValue(self.errors, self.errors + 1)
|
||||
),
|
||||
If(data_counter == (len(init) - 1),
|
||||
NextState("DONE")
|
||||
)
|
||||
),
|
||||
NextValue(self.ticks, self.ticks + 1)
|
||||
)
|
||||
data_fsm.act("DONE",
|
||||
self.done.eq(1)
|
||||
)
|
||||
|
||||
# LiteDRAMBISTChecker ------------------------------------------------------------------------------
|
||||
|
||||
class LiteDRAMBISTChecker(Module, AutoCSR):
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# License: BSD
|
||||
|
||||
import csv
|
||||
import argparse
|
||||
|
||||
from migen import *
|
||||
|
@ -16,9 +17,8 @@ from litex.soc.integration.builder import *
|
|||
|
||||
from litex.tools.litex_sim import SimSoC
|
||||
|
||||
from litedram.frontend.bist import _LiteDRAMBISTGenerator
|
||||
from litedram.frontend.bist import _LiteDRAMBISTChecker
|
||||
|
||||
from litedram.frontend.bist import _LiteDRAMBISTGenerator, _LiteDRAMBISTChecker, \
|
||||
_LiteDRAMPatternGenerator, _LiteDRAMPatternChecker
|
||||
|
||||
# LiteDRAM Benchmark SoC ---------------------------------------------------------------------------
|
||||
|
||||
|
@ -29,6 +29,7 @@ class LiteDRAMBenchmarkSoC(SimSoC):
|
|||
bist_base = 0x00000000,
|
||||
bist_length = 1024,
|
||||
bist_random = False,
|
||||
pattern_init = None,
|
||||
**kwargs):
|
||||
|
||||
# SimSoC -----------------------------------------------------------------------------------
|
||||
|
@ -42,12 +43,34 @@ class LiteDRAMBenchmarkSoC(SimSoC):
|
|||
# make sure that we perform at least one access
|
||||
bist_length = max(bist_length, self.sdram.controller.interface.data_width // 8)
|
||||
|
||||
# BIST Generator ---------------------------------------------------------------------------
|
||||
bist_generator = _LiteDRAMBISTGenerator(self.sdram.crossbar.get_port())
|
||||
self.submodules.bist_generator = bist_generator
|
||||
# BIST Generator / Checker -----------------------------------------------------------------
|
||||
if pattern_init is None:
|
||||
bist_generator = _LiteDRAMBISTGenerator(self.sdram.crossbar.get_port())
|
||||
bist_checker = _LiteDRAMBISTChecker(self.sdram.crossbar.get_port())
|
||||
|
||||
# BIST Checker -----------------------------------------------------------------------------
|
||||
bist_checker = _LiteDRAMBISTChecker(self.sdram.crossbar.get_port())
|
||||
generator_config = [
|
||||
bist_generator.base.eq(bist_base),
|
||||
bist_generator.length.eq(bist_length),
|
||||
bist_generator.random.eq(bist_random),
|
||||
]
|
||||
checker_config = [
|
||||
bist_checker.base.eq(bist_base),
|
||||
bist_checker.length.eq(bist_length),
|
||||
bist_checker.random.eq(bist_random),
|
||||
]
|
||||
else:
|
||||
# TODO: run checker in parallel to avoid overwriting previously written data
|
||||
address_set = set()
|
||||
for addr, _ in pattern_init:
|
||||
assert addr not in address_set, \
|
||||
'Duplicate address 0x%08x in pattern_init, write will overwrite previous value!' % addr
|
||||
address_set.add(addr)
|
||||
|
||||
bist_generator = _LiteDRAMPatternGenerator(self.sdram.crossbar.get_port(), init=pattern_init)
|
||||
bist_checker = _LiteDRAMPatternChecker(self.sdram.crossbar.get_port(), init=pattern_init)
|
||||
generator_config = checker_config = []
|
||||
|
||||
self.submodules.bist_generator = bist_generator
|
||||
self.submodules.bist_checker = bist_checker
|
||||
|
||||
# Sequencer --------------------------------------------------------------------------------
|
||||
|
@ -68,18 +91,14 @@ class LiteDRAMBenchmarkSoC(SimSoC):
|
|||
)
|
||||
fsm.act("BIST-GENERATOR",
|
||||
bist_generator.start.eq(1),
|
||||
bist_generator.base.eq(bist_base),
|
||||
bist_generator.length.eq(bist_length),
|
||||
bist_generator.random.eq(bist_random),
|
||||
*generator_config,
|
||||
If(bist_generator.done,
|
||||
NextState("BIST-CHECKER")
|
||||
)
|
||||
)
|
||||
fsm.act("BIST-CHECKER",
|
||||
bist_checker.start.eq(1),
|
||||
bist_checker.base.eq(bist_base),
|
||||
bist_checker.length.eq(bist_length),
|
||||
bist_checker.random.eq(bist_random),
|
||||
*checker_config,
|
||||
If(bist_checker.done,
|
||||
NextState("DISPLAY")
|
||||
)
|
||||
|
@ -113,16 +132,17 @@ def main():
|
|||
parser = argparse.ArgumentParser(description="LiteDRAM Benchmark SoC Simulation")
|
||||
builder_args(parser)
|
||||
soc_sdram_args(parser)
|
||||
parser.add_argument("--threads", default=1, help="Set number of threads (default=1)")
|
||||
parser.add_argument("--sdram-module", default="MT48LC16M16", help="Select SDRAM chip")
|
||||
parser.add_argument("--sdram-data-width", default=32, help="Set SDRAM chip data width")
|
||||
parser.add_argument("--trace", action="store_true", help="Enable VCD tracing")
|
||||
parser.add_argument("--trace-start", default=0, help="Cycle to start VCD tracing")
|
||||
parser.add_argument("--trace-end", default=-1, help="Cycle to end VCD tracing")
|
||||
parser.add_argument("--opt-level", default="O0", help="Compilation optimization level")
|
||||
parser.add_argument("--bist-base", default="0x00000000", help="Base address of the test (default=0)")
|
||||
parser.add_argument("--bist-length", default="1024", help="Length of the test (default=1024)")
|
||||
parser.add_argument("--bist-random", action="store_true", help="Use random data during the test")
|
||||
parser.add_argument("--threads", default=1, help="Set number of threads (default=1)")
|
||||
parser.add_argument("--sdram-module", default="MT48LC16M16", help="Select SDRAM chip")
|
||||
parser.add_argument("--sdram-data-width", default=32, help="Set SDRAM chip data width")
|
||||
parser.add_argument("--trace", action="store_true", help="Enable VCD tracing")
|
||||
parser.add_argument("--trace-start", default=0, help="Cycle to start VCD tracing")
|
||||
parser.add_argument("--trace-end", default=-1, help="Cycle to end VCD tracing")
|
||||
parser.add_argument("--opt-level", default="O0", help="Compilation optimization level")
|
||||
parser.add_argument("--bist-base", default="0x00000000", help="Base address of the test (default=0)")
|
||||
parser.add_argument("--bist-length", default="1024", help="Length of the test (default=1024)")
|
||||
parser.add_argument("--bist-random", action="store_true", help="Use random data during the test")
|
||||
parser.add_argument("--access-pattern", help="Load access pattern (address, data) from CSV (ignores --bist-*)")
|
||||
args = parser.parse_args()
|
||||
|
||||
soc_kwargs = soc_sdram_argdict(args)
|
||||
|
@ -138,6 +158,12 @@ def main():
|
|||
soc_kwargs["bist_length"] = int(args.bist_length, 0)
|
||||
soc_kwargs["bist_random"] = args.bist_random
|
||||
|
||||
if args.access_pattern:
|
||||
with open(args.access_pattern, newline='') as f:
|
||||
reader = csv.reader(f)
|
||||
pattern_init = [(int(addr, 0), int(data, 0)) for addr, data in reader]
|
||||
soc_kwargs["pattern_init"] = pattern_init
|
||||
|
||||
# SoC ------------------------------------------------------------------------------------------
|
||||
soc = LiteDRAMBenchmarkSoC(**soc_kwargs)
|
||||
|
||||
|
|
Loading…
Reference in New Issue