test: add option to benchmark predefined access patterns

This commit is contained in:
Jędrzej Boczar 2020-02-04 12:34:15 +01:00
parent 4a3ad56146
commit fcbcd4d3fe
2 changed files with 186 additions and 24 deletions

View File

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

View File

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