-
Notifications
You must be signed in to change notification settings - Fork 1
/
conftest.py
146 lines (120 loc) · 4.63 KB
/
conftest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import functools
import pytest
from amaranth import Value
from amaranth.hdl import ValueCastable
from amaranth.sim import Simulator, Passive, Tick
from amaranth.lib.wiring import Signature
def pytest_addoption(parser):
parser.addoption(
"--vcds",
action="store_true",
help="generate Value Change Dump (vcds) from simulations",
)
parser.addoption(
"--runbench", action="store_true", default=False, help="run benchmarks"
)
parser.addoption(
"--runsoc", action="store_true", default=False,
help="run SoC simulation"
)
def pytest_collection_modifyitems(config, items):
if not config.getoption("--runbench"):
skip_bench = pytest.mark.skip(reason="need --runbench option to run")
for item in items:
if "bench" in item.keywords:
item.add_marker(skip_bench)
if not config.getoption("--runsoc"):
skip_soc = pytest.mark.skip(reason="need --runsoc option to run")
for item in items:
if "soc" in item.keywords:
item.add_marker(skip_soc)
class SimulatorFixture:
def __init__(self, req, cfg):
mod = req.node.get_closest_marker("module").args[0]
# FIXME: Depending on module contents, some amaranth code, such as
# amaranth_soc.csr classes don't interact well with elaborating
# the same object multiple times. This happens during parametrized
# tests. Therefore, provide an escape hatch to create a fresh object
# for all arguments of a parameterized test.
#
# Ideally, I should figure out the exact conditions under where it's
# safe to reuse an already-elaborated object (if ever); the tests
# didn't break until I started using amaranth_soc.csr. But this will
# do for now.
if isinstance(mod, functools.partial):
self.mod = mod()
else:
self.mod = mod
self.name = req.node.name
self.vcds = cfg.getoption("vcds")
self.clks = req.node.get_closest_marker("clks").args[0]
@property
def ports(self):
if hasattr(self, "_ports"):
return self._ports
else:
# Back-compat
if hasattr(self.mod, "ports"):
return self.mod.ports()
# Stolen from Amaranth 33c2246- intended to be "new" way to
# populate GTKW files.
elif hasattr(self.mod, "signature") and \
isinstance(self.mod.signature, Signature):
ports = []
for path, member, value in self.mod.signature.flatten(self.mod): # noqa: E501
if isinstance(value, ValueCastable):
value = value.as_value()
if isinstance(value, Value):
ports.append(value)
return ports
else:
return ()
@ports.setter
def ports(self, ports):
self._ports = ports
def run(self, testbenches=[], sync_processes=[], comb_processes=[]):
# Don't elaborate until we're ready to sim. This causes weird
# behaviors if you modify the object after elaboration. For instance,
# changing a Memory's init file after elaboration causes memory
# contents to not what's on the bus according to the Python Simulator.
sim = Simulator(self.mod)
for c in self.clks:
sim.add_clock(c)
for t in testbenches:
sim.add_testbench(t)
for s in sync_processes:
sim.add_process(s)
for p in comb_processes:
sim.add_process(p)
if self.vcds:
with sim.write_vcd(self.name + ".vcd", self.name + ".gtkw",
traces=self.ports):
sim.run()
else:
sim.run()
@pytest.fixture
def sim_mod(request, pytestconfig):
simfix = SimulatorFixture(request, pytestconfig)
return (simfix, simfix.mod)
@pytest.fixture
def ucode_panic(sim_mod):
_, m = sim_mod
def ucode_panic():
yield Passive()
addr = 0
prev_addr = 0
count = 0
while True:
yield Tick()
if (yield m.cpu.control.ucoderom.addr == 255):
raise AssertionError("microcode panic (not implemented)")
prev_addr = addr
addr = (yield m.cpu.control.ucoderom.addr)
if prev_addr == addr:
count += 1
if count > 100:
raise AssertionError("microcode probably stuck in "
"infinite loop")
else:
count = 0
return ucode_panic