Skip to content

Commit f243cea

Browse files
wanda-phiwhitequark
authored andcommitted
sim: implement Format.* for memories in VCD.
1 parent 625dac3 commit f243cea

File tree

2 files changed

+89
-24
lines changed

2 files changed

+89
-24
lines changed

amaranth/sim/pysim.py

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -172,23 +172,60 @@ def add_format(path, fmt):
172172
for memory, memory_name in memories.items():
173173
self.vcd_memory_vars[memory] = vcd_vars = []
174174
self.gtkw_memory_names[memory] = gtkw_names = []
175-
width = Shape.cast(memory.shape).width
176-
if width > 1:
177-
suffix = f"[{width - 1}:0]"
178-
else:
179-
suffix = ""
180-
for idx, init in enumerate(memory._init._raw):
181-
field_name = "\\" + memory_name[-1] + f"[{idx}]"
175+
176+
for idx, row in enumerate(memory):
177+
row_vcd_vars = []
178+
row_gtkw_names = []
182179
var_scope = memory_name[:-1]
183-
vcd_var = self.vcd_writer.register_var(
184-
scope=var_scope, name=field_name,
185-
var_type="wire", size=width, init=init,
186-
)
187-
vcd_vars.append(vcd_var)
188-
gtkw_field_name = field_name + suffix
189-
gtkw_name = ".".join((*var_scope, gtkw_field_name))
190-
gtkw_names.append(gtkw_name)
191180

181+
def add_mem_var(path, var_type, var_size, var_init, value):
182+
field_name = "\\" + memory_name[-1] + f"[{idx}]"
183+
for item in path:
184+
if isinstance(item, int):
185+
field_name += f"[{item}]"
186+
else:
187+
field_name += f".{item}"
188+
row_vcd_vars.append((self.vcd_writer.register_var(
189+
scope=var_scope, name=field_name, var_type=var_type,
190+
size=var_size, init=var_init
191+
), value))
192+
if var_size > 1:
193+
suffix = f"[{var_size - 1}:0]"
194+
else:
195+
suffix = ""
196+
row_gtkw_names.append(".".join((*var_scope, field_name)) + suffix)
197+
198+
def add_mem_wire_var(path, value):
199+
add_mem_var(path, "wire", len(value), eval_value(self.state, value), value)
200+
201+
def add_mem_format_var(path, fmt):
202+
add_mem_var(path, "string", 1, eval_format(self.state, fmt), fmt)
203+
204+
def add_mem_format(path, fmt):
205+
if isinstance(fmt, Format.Struct):
206+
add_mem_wire_var(path, fmt._value)
207+
for name, subfmt in fmt._fields.items():
208+
add_mem_format(path + (name,), subfmt)
209+
elif isinstance(fmt, Format.Array):
210+
add_mem_wire_var(path, fmt._value)
211+
for idx, subfmt in enumerate(fmt._fields):
212+
add_mem_format(path + (idx,), subfmt)
213+
elif (isinstance(fmt, Format) and
214+
len(fmt._chunks) == 1 and
215+
isinstance(fmt._chunks[0], tuple) and
216+
fmt._chunks[0][1] == ""):
217+
add_mem_wire_var(path, fmt._chunks[0][0])
218+
else:
219+
add_mem_format_var(path, fmt)
220+
221+
if isinstance(memory._shape, ShapeCastable):
222+
fmt = memory._shape.format(memory._shape(row), "")
223+
add_mem_format((), fmt)
224+
else:
225+
add_mem_wire_var((), row)
226+
227+
vcd_vars.append(row_vcd_vars)
228+
gtkw_names.append(row_gtkw_names)
192229

193230
self.vcd_process_vars = {}
194231
if fs_per_delta == 0:
@@ -221,9 +258,15 @@ def update_signal(self, timestamp, signal):
221258
var_value = repr(eval_value(self.state, signal))
222259
self.vcd_writer.change(vcd_var, timestamp, var_value)
223260

224-
def update_memory(self, timestamp, memory, addr, value):
225-
vcd_var = self.vcd_memory_vars[memory][addr]
226-
self.vcd_writer.change(vcd_var, timestamp, value)
261+
def update_memory(self, timestamp, memory, addr):
262+
if memory not in self.vcd_memory_vars:
263+
return
264+
for vcd_var, repr in self.vcd_memory_vars[memory][addr]:
265+
if isinstance(repr, Value):
266+
var_value = eval_value(self.state, repr)
267+
else:
268+
var_value = eval_format(self.state, repr)
269+
self.vcd_writer.change(vcd_var, timestamp, var_value)
227270

228271
def update_process(self, timestamp, process, command):
229272
try:
@@ -249,11 +292,12 @@ def close(self, timestamp):
249292
for name in self.gtkw_signal_names[trace]:
250293
self.gtkw_save.trace(name)
251294
elif isinstance(trace, MemoryData):
252-
for name in self.gtkw_memory_names[trace]:
253-
self.gtkw_save.trace(name)
295+
for row_names in self.gtkw_memory_names[trace]:
296+
for name in row_names:
297+
self.gtkw_save.trace(name)
254298
elif isinstance(trace, MemoryData._Row):
255-
name = self.gtkw_memory_names[trace._memory][trace._index]
256-
self.gtkw_save.trace(name)
299+
for name in self.gtkw_memory_names[trace._memory][trace._index]:
300+
self.gtkw_save.trace(name)
257301
else:
258302
assert False # :nocov:
259303

@@ -524,7 +568,7 @@ def _step_rtl(self):
524568
signal_state.signal)
525569
elif isinstance(change, _PyMemoryChange):
526570
vcd_writer.update_memory(now_plus_deltas, change.state.memory,
527-
change.addr, change.state.data[change.addr])
571+
change.addr)
528572
else:
529573
assert False # :nocov:
530574

tests/test_sim.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
with warnings.catch_warnings():
1111
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
1212
from amaranth.hdl.rec import *
13-
from amaranth.hdl._dsl import *
13+
from amaranth.hdl._dsl import *
14+
from amaranth.hdl._mem import MemoryData
1415
from amaranth.hdl._ir import *
1516
from amaranth.sim import *
1617
from amaranth.sim._pyeval import eval_format
@@ -1355,6 +1356,26 @@ def testbench():
13551356
with self.assertSimulation(Module(), traces=[sig]) as sim:
13561357
sim.add_testbench(testbench)
13571358

1359+
def test_mem_shape(self):
1360+
class MyEnum(enum.Enum, shape=2):
1361+
A = 0
1362+
B = 1
1363+
C = 2
1364+
1365+
mem1 = MemoryData(shape=8, depth=4, init=[1, 2, 3])
1366+
mem2 = MemoryData(shape=MyEnum, depth=4, init=[MyEnum.A, MyEnum.B, MyEnum.C])
1367+
mem3 = MemoryData(shape=data.StructLayout({"a": signed(3), "b": 2}), depth=4, init=[{"a": 2, "b": 1}])
1368+
1369+
def testbench():
1370+
yield Delay(1e-6)
1371+
yield mem1[0].eq(4)
1372+
yield mem2[3].eq(MyEnum.C)
1373+
yield mem3[2].eq(mem3._shape.const({"a": -1, "b": 2}))
1374+
yield Delay(1e-6)
1375+
1376+
with self.assertSimulation(Module(), traces=[mem1, mem2, mem3]) as sim:
1377+
sim.add_testbench(testbench)
1378+
13581379

13591380
class SimulatorRegressionTestCase(FHDLTestCase):
13601381
def test_bug_325(self):

0 commit comments

Comments
 (0)