From eebffc15d6d35c08acae67475072caac7215adef Mon Sep 17 00:00:00 2001 From: Wanda Date: Fri, 12 Apr 2024 21:14:53 +0200 Subject: [PATCH] sim: add `eval_format` function. This will be used in an upcoming PR for VCD output. --- amaranth/sim/_pyeval.py | 27 ++++++++++++++++++++++++++ amaranth/sim/_pyrtl.py | 12 +----------- tests/test_sim.py | 42 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 13 deletions(-) diff --git a/amaranth/sim/_pyeval.py b/amaranth/sim/_pyeval.py index 32a4d0a..10ecb64 100644 --- a/amaranth/sim/_pyeval.py +++ b/amaranth/sim/_pyeval.py @@ -128,6 +128,33 @@ def eval_value(sim, value): assert False # :nocov: +def value_to_string(value): + """Unpack a Verilog-like (but LSB-first) string of unknown width from an integer.""" + msg = bytearray() + while value: + byte = value & 0xff + value >>= 8 + if byte: + msg.append(byte) + return msg.decode() + + +def eval_format(sim, fmt): + fmt = Format("{}", fmt) + chunks = [] + for chunk in fmt._chunks: + if isinstance(chunk, str): + chunks.append(chunk) + else: + value, spec = chunk + value = eval_value(sim, value) + if spec.endswith("s"): + chunks.append(format(value_to_string(value), spec[:-1])) + else: + chunks.append(format(value, spec)) + return "".join(chunks) + + def _eval_assign_inner(sim, lhs, lhs_start, rhs, rhs_len): if isinstance(lhs, Operator) and lhs.operator in ("u", "s"): _eval_assign_inner(sim, lhs.operands[0], lhs_start, rhs, rhs_len) diff --git a/amaranth/sim/_pyrtl.py b/amaranth/sim/_pyrtl.py index 5505cfb..0483dfa 100644 --- a/amaranth/sim/_pyrtl.py +++ b/amaranth/sim/_pyrtl.py @@ -8,6 +8,7 @@ from ..hdl._ast import SignalSet, _StatementList, Property from ..hdl._xfrm import ValueVisitor, StatementVisitor from ..hdl._mem import MemoryInstance from ._base import BaseProcess +from ._pyeval import value_to_string __all__ = ["PyRTLProcess"] @@ -356,17 +357,6 @@ class _LHSValueCompiler(_ValueCompiler): return gen -def value_to_string(value): - """Unpack a Verilog-like (but LSB-first) string of unknown width from an integer.""" - msg = bytearray() - while value: - byte = value & 0xff - value >>= 8 - if byte: - msg.append(byte) - return msg.decode() - - def pin_blame(src_loc, exc): if src_loc is None: raise exc diff --git a/tests/test_sim.py b/tests/test_sim.py index 3bb52b6..6e43011 100644 --- a/tests/test_sim.py +++ b/tests/test_sim.py @@ -13,9 +13,9 @@ with warnings.catch_warnings(): from amaranth.hdl._dsl import * from amaranth.hdl._ir import * from amaranth.sim import * +from amaranth.sim._pyeval import eval_format from amaranth.lib.memory import Memory -from amaranth.lib.data import View, StructLayout -from amaranth.lib import enum +from amaranth.lib import enum, data from .utils import * from amaranth._utils import _ignore_deprecated @@ -1302,6 +1302,44 @@ class SimulatorIntegrationTestCase(FHDLTestCase): with sim.write_vcd("test.vcd", fs_per_delta=1): sim.run() + def test_eval_format(self): + class MyEnum(enum.Enum, shape=2): + A = 0 + B = 1 + C = 2 + + sig = Signal(8) + sig2 = Signal(MyEnum) + sig3 = Signal(data.StructLayout({"a": signed(3), "b": 2})) + sig4 = Signal(data.ArrayLayout(2, 4)) + sig5 = Signal(32, init=0x44434241) + + def testbench(): + state = sim._engine._state + yield sig.eq(123) + self.assertEqual(eval_format(state, sig._format), "123") + self.assertEqual(eval_format(state, Format("{:#04x}", sig)), "0x7b") + self.assertEqual(eval_format(state, Format("sig={}", sig)), "sig=123") + + self.assertEqual(eval_format(state, sig2.as_value()._format), "A") + yield sig2.eq(1) + self.assertEqual(eval_format(state, sig2.as_value()._format), "B") + yield sig2.eq(3) + self.assertEqual(eval_format(state, sig2.as_value()._format), "[unknown]") + + yield sig3.eq(0xc) + self.assertEqual(eval_format(state, sig3.as_value()._format), "{a=-4, b=1}") + + yield sig4.eq(0x1e) + self.assertEqual(eval_format(state, sig4.as_value()._format), "[2, 3, 1, 0]") + + self.assertEqual(eval_format(state, Format("{:s}", sig5)), "ABCD") + self.assertEqual(eval_format(state, Format("{:<5s}", sig5)), "ABCD ") + + sim = Simulator(Module()) + sim.add_testbench(testbench) + with sim.write_vcd("test.vcd", fs_per_delta=1): + sim.run() class SimulatorRegressionTestCase(FHDLTestCase): def test_bug_325(self):