- (⊙) `core` **brk**
- (⊙) `vcd` **brk** → `vcd`
- (⊙) `Simulator` **brk**
- - (+) `run_simulation` **obs** → `.back.pysim.Simulator`
- - (â\88\92) `passive` **obs** → `.hdl.ast.Passive`
+ - (⊕) `run_simulation` **obs** → `.back.pysim.Simulator`
+ - (â\8a\95) `passive` **obs** → `.hdl.ast.Passive`
- (−) `build` ?
- (+) `util` **obs**
- (+) `misc` ⇒ `.tools`
+import functools
+import collections
+import inspect
from ...back.pysim import *
-__all__ = ["run_simulation"]
+__all__ = ["run_simulation", "passive"]
def run_simulation(fragment_or_module, generators, clocks={"sync": 10}, vcd_name=None,
with Simulator(fragment, vcd_file=open(vcd_name, "w") if vcd_name else None) as sim:
for domain, period in clocks.items():
sim.add_clock(period / 1e9, domain=domain)
- for domain, process in generators.items():
- sim.add_sync_process(process, domain=domain)
+ for domain, processes in generators.items():
+ if isinstance(processes, collections.Iterable) and not inspect.isgenerator(processes):
+ for process in processes:
+ sim.add_sync_process(process, domain=domain)
+ else:
+ sim.add_sync_process(processes, domain=domain)
sim.run()
+
+
+def passive(generator):
+ @functools.wraps(generator)
+ def wrapper(*args, **kwargs):
+ yield Passive()
+ yield from generator(*args, **kwargs)
+ return wrapper
--- /dev/null
+from ...compat import *
+# from ...compat.fhdl import verilog
+
+
+class SimCase:
+ def setUp(self, *args, **kwargs):
+ self.tb = self.TestBench(*args, **kwargs)
+
+ # def test_to_verilog(self):
+ # verilog.convert(self.tb)
+
+ def run_with(self, generator):
+ run_simulation(self.tb, generator)
--- /dev/null
+import unittest
+
+from ...compat import *
+from ...compat.genlib.coding import *
+
+from .support import SimCase
+
+
+class EncCase(SimCase, unittest.TestCase):
+ class TestBench(Module):
+ def __init__(self):
+ self.submodules.dut = Encoder(8)
+
+ def test_sizes(self):
+ self.assertEqual(len(self.tb.dut.i), 8)
+ self.assertEqual(len(self.tb.dut.o), 3)
+ self.assertEqual(len(self.tb.dut.n), 1)
+
+ def test_run_sequence(self):
+ seq = list(range(1<<8))
+ def gen():
+ for _ in range(256):
+ if seq:
+ yield self.tb.dut.i.eq(seq.pop(0))
+ yield
+ if (yield self.tb.dut.n):
+ self.assertNotIn((yield self.tb.dut.i), [1<<i for i in range(8)])
+ else:
+ self.assertEqual((yield self.tb.dut.i), 1<<(yield self.tb.dut.o))
+ self.run_with(gen())
+
+
+class PrioEncCase(SimCase, unittest.TestCase):
+ class TestBench(Module):
+ def __init__(self):
+ self.submodules.dut = PriorityEncoder(8)
+
+ def test_sizes(self):
+ self.assertEqual(len(self.tb.dut.i), 8)
+ self.assertEqual(len(self.tb.dut.o), 3)
+ self.assertEqual(len(self.tb.dut.n), 1)
+
+ def test_run_sequence(self):
+ seq = list(range(1<<8))
+ def gen():
+ for _ in range(256):
+ if seq:
+ yield self.tb.dut.i.eq(seq.pop(0))
+ yield
+ i = yield self.tb.dut.i
+ if (yield self.tb.dut.n):
+ self.assertEqual(i, 0)
+ else:
+ o = yield self.tb.dut.o
+ if o > 0:
+ self.assertEqual(i & 1<<(o - 1), 0)
+ self.assertGreaterEqual(i, 1<<o)
+ self.run_with(gen())
+
+
+class DecCase(SimCase, unittest.TestCase):
+ class TestBench(Module):
+ def __init__(self):
+ self.submodules.dut = Decoder(8)
+
+ def test_sizes(self):
+ self.assertEqual(len(self.tb.dut.i), 3)
+ self.assertEqual(len(self.tb.dut.o), 8)
+ self.assertEqual(len(self.tb.dut.n), 1)
+
+ def test_run_sequence(self):
+ seq = list(range(8*2))
+ def gen():
+ for _ in range(256):
+ if seq:
+ i = seq.pop()
+ yield self.tb.dut.i.eq(i//2)
+ yield self.tb.dut.n.eq(i%2)
+ yield
+ i = yield self.tb.dut.i
+ o = yield self.tb.dut.o
+ if (yield self.tb.dut.n):
+ self.assertEqual(o, 0)
+ else:
+ self.assertEqual(o, 1<<i)
+ self.run_with(gen())
+
+
+class SmallPrioEncCase(SimCase, unittest.TestCase):
+ class TestBench(Module):
+ def __init__(self):
+ self.submodules.dut = PriorityEncoder(1)
+
+ def test_sizes(self):
+ self.assertEqual(len(self.tb.dut.i), 1)
+ self.assertEqual(len(self.tb.dut.o), 1)
+ self.assertEqual(len(self.tb.dut.n), 1)
+
+ def test_run_sequence(self):
+ seq = list(range(1))
+ def gen():
+ for _ in range(5):
+ if seq:
+ yield self.tb.dut.i.eq(seq.pop(0))
+ yield
+ i = yield self.tb.dut.i
+ if (yield self.tb.dut.n):
+ self.assertEqual(i, 0)
+ else:
+ o = yield self.tb.dut.o
+ if o > 0:
+ self.assertEqual(i & 1<<(o - 1), 0)
+ self.assertGreaterEqual(i, 1<<o)
+ self.run_with(gen())
--- /dev/null
+import unittest
+
+from ...compat import *
+from .support import SimCase
+
+
+class ConstantCase(SimCase, unittest.TestCase):
+ class TestBench(Module):
+ def __init__(self):
+ self.sigs = [
+ (Signal(3), Constant(0), 0),
+ (Signal(3), Constant(5), 5),
+ (Signal(3), Constant(1, 2), 1),
+ (Signal(3), Constant(-1, 7), 7),
+ (Signal(3), Constant(0b10101)[:3], 0b101),
+ (Signal(3), Constant(0b10101)[1:4], 0b10),
+ (Signal(4), Constant(0b1100)[::-1], 0b0011),
+ ]
+ self.comb += [a.eq(b) for a, b, c in self.sigs]
+
+ def test_comparisons(self):
+ def gen():
+ for s, l, v in self.tb.sigs:
+ s = yield s
+ self.assertEqual(
+ s, int(v),
+ "got {}, want {} from literal {}".format(
+ s, v, l))
+ self.run_with(gen())
--- /dev/null
+import unittest
+from itertools import count
+
+from ...compat import *
+from ...compat.genlib.fifo import SyncFIFO
+
+from .support import SimCase
+
+
+class SyncFIFOCase(SimCase, unittest.TestCase):
+ class TestBench(Module):
+ def __init__(self):
+ self.submodules.dut = SyncFIFO(64, 2)
+
+ self.sync += [
+ If(self.dut.we & self.dut.writable,
+ self.dut.din[:32].eq(self.dut.din[:32] + 1),
+ self.dut.din[32:].eq(self.dut.din[32:] + 2)
+ )
+ ]
+
+ def test_run_sequence(self):
+ seq = list(range(20))
+ def gen():
+ for cycle in count():
+ # fire re and we at "random"
+ yield self.tb.dut.we.eq(cycle % 2 == 0)
+ yield self.tb.dut.re.eq(cycle % 3 == 0)
+ # the output if valid must be correct
+ if (yield self.tb.dut.readable) and (yield self.tb.dut.re):
+ try:
+ i = seq.pop(0)
+ except IndexError:
+ break
+ self.assertEqual((yield self.tb.dut.dout[:32]), i)
+ self.assertEqual((yield self.tb.dut.dout[32:]), i*2)
+ yield
+ self.run_with(gen())
+
+ def test_replace(self):
+ seq = [x for x in range(20) if x % 5]
+ def gen():
+ for cycle in count():
+ yield self.tb.dut.we.eq(cycle % 2 == 0)
+ yield self.tb.dut.re.eq(cycle % 7 == 0)
+ yield self.tb.dut.replace.eq(
+ (yield self.tb.dut.din[:32]) % 5 == 1)
+ if (yield self.tb.dut.readable) and (yield self.tb.dut.re):
+ try:
+ i = seq.pop(0)
+ except IndexError:
+ break
+ self.assertEqual((yield self.tb.dut.dout[:32]), i)
+ self.assertEqual((yield self.tb.dut.dout[32:]), i*2)
+ yield
+ self.run_with(gen())
--- /dev/null
+import unittest
+from itertools import count
+
+from ...compat import *
+from ...compat.genlib.fsm import FSM
+
+from .support import SimCase
+
+
+class FSMCase(SimCase, unittest.TestCase):
+ class TestBench(Module):
+ def __init__(self):
+ self.ctrl = Signal()
+ self.data = Signal()
+ self.status = Signal(8)
+
+ self.submodules.dut = FSM()
+ self.dut.act("IDLE",
+ If(self.ctrl,
+ NextState("START")
+ )
+ )
+ self.dut.act("START",
+ If(self.data,
+ NextState("SET-STATUS-LOW")
+ ).Else(
+ NextState("SET-STATUS")
+ )
+ )
+ self.dut.act("SET-STATUS",
+ NextValue(self.status, 0xaa),
+ NextState("IDLE")
+ )
+ self.dut.act("SET-STATUS-LOW",
+ NextValue(self.status[:4], 0xb),
+ NextState("IDLE")
+ )
+
+ def assertState(self, fsm, state):
+ self.assertEqual(fsm.decoding[(yield fsm.state)], state)
+
+ def test_next_state(self):
+ def gen():
+ yield from self.assertState(self.tb.dut, "IDLE")
+ yield
+ yield from self.assertState(self.tb.dut, "IDLE")
+ yield self.tb.ctrl.eq(1)
+ yield
+ yield from self.assertState(self.tb.dut, "IDLE")
+ yield self.tb.ctrl.eq(0)
+ yield
+ yield from self.assertState(self.tb.dut, "START")
+ yield
+ yield from self.assertState(self.tb.dut, "SET-STATUS")
+ yield self.tb.ctrl.eq(1)
+ yield
+ yield from self.assertState(self.tb.dut, "IDLE")
+ yield self.tb.ctrl.eq(0)
+ yield self.tb.data.eq(1)
+ yield
+ yield from self.assertState(self.tb.dut, "START")
+ yield self.tb.data.eq(0)
+ yield
+ yield from self.assertState(self.tb.dut, "SET-STATUS-LOW")
+ self.run_with(gen())
+
+ def test_next_value(self):
+ def gen():
+ self.assertEqual((yield self.tb.status), 0x00)
+ yield self.tb.ctrl.eq(1)
+ yield
+ yield self.tb.ctrl.eq(0)
+ yield
+ yield
+ yield from self.assertState(self.tb.dut, "SET-STATUS")
+ yield self.tb.ctrl.eq(1)
+ yield
+ self.assertEqual((yield self.tb.status), 0xaa)
+ yield self.tb.ctrl.eq(0)
+ yield self.tb.data.eq(1)
+ yield
+ yield self.tb.data.eq(0)
+ yield
+ yield from self.assertState(self.tb.dut, "SET-STATUS-LOW")
+ yield
+ self.assertEqual((yield self.tb.status), 0xab)
+ self.run_with(gen())
--- /dev/null
+import unittest
+
+from ...compat import *
+
+
+class PassiveCase(unittest.TestCase):
+ def test_terminates_correctly(self):
+ n = 5
+
+ count = 0
+ @passive
+ def counter():
+ nonlocal count
+ while True:
+ yield
+ count += 1
+
+ def terminator():
+ for i in range(n):
+ yield
+
+ run_simulation(Module(), [counter(), terminator()])
+ self.assertEqual(count, n)
--- /dev/null
+import unittest
+
+from ...compat import *
+from .support import SimCase
+
+
+class SignedCase(SimCase, unittest.TestCase):
+ class TestBench(Module):
+ def __init__(self):
+ self.a = Signal((3, True))
+ self.b = Signal((4, True))
+ comps = [
+ lambda p, q: p > q,
+ lambda p, q: p >= q,
+ lambda p, q: p < q,
+ lambda p, q: p <= q,
+ lambda p, q: p == q,
+ lambda p, q: p != q,
+ ]
+ self.vals = []
+ for asign in 1, -1:
+ for bsign in 1, -1:
+ for f in comps:
+ r = Signal()
+ r0 = f(asign*self.a, bsign*self.b)
+ self.comb += r.eq(r0)
+ self.vals.append((asign, bsign, f, r, r0.op))
+
+ def test_comparisons(self):
+ def gen():
+ for i in range(-4, 4):
+ yield self.tb.a.eq(i)
+ yield self.tb.b.eq(i)
+ yield
+ a = yield self.tb.a
+ b = yield self.tb.b
+ for asign, bsign, f, r, op in self.tb.vals:
+ r, r0 = (yield r), f(asign*a, bsign*b)
+ self.assertEqual(r, int(r0),
+ "got {}, want {}*{} {} {}*{} = {}".format(
+ r, asign, a, op, bsign, b, r0))
+ self.run_with(gen())
--- /dev/null
+import unittest
+
+from ...compat import *
+
+
+def _same_slices(a, b):
+ return a.value is b.value and a.start == b.start and a.stop == b.stop
+
+
+class SignalSizeCase(unittest.TestCase):
+ def setUp(self):
+ self.i = C(0xaa)
+ self.j = C(-127)
+ self.s = Signal((13, True))
+
+ def test_len(self):
+ self.assertEqual(len(self.s), 13)
+ self.assertEqual(len(self.i), 8)
+ self.assertEqual(len(self.j), 8)