sim: implement Format.*
for memories in VCD.
This commit is contained in:
parent
625dac376a
commit
f243cea0fb
|
@ -172,23 +172,60 @@ class _VCDWriter:
|
|||
for memory, memory_name in memories.items():
|
||||
self.vcd_memory_vars[memory] = vcd_vars = []
|
||||
self.gtkw_memory_names[memory] = gtkw_names = []
|
||||
width = Shape.cast(memory.shape).width
|
||||
if width > 1:
|
||||
suffix = f"[{width - 1}:0]"
|
||||
else:
|
||||
suffix = ""
|
||||
for idx, init in enumerate(memory._init._raw):
|
||||
field_name = "\\" + memory_name[-1] + f"[{idx}]"
|
||||
var_scope = memory_name[:-1]
|
||||
vcd_var = self.vcd_writer.register_var(
|
||||
scope=var_scope, name=field_name,
|
||||
var_type="wire", size=width, init=init,
|
||||
)
|
||||
vcd_vars.append(vcd_var)
|
||||
gtkw_field_name = field_name + suffix
|
||||
gtkw_name = ".".join((*var_scope, gtkw_field_name))
|
||||
gtkw_names.append(gtkw_name)
|
||||
|
||||
for idx, row in enumerate(memory):
|
||||
row_vcd_vars = []
|
||||
row_gtkw_names = []
|
||||
var_scope = memory_name[:-1]
|
||||
|
||||
def add_mem_var(path, var_type, var_size, var_init, value):
|
||||
field_name = "\\" + memory_name[-1] + f"[{idx}]"
|
||||
for item in path:
|
||||
if isinstance(item, int):
|
||||
field_name += f"[{item}]"
|
||||
else:
|
||||
field_name += f".{item}"
|
||||
row_vcd_vars.append((self.vcd_writer.register_var(
|
||||
scope=var_scope, name=field_name, var_type=var_type,
|
||||
size=var_size, init=var_init
|
||||
), value))
|
||||
if var_size > 1:
|
||||
suffix = f"[{var_size - 1}:0]"
|
||||
else:
|
||||
suffix = ""
|
||||
row_gtkw_names.append(".".join((*var_scope, field_name)) + suffix)
|
||||
|
||||
def add_mem_wire_var(path, value):
|
||||
add_mem_var(path, "wire", len(value), eval_value(self.state, value), value)
|
||||
|
||||
def add_mem_format_var(path, fmt):
|
||||
add_mem_var(path, "string", 1, eval_format(self.state, fmt), fmt)
|
||||
|
||||
def add_mem_format(path, fmt):
|
||||
if isinstance(fmt, Format.Struct):
|
||||
add_mem_wire_var(path, fmt._value)
|
||||
for name, subfmt in fmt._fields.items():
|
||||
add_mem_format(path + (name,), subfmt)
|
||||
elif isinstance(fmt, Format.Array):
|
||||
add_mem_wire_var(path, fmt._value)
|
||||
for idx, subfmt in enumerate(fmt._fields):
|
||||
add_mem_format(path + (idx,), subfmt)
|
||||
elif (isinstance(fmt, Format) and
|
||||
len(fmt._chunks) == 1 and
|
||||
isinstance(fmt._chunks[0], tuple) and
|
||||
fmt._chunks[0][1] == ""):
|
||||
add_mem_wire_var(path, fmt._chunks[0][0])
|
||||
else:
|
||||
add_mem_format_var(path, fmt)
|
||||
|
||||
if isinstance(memory._shape, ShapeCastable):
|
||||
fmt = memory._shape.format(memory._shape(row), "")
|
||||
add_mem_format((), fmt)
|
||||
else:
|
||||
add_mem_wire_var((), row)
|
||||
|
||||
vcd_vars.append(row_vcd_vars)
|
||||
gtkw_names.append(row_gtkw_names)
|
||||
|
||||
self.vcd_process_vars = {}
|
||||
if fs_per_delta == 0:
|
||||
|
@ -221,9 +258,15 @@ class _VCDWriter:
|
|||
var_value = repr(eval_value(self.state, signal))
|
||||
self.vcd_writer.change(vcd_var, timestamp, var_value)
|
||||
|
||||
def update_memory(self, timestamp, memory, addr, value):
|
||||
vcd_var = self.vcd_memory_vars[memory][addr]
|
||||
self.vcd_writer.change(vcd_var, timestamp, value)
|
||||
def update_memory(self, timestamp, memory, addr):
|
||||
if memory not in self.vcd_memory_vars:
|
||||
return
|
||||
for vcd_var, repr in self.vcd_memory_vars[memory][addr]:
|
||||
if isinstance(repr, Value):
|
||||
var_value = eval_value(self.state, repr)
|
||||
else:
|
||||
var_value = eval_format(self.state, repr)
|
||||
self.vcd_writer.change(vcd_var, timestamp, var_value)
|
||||
|
||||
def update_process(self, timestamp, process, command):
|
||||
try:
|
||||
|
@ -249,11 +292,12 @@ class _VCDWriter:
|
|||
for name in self.gtkw_signal_names[trace]:
|
||||
self.gtkw_save.trace(name)
|
||||
elif isinstance(trace, MemoryData):
|
||||
for name in self.gtkw_memory_names[trace]:
|
||||
self.gtkw_save.trace(name)
|
||||
for row_names in self.gtkw_memory_names[trace]:
|
||||
for name in row_names:
|
||||
self.gtkw_save.trace(name)
|
||||
elif isinstance(trace, MemoryData._Row):
|
||||
name = self.gtkw_memory_names[trace._memory][trace._index]
|
||||
self.gtkw_save.trace(name)
|
||||
for name in self.gtkw_memory_names[trace._memory][trace._index]:
|
||||
self.gtkw_save.trace(name)
|
||||
else:
|
||||
assert False # :nocov:
|
||||
|
||||
|
@ -524,7 +568,7 @@ class PySimEngine(BaseEngine):
|
|||
signal_state.signal)
|
||||
elif isinstance(change, _PyMemoryChange):
|
||||
vcd_writer.update_memory(now_plus_deltas, change.state.memory,
|
||||
change.addr, change.state.data[change.addr])
|
||||
change.addr)
|
||||
else:
|
||||
assert False # :nocov:
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ from amaranth.hdl._cd import *
|
|||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
|
||||
from amaranth.hdl.rec import *
|
||||
from amaranth.hdl._dsl import *
|
||||
from amaranth.hdl._dsl import *
|
||||
from amaranth.hdl._mem import MemoryData
|
||||
from amaranth.hdl._ir import *
|
||||
from amaranth.sim import *
|
||||
from amaranth.sim._pyeval import eval_format
|
||||
|
@ -1355,6 +1356,26 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
with self.assertSimulation(Module(), traces=[sig]) as sim:
|
||||
sim.add_testbench(testbench)
|
||||
|
||||
def test_mem_shape(self):
|
||||
class MyEnum(enum.Enum, shape=2):
|
||||
A = 0
|
||||
B = 1
|
||||
C = 2
|
||||
|
||||
mem1 = MemoryData(shape=8, depth=4, init=[1, 2, 3])
|
||||
mem2 = MemoryData(shape=MyEnum, depth=4, init=[MyEnum.A, MyEnum.B, MyEnum.C])
|
||||
mem3 = MemoryData(shape=data.StructLayout({"a": signed(3), "b": 2}), depth=4, init=[{"a": 2, "b": 1}])
|
||||
|
||||
def testbench():
|
||||
yield Delay(1e-6)
|
||||
yield mem1[0].eq(4)
|
||||
yield mem2[3].eq(MyEnum.C)
|
||||
yield mem3[2].eq(mem3._shape.const({"a": -1, "b": 2}))
|
||||
yield Delay(1e-6)
|
||||
|
||||
with self.assertSimulation(Module(), traces=[mem1, mem2, mem3]) as sim:
|
||||
sim.add_testbench(testbench)
|
||||
|
||||
|
||||
class SimulatorRegressionTestCase(FHDLTestCase):
|
||||
def test_bug_325(self):
|
||||
|
|
Loading…
Reference in a new issue