From edd00310c4e357c4f2d0eb16fd0bbe052e37fb1d Mon Sep 17 00:00:00 2001 From: Fischer Moseley <42497969+fischermoseley@users.noreply.github.com> Date: Sun, 14 Jan 2024 14:49:02 -0800 Subject: [PATCH] first pass at logic analyzer trigger block tests --- src/manta/logic_analyzer/__init__.py | 6 +- src/manta/logic_analyzer/trigger_block.py | 4 +- test/logic_analyzer_trig_blk_sim.py | 181 ++++++++++++++++++++++ 3 files changed, 186 insertions(+), 5 deletions(-) create mode 100644 test/logic_analyzer_trig_blk_sim.py diff --git a/src/manta/logic_analyzer/__init__.py b/src/manta/logic_analyzer/__init__.py index ffce911..bfbf295 100644 --- a/src/manta/logic_analyzer/__init__.py +++ b/src/manta/logic_analyzer/__init__.py @@ -92,10 +92,10 @@ class LogicAnalyzerCore(Elaboratable): ) # Check triggers - if (trigger_mode) and (trigger_mode != "immediate"): - if ("triggers" not in config) or (config["triggers"] == 0): + if trigger_mode and trigger_mode != "immediate": + if "triggers" not in config or config["triggers"] == 0: raise ValueError( - "Logic Analyzer must have at least one trigger specified." + "Logic Analyzer must have at least one trigger specified if not running in immediate mode." ) # Check trigger location diff --git a/src/manta/logic_analyzer/trigger_block.py b/src/manta/logic_analyzer/trigger_block.py index 0591e2e..7dca023 100644 --- a/src/manta/logic_analyzer/trigger_block.py +++ b/src/manta/logic_analyzer/trigger_block.py @@ -101,10 +101,10 @@ class LogicAnalyzerTrigger(Elaboratable): m.d.comb += self.triggered.eq(0) with m.Elif(self.op == self.operations["RISING"]): - m.d.comb += self.triggered.eq((self.signal) & (~prev)) + m.d.comb += self.triggered.eq(self.signal > prev) with m.Elif(self.op == self.operations["FALLING"]): - m.d.comb += self.triggered.eq((~self.signal) & (prev)) + m.d.comb += self.triggered.eq(self.signal < prev) with m.Elif(self.op == self.operations["CHANGING"]): m.d.comb += self.triggered.eq(self.signal != prev) diff --git a/test/logic_analyzer_trig_blk_sim.py b/test/logic_analyzer_trig_blk_sim.py new file mode 100644 index 0000000..910bfa6 --- /dev/null +++ b/test/logic_analyzer_trig_blk_sim.py @@ -0,0 +1,181 @@ +from amaranth import * +from amaranth.sim import Simulator +from manta.logic_analyzer import LogicAnalyzerTriggerBlock +from manta.utils import * +from random import randint, sample + + +# Make random number of random width probes +probes = [Signal(randint(1, 32), name=str(i)) for i in range(randint(1, 32))] +trig_blk = LogicAnalyzerTriggerBlock(probes, base_addr=0, interface=None) + + +def write_trig_blk_register(name, value): + strobe_addr = trig_blk.r.base_addr + yield from write_register(trig_blk, strobe_addr, 0) + + addrs = trig_blk.r.mmap[f"{name}_buf"]["addrs"] + datas = value_to_words(value, len(addrs)) + for addr, data in zip(addrs, datas): + yield from write_register(trig_blk, addr, data) + + yield from write_register(trig_blk, strobe_addr, 1) + yield from write_register(trig_blk, strobe_addr, 0) + + +def test(): + def testbench(): + # Step through each probe and perform all functions in random order + for p in trig_blk.probes: + ops = trig_blk.triggers[0].operations + for op in sample(list(ops.keys()), len(ops)): + # Program operation register with selected register + yield from write_trig_blk_register(f"{p.name}_op", ops[op]) + + if op == "DISABLE": + # Argument can be anything, since it's not used for this operation + yield from write_trig_blk_register( + f"{p.name}_arg", randint(0, (2**p.width) - 1) + ) + yield p.eq(randint(0, (2**p.width) - 1)) + yield + + if (yield trig_blk.trig): + raise ValueError("Trigger raised when disabled!") + + if op == "RISING": + # Argument can be anything, since it's not used for this operation + yield from write_trig_blk_register( + f"{p.name}_arg", randint(0, (2**p.width) - 1) + ) + yield p.eq(0) + yield + yield p.eq(randint(1, (2**p.width) - 1)) + yield + + if not (yield trig_blk.trig): + raise ValueError(f"Trigger not raised on probe {p.name}!") + + if op == "FALLING": + # Argument can be anything, since it's not used for this operation + yield from write_trig_blk_register( + f"{p.name}_arg", randint(0, (2**p.width) - 1) + ) + yield p.eq(randint(1, (2**p.width) - 1)) + yield + yield p.eq(0) + yield + + if not (yield trig_blk.trig): + raise ValueError(f"Trigger not raised on probe {p.name}!") + pass + + if op == "CHANGING": + # Argument can be anything, since it's not used for this operation + yield from write_trig_blk_register( + f"{p.name}_arg", randint(0, (2**p.width) - 1) + ) + yield p.eq(randint(1, (2**p.width) - 1)) + yield + + if not (yield trig_blk.trig): + raise ValueError(f"Trigger not raised on probe {p.name}!") + pass + + if op == "GT": + upper = randint(1, (2**p.width) - 1) + lower = randint(0, upper - 1) + + yield from write_trig_blk_register(f"{p.name}_arg", lower) + yield p.eq(upper) + yield + + if not (yield trig_blk.trig): + raise ValueError(f"Trigger not raised on probe {p.name}!") + pass + + if op == "LT": + upper = randint(1, (2**p.width) - 1) + lower = randint(0, upper - 1) + + yield from write_trig_blk_register(f"{p.name}_arg", upper) + yield p.eq(lower) + yield + + if not (yield trig_blk.trig): + raise ValueError(f"Trigger not raised on probe {p.name}!") + pass + + if op == "GEQ": + upper = randint(1, (2**p.width) - 1) + lower = randint(0, upper - 1) + + # test that the case where it's equal + yield from write_trig_blk_register(f"{p.name}_arg", lower) + yield p.eq(lower) + yield + + if not (yield trig_blk.trig): + raise ValueError(f"Trigger not raised on probe {p.name}!") + pass + + # test the case where it's greater than + yield p.eq(upper) + yield + + if not (yield trig_blk.trig): + raise ValueError(f"Trigger not raised on probe {p.name}!") + pass + + if op == "LEQ": + upper = randint(1, (2**p.width) - 1) + lower = randint(0, upper - 1) + + # test that the case where it's equal + yield from write_trig_blk_register(f"{p.name}_arg", upper) + yield p.eq(upper) + yield + + if not (yield trig_blk.trig): + raise ValueError(f"Trigger not raised on probe {p.name}!") + pass + + # test the case where it's less than + yield p.eq(lower) + yield + + if not (yield trig_blk.trig): + raise ValueError(f"Trigger not raised on probe {p.name}!") + pass + + if op == "EQ": + value = randint(0, (2**p.width) - 1) + yield from write_trig_blk_register(f"{p.name}_arg", value) + yield p.eq(value) + yield + + if not (yield trig_blk.trig): + raise ValueError(f"Trigger not raised on probe {p.name}!") + pass + + if op == "NEQ": + upper = randint(1, (2**p.width) - 1) + lower = randint(0, upper - 1) + + # test that the case where it's equal + yield from write_trig_blk_register(f"{p.name}_arg", upper) + yield p.eq(lower) + yield + + if not (yield trig_blk.trig): + raise ValueError(f"Trigger not raised on probe {p.name}!") + pass + + + # disable probe once complete + yield + yield from write_trig_blk_register(f"{p.name}_op", ops["DISABLE"]) + yield from write_trig_blk_register(f"{p.name}_arg", 0) + yield p.eq(0) + + simulate(trig_blk, testbench, "out.vcd")