Implement RFC 27: Testbench processes for the simulator.
Co-authored-by: Wanda <wanda@phinode.net>
This commit is contained in:
parent
f48b8650c4
commit
9e75962c35
|
@ -15,6 +15,12 @@ class Command:
|
|||
|
||||
|
||||
class Settle(Command):
|
||||
@deprecated("The `Settle` command is deprecated per RFC 27. Use `add_testbench` to write "
|
||||
"testbenches; in them, an equivalent of `yield Settle()` is performed "
|
||||
"automatically.")
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __repr__(self):
|
||||
return "(settle)"
|
||||
|
||||
|
@ -74,11 +80,12 @@ class Simulator:
|
|||
.format(process))
|
||||
return process
|
||||
|
||||
@deprecated("The `add_process` method is deprecated per RFC 27. Use `add_testbench` instead.")
|
||||
def add_process(self, process):
|
||||
process = self._check_process(process)
|
||||
def wrapper():
|
||||
# Only start a bench process after comb settling, so that the reset values are correct.
|
||||
yield Settle()
|
||||
yield object.__new__(Settle)
|
||||
yield from process()
|
||||
self._engine.add_coroutine_process(wrapper, default_cmd=None)
|
||||
|
||||
|
@ -87,10 +94,74 @@ class Simulator:
|
|||
def wrapper():
|
||||
# Only start a sync process after the first clock edge (or reset edge, if the domain
|
||||
# uses an asynchronous reset). This matches the behavior of synchronous FFs.
|
||||
generator = process()
|
||||
result = None
|
||||
exception = None
|
||||
yield Tick(domain)
|
||||
yield from process()
|
||||
while True:
|
||||
try:
|
||||
if exception is None:
|
||||
command = generator.send(result)
|
||||
else:
|
||||
command = generator.throw(exception)
|
||||
except StopIteration:
|
||||
break
|
||||
try:
|
||||
if isinstance(command, (Settle, Delay, Tick)):
|
||||
frame = generator.gi_frame
|
||||
module_globals = frame.f_globals
|
||||
if '__name__' in module_globals:
|
||||
module = module_globals['__name__']
|
||||
else:
|
||||
module = "<string>"
|
||||
# If the warning action is "error", this call will throw the warning, and
|
||||
# the try block will redirect it into the generator.
|
||||
warnings.warn_explicit(
|
||||
f"Using `{command.__class__.__name__}` is deprecated within "
|
||||
f"`add_sync_process` per RFC 27; use `add_testbench` instead.",
|
||||
DeprecationWarning,
|
||||
filename=frame.f_code.co_filename,
|
||||
lineno=frame.f_lineno,
|
||||
module=module,
|
||||
registry=module_globals.setdefault("__warningregistry__", {}),
|
||||
module_globals=module_globals,
|
||||
)
|
||||
result = yield command
|
||||
exception = None
|
||||
except Exception as e:
|
||||
result = None
|
||||
exception = e
|
||||
self._engine.add_coroutine_process(wrapper, default_cmd=Tick(domain))
|
||||
|
||||
def add_testbench(self, process):
|
||||
process = self._check_process(process)
|
||||
def wrapper():
|
||||
generator = process()
|
||||
# Only start a bench process after power-on reset finishes. Use object.__new__ to
|
||||
# avoid deprecation warning.
|
||||
yield object.__new__(Settle)
|
||||
result = None
|
||||
exception = None
|
||||
while True:
|
||||
try:
|
||||
if exception is None:
|
||||
command = generator.send(result)
|
||||
else:
|
||||
command = generator.throw(exception)
|
||||
except StopIteration:
|
||||
break
|
||||
if command is None or isinstance(command, Settle):
|
||||
exception = TypeError(f"Command {command!r} is not allowed in testbenches")
|
||||
else:
|
||||
try:
|
||||
result = yield command
|
||||
exception = None
|
||||
yield object.__new__(Settle)
|
||||
except Exception as e:
|
||||
result = None
|
||||
exception = e
|
||||
self._engine.add_coroutine_process(wrapper, default_cmd=None)
|
||||
|
||||
def add_clock(self, period, *, phase=None, domain="sync", if_exists=False):
|
||||
"""Add a clock process.
|
||||
|
||||
|
|
|
@ -29,16 +29,21 @@ Apply the following changes to code written against Amaranth 0.4 to migrate it t
|
|||
* Replace uses of ``Value.matches()`` with no patterns with ``Const(1)``
|
||||
* Update uses of ``amaranth.utils.log2_int(need_pow2=False)`` to :func:`amaranth.utils.ceil_log2`
|
||||
* Update uses of ``amaranth.utils.log2_int(need_pow2=True)`` to :func:`amaranth.utils.exact_log2`
|
||||
* Update uses of ``Simulator.add_process`` to ``Simulator.add_testbench``
|
||||
* Convert uses of ``Simulator.add_sync_process`` used as testbenches to ``Simulator.add_testbench``
|
||||
* Convert uses of ``yield Tick()`` within remaining ``Simulator.add_sync_process`` to plain ``yield``
|
||||
|
||||
|
||||
Implemented RFCs
|
||||
----------------
|
||||
|
||||
.. _RFC 17: https://amaranth-lang.org/rfcs/0017-remove-log2-int.html
|
||||
.. _RFC 27: https://amaranth-lang.org/rfcs/0027-simulator-testbenches.html
|
||||
.. _RFC 39: https://amaranth-lang.org/rfcs/0039-empty-case.html
|
||||
.. _RFC 46: https://amaranth-lang.org/rfcs/0046-shape-range-1.html
|
||||
|
||||
* `RFC 17`_: Remove ``log2_int``
|
||||
* `RFC 27`_: Testbench processes for the simulator
|
||||
* `RFC 39`_: Change semantics of no-argument ``m.Case()``
|
||||
* `RFC 46`_: Change ``Shape.cast(range(1))`` to ``unsigned(0)``
|
||||
|
||||
|
@ -71,6 +76,14 @@ Standard library changes
|
|||
* Removed: (deprecated in 0.4) :class:`amaranth.lib.fifo.SyncFIFO` with ``fwft=False``. (`RFC 20`_)
|
||||
|
||||
|
||||
Toolchain changes
|
||||
-----------------
|
||||
|
||||
* Added: ``Simulator.add_testbench``. (`RFC 27`_)
|
||||
* Deprecated: ``Settle`` simulation command. (`RFC 27`_)
|
||||
* Deprecated: ``Simulator.add_process``. (`RFC 27`_)
|
||||
|
||||
|
||||
Platform integration changes
|
||||
----------------------------
|
||||
|
||||
|
|
|
@ -26,13 +26,13 @@ class FFSynchronizerTestCase(FHDLTestCase):
|
|||
def process():
|
||||
self.assertEqual((yield o), 0)
|
||||
yield i.eq(1)
|
||||
yield Tick()
|
||||
yield
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick()
|
||||
yield
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick()
|
||||
yield
|
||||
self.assertEqual((yield o), 1)
|
||||
sim.add_process(process)
|
||||
sim.add_sync_process(process)
|
||||
sim.run()
|
||||
|
||||
def test_reset_value(self):
|
||||
|
@ -45,13 +45,13 @@ class FFSynchronizerTestCase(FHDLTestCase):
|
|||
def process():
|
||||
self.assertEqual((yield o), 1)
|
||||
yield i.eq(0)
|
||||
yield Tick()
|
||||
yield
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick()
|
||||
yield
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick()
|
||||
yield
|
||||
self.assertEqual((yield o), 0)
|
||||
sim.add_process(process)
|
||||
sim.add_sync_process(process)
|
||||
sim.run()
|
||||
|
||||
|
||||
|
@ -90,28 +90,27 @@ class AsyncFFSynchronizerTestCase(FHDLTestCase):
|
|||
# initial reset
|
||||
self.assertEqual((yield i), 0)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
|
||||
yield i.eq(1)
|
||||
yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 1)
|
||||
yield i.eq(0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
sim.add_process(process)
|
||||
yield Tick()
|
||||
sim.add_testbench(process)
|
||||
with sim.write_vcd("test.vcd"):
|
||||
sim.run()
|
||||
|
||||
|
@ -128,28 +127,27 @@ class AsyncFFSynchronizerTestCase(FHDLTestCase):
|
|||
# initial reset
|
||||
self.assertEqual((yield i), 1)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
|
||||
yield i.eq(0)
|
||||
yield Delay(1e-8)
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 1)
|
||||
yield i.eq(1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield o), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
sim.add_process(process)
|
||||
yield Tick()
|
||||
sim.add_testbench(process)
|
||||
with sim.write_vcd("test.vcd"):
|
||||
sim.run()
|
||||
|
||||
|
@ -176,28 +174,28 @@ class ResetSynchronizerTestCase(FHDLTestCase):
|
|||
def process():
|
||||
# initial reset
|
||||
self.assertEqual((yield s), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield s), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield s), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield s), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
|
||||
yield arst.eq(1)
|
||||
yield Delay(1e-8)
|
||||
self.assertEqual((yield s), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield s), 1)
|
||||
yield arst.eq(0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield s), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield s), 1)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
yield Tick()
|
||||
self.assertEqual((yield s), 0)
|
||||
yield Tick(); yield Delay(1e-8)
|
||||
sim.add_process(process)
|
||||
yield Tick()
|
||||
sim.add_testbench(process)
|
||||
with sim.write_vcd("test.vcd"):
|
||||
sim.run()
|
||||
|
||||
|
@ -223,17 +221,17 @@ class PulseSynchronizerTestCase(FHDLTestCase):
|
|||
yield ps.i.eq(0)
|
||||
# TODO: think about reset
|
||||
for n in range(5):
|
||||
yield Tick()
|
||||
yield
|
||||
# Make sure no pulses are generated in quiescent state
|
||||
for n in range(3):
|
||||
yield Tick()
|
||||
yield
|
||||
self.assertEqual((yield ps.o), 0)
|
||||
# Check conservation of pulses
|
||||
accum = 0
|
||||
for n in range(10):
|
||||
yield ps.i.eq(1 if n < 4 else 0)
|
||||
yield Tick()
|
||||
yield
|
||||
accum += yield ps.o
|
||||
self.assertEqual(accum, 4)
|
||||
sim.add_process(process)
|
||||
sim.add_sync_process(process)
|
||||
sim.run()
|
||||
|
|
|
@ -14,22 +14,19 @@ class EncoderTestCase(FHDLTestCase):
|
|||
self.assertEqual((yield enc.o), 0)
|
||||
|
||||
yield enc.i.eq(0b0001)
|
||||
yield Settle()
|
||||
self.assertEqual((yield enc.n), 0)
|
||||
self.assertEqual((yield enc.o), 0)
|
||||
|
||||
yield enc.i.eq(0b0100)
|
||||
yield Settle()
|
||||
self.assertEqual((yield enc.n), 0)
|
||||
self.assertEqual((yield enc.o), 2)
|
||||
|
||||
yield enc.i.eq(0b0110)
|
||||
yield Settle()
|
||||
self.assertEqual((yield enc.n), 1)
|
||||
self.assertEqual((yield enc.o), 0)
|
||||
|
||||
sim = Simulator(enc)
|
||||
sim.add_process(process)
|
||||
sim.add_testbench(process)
|
||||
sim.run()
|
||||
|
||||
|
||||
|
@ -41,22 +38,19 @@ class PriorityEncoderTestCase(FHDLTestCase):
|
|||
self.assertEqual((yield enc.o), 0)
|
||||
|
||||
yield enc.i.eq(0b0001)
|
||||
yield Settle()
|
||||
self.assertEqual((yield enc.n), 0)
|
||||
self.assertEqual((yield enc.o), 0)
|
||||
|
||||
yield enc.i.eq(0b0100)
|
||||
yield Settle()
|
||||
self.assertEqual((yield enc.n), 0)
|
||||
self.assertEqual((yield enc.o), 2)
|
||||
|
||||
yield enc.i.eq(0b0110)
|
||||
yield Settle()
|
||||
self.assertEqual((yield enc.n), 0)
|
||||
self.assertEqual((yield enc.o), 1)
|
||||
|
||||
sim = Simulator(enc)
|
||||
sim.add_process(process)
|
||||
sim.add_testbench(process)
|
||||
sim.run()
|
||||
|
||||
|
||||
|
@ -67,19 +61,16 @@ class DecoderTestCase(FHDLTestCase):
|
|||
self.assertEqual((yield dec.o), 0b0001)
|
||||
|
||||
yield dec.i.eq(1)
|
||||
yield Settle()
|
||||
self.assertEqual((yield dec.o), 0b0010)
|
||||
|
||||
yield dec.i.eq(3)
|
||||
yield Settle()
|
||||
self.assertEqual((yield dec.o), 0b1000)
|
||||
|
||||
yield dec.n.eq(1)
|
||||
yield Settle()
|
||||
self.assertEqual((yield dec.o), 0b0000)
|
||||
|
||||
sim = Simulator(dec)
|
||||
sim.add_process(process)
|
||||
sim.add_testbench(process)
|
||||
sim.run()
|
||||
|
||||
|
||||
|
|
|
@ -870,7 +870,7 @@ class RFCExamplesTestCase(TestCase):
|
|||
def simulate(m):
|
||||
def wrapper(fn):
|
||||
sim = Simulator(m)
|
||||
sim.add_process(fn)
|
||||
sim.add_testbench(fn)
|
||||
sim.run()
|
||||
return wrapper
|
||||
|
||||
|
|
|
@ -315,10 +315,10 @@ class AsyncFIFOSimCase(FHDLTestCase):
|
|||
for i in range(fill_in):
|
||||
yield fifo.w_data.eq(i)
|
||||
yield fifo.w_en.eq(1)
|
||||
yield Tick("write")
|
||||
yield
|
||||
yield fifo.w_en.eq(0)
|
||||
yield Tick("write")
|
||||
yield Tick("write")
|
||||
yield
|
||||
yield
|
||||
self.assertEqual((yield fifo.w_level), expected_level)
|
||||
yield write_done.eq(1)
|
||||
|
||||
|
@ -326,7 +326,7 @@ class AsyncFIFOSimCase(FHDLTestCase):
|
|||
if read:
|
||||
yield fifo.r_en.eq(1)
|
||||
while not (yield write_done):
|
||||
yield Tick("read")
|
||||
yield
|
||||
self.assertEqual((yield fifo.r_level), expected_level)
|
||||
|
||||
simulator = Simulator(fifo)
|
||||
|
|
|
@ -35,9 +35,8 @@ class SimulatorUnitTestCase(FHDLTestCase):
|
|||
def process():
|
||||
for isig, input in zip(isigs, inputs):
|
||||
yield isig.eq(input)
|
||||
yield Settle()
|
||||
self.assertEqual((yield osig), output.value)
|
||||
sim.add_process(process)
|
||||
sim.add_testbench(process)
|
||||
with sim.write_vcd("test.vcd", "test.gtkw", traces=[*isigs, osig]):
|
||||
sim.run()
|
||||
|
||||
|
@ -436,28 +435,29 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
|
||||
def test_counter_process(self):
|
||||
self.setUp_counter()
|
||||
with self.assertSimulation(self.m) as sim:
|
||||
def process():
|
||||
self.assertEqual((yield self.count), 4)
|
||||
yield Delay(1e-6)
|
||||
self.assertEqual((yield self.count), 4)
|
||||
yield self.sync.clk.eq(1)
|
||||
self.assertEqual((yield self.count), 4)
|
||||
yield Settle()
|
||||
self.assertEqual((yield self.count), 5)
|
||||
yield Delay(1e-6)
|
||||
self.assertEqual((yield self.count), 5)
|
||||
yield self.sync.clk.eq(0)
|
||||
self.assertEqual((yield self.count), 5)
|
||||
yield Settle()
|
||||
self.assertEqual((yield self.count), 5)
|
||||
for _ in range(3):
|
||||
with _ignore_deprecated():
|
||||
with self.assertSimulation(self.m) as sim:
|
||||
def process():
|
||||
self.assertEqual((yield self.count), 4)
|
||||
yield Delay(1e-6)
|
||||
self.assertEqual((yield self.count), 4)
|
||||
yield self.sync.clk.eq(1)
|
||||
self.assertEqual((yield self.count), 4)
|
||||
yield Settle()
|
||||
self.assertEqual((yield self.count), 5)
|
||||
yield Delay(1e-6)
|
||||
self.assertEqual((yield self.count), 5)
|
||||
yield self.sync.clk.eq(0)
|
||||
self.assertEqual((yield self.count), 0)
|
||||
sim.add_process(process)
|
||||
self.assertEqual((yield self.count), 5)
|
||||
yield Settle()
|
||||
self.assertEqual((yield self.count), 5)
|
||||
for _ in range(3):
|
||||
yield Delay(1e-6)
|
||||
yield self.sync.clk.eq(1)
|
||||
yield Delay(1e-6)
|
||||
yield self.sync.clk.eq(0)
|
||||
self.assertEqual((yield self.count), 0)
|
||||
sim.add_process(process)
|
||||
|
||||
def test_counter_clock_and_sync_process(self):
|
||||
self.setUp_counter()
|
||||
|
@ -611,10 +611,9 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
def process():
|
||||
yield self.i.eq(0b10101010)
|
||||
yield self.i[:4].eq(-1)
|
||||
yield Settle()
|
||||
self.assertEqual((yield self.i[:4]), 0b1111)
|
||||
self.assertEqual((yield self.i), 0b10101111)
|
||||
sim.add_process(process)
|
||||
sim.add_testbench(process)
|
||||
|
||||
def test_run_until(self):
|
||||
m = Module()
|
||||
|
@ -626,7 +625,7 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
for _ in range(101):
|
||||
yield Delay(1e-6)
|
||||
self.fail()
|
||||
sim.add_process(process)
|
||||
sim.add_testbench(process)
|
||||
|
||||
def test_run_until_fail(self):
|
||||
m = Module()
|
||||
|
@ -639,13 +638,13 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
for _ in range(99):
|
||||
yield Delay(1e-6)
|
||||
self.fail()
|
||||
sim.add_process(process)
|
||||
sim.add_testbench(process)
|
||||
|
||||
def test_add_process_wrong(self):
|
||||
with self.assertSimulation(Module()) as sim:
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r"^Cannot add a process 1 because it is not a generator function$"):
|
||||
sim.add_process(1)
|
||||
sim.add_sync_process(1)
|
||||
|
||||
def test_add_process_wrong_generator(self):
|
||||
with self.assertSimulation(Module()) as sim:
|
||||
|
@ -653,7 +652,7 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
r"^Cannot add a process <.+?> because it is not a generator function$"):
|
||||
def process():
|
||||
yield Delay()
|
||||
sim.add_process(process())
|
||||
sim.add_sync_process(process())
|
||||
|
||||
def test_add_clock_wrong_twice(self):
|
||||
m = Module()
|
||||
|
@ -679,14 +678,47 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
|
||||
def test_command_wrong(self):
|
||||
survived = False
|
||||
with self.assertSimulation(Module()) as sim:
|
||||
with _ignore_deprecated():
|
||||
with self.assertSimulation(Module()) as sim:
|
||||
def process():
|
||||
nonlocal survived
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r"Received unsupported command 1 from process .+?"):
|
||||
yield 1
|
||||
survived = True
|
||||
sim.add_process(process)
|
||||
self.assertTrue(survived)
|
||||
|
||||
def test_sync_command_deprecated(self):
|
||||
survived = False
|
||||
m = Module()
|
||||
dummy = Signal()
|
||||
m.d.sync += dummy.eq(1)
|
||||
with self.assertSimulation(m) as sim:
|
||||
def process():
|
||||
nonlocal survived
|
||||
with self.assertWarnsRegex(DeprecationWarning,
|
||||
r"Using `Delay` is deprecated within `add_sync_process`"):
|
||||
yield Delay(1e-8)
|
||||
survived = True
|
||||
sim.add_sync_process(process)
|
||||
sim.add_clock(1e-6)
|
||||
self.assertTrue(survived)
|
||||
|
||||
def test_sync_command_wrong(self):
|
||||
survived = False
|
||||
m = Module()
|
||||
dummy = Signal()
|
||||
m.d.sync += dummy.eq(1)
|
||||
with self.assertSimulation(m) as sim:
|
||||
def process():
|
||||
nonlocal survived
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r"Received unsupported command 1 from process .+?"):
|
||||
yield 1
|
||||
survived = True
|
||||
sim.add_process(process)
|
||||
sim.add_sync_process(process)
|
||||
sim.add_clock(1e-6)
|
||||
self.assertTrue(survived)
|
||||
|
||||
def test_value_castable(self):
|
||||
|
@ -701,13 +733,19 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
a = Array([1,2,3])
|
||||
a[MyValue()]
|
||||
|
||||
def test_bench_command_wrong(self):
|
||||
survived = False
|
||||
with self.assertSimulation(Module()) as sim:
|
||||
def process():
|
||||
nonlocal survived
|
||||
yield MyValue()
|
||||
with self.assertWarnsRegex(DeprecationWarning,
|
||||
r"The `Settle` command is deprecated"):
|
||||
settle = Settle()
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r"Command \(settle\) is not allowed in testbenches"):
|
||||
yield settle
|
||||
survived = True
|
||||
sim.add_process(process)
|
||||
sim.add_testbench(process)
|
||||
self.assertTrue(survived)
|
||||
|
||||
def setUp_memory(self, rd_synchronous=True, rd_transparent=True, wr_granularity=None):
|
||||
|
@ -755,23 +793,23 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
def process():
|
||||
yield self.wrport.data.eq(0x50)
|
||||
yield self.wrport.en.eq(0b00)
|
||||
yield
|
||||
yield Tick()
|
||||
yield self.wrport.en.eq(0)
|
||||
yield
|
||||
yield Tick()
|
||||
self.assertEqual((yield self.rdport.data), 0xaa)
|
||||
yield self.wrport.en.eq(0b10)
|
||||
yield
|
||||
yield Tick()
|
||||
yield self.wrport.en.eq(0)
|
||||
yield
|
||||
yield Tick()
|
||||
self.assertEqual((yield self.rdport.data), 0x5a)
|
||||
yield self.wrport.data.eq(0x33)
|
||||
yield self.wrport.en.eq(0b01)
|
||||
yield
|
||||
yield Tick()
|
||||
yield self.wrport.en.eq(0)
|
||||
yield
|
||||
yield Tick()
|
||||
self.assertEqual((yield self.rdport.data), 0x53)
|
||||
sim.add_clock(1e-6)
|
||||
sim.add_sync_process(process)
|
||||
sim.add_testbench(process)
|
||||
|
||||
def test_memory_read_before_write(self):
|
||||
self.setUp_memory(rd_transparent=False)
|
||||
|
@ -779,52 +817,46 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
def process():
|
||||
yield self.wrport.data.eq(0x33)
|
||||
yield self.wrport.en.eq(1)
|
||||
yield
|
||||
yield Tick()
|
||||
self.assertEqual((yield self.rdport.data), 0xaa)
|
||||
yield
|
||||
self.assertEqual((yield self.rdport.data), 0xaa)
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield self.rdport.data), 0x33)
|
||||
sim.add_clock(1e-6)
|
||||
sim.add_sync_process(process)
|
||||
sim.add_testbench(process)
|
||||
|
||||
def test_memory_write_through(self):
|
||||
self.setUp_memory(rd_transparent=True)
|
||||
with self.assertSimulation(self.m) as sim:
|
||||
def process():
|
||||
yield Tick()
|
||||
yield self.wrport.data.eq(0x33)
|
||||
yield self.wrport.en.eq(1)
|
||||
yield
|
||||
self.assertEqual((yield self.rdport.data), 0xaa)
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield self.rdport.data), 0x33)
|
||||
yield
|
||||
yield Tick()
|
||||
yield self.rdport.addr.eq(1)
|
||||
yield Settle()
|
||||
self.assertEqual((yield self.rdport.data), 0x33)
|
||||
sim.add_clock(1e-6)
|
||||
sim.add_sync_process(process)
|
||||
sim.add_testbench(process)
|
||||
|
||||
def test_memory_async_read_write(self):
|
||||
self.setUp_memory(rd_synchronous=False)
|
||||
with self.assertSimulation(self.m) as sim:
|
||||
def process():
|
||||
yield self.rdport.addr.eq(0)
|
||||
yield Settle()
|
||||
self.assertEqual((yield self.rdport.data), 0xaa)
|
||||
yield self.rdport.addr.eq(1)
|
||||
yield Settle()
|
||||
self.assertEqual((yield self.rdport.data), 0x55)
|
||||
yield self.rdport.addr.eq(0)
|
||||
yield self.wrport.addr.eq(0)
|
||||
yield self.wrport.data.eq(0x33)
|
||||
yield self.wrport.en.eq(1)
|
||||
yield Tick("sync")
|
||||
self.assertEqual((yield self.rdport.data), 0xaa)
|
||||
yield Settle()
|
||||
yield Tick("sync")
|
||||
self.assertEqual((yield self.rdport.data), 0x33)
|
||||
sim.add_clock(1e-6)
|
||||
sim.add_process(process)
|
||||
sim.add_testbench(process)
|
||||
|
||||
def test_memory_read_only(self):
|
||||
self.m = Module()
|
||||
|
@ -841,6 +873,49 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
sim.add_clock(1e-6)
|
||||
sim.add_sync_process(process)
|
||||
|
||||
def test_comb_bench_process(self):
|
||||
m = Module()
|
||||
a = Signal(reset=1)
|
||||
b = Signal()
|
||||
m.d.comb += b.eq(a)
|
||||
with self.assertSimulation(m) as sim:
|
||||
def process():
|
||||
self.assertEqual((yield a), 1)
|
||||
self.assertEqual((yield b), 1)
|
||||
yield a.eq(0)
|
||||
self.assertEqual((yield a), 0)
|
||||
self.assertEqual((yield b), 0)
|
||||
sim.add_testbench(process)
|
||||
|
||||
def test_sync_bench_process(self):
|
||||
m = Module()
|
||||
a = Signal(reset=1)
|
||||
b = Signal()
|
||||
m.d.sync += b.eq(a)
|
||||
t = Signal()
|
||||
m.d.sync += t.eq(~t)
|
||||
with self.assertSimulation(m) as sim:
|
||||
def process():
|
||||
self.assertEqual((yield a), 1)
|
||||
self.assertEqual((yield b), 0)
|
||||
self.assertEqual((yield t), 0)
|
||||
yield Tick()
|
||||
self.assertEqual((yield a), 1)
|
||||
self.assertEqual((yield b), 1)
|
||||
self.assertEqual((yield t), 1)
|
||||
yield Tick()
|
||||
self.assertEqual((yield a), 1)
|
||||
self.assertEqual((yield b), 1)
|
||||
self.assertEqual((yield t), 0)
|
||||
yield a.eq(0)
|
||||
self.assertEqual((yield a), 0)
|
||||
self.assertEqual((yield b), 1)
|
||||
yield Tick()
|
||||
self.assertEqual((yield a), 0)
|
||||
self.assertEqual((yield b), 0)
|
||||
sim.add_clock(1e-6)
|
||||
sim.add_testbench(process)
|
||||
|
||||
def test_memory_transparency_simple(self):
|
||||
m = Module()
|
||||
init = [0x11, 0x22, 0x33, 0x44]
|
||||
|
@ -850,41 +925,35 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
with self.assertSimulation(m) as sim:
|
||||
def process():
|
||||
yield rdport.addr.eq(0)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x11)
|
||||
yield rdport.addr.eq(1)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x22)
|
||||
yield wrport.addr.eq(0)
|
||||
yield wrport.data.eq(0x44444444)
|
||||
yield wrport.en.eq(1)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x22)
|
||||
yield wrport.addr.eq(1)
|
||||
yield wrport.data.eq(0x55)
|
||||
yield wrport.en.eq(1)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x55)
|
||||
yield wrport.addr.eq(1)
|
||||
yield wrport.data.eq(0x66)
|
||||
yield wrport.en.eq(1)
|
||||
yield rdport.en.eq(0)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x55)
|
||||
yield wrport.addr.eq(2)
|
||||
yield wrport.data.eq(0x77)
|
||||
yield wrport.en.eq(1)
|
||||
yield rdport.en.eq(1)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x66)
|
||||
sim.add_clock(1e-6)
|
||||
sim.add_sync_process(process)
|
||||
sim.add_testbench(process)
|
||||
|
||||
def test_memory_transparency_multibit(self):
|
||||
m = Module()
|
||||
|
@ -895,41 +964,35 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
with self.assertSimulation(m) as sim:
|
||||
def process():
|
||||
yield rdport.addr.eq(0)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x11111111)
|
||||
yield rdport.addr.eq(1)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x22222222)
|
||||
yield wrport.addr.eq(0)
|
||||
yield wrport.data.eq(0x44444444)
|
||||
yield wrport.en.eq(1)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x22222222)
|
||||
yield wrport.addr.eq(1)
|
||||
yield wrport.data.eq(0x55555555)
|
||||
yield wrport.en.eq(1)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x22222255)
|
||||
yield wrport.addr.eq(1)
|
||||
yield wrport.data.eq(0x66666666)
|
||||
yield wrport.en.eq(2)
|
||||
yield rdport.en.eq(0)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x22222255)
|
||||
yield wrport.addr.eq(1)
|
||||
yield wrport.data.eq(0x77777777)
|
||||
yield wrport.en.eq(4)
|
||||
yield rdport.en.eq(1)
|
||||
yield
|
||||
yield Settle()
|
||||
yield Tick()
|
||||
self.assertEqual((yield rdport.data), 0x22776655)
|
||||
sim.add_clock(1e-6)
|
||||
sim.add_sync_process(process)
|
||||
sim.add_testbench(process)
|
||||
|
||||
def test_vcd_wrong_nonzero_time(self):
|
||||
s = Signal()
|
||||
|
@ -977,7 +1040,7 @@ class SimulatorRegressionTestCase(FHDLTestCase):
|
|||
sim = Simulator(Module())
|
||||
def process():
|
||||
self.assertEqual((yield -(Const(0b11, 2).as_signed())), 1)
|
||||
sim.add_process(process)
|
||||
sim.add_testbench(process)
|
||||
sim.run()
|
||||
|
||||
def test_bug_595(self):
|
||||
|
@ -1018,5 +1081,5 @@ class SimulatorRegressionTestCase(FHDLTestCase):
|
|||
self.assertEqual((yield C(0b0000, 4) | ~C(1, 1)), 0b0000)
|
||||
self.assertEqual((yield C(0b1111, 4) & ~C(1, 1)), 0b0000)
|
||||
self.assertEqual((yield C(0b1111, 4) ^ ~C(1, 1)), 0b1111)
|
||||
sim.add_process(process)
|
||||
sim.add_testbench(process)
|
||||
sim.run()
|
||||
|
|
Loading…
Reference in a new issue