2021-12-09 22:39:50 -07:00
|
|
|
# amaranth: UnusedElaboratable=no
|
2019-10-26 00:36:54 -06:00
|
|
|
|
2018-12-17 15:55:30 -07:00
|
|
|
from collections import OrderedDict
|
|
|
|
|
2024-01-30 09:43:33 -07:00
|
|
|
from amaranth.hdl._ast import *
|
|
|
|
from amaranth.hdl._cd import *
|
2024-02-13 07:54:54 -07:00
|
|
|
from amaranth.hdl._dsl import *
|
2024-01-30 09:43:33 -07:00
|
|
|
from amaranth.hdl._ir import *
|
|
|
|
from amaranth.hdl._mem import *
|
2024-04-13 05:38:47 -06:00
|
|
|
from amaranth.hdl._nir import SignalField, CombinationalCycle
|
2024-04-11 11:53:49 -06:00
|
|
|
|
|
|
|
from amaranth.lib import enum, data
|
tests: move out of the main package.
Compared to tests in the repository root, tests in the package have
many downsides:
* Unless explicitly excluded in find_packages(), tests and their
support code effectively become a part of public API.
This, unfortunately, happened with FHDLTestCase, which was never
intended for downstream use.
* Even if explicitly excluded from the setuptools package, using
an editable install, or setting PYTHONPATH still allows accessing
the tests.
* Having a sub-package that is present in the source tree but not
exported (or, worse, exported only sometimes) is confusing.
* The name `nmigen.test` cannot be used for anything else, such as
testing utilities that *are* intended for downstream use.
2020-08-26 18:33:31 -06:00
|
|
|
|
2019-10-13 12:53:38 -06:00
|
|
|
from .utils import *
|
2018-12-13 01:09:39 -07:00
|
|
|
|
|
|
|
|
2021-12-11 05:39:34 -07:00
|
|
|
class ElaboratesToNone(Elaboratable):
|
2019-08-03 06:30:39 -06:00
|
|
|
def elaborate(self, platform):
|
|
|
|
return
|
|
|
|
|
|
|
|
|
2021-12-11 05:39:34 -07:00
|
|
|
class ElaboratesToSelf(Elaboratable):
|
|
|
|
def elaborate(self, platform):
|
|
|
|
return self
|
|
|
|
|
|
|
|
|
2019-02-14 13:52:42 -07:00
|
|
|
class FragmentGetTestCase(FHDLTestCase):
|
2021-12-11 05:39:34 -07:00
|
|
|
def test_get_wrong_none(self):
|
2024-03-19 15:23:30 -06:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Object None is not an 'Elaboratable' nor 'Fragment'$"):
|
2019-02-14 13:52:42 -07:00
|
|
|
Fragment.get(None, platform=None)
|
|
|
|
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertWarnsRegex(UserWarning,
|
|
|
|
r"^\.elaborate\(\) returned None; missing return statement\?$"):
|
2024-03-19 15:23:30 -06:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Object None is not an 'Elaboratable' nor 'Fragment'$"):
|
2021-12-11 05:39:34 -07:00
|
|
|
Fragment.get(ElaboratesToNone(), platform=None)
|
|
|
|
|
|
|
|
def test_get_wrong_self(self):
|
|
|
|
with self.assertRaisesRegex(RecursionError,
|
|
|
|
r"^Object <.+?ElaboratesToSelf.+?> elaborates to itself$"):
|
|
|
|
Fragment.get(ElaboratesToSelf(), platform=None)
|
2019-08-03 06:30:39 -06:00
|
|
|
|
2019-02-14 13:52:42 -07:00
|
|
|
|
2018-12-26 05:35:27 -07:00
|
|
|
class FragmentGeneratedTestCase(FHDLTestCase):
|
|
|
|
def test_find_subfragment(self):
|
|
|
|
f1 = Fragment()
|
|
|
|
f2 = Fragment()
|
|
|
|
f1.add_subfragment(f2, "f2")
|
|
|
|
|
|
|
|
self.assertEqual(f1.find_subfragment(0), f2)
|
|
|
|
self.assertEqual(f1.find_subfragment("f2"), f2)
|
|
|
|
|
|
|
|
def test_find_subfragment_wrong(self):
|
|
|
|
f1 = Fragment()
|
|
|
|
f2 = Fragment()
|
|
|
|
f1.add_subfragment(f2, "f2")
|
|
|
|
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(NameError,
|
|
|
|
r"^No subfragment at index #1$"):
|
2018-12-26 05:35:27 -07:00
|
|
|
f1.find_subfragment(1)
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(NameError,
|
|
|
|
r"^No subfragment with name 'fx'$"):
|
2018-12-26 05:35:27 -07:00
|
|
|
f1.find_subfragment("fx")
|
|
|
|
|
|
|
|
def test_find_generated(self):
|
|
|
|
f1 = Fragment()
|
|
|
|
f2 = Fragment()
|
|
|
|
f2.generated["sig"] = sig = Signal()
|
|
|
|
f1.add_subfragment(f2, "f2")
|
|
|
|
|
|
|
|
self.assertEqual(SignalKey(f1.find_generated("f2", "sig")),
|
|
|
|
SignalKey(sig))
|
|
|
|
|
|
|
|
|
2024-04-03 04:02:32 -06:00
|
|
|
class DuplicateElaboratableTestCase(FHDLTestCase):
|
|
|
|
def test_duplicate(self):
|
|
|
|
sub = Module()
|
|
|
|
m = Module()
|
|
|
|
m.submodules.a = sub
|
|
|
|
m.submodules.b = sub
|
|
|
|
with self.assertRaisesRegex(DuplicateElaboratable,
|
|
|
|
r"^Elaboratable .* is included twice in the hierarchy, as "
|
|
|
|
r"top\.a and top\.b$"):
|
|
|
|
Fragment.get(m, None).prepare()
|
|
|
|
|
|
|
|
|
2018-12-13 02:19:16 -07:00
|
|
|
class FragmentPortsTestCase(FHDLTestCase):
|
2018-12-13 01:09:39 -07:00
|
|
|
def setUp(self):
|
|
|
|
self.s1 = Signal()
|
|
|
|
self.s2 = Signal()
|
|
|
|
self.s3 = Signal()
|
|
|
|
self.c1 = Signal()
|
|
|
|
self.c2 = Signal()
|
|
|
|
self.c3 = Signal()
|
|
|
|
|
2018-12-13 04:25:49 -07:00
|
|
|
def test_empty(self):
|
|
|
|
f = Fragment()
|
2024-02-11 04:07:45 -07:00
|
|
|
nl = build_netlist(f, ports=[])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top'))
|
2024-03-14 23:37:17 -06:00
|
|
|
(cell 0 0 (top))
|
2018-12-13 01:09:39 -07:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
""")
|
2018-12-13 04:01:03 -07:00
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
def test_loopback(self):
|
2018-12-13 01:09:39 -07:00
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
2024-02-09 12:27:25 -07:00
|
|
|
"comb",
|
2024-02-11 04:07:45 -07:00
|
|
|
self.c1.eq(self.s1),
|
2018-12-13 01:09:39 -07:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
nl = build_netlist(f, ports=[self.c1, self.s1])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top') (input 's1' 0.2) (output 'c1' 0.2))
|
2024-02-29 13:42:25 -07:00
|
|
|
(cell 0 0 (top (input 's1' 2:3) (output 'c1' 0.2)))
|
2018-12-13 01:09:39 -07:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
""")
|
2018-12-13 04:01:03 -07:00
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
def test_subfragment_simple(self):
|
2018-12-13 01:09:39 -07:00
|
|
|
f1 = Fragment()
|
|
|
|
f2 = Fragment()
|
|
|
|
f2.add_statements(
|
2024-02-09 12:27:25 -07:00
|
|
|
"comb",
|
2024-02-11 04:07:45 -07:00
|
|
|
self.c1.eq(~self.s1),
|
2018-12-13 01:09:39 -07:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
f1.add_subfragment(f2, "f2")
|
|
|
|
nl = build_netlist(f1, ports=[self.c1, self.s1])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top') (input 's1' 0.2) (output 'c1' 1.0))
|
|
|
|
(module 1 0 ('top' 'f2') (input 's1' 0.2) (output 'c1' 1.0))
|
2024-02-29 13:42:25 -07:00
|
|
|
(cell 0 0 (top (input 's1' 2:3) (output 'c1' 1.0)))
|
2024-02-11 04:07:45 -07:00
|
|
|
(cell 1 1 (~ 0.2))
|
2018-12-13 04:50:56 -07:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
""")
|
2018-12-13 04:50:56 -07:00
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
def test_tree(self):
|
|
|
|
f = Fragment()
|
2018-12-13 01:09:39 -07:00
|
|
|
f1 = Fragment()
|
2024-02-11 04:07:45 -07:00
|
|
|
f.add_subfragment(f1, "f1")
|
|
|
|
f11 = Fragment()
|
|
|
|
f1.add_subfragment(f11, "f11")
|
|
|
|
f111 = Fragment()
|
|
|
|
f11.add_subfragment(f111, "f111")
|
|
|
|
f1111 = Fragment()
|
|
|
|
f111.add_subfragment(f1111, "f1111")
|
|
|
|
f12 = Fragment()
|
|
|
|
f1.add_subfragment(f12, "f12")
|
|
|
|
f13 = Fragment()
|
|
|
|
f1.add_subfragment(f13, "f13")
|
|
|
|
f131 = Fragment()
|
|
|
|
f13.add_subfragment(f131, "f131")
|
2018-12-13 01:09:39 -07:00
|
|
|
f2 = Fragment()
|
2024-02-11 04:07:45 -07:00
|
|
|
f.add_subfragment(f2, "f2")
|
2018-12-13 01:09:39 -07:00
|
|
|
f2.add_statements(
|
2024-02-09 12:27:25 -07:00
|
|
|
"comb",
|
2024-02-11 04:07:45 -07:00
|
|
|
self.s2.eq(~self.s1),
|
2018-12-13 01:09:39 -07:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
f131.add_statements(
|
2024-02-09 12:27:25 -07:00
|
|
|
"comb",
|
2024-02-11 04:07:45 -07:00
|
|
|
self.s3.eq(~self.s2),
|
|
|
|
Assert(~self.s1),
|
2019-05-13 09:34:13 -06:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
f12.add_statements(
|
2024-02-09 12:27:25 -07:00
|
|
|
"comb",
|
2024-02-11 04:07:45 -07:00
|
|
|
self.c1.eq(~self.s3),
|
2019-05-13 09:34:13 -06:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
f1111.add_statements(
|
2024-02-09 12:27:25 -07:00
|
|
|
"comb",
|
2024-02-11 04:07:45 -07:00
|
|
|
self.c2.eq(~self.s3),
|
|
|
|
Assert(self.s1),
|
2019-05-13 09:34:13 -06:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
f111.add_statements(
|
2024-02-09 12:27:25 -07:00
|
|
|
"comb",
|
2024-02-11 04:07:45 -07:00
|
|
|
self.c3.eq(~self.c2),
|
2018-12-21 16:53:18 -07:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
nl = build_netlist(f, ports=[self.c1, self.c2, self.c3, self.s1])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's1' 0.2)
|
|
|
|
(output 'c1' 5.0)
|
|
|
|
(output 'c2' 2.0)
|
|
|
|
(output 'c3' 1.0))
|
|
|
|
(module 1 0 ('top' 'f1')
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 's1' 0.2)
|
|
|
|
(output 'c3' 1.0)
|
|
|
|
(output 'c2' 2.0)
|
|
|
|
(output 'c1' 5.0)
|
|
|
|
(input 's2' 10.0))
|
2024-02-11 04:07:45 -07:00
|
|
|
(module 2 1 ('top' 'f1' 'f11')
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 's1' 0.2)
|
|
|
|
(output 'c3' 1.0)
|
|
|
|
(output 'c2' 2.0)
|
|
|
|
(input 's3' 6.0))
|
2024-02-11 04:07:45 -07:00
|
|
|
(module 3 2 ('top' 'f1' 'f11' 'f111')
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 's1' 0.2)
|
2024-02-11 04:07:45 -07:00
|
|
|
(output 'c3' 1.0)
|
|
|
|
(output 'c2' 2.0)
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 's3' 6.0))
|
2024-02-11 04:07:45 -07:00
|
|
|
(module 4 3 ('top' 'f1' 'f11' 'f111' 'f1111')
|
|
|
|
(input 's1' 0.2)
|
|
|
|
(output 'c2' 2.0)
|
|
|
|
(input 's3' 6.0))
|
|
|
|
(module 5 1 ('top' 'f1' 'f12')
|
|
|
|
(output 'c1' 5.0)
|
|
|
|
(input 's3' 6.0))
|
|
|
|
(module 6 1 ('top' 'f1' 'f13')
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 's1' 0.2)
|
|
|
|
(output 's3' 6.0)
|
|
|
|
(input 's2' 10.0))
|
2024-02-11 04:07:45 -07:00
|
|
|
(module 7 6 ('top' 'f1' 'f13' 'f131')
|
|
|
|
(input 's1' 0.2)
|
|
|
|
(output 's3' 6.0)
|
|
|
|
(input 's2' 10.0))
|
|
|
|
(module 8 0 ('top' 'f2')
|
|
|
|
(input 's1' 0.2)
|
|
|
|
(output 's2' 10.0))
|
2024-02-29 13:42:25 -07:00
|
|
|
(cell 0 0 (top (input 's1' 2:3) (output 'c1' 5.0) (output 'c2' 2.0) (output 'c3' 1.0)))
|
2024-02-11 04:07:45 -07:00
|
|
|
(cell 1 3 (~ 2.0))
|
|
|
|
(cell 2 4 (~ 6.0))
|
|
|
|
(cell 3 4 (assignment_list 1'd0 (1 0:1 1'd1)))
|
2024-03-05 21:23:47 -07:00
|
|
|
(cell 4 4 (assert 0.2 3.0 None))
|
2024-02-11 04:07:45 -07:00
|
|
|
(cell 5 5 (~ 6.0))
|
|
|
|
(cell 6 7 (~ 10.0))
|
|
|
|
(cell 7 7 (~ 0.2))
|
|
|
|
(cell 8 7 (assignment_list 1'd0 (1 0:1 1'd1)))
|
2024-03-05 21:23:47 -07:00
|
|
|
(cell 9 7 (assert 7.0 8.0 None))
|
2024-02-11 04:07:45 -07:00
|
|
|
(cell 10 8 (~ 0.2))
|
2018-12-21 16:53:18 -07:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
""")
|
2018-12-21 16:53:18 -07:00
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
def test_port_dict(self):
|
|
|
|
f = Fragment()
|
|
|
|
nl = build_netlist(f, ports={
|
|
|
|
"a": (self.s1, PortDirection.Output),
|
|
|
|
"b": (self.s2, PortDirection.Input),
|
2024-03-14 23:37:17 -06:00
|
|
|
"c": (IOPort(1, name="io3"), PortDirection.Inout),
|
2024-02-11 04:07:45 -07:00
|
|
|
})
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
2024-03-14 23:37:17 -06:00
|
|
|
(module 0 None ('top') (input 'b' 0.2) (output 'a' 1'd0) (io inout 'c' 0.0))
|
|
|
|
(cell 0 0 (top (input 'b' 2:3) (output 'a' 1'd0)))
|
2018-12-21 17:31:31 -07:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
""")
|
2018-12-21 17:31:31 -07:00
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
def test_port_domain(self):
|
2018-12-13 04:01:03 -07:00
|
|
|
f = Fragment()
|
2024-02-11 04:07:45 -07:00
|
|
|
cd_sync = ClockDomain()
|
|
|
|
ctr = Signal(4)
|
|
|
|
f.add_domains(cd_sync)
|
|
|
|
f.add_statements("sync", ctr.eq(ctr + 1))
|
|
|
|
nl = build_netlist(f, ports=[
|
|
|
|
ClockSignal("sync"),
|
|
|
|
ResetSignal("sync"),
|
|
|
|
ctr,
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top') (input 'clk' 0.2) (input 'rst' 0.3) (output 'ctr' 5.0:4))
|
2024-02-29 13:42:25 -07:00
|
|
|
(cell 0 0 (top (input 'clk' 2:3) (input 'rst' 3:4) (output 'ctr' 5.0:4)))
|
2024-02-11 04:07:45 -07:00
|
|
|
(cell 1 0 (+ (cat 5.0:4 1'd0) 5'd1))
|
|
|
|
(cell 2 0 (matches 0.3 1))
|
|
|
|
(cell 3 0 (priority_match 1 2.0))
|
|
|
|
(cell 4 0 (assignment_list 5.0:4 (1 0:4 1.0:4) (3.0 0:4 4'd0)))
|
|
|
|
(cell 5 0 (flipflop 4.0:4 0 pos 0.2 0))
|
2018-12-13 04:01:03 -07:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
""")
|
2018-12-13 04:01:03 -07:00
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
def test_port_autodomain(self):
|
2018-12-13 04:01:03 -07:00
|
|
|
f = Fragment()
|
2024-02-11 04:07:45 -07:00
|
|
|
ctr = Signal(4)
|
|
|
|
f.add_statements("sync", ctr.eq(ctr + 1))
|
|
|
|
nl = build_netlist(f, ports=[ctr])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top') (input 'clk' 0.2) (input 'rst' 0.3) (output 'ctr' 5.0:4))
|
2024-02-29 13:42:25 -07:00
|
|
|
(cell 0 0 (top (input 'clk' 2:3) (input 'rst' 3:4) (output 'ctr' 5.0:4)))
|
2024-02-11 04:07:45 -07:00
|
|
|
(cell 1 0 (+ (cat 5.0:4 1'd0) 5'd1))
|
|
|
|
(cell 2 0 (matches 0.3 1))
|
|
|
|
(cell 3 0 (priority_match 1 2.0))
|
|
|
|
(cell 4 0 (assignment_list 5.0:4 (1 0:4 1.0:4) (3.0 0:4 4'd0)))
|
|
|
|
(cell 5 0 (flipflop 4.0:4 0 pos 0.2 0))
|
2018-12-13 04:01:03 -07:00
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
""")
|
2018-12-13 04:01:03 -07:00
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
def test_port_partial(self):
|
|
|
|
f = Fragment()
|
2018-12-17 15:55:30 -07:00
|
|
|
f1 = Fragment()
|
2024-02-11 04:07:45 -07:00
|
|
|
f.add_subfragment(f1, "f1")
|
|
|
|
a = Signal(4)
|
|
|
|
b = Signal(4)
|
|
|
|
c = Signal(3)
|
|
|
|
f1.add_statements("comb", c.eq((a * b).shift_right(4)))
|
|
|
|
nl = build_netlist(f, ports=[a, b, c])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'a' 0.2:6)
|
|
|
|
(input 'b' 0.6:10)
|
|
|
|
(output 'c' 1.4:7))
|
|
|
|
(module 1 0 ('top' 'f1')
|
|
|
|
(input 'a' 0.2:6)
|
|
|
|
(input 'b' 0.6:10)
|
|
|
|
(output 'c' 1.4:7))
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'a' 2:6)
|
2024-02-29 13:42:25 -07:00
|
|
|
(input 'b' 6:10)
|
|
|
|
(output 'c' 1.4:7)))
|
2024-02-11 04:07:45 -07:00
|
|
|
(cell 1 1 (* (cat 0.2:6 4'd0) (cat 0.6:10 4'd0)))
|
|
|
|
)
|
|
|
|
""")
|
2019-11-26 14:17:12 -07:00
|
|
|
|
2024-03-14 23:37:17 -06:00
|
|
|
def test_port_io(self):
|
|
|
|
io = IOPort(8)
|
|
|
|
f = Fragment()
|
|
|
|
f1 = Fragment()
|
|
|
|
f1.add_subfragment(Instance("t", i_io=io[:2]), "i")
|
|
|
|
f.add_subfragment(f1, "f1")
|
|
|
|
f2 = Fragment()
|
|
|
|
f2.add_subfragment(Instance("t", o_io=io[2:4]), "i")
|
|
|
|
f.add_subfragment(f2, "f2")
|
|
|
|
f3 = Fragment()
|
|
|
|
f3.add_subfragment(Instance("t", io_io=io[4:6]), "i")
|
|
|
|
f.add_subfragment(f3, "f3")
|
|
|
|
nl = build_netlist(f, ports=[])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(io inout 'io' 0.0:8)
|
|
|
|
)
|
|
|
|
(module 1 0 ('top' 'f1')
|
|
|
|
(io input 'ioport$0$0' 0.0:2)
|
|
|
|
)
|
|
|
|
(module 2 0 ('top' 'f2')
|
|
|
|
(io output 'ioport$0$2' 0.2:4)
|
|
|
|
)
|
|
|
|
(module 3 0 ('top' 'f3')
|
|
|
|
(io inout 'ioport$0$4' 0.4:6)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top))
|
|
|
|
(cell 1 1 (instance 't' 'i' (io input 'io' 0.0:2)))
|
|
|
|
(cell 2 2 (instance 't' 'i' (io output 'io' 0.2:4)))
|
|
|
|
(cell 3 3 (instance 't' 'i' (io inout 'io' 0.4:6)))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_port_io_part(self):
|
|
|
|
io = IOPort(4)
|
|
|
|
f = Fragment()
|
|
|
|
f1 = Fragment()
|
|
|
|
f1.add_subfragment(Instance("t", i_i=io[0], o_o=io[1], io_io=io[2]), "i")
|
|
|
|
f.add_subfragment(f1, "f1")
|
|
|
|
nl = build_netlist(f, ports=[])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(io inout 'io' 0.0:4)
|
|
|
|
)
|
|
|
|
(module 1 0 ('top' 'f1')
|
|
|
|
(io input 'ioport$0$0' 0.0)
|
|
|
|
(io output 'ioport$0$1' 0.1)
|
|
|
|
(io inout 'ioport$0$2' 0.2)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top))
|
|
|
|
(cell 1 1 (instance 't' 'i'
|
|
|
|
(io input 'i' 0.0)
|
|
|
|
(io output 'o' 0.1)
|
|
|
|
(io inout 'io' 0.2)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
2019-11-26 14:17:12 -07:00
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
def test_port_instance(self):
|
2019-10-12 21:39:56 -06:00
|
|
|
f = Fragment()
|
2024-02-11 04:07:45 -07:00
|
|
|
f1 = Fragment()
|
|
|
|
f.add_subfragment(f1, "f1")
|
|
|
|
a = Signal(4)
|
|
|
|
b = Signal(4)
|
|
|
|
c = Signal(4)
|
2024-03-14 23:37:17 -06:00
|
|
|
ioa = IOPort(4)
|
|
|
|
iob = IOPort(4)
|
|
|
|
ioc = IOPort(4)
|
2024-02-11 04:07:45 -07:00
|
|
|
f1.add_subfragment(Instance("t",
|
|
|
|
p_p = "meow",
|
|
|
|
a_a = True,
|
|
|
|
i_aa=a,
|
2024-03-14 23:37:17 -06:00
|
|
|
o_bb=b,
|
2024-02-11 04:07:45 -07:00
|
|
|
o_cc=c,
|
2024-03-14 23:37:17 -06:00
|
|
|
i_aaa=ioa,
|
|
|
|
o_bbb=iob,
|
|
|
|
io_ccc=ioc,
|
2024-02-11 04:07:45 -07:00
|
|
|
), "i")
|
2024-03-14 23:37:17 -06:00
|
|
|
nl = build_netlist(f, ports=[a, b, c])
|
2024-02-11 04:07:45 -07:00
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'a' 0.2:6)
|
2024-03-14 23:37:17 -06:00
|
|
|
(output 'b' 1.0:4)
|
|
|
|
(output 'c' 1.4:8)
|
|
|
|
(io input 'ioa' 0.0:4)
|
|
|
|
(io output 'iob' 1.0:4)
|
|
|
|
(io inout 'ioc' 2.0:4)
|
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
(module 1 0 ('top' 'f1')
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 'a' 0.2:6)
|
|
|
|
(output 'b' 1.0:4)
|
|
|
|
(output 'c' 1.4:8)
|
|
|
|
(io input 'ioa' 0.0:4)
|
|
|
|
(io output 'iob' 1.0:4)
|
|
|
|
(io inout 'ioc' 2.0:4)
|
|
|
|
)
|
2024-02-11 04:07:45 -07:00
|
|
|
(cell 0 0 (top
|
2024-02-29 13:42:25 -07:00
|
|
|
(input 'a' 2:6)
|
2024-03-14 23:37:17 -06:00
|
|
|
(output 'b' 1.0:4)
|
|
|
|
(output 'c' 1.4:8)
|
|
|
|
))
|
2024-02-11 04:07:45 -07:00
|
|
|
(cell 1 1 (instance 't' 'i'
|
|
|
|
(param 'p' 'meow')
|
|
|
|
(attr 'a' True)
|
|
|
|
(input 'aa' 0.2:6)
|
2024-03-14 23:37:17 -06:00
|
|
|
(output 'bb' 0:4)
|
|
|
|
(output 'cc' 4:8)
|
|
|
|
(io input 'aaa' 0.0:4)
|
|
|
|
(io output 'bbb' 1.0:4)
|
|
|
|
(io inout 'ccc' 2.0:4)
|
|
|
|
))
|
2024-02-11 04:07:45 -07:00
|
|
|
)
|
|
|
|
""")
|
2019-10-12 21:39:56 -06:00
|
|
|
|
2020-02-06 10:33:41 -07:00
|
|
|
def test_port_wrong(self):
|
|
|
|
f = Fragment()
|
2024-02-11 04:07:45 -07:00
|
|
|
a = Signal()
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
2024-03-14 23:37:17 -06:00
|
|
|
r"^Only signals and IO ports may be added as ports, not \(const 1'd1\)$"):
|
2024-02-11 04:07:45 -07:00
|
|
|
build_netlist(f, ports=(Const(1),))
|
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Port name must be a string, not 1$"):
|
|
|
|
build_netlist(f, ports={1: (a, PortDirection.Input)})
|
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Port direction must be a `PortDirection` instance or None, not 'i'$"):
|
|
|
|
build_netlist(f, ports={"a": (a, "i")})
|
2018-12-13 04:01:03 -07:00
|
|
|
|
2020-04-24 15:15:00 -06:00
|
|
|
def test_port_not_iterable(self):
|
|
|
|
f = Fragment()
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
2024-02-11 04:07:45 -07:00
|
|
|
r"^`ports` must be a dict, a list or a tuple, not 1$"):
|
|
|
|
build_netlist(f, ports=1)
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
2024-02-11 04:07:45 -07:00
|
|
|
(r"^`ports` must be a dict, a list or a tuple, not \(const 1'd1\)"
|
2020-07-28 13:35:25 -06:00
|
|
|
r" \(did you mean `ports=\(<signal>,\)`, rather than `ports=<signal>`\?\)$")):
|
2024-02-11 04:07:45 -07:00
|
|
|
build_netlist(f, ports=Const(1))
|
2020-04-24 15:15:00 -06:00
|
|
|
|
2024-03-05 02:34:58 -07:00
|
|
|
|
2018-12-13 04:01:03 -07:00
|
|
|
class FragmentDomainsTestCase(FHDLTestCase):
|
|
|
|
def test_propagate_up(self):
|
|
|
|
cd = ClockDomain()
|
|
|
|
|
|
|
|
f1 = Fragment()
|
|
|
|
f2 = Fragment()
|
|
|
|
f1.add_subfragment(f2)
|
|
|
|
f2.add_domains(cd)
|
|
|
|
|
|
|
|
f1._propagate_domains_up()
|
|
|
|
self.assertEqual(f1.domains, {"cd": cd})
|
|
|
|
|
2019-08-19 14:46:46 -06:00
|
|
|
def test_propagate_up_local(self):
|
|
|
|
cd = ClockDomain(local=True)
|
|
|
|
|
|
|
|
f1 = Fragment()
|
|
|
|
f2 = Fragment()
|
|
|
|
f1.add_subfragment(f2)
|
|
|
|
f2.add_domains(cd)
|
|
|
|
|
|
|
|
f1._propagate_domains_up()
|
|
|
|
self.assertEqual(f1.domains, {})
|
|
|
|
|
2018-12-13 04:01:03 -07:00
|
|
|
def test_domain_conflict(self):
|
|
|
|
cda = ClockDomain("sync")
|
|
|
|
cdb = ClockDomain("sync")
|
|
|
|
|
|
|
|
fa = Fragment()
|
|
|
|
fa.add_domains(cda)
|
|
|
|
fb = Fragment()
|
|
|
|
fb.add_domains(cdb)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_subfragment(fa, "a")
|
|
|
|
f.add_subfragment(fb, "b")
|
|
|
|
|
|
|
|
f._propagate_domains_up()
|
|
|
|
self.assertEqual(f.domains, {"a_sync": cda, "b_sync": cdb})
|
2024-02-16 08:16:26 -07:00
|
|
|
(fa, _, _), (fb, _, _) = f.subfragments
|
2018-12-13 04:01:03 -07:00
|
|
|
self.assertEqual(fa.domains, {"a_sync": cda})
|
|
|
|
self.assertEqual(fb.domains, {"b_sync": cdb})
|
|
|
|
|
|
|
|
def test_domain_conflict_anon(self):
|
|
|
|
cda = ClockDomain("sync")
|
|
|
|
cdb = ClockDomain("sync")
|
|
|
|
|
|
|
|
fa = Fragment()
|
|
|
|
fa.add_domains(cda)
|
|
|
|
fb = Fragment()
|
|
|
|
fb.add_domains(cdb)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_subfragment(fa, "a")
|
|
|
|
f.add_subfragment(fb)
|
|
|
|
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(DomainError,
|
|
|
|
(r"^Domain 'sync' is defined by subfragments 'a', <unnamed #1> of fragment "
|
|
|
|
r"'top'; it is necessary to either rename subfragment domains explicitly, "
|
|
|
|
r"or give names to subfragments$")):
|
2018-12-13 04:01:03 -07:00
|
|
|
f._propagate_domains_up()
|
|
|
|
|
|
|
|
def test_domain_conflict_name(self):
|
|
|
|
cda = ClockDomain("sync")
|
|
|
|
cdb = ClockDomain("sync")
|
|
|
|
|
|
|
|
fa = Fragment()
|
|
|
|
fa.add_domains(cda)
|
|
|
|
fb = Fragment()
|
|
|
|
fb.add_domains(cdb)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_subfragment(fa, "x")
|
|
|
|
f.add_subfragment(fb, "x")
|
|
|
|
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(DomainError,
|
|
|
|
(r"^Domain 'sync' is defined by subfragments #0, #1 of fragment 'top', some "
|
|
|
|
r"of which have identical names; it is necessary to either rename subfragment "
|
|
|
|
r"domains explicitly, or give distinct names to subfragments$")):
|
2018-12-13 04:01:03 -07:00
|
|
|
f._propagate_domains_up()
|
|
|
|
|
2020-01-16 19:13:46 -07:00
|
|
|
def test_domain_conflict_rename_drivers(self):
|
|
|
|
cda = ClockDomain("sync")
|
|
|
|
cdb = ClockDomain("sync")
|
|
|
|
|
|
|
|
fa = Fragment()
|
|
|
|
fa.add_domains(cda)
|
|
|
|
fb = Fragment()
|
|
|
|
fb.add_domains(cdb)
|
2024-04-03 16:19:37 -06:00
|
|
|
fb.add_statements("comb", ResetSignal("sync").eq(1))
|
2020-01-16 19:13:46 -07:00
|
|
|
f = Fragment()
|
|
|
|
f.add_subfragment(fa, "a")
|
|
|
|
f.add_subfragment(fb, "b")
|
|
|
|
|
|
|
|
f._propagate_domains_up()
|
2024-02-16 08:16:26 -07:00
|
|
|
fb_new, _, _ = f.subfragments[1]
|
2024-04-03 16:19:37 -06:00
|
|
|
self.assertRepr(fb_new.statements["comb"], "((eq (rst b_sync) (const 1'd1)))")
|
2020-01-16 19:13:46 -07:00
|
|
|
|
2021-05-18 13:18:14 -06:00
|
|
|
def test_domain_conflict_rename_drivers_before_creating_missing(self):
|
2020-01-18 03:30:36 -07:00
|
|
|
cda = ClockDomain("sync")
|
|
|
|
cdb = ClockDomain("sync")
|
|
|
|
s = Signal()
|
|
|
|
|
|
|
|
fa = Fragment()
|
|
|
|
fa.add_domains(cda)
|
|
|
|
fb = Fragment()
|
|
|
|
fb.add_domains(cdb)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_subfragment(fa, "a")
|
|
|
|
f.add_subfragment(fb, "b")
|
2024-04-03 16:19:37 -06:00
|
|
|
f.add_statements("b_sync", s.eq(1))
|
2020-01-18 03:30:36 -07:00
|
|
|
|
|
|
|
f._propagate_domains(lambda name: ClockDomain(name))
|
|
|
|
|
2018-12-13 04:01:03 -07:00
|
|
|
def test_propagate_down(self):
|
|
|
|
cd = ClockDomain()
|
|
|
|
|
|
|
|
f1 = Fragment()
|
|
|
|
f2 = Fragment()
|
|
|
|
f1.add_domains(cd)
|
|
|
|
f1.add_subfragment(f2)
|
|
|
|
|
|
|
|
f1._propagate_domains_down()
|
|
|
|
self.assertEqual(f2.domains, {"cd": cd})
|
|
|
|
|
|
|
|
def test_propagate_down_idempotent(self):
|
|
|
|
cd = ClockDomain()
|
|
|
|
|
|
|
|
f1 = Fragment()
|
|
|
|
f1.add_domains(cd)
|
|
|
|
f2 = Fragment()
|
|
|
|
f2.add_domains(cd)
|
|
|
|
f1.add_subfragment(f2)
|
|
|
|
|
|
|
|
f1._propagate_domains_down()
|
|
|
|
self.assertEqual(f1.domains, {"cd": cd})
|
|
|
|
self.assertEqual(f2.domains, {"cd": cd})
|
|
|
|
|
|
|
|
def test_propagate(self):
|
|
|
|
cd = ClockDomain()
|
|
|
|
|
|
|
|
f1 = Fragment()
|
|
|
|
f2 = Fragment()
|
|
|
|
f1.add_domains(cd)
|
|
|
|
f1.add_subfragment(f2)
|
|
|
|
|
2019-08-03 09:44:02 -06:00
|
|
|
new_domains = f1._propagate_domains(missing_domain=lambda name: None)
|
2018-12-13 04:01:03 -07:00
|
|
|
self.assertEqual(f1.domains, {"cd": cd})
|
|
|
|
self.assertEqual(f2.domains, {"cd": cd})
|
2019-08-03 09:44:02 -06:00
|
|
|
self.assertEqual(new_domains, [])
|
2018-12-13 04:01:03 -07:00
|
|
|
|
2019-08-03 09:31:00 -06:00
|
|
|
def test_propagate_missing(self):
|
|
|
|
s1 = Signal()
|
|
|
|
f1 = Fragment()
|
2024-02-08 17:53:45 -07:00
|
|
|
f1.add_statements("sync", s1.eq(1))
|
2019-08-03 09:31:00 -06:00
|
|
|
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(DomainError,
|
|
|
|
r"^Domain 'sync' is used but not defined$"):
|
2019-08-03 09:31:00 -06:00
|
|
|
f1._propagate_domains(missing_domain=lambda name: None)
|
|
|
|
|
2019-08-03 08:54:20 -06:00
|
|
|
def test_propagate_create_missing(self):
|
|
|
|
s1 = Signal()
|
2018-12-13 04:01:03 -07:00
|
|
|
f1 = Fragment()
|
2024-02-08 17:53:45 -07:00
|
|
|
f1.add_statements("sync", s1.eq(1))
|
2018-12-13 04:01:03 -07:00
|
|
|
f2 = Fragment()
|
|
|
|
f1.add_subfragment(f2)
|
|
|
|
|
2019-08-03 09:44:02 -06:00
|
|
|
new_domains = f1._propagate_domains(missing_domain=lambda name: ClockDomain(name))
|
2018-12-13 04:01:03 -07:00
|
|
|
self.assertEqual(f1.domains.keys(), {"sync"})
|
|
|
|
self.assertEqual(f2.domains.keys(), {"sync"})
|
|
|
|
self.assertEqual(f1.domains["sync"], f2.domains["sync"])
|
2019-08-03 09:44:02 -06:00
|
|
|
self.assertEqual(new_domains, [f1.domains["sync"]])
|
|
|
|
|
|
|
|
def test_propagate_create_missing_fragment(self):
|
|
|
|
s1 = Signal()
|
|
|
|
f1 = Fragment()
|
2024-02-08 17:53:45 -07:00
|
|
|
f1.add_statements("sync", s1.eq(1))
|
2019-08-03 09:44:02 -06:00
|
|
|
|
|
|
|
cd = ClockDomain("sync")
|
|
|
|
f2 = Fragment()
|
|
|
|
f2.add_domains(cd)
|
|
|
|
|
|
|
|
new_domains = f1._propagate_domains(missing_domain=lambda name: f2)
|
|
|
|
self.assertEqual(f1.domains.keys(), {"sync"})
|
|
|
|
self.assertEqual(f1.domains["sync"], f2.domains["sync"])
|
2019-08-03 10:39:21 -06:00
|
|
|
self.assertEqual(new_domains, [])
|
2019-08-03 09:44:02 -06:00
|
|
|
self.assertEqual(f1.subfragments, [
|
2024-02-16 08:16:26 -07:00
|
|
|
(f2, "cd_sync", None)
|
2019-08-03 09:44:02 -06:00
|
|
|
])
|
|
|
|
|
2019-08-03 12:19:40 -06:00
|
|
|
def test_propagate_create_missing_fragment_many_domains(self):
|
|
|
|
s1 = Signal()
|
|
|
|
f1 = Fragment()
|
2024-02-08 17:53:45 -07:00
|
|
|
f1.add_statements("sync", s1.eq(1))
|
2019-08-03 12:19:40 -06:00
|
|
|
|
|
|
|
cd_por = ClockDomain("por")
|
|
|
|
cd_sync = ClockDomain("sync")
|
|
|
|
f2 = Fragment()
|
|
|
|
f2.add_domains(cd_por, cd_sync)
|
|
|
|
|
|
|
|
new_domains = f1._propagate_domains(missing_domain=lambda name: f2)
|
|
|
|
self.assertEqual(f1.domains.keys(), {"sync", "por"})
|
|
|
|
self.assertEqual(f2.domains.keys(), {"sync", "por"})
|
|
|
|
self.assertEqual(f1.domains["sync"], f2.domains["sync"])
|
|
|
|
self.assertEqual(new_domains, [])
|
|
|
|
self.assertEqual(f1.subfragments, [
|
2024-02-16 08:16:26 -07:00
|
|
|
(f2, "cd_sync", None)
|
2019-08-03 12:19:40 -06:00
|
|
|
])
|
|
|
|
|
2019-08-03 09:44:02 -06:00
|
|
|
def test_propagate_create_missing_fragment_wrong(self):
|
|
|
|
s1 = Signal()
|
|
|
|
f1 = Fragment()
|
2024-02-08 17:53:45 -07:00
|
|
|
f1.add_statements("sync", s1.eq(1))
|
2019-08-03 09:44:02 -06:00
|
|
|
|
|
|
|
f2 = Fragment()
|
|
|
|
f2.add_domains(ClockDomain("foo"))
|
|
|
|
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(DomainError,
|
|
|
|
(r"^Fragment returned by missing domain callback does not define requested "
|
|
|
|
r"domain 'sync' \(defines 'foo'\)\.$")):
|
2019-08-03 09:44:02 -06:00
|
|
|
f1._propagate_domains(missing_domain=lambda name: f2)
|
2018-12-14 15:47:58 -07:00
|
|
|
|
2024-04-02 10:45:24 -06:00
|
|
|
def test_propagate_up_use(self):
|
|
|
|
a = Signal()
|
|
|
|
m = Module()
|
|
|
|
m1 = Module()
|
|
|
|
m2 = Module()
|
|
|
|
m.submodules.m1 = m1
|
|
|
|
m.submodules.m2 = m2
|
|
|
|
m1.d.test += a.eq(1)
|
|
|
|
m2.domains.test = ClockDomain()
|
|
|
|
with self.assertWarnsRegex(DeprecationWarning,
|
|
|
|
r"^Domain 'test' is used in 'top.m1', but defined in 'top.m2', which will not be "
|
|
|
|
r"supported in Amaranth 0.6; define the domain in 'top' or one of its parents$"):
|
|
|
|
Fragment.get(m, None).prepare()
|
|
|
|
|
2018-12-14 15:47:58 -07:00
|
|
|
|
2018-12-22 14:43:46 -07:00
|
|
|
class FragmentHierarchyConflictTestCase(FHDLTestCase):
|
2019-11-07 01:20:27 -07:00
|
|
|
def test_no_conflict_local_domains(self):
|
|
|
|
f1 = Fragment()
|
|
|
|
cd1 = ClockDomain("d", local=True)
|
|
|
|
f1.add_domains(cd1)
|
2024-04-03 16:19:37 -06:00
|
|
|
f1.add_statements("comb", ClockSignal("d").eq(1))
|
2019-11-07 01:20:27 -07:00
|
|
|
f2 = Fragment()
|
|
|
|
cd2 = ClockDomain("d", local=True)
|
|
|
|
f2.add_domains(cd2)
|
2024-04-03 16:19:37 -06:00
|
|
|
f2.add_statements("comb", ClockSignal("d").eq(1))
|
2019-11-07 01:20:27 -07:00
|
|
|
f3 = Fragment()
|
|
|
|
f3.add_subfragment(f1)
|
|
|
|
f3.add_subfragment(f2)
|
|
|
|
f3.prepare()
|
|
|
|
|
2018-12-17 15:55:30 -07:00
|
|
|
|
|
|
|
class InstanceTestCase(FHDLTestCase):
|
2019-06-02 20:12:01 -06:00
|
|
|
def test_construct(self):
|
|
|
|
s1 = Signal()
|
|
|
|
s2 = Signal()
|
|
|
|
s3 = Signal()
|
|
|
|
s4 = Signal()
|
2024-03-14 23:37:17 -06:00
|
|
|
io1 = IOPort(1)
|
|
|
|
io2 = IOPort(1)
|
|
|
|
io3 = IOPort(1)
|
|
|
|
io4 = IOPort(1)
|
|
|
|
io5 = IOPort(1)
|
|
|
|
io6 = IOPort(1)
|
2019-06-02 20:12:01 -06:00
|
|
|
inst = Instance("foo",
|
2019-06-27 22:14:38 -06:00
|
|
|
("a", "ATTR1", 1),
|
2019-06-02 20:12:01 -06:00
|
|
|
("p", "PARAM1", 0x1234),
|
|
|
|
("i", "s1", s1),
|
|
|
|
("o", "s2", s2),
|
2024-03-14 23:37:17 -06:00
|
|
|
("i", "io1", io1),
|
|
|
|
("o", "io2", io2),
|
|
|
|
("io", "io3", io3),
|
2019-06-27 22:14:38 -06:00
|
|
|
a_ATTR2=2,
|
2019-06-02 20:12:01 -06:00
|
|
|
p_PARAM2=0x5678,
|
2024-03-14 23:37:17 -06:00
|
|
|
i_s3=s3,
|
|
|
|
o_s4=s4,
|
|
|
|
i_io4=io4,
|
|
|
|
o_io5=io5,
|
|
|
|
io_io6=io6,
|
2019-06-02 20:12:01 -06:00
|
|
|
)
|
2019-06-27 22:14:38 -06:00
|
|
|
self.assertEqual(inst.attrs, OrderedDict([
|
|
|
|
("ATTR1", 1),
|
|
|
|
("ATTR2", 2),
|
|
|
|
]))
|
2019-06-02 20:12:01 -06:00
|
|
|
self.assertEqual(inst.parameters, OrderedDict([
|
|
|
|
("PARAM1", 0x1234),
|
|
|
|
("PARAM2", 0x5678),
|
|
|
|
]))
|
2024-03-26 12:18:48 -06:00
|
|
|
self.assertEqual(inst.ports, OrderedDict([
|
2019-06-02 20:12:01 -06:00
|
|
|
("s1", (s1, "i")),
|
|
|
|
("s2", (s2, "o")),
|
2024-03-14 23:37:17 -06:00
|
|
|
("io1", (io1, "i")),
|
|
|
|
("io2", (io2, "o")),
|
|
|
|
("io3", (io3, "io")),
|
|
|
|
("s3", (s3, "i")),
|
|
|
|
("s4", (s4, "o")),
|
|
|
|
("io4", (io4, "i")),
|
|
|
|
("io5", (io5, "o")),
|
|
|
|
("io6", (io6, "io")),
|
2019-06-02 20:12:01 -06:00
|
|
|
]))
|
|
|
|
|
2019-10-12 21:19:17 -06:00
|
|
|
def test_cast_ports(self):
|
|
|
|
inst = Instance("foo",
|
|
|
|
("i", "s1", 1),
|
2024-03-14 23:37:17 -06:00
|
|
|
("io", "s2", Cat()),
|
|
|
|
i_s3=3,
|
|
|
|
io_s4=Cat(),
|
2019-10-12 21:19:17 -06:00
|
|
|
)
|
2024-03-26 12:18:48 -06:00
|
|
|
self.assertRepr(inst.ports["s1"][0], "(const 1'd1)")
|
|
|
|
self.assertRepr(inst.ports["s2"][0], "(io-cat )")
|
|
|
|
self.assertRepr(inst.ports["s3"][0], "(const 2'd3)")
|
|
|
|
self.assertRepr(inst.ports["s4"][0], "(io-cat )")
|
2019-10-12 21:19:17 -06:00
|
|
|
|
2019-06-02 20:12:01 -06:00
|
|
|
def test_wrong_construct_arg(self):
|
|
|
|
s = Signal()
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(NameError,
|
|
|
|
(r"^Instance argument \('', 's1', \(sig s\)\) should be a tuple "
|
2020-10-16 10:36:56 -06:00
|
|
|
r"\(kind, name, value\) where kind is one of \"a\", \"p\", \"i\", \"o\", or \"io\"$")):
|
2019-06-02 20:12:01 -06:00
|
|
|
Instance("foo", ("", "s1", s))
|
|
|
|
|
|
|
|
def test_wrong_construct_kwarg(self):
|
|
|
|
s = Signal()
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(NameError,
|
|
|
|
(r"^Instance keyword argument x_s1=\(sig s\) does not start with one of "
|
2020-10-16 10:36:56 -06:00
|
|
|
r"\"a_\", \"p_\", \"i_\", \"o_\", or \"io_\"$")):
|
2019-06-02 20:12:01 -06:00
|
|
|
Instance("foo", x_s1=s)
|
|
|
|
|
2018-12-20 21:03:03 -07:00
|
|
|
def setUp_cpu(self):
|
|
|
|
self.rst = Signal()
|
|
|
|
self.stb = Signal()
|
2024-03-14 23:37:17 -06:00
|
|
|
self.pins = IOPort(8)
|
2019-04-22 01:46:47 -06:00
|
|
|
self.datal = Signal(4)
|
|
|
|
self.datah = Signal(4)
|
2018-12-20 21:03:03 -07:00
|
|
|
self.inst = Instance("cpu",
|
2018-12-20 16:38:01 -07:00
|
|
|
p_RESET=0x1234,
|
|
|
|
i_clk=ClockSignal(),
|
2018-12-20 21:03:03 -07:00
|
|
|
i_rst=self.rst,
|
|
|
|
o_stb=self.stb,
|
2019-04-22 01:46:47 -06:00
|
|
|
o_data=Cat(self.datal, self.datah),
|
2019-06-02 20:39:14 -06:00
|
|
|
io_pins=self.pins[:]
|
2018-12-20 16:38:01 -07:00
|
|
|
)
|
2019-05-25 14:09:26 -06:00
|
|
|
self.wrap = Fragment()
|
|
|
|
self.wrap.add_subfragment(self.inst)
|
2018-12-20 21:03:03 -07:00
|
|
|
|
|
|
|
def test_init(self):
|
|
|
|
self.setUp_cpu()
|
|
|
|
f = self.inst
|
|
|
|
self.assertEqual(f.type, "cpu")
|
|
|
|
self.assertEqual(f.parameters, OrderedDict([("RESET", 0x1234)]))
|
2024-03-26 12:18:48 -06:00
|
|
|
self.assertEqual(list(f.ports.keys()), ["clk", "rst", "stb", "data", "pins"])
|
2019-06-27 22:14:38 -06:00
|
|
|
|
|
|
|
def test_prepare_attrs(self):
|
|
|
|
self.setUp_cpu()
|
|
|
|
self.inst.attrs["ATTR"] = 1
|
2024-02-11 04:07:45 -07:00
|
|
|
design = self.inst.prepare()
|
|
|
|
self.assertEqual(design.fragment.attrs, OrderedDict([
|
2019-06-27 22:14:38 -06:00
|
|
|
("ATTR", 1),
|
|
|
|
]))
|
2023-11-24 21:21:00 -07:00
|
|
|
|
2024-02-29 12:33:26 -07:00
|
|
|
def test_nir_simple(self):
|
|
|
|
f = Fragment()
|
|
|
|
i = Signal(3)
|
|
|
|
o = Signal(4)
|
2024-03-14 23:37:17 -06:00
|
|
|
ioa = IOPort(5)
|
|
|
|
iob = IOPort(6)
|
|
|
|
ioc = IOPort(7)
|
2024-02-29 12:33:26 -07:00
|
|
|
f.add_subfragment(Instance("gadget",
|
|
|
|
i_i=i,
|
|
|
|
o_o=o,
|
2024-03-14 23:37:17 -06:00
|
|
|
i_ioa=ioa,
|
|
|
|
o_iob=iob,
|
|
|
|
io_ioc=ioc,
|
2024-02-29 12:33:26 -07:00
|
|
|
p_param="TEST",
|
|
|
|
a_attr=1234,
|
|
|
|
), "my_gadget")
|
2024-03-14 23:37:17 -06:00
|
|
|
nl = build_netlist(f, [i, o])
|
2024-02-29 12:33:26 -07:00
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i' 0.2:5)
|
|
|
|
(output 'o' 1.0:4)
|
2024-03-14 23:37:17 -06:00
|
|
|
(io input 'ioa' 0.0:5)
|
|
|
|
(io output 'iob' 1.0:6)
|
|
|
|
(io inout 'ioc' 2.0:7)
|
2024-02-29 12:33:26 -07:00
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i' 2:5)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 'o' 1.0:4)
|
2024-02-29 12:33:26 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (instance 'gadget' 'my_gadget'
|
|
|
|
(param 'param' 'TEST')
|
|
|
|
(attr 'attr' 1234)
|
|
|
|
(input 'i' 0.2:5)
|
|
|
|
(output 'o' 0:4)
|
2024-03-14 23:37:17 -06:00
|
|
|
(io input 'ioa' 0.0:5)
|
|
|
|
(io output 'iob' 1.0:6)
|
|
|
|
(io inout 'ioc' 2.0:7)
|
2024-02-29 12:33:26 -07:00
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_nir_out_slice(self):
|
|
|
|
f = Fragment()
|
|
|
|
o = Signal(6)
|
|
|
|
f.add_subfragment(Instance("test",
|
|
|
|
o_o=o[:2],
|
|
|
|
), "t1")
|
|
|
|
f.add_subfragment(Instance("test",
|
|
|
|
o_o=o[2:4],
|
|
|
|
), "t2")
|
|
|
|
nl = build_netlist(f, [o])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(output 'o' (cat 1.0:2 2.0:2 2'd0))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(output 'o' (cat 1.0:2 2.0:2 2'd0))
|
|
|
|
))
|
|
|
|
(cell 1 0 (instance 'test' 't1'
|
|
|
|
(output 'o' 0:2)
|
|
|
|
))
|
|
|
|
(cell 2 0 (instance 'test' 't2'
|
|
|
|
(output 'o' 0:2)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_nir_out_concat(self):
|
|
|
|
f = Fragment()
|
|
|
|
o1 = Signal(4)
|
|
|
|
o2 = Signal(4)
|
|
|
|
f.add_subfragment(Instance("test",
|
|
|
|
o_o=Cat(o1, o2),
|
|
|
|
))
|
|
|
|
nl = build_netlist(f, [o1, o2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(output 'o1' 1.0:4)
|
|
|
|
(output 'o2' 1.4:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(output 'o1' 1.0:4)
|
|
|
|
(output 'o2' 1.4:8)
|
|
|
|
))
|
|
|
|
(cell 1 0 (instance 'test' 'U$0'
|
|
|
|
(output 'o' 0:8)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
2024-03-14 23:37:17 -06:00
|
|
|
def test_nir_io_slice(self):
|
|
|
|
f = Fragment()
|
|
|
|
io = IOPort(8)
|
|
|
|
f.add_subfragment(Instance("test",
|
|
|
|
i_i=io[:2],
|
|
|
|
o_o=io[2:4],
|
|
|
|
io_io=io[4:6],
|
|
|
|
), "t1")
|
|
|
|
nl = build_netlist(f, [])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(io inout 'io' 0.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top))
|
|
|
|
(cell 1 0 (instance 'test' 't1'
|
|
|
|
(io input 'i' 0.0:2)
|
|
|
|
(io output 'o' 0.2:4)
|
|
|
|
(io inout 'io' 0.4:6)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_nir_io_concat(self):
|
|
|
|
f = Fragment()
|
|
|
|
io1 = IOPort(4)
|
|
|
|
io2 = IOPort(4)
|
|
|
|
f.add_subfragment(Instance("test",
|
|
|
|
io_io=Cat(io1, io2),
|
|
|
|
))
|
|
|
|
nl = build_netlist(f, [io1, io2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(io inout 'io1' 0.0:4)
|
|
|
|
(io inout 'io2' 1.0:4)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top))
|
|
|
|
(cell 1 0 (instance 'test' 'U$0'
|
|
|
|
(io inout 'io' (io-cat 0.0:4 1.0:4))
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
2024-02-29 12:33:26 -07:00
|
|
|
def test_nir_operator(self):
|
|
|
|
f = Fragment()
|
|
|
|
i = Signal(3)
|
|
|
|
o = Signal(4)
|
|
|
|
f.add_subfragment(Instance("gadget",
|
|
|
|
i_i=i.as_signed(),
|
|
|
|
o_o=o.as_signed(),
|
|
|
|
), "my_gadget")
|
2024-03-14 23:37:17 -06:00
|
|
|
nl = build_netlist(f, [i, o])
|
2024-02-29 12:33:26 -07:00
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i' 0.2:5)
|
|
|
|
(output 'o' 1.0:4)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i' 2:5)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 'o' 1.0:4)
|
2024-02-29 12:33:26 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (instance 'gadget' 'my_gadget'
|
|
|
|
(input 'i' 0.2:5)
|
|
|
|
(output 'o' 0:4)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
2024-02-11 04:07:45 -07:00
|
|
|
|
2024-03-05 02:34:58 -07:00
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
class NamesTestCase(FHDLTestCase):
|
2023-11-24 21:21:00 -07:00
|
|
|
def test_assign_names_to_signals(self):
|
|
|
|
i = Signal()
|
|
|
|
rst = Signal()
|
|
|
|
o1 = Signal()
|
|
|
|
o2 = Signal()
|
|
|
|
o3 = Signal()
|
2024-03-23 10:33:29 -06:00
|
|
|
o4 = Signal(name="")
|
2023-11-24 21:21:00 -07:00
|
|
|
i1 = Signal(name="i")
|
|
|
|
|
|
|
|
f = Fragment()
|
|
|
|
f.add_domains(cd_sync := ClockDomain())
|
|
|
|
f.add_domains(cd_sync_norst := ClockDomain(reset_less=True))
|
2024-02-09 12:27:25 -07:00
|
|
|
f.add_statements("comb", [o1.eq(0)])
|
2024-02-08 17:53:45 -07:00
|
|
|
f.add_statements("sync", [o2.eq(i1)])
|
|
|
|
f.add_statements("sync_norst", [o3.eq(i1)])
|
2023-11-24 21:21:00 -07:00
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
ports = {
|
|
|
|
"i": (i, PortDirection.Input),
|
|
|
|
"rst": (rst, PortDirection.Input),
|
|
|
|
"o1": (o1, PortDirection.Output),
|
|
|
|
"o2": (o2, PortDirection.Output),
|
|
|
|
"o3": (o3, PortDirection.Output),
|
2024-03-23 10:33:29 -06:00
|
|
|
"o4": (o4, PortDirection.Output),
|
2024-02-11 04:07:45 -07:00
|
|
|
}
|
|
|
|
design = f.prepare(ports)
|
2024-03-14 23:37:17 -06:00
|
|
|
self.assertEqual(design.fragments[design.fragment].signal_names, SignalDict([
|
2023-11-24 21:21:00 -07:00
|
|
|
(i, "i"),
|
|
|
|
(rst, "rst"),
|
|
|
|
(o1, "o1"),
|
|
|
|
(o2, "o2"),
|
|
|
|
(o3, "o3"),
|
2024-03-23 10:33:29 -06:00
|
|
|
# (o4, "o4"), # Signal has a private name.
|
2023-11-24 21:21:00 -07:00
|
|
|
(cd_sync.clk, "clk"),
|
2024-03-23 10:33:29 -06:00
|
|
|
(cd_sync.rst, "rst$7"),
|
2023-11-24 21:21:00 -07:00
|
|
|
(cd_sync_norst.clk, "sync_norst_clk"),
|
2024-03-23 10:33:29 -06:00
|
|
|
(i1, "i$8"),
|
2023-11-24 21:21:00 -07:00
|
|
|
]))
|
|
|
|
|
2024-03-23 10:33:29 -06:00
|
|
|
def test_wrong_private_unnamed_toplevel_ports(self):
|
|
|
|
s = Signal(name="")
|
|
|
|
f = Fragment()
|
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Signals with private names cannot be used in unnamed top-level ports$"):
|
|
|
|
Design(f, ports=((None, s, None),), hierarchy=("top",))
|
|
|
|
|
2023-11-24 21:21:00 -07:00
|
|
|
def test_assign_names_to_fragments(self):
|
|
|
|
f = Fragment()
|
|
|
|
f.add_subfragment(a := Fragment())
|
|
|
|
f.add_subfragment(b := Fragment(), name="b")
|
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
design = Design(f, ports=(), hierarchy=("top",))
|
2024-03-14 23:37:17 -06:00
|
|
|
self.assertEqual(design.fragments[f].name, ("top",))
|
|
|
|
self.assertEqual(design.fragments[a].name, ("top", "U$0"))
|
|
|
|
self.assertEqual(design.fragments[b].name, ("top", "b"))
|
2023-11-24 21:21:00 -07:00
|
|
|
|
|
|
|
def test_assign_names_to_fragments_rename_top(self):
|
|
|
|
f = Fragment()
|
|
|
|
f.add_subfragment(a := Fragment())
|
|
|
|
f.add_subfragment(b := Fragment(), name="b")
|
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
design = Design(f, ports=[], hierarchy=("bench", "cpu"))
|
2024-03-14 23:37:17 -06:00
|
|
|
self.assertEqual(design.fragments[f].name, ("bench", "cpu",))
|
|
|
|
self.assertEqual(design.fragments[a].name, ("bench", "cpu", "U$0"))
|
|
|
|
self.assertEqual(design.fragments[b].name, ("bench", "cpu", "b"))
|
2023-11-24 21:21:00 -07:00
|
|
|
|
|
|
|
def test_assign_names_to_fragments_collide_with_signal(self):
|
|
|
|
f = Fragment()
|
|
|
|
f.add_subfragment(a_f := Fragment(), name="a")
|
2024-02-11 04:07:45 -07:00
|
|
|
a_s = Signal(name="a")
|
2023-11-24 21:21:00 -07:00
|
|
|
|
2024-02-11 04:07:45 -07:00
|
|
|
design = Design(f, ports=[("a", a_s, None)], hierarchy=("top",))
|
2024-03-14 23:37:17 -06:00
|
|
|
self.assertEqual(design.fragments[f].name, ("top",))
|
|
|
|
self.assertEqual(design.fragments[a_f].name, ("top", "a$1"))
|
2024-02-13 07:54:54 -07:00
|
|
|
|
2024-02-29 12:57:23 -07:00
|
|
|
def test_assign_names_to_fragments_duplicate(self):
|
|
|
|
f = Fragment()
|
|
|
|
f.add_subfragment(a1_f := Fragment(), name="a")
|
|
|
|
f.add_subfragment(a2_f := Fragment(), name="a")
|
|
|
|
|
|
|
|
design = Design(f, ports=[], hierarchy=("top",))
|
2024-03-14 23:37:17 -06:00
|
|
|
self.assertEqual(design.fragments[f].name, ("top",))
|
|
|
|
self.assertEqual(design.fragments[a1_f].name, ("top", "a"))
|
|
|
|
self.assertEqual(design.fragments[a2_f].name, ("top", "a$1"))
|
2024-02-29 12:57:23 -07:00
|
|
|
|
2024-02-13 07:54:54 -07:00
|
|
|
|
|
|
|
class ElaboratesTo(Elaboratable):
|
|
|
|
def __init__(self, lower):
|
|
|
|
self.lower = lower
|
|
|
|
|
|
|
|
def elaborate(self, platform):
|
|
|
|
return self.lower
|
|
|
|
|
|
|
|
|
|
|
|
class OriginsTestCase(FHDLTestCase):
|
|
|
|
def test_origins(self):
|
|
|
|
elab1 = ElaboratesTo(elab2 := ElaboratesTo(m := Module()))
|
|
|
|
frag = Fragment.get(elab1, platform=None)
|
|
|
|
self.assertEqual(len(frag.origins), 3)
|
|
|
|
self.assertIsInstance(frag.origins, tuple)
|
|
|
|
self.assertIs(frag.origins[0], elab1)
|
|
|
|
self.assertIs(frag.origins[1], elab2)
|
|
|
|
self.assertIs(frag.origins[2], m)
|
|
|
|
|
|
|
|
def test_origins_disable(self):
|
|
|
|
inst = Instance("test")
|
|
|
|
del inst.origins
|
|
|
|
elab = ElaboratesTo(inst)
|
|
|
|
frag = Fragment.get(elab, platform=None)
|
2024-02-12 07:11:42 -07:00
|
|
|
self.assertFalse(hasattr(frag, "_origins"))
|
|
|
|
|
|
|
|
|
|
|
|
class IOBufferTestCase(FHDLTestCase):
|
|
|
|
def test_nir_i(self):
|
2024-03-14 23:37:17 -06:00
|
|
|
port = IOPort(4)
|
2024-02-12 07:11:42 -07:00
|
|
|
i = Signal(4)
|
|
|
|
f = Fragment()
|
2024-03-14 23:37:17 -06:00
|
|
|
f.add_subfragment(IOBufferInstance(port, i=i))
|
|
|
|
nl = build_netlist(f, ports=[i])
|
2024-02-12 07:11:42 -07:00
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(output 'i' 1.0:4)
|
2024-03-14 23:37:17 -06:00
|
|
|
(io input 'port' 0.0:4)
|
2024-02-12 07:11:42 -07:00
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(output 'i' 1.0:4)
|
|
|
|
))
|
2024-03-14 23:37:17 -06:00
|
|
|
(cell 1 0 (iob input 0.0:4))
|
2024-02-12 07:11:42 -07:00
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_nir_o(self):
|
2024-03-14 23:37:17 -06:00
|
|
|
port = IOPort(4)
|
2024-02-12 07:11:42 -07:00
|
|
|
o = Signal(4)
|
|
|
|
f = Fragment()
|
2024-03-14 23:37:17 -06:00
|
|
|
f.add_subfragment(IOBufferInstance(port, o=o))
|
|
|
|
nl = build_netlist(f, ports=[o])
|
2024-02-12 07:11:42 -07:00
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 'o' 0.2:6)
|
|
|
|
(io output 'port' 0.0:4)
|
2024-02-12 07:11:42 -07:00
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 'o' 2:6)
|
2024-02-12 07:11:42 -07:00
|
|
|
))
|
2024-03-14 23:37:17 -06:00
|
|
|
(cell 1 0 (iob output 0.0:4 0.2:6 1))
|
2024-02-12 07:11:42 -07:00
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_nir_oe(self):
|
2024-03-14 23:37:17 -06:00
|
|
|
port = IOPort(4)
|
2024-02-12 07:11:42 -07:00
|
|
|
o = Signal(4)
|
|
|
|
oe = Signal()
|
|
|
|
f = Fragment()
|
2024-03-14 23:37:17 -06:00
|
|
|
f.add_subfragment(IOBufferInstance(port, o=o, oe=oe))
|
|
|
|
nl = build_netlist(f, ports=[ o, oe])
|
2024-02-12 07:11:42 -07:00
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 'o' 0.2:6)
|
|
|
|
(input 'oe' 0.6)
|
|
|
|
(io output 'port' 0.0:4)
|
2024-02-12 07:11:42 -07:00
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 'o' 2:6)
|
|
|
|
(input 'oe' 6:7)
|
2024-02-12 07:11:42 -07:00
|
|
|
))
|
2024-03-14 23:37:17 -06:00
|
|
|
(cell 1 0 (iob output 0.0:4 0.2:6 0.6))
|
2024-02-12 07:11:42 -07:00
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_nir_io(self):
|
2024-03-14 23:37:17 -06:00
|
|
|
port = IOPort(4)
|
2024-02-12 07:11:42 -07:00
|
|
|
i = Signal(4)
|
|
|
|
o = Signal(4)
|
|
|
|
oe = Signal()
|
|
|
|
f = Fragment()
|
2024-03-14 23:37:17 -06:00
|
|
|
f.add_subfragment(IOBufferInstance(port, i=i, o=o, oe=oe))
|
|
|
|
nl = build_netlist(f, ports=[i, o, oe])
|
2024-02-12 07:11:42 -07:00
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 'o' 0.2:6)
|
|
|
|
(input 'oe' 0.6)
|
2024-02-12 07:11:42 -07:00
|
|
|
(output 'i' 1.0:4)
|
2024-03-14 23:37:17 -06:00
|
|
|
(io inout 'port' 0.0:4)
|
2024-02-12 07:11:42 -07:00
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
2024-03-14 23:37:17 -06:00
|
|
|
(input 'o' 2:6)
|
|
|
|
(input 'oe' 6:7)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 'i' 1.0:4)
|
2024-02-12 07:11:42 -07:00
|
|
|
))
|
2024-03-14 23:37:17 -06:00
|
|
|
(cell 1 0 (iob inout 0.0:4 0.2:6 0.6))
|
2024-02-12 07:11:42 -07:00
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
2024-03-14 23:37:17 -06:00
|
|
|
def test_wrong_port(self):
|
|
|
|
port = Signal(4)
|
|
|
|
i = Signal(4)
|
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Object \(sig port\) cannot be converted to an IO value"):
|
|
|
|
IOBufferInstance(port, i=i)
|
|
|
|
|
2024-02-12 07:11:42 -07:00
|
|
|
def test_wrong_i(self):
|
2024-03-14 23:37:17 -06:00
|
|
|
port = IOPort(4)
|
2024-02-12 07:11:42 -07:00
|
|
|
i = Signal()
|
|
|
|
with self.assertRaisesRegex(ValueError,
|
2024-03-14 23:37:17 -06:00
|
|
|
r"^'port' length \(4\) doesn't match 'i' length \(1\)"):
|
|
|
|
IOBufferInstance(port, i=i)
|
2024-02-12 07:11:42 -07:00
|
|
|
|
|
|
|
def test_wrong_o(self):
|
2024-03-14 23:37:17 -06:00
|
|
|
port = IOPort(4)
|
2024-02-12 07:11:42 -07:00
|
|
|
o = Signal()
|
|
|
|
with self.assertRaisesRegex(ValueError,
|
2024-03-14 23:37:17 -06:00
|
|
|
r"^'port' length \(4\) doesn't match 'o' length \(1\)"):
|
|
|
|
IOBufferInstance(port, o=o)
|
2024-02-12 07:11:42 -07:00
|
|
|
|
|
|
|
def test_wrong_oe(self):
|
2024-03-14 23:37:17 -06:00
|
|
|
port = IOPort(4)
|
2024-02-12 07:11:42 -07:00
|
|
|
o = Signal(4)
|
|
|
|
oe = Signal(4)
|
|
|
|
with self.assertRaisesRegex(ValueError,
|
2024-03-14 23:37:17 -06:00
|
|
|
r"^'oe' length \(4\) must be 1"):
|
|
|
|
IOBufferInstance(port, o=o, oe=oe)
|
2024-02-12 07:11:42 -07:00
|
|
|
|
|
|
|
def test_wrong_oe_without_o(self):
|
2024-03-14 23:37:17 -06:00
|
|
|
port = IOPort(4)
|
2024-02-12 07:11:42 -07:00
|
|
|
oe = Signal()
|
|
|
|
with self.assertRaisesRegex(ValueError,
|
2024-03-14 23:37:17 -06:00
|
|
|
r"^'oe' must not be used if 'o' is not used"):
|
|
|
|
IOBufferInstance(port, oe=oe)
|
|
|
|
|
|
|
|
def test_conflict(self):
|
|
|
|
port = IOPort(4)
|
|
|
|
i1 = Signal(4)
|
|
|
|
i2 = Signal(4)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_subfragment(IOBufferInstance(port, i=i1))
|
|
|
|
f.add_subfragment(IOBufferInstance(port, i=i2))
|
|
|
|
with self.assertRaisesRegex(DriverConflict,
|
|
|
|
r"^Bit 0 of I/O port \(io-port port\) used twice, at .*test_hdl_ir.py:\d+ and "
|
|
|
|
r".*test_hdl_ir.py:\d+$"):
|
|
|
|
build_netlist(f, ports=[i1, i2])
|
2024-02-28 07:45:08 -07:00
|
|
|
|
|
|
|
|
|
|
|
class AssignTestCase(FHDLTestCase):
|
|
|
|
def test_simple(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(8)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1.eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:10)
|
|
|
|
(output 's1' 0.2:10)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:10)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 0.2:10)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_trunc(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(10)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1.eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:12)
|
|
|
|
(output 's1' 0.2:10)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:12)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 0.2:10)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_zext(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(6)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1.eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:8)
|
|
|
|
(output 's1' (cat 0.2:8 2'd0))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:8)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' (cat 0.2:8 2'd0))
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_sext(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(signed(6))
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1.eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:8)
|
|
|
|
(output 's1' (cat 0.2:8 0.7 0.7))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:8)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' (cat 0.2:8 0.7 0.7))
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_slice(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(4)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1[2:6].eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:6)
|
|
|
|
(output 's1' 1.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:6)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 1.0:8)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (assignment_list 8'd0 (1 2:6 0.2:6)))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_part(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(4)
|
|
|
|
s3 = Signal(4)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1.bit_select(s3, 4).eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:6)
|
|
|
|
(input 's3' 0.6:10)
|
|
|
|
(output 's1' 10.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:6)
|
|
|
|
(input 's3' 6:10)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 10.0:8)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.6:10 0000))
|
|
|
|
(cell 2 0 (matches 0.6:10 0001))
|
|
|
|
(cell 3 0 (matches 0.6:10 0010))
|
|
|
|
(cell 4 0 (matches 0.6:10 0011))
|
|
|
|
(cell 5 0 (matches 0.6:10 0100))
|
|
|
|
(cell 6 0 (matches 0.6:10 0101))
|
|
|
|
(cell 7 0 (matches 0.6:10 0110))
|
|
|
|
(cell 8 0 (matches 0.6:10 0111))
|
|
|
|
(cell 9 0 (priority_match 1 (cat 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0)))
|
|
|
|
(cell 10 0 (assignment_list 8'd0
|
|
|
|
(9.0 0:4 0.2:6)
|
|
|
|
(9.1 1:5 0.2:6)
|
|
|
|
(9.2 2:6 0.2:6)
|
|
|
|
(9.3 3:7 0.2:6)
|
|
|
|
(9.4 4:8 0.2:6)
|
|
|
|
(9.5 5:8 0.2:5)
|
|
|
|
(9.6 6:8 0.2:4)
|
|
|
|
(9.7 7:8 0.2)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_part_short(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(4)
|
|
|
|
s3 = Signal(2)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1.bit_select(s3, 4).eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:6)
|
|
|
|
(input 's3' 0.6:8)
|
|
|
|
(output 's1' 6.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:6)
|
|
|
|
(input 's3' 6:8)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 6.0:8)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.6:8 00))
|
|
|
|
(cell 2 0 (matches 0.6:8 01))
|
|
|
|
(cell 3 0 (matches 0.6:8 10))
|
|
|
|
(cell 4 0 (matches 0.6:8 11))
|
|
|
|
(cell 5 0 (priority_match 1 (cat 1.0 2.0 3.0 4.0)))
|
|
|
|
(cell 6 0 (assignment_list 8'd0
|
|
|
|
(5.0 0:4 0.2:6)
|
|
|
|
(5.1 1:5 0.2:6)
|
|
|
|
(5.2 2:6 0.2:6)
|
|
|
|
(5.3 3:7 0.2:6)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_part_word(self):
|
|
|
|
s1 = Signal(16)
|
|
|
|
s2 = Signal(4)
|
|
|
|
s3 = Signal(4)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1.word_select(s3, 4).eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:6)
|
|
|
|
(input 's3' 0.6:10)
|
|
|
|
(output 's1' 6.0:16)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:6)
|
|
|
|
(input 's3' 6:10)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 6.0:16)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.6:10 0000))
|
|
|
|
(cell 2 0 (matches 0.6:10 0001))
|
|
|
|
(cell 3 0 (matches 0.6:10 0010))
|
|
|
|
(cell 4 0 (matches 0.6:10 0011))
|
|
|
|
(cell 5 0 (priority_match 1 (cat 1.0 2.0 3.0 4.0)))
|
|
|
|
(cell 6 0 (assignment_list 16'd0
|
|
|
|
(5.0 0:4 0.2:6)
|
|
|
|
(5.1 4:8 0.2:6)
|
|
|
|
(5.2 8:12 0.2:6)
|
|
|
|
(5.3 12:16 0.2:6)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_part_word_misalign(self):
|
|
|
|
s1 = Signal(17)
|
|
|
|
s2 = Signal(4)
|
|
|
|
s3 = Signal(4)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1.word_select(s3, 4).eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:6)
|
|
|
|
(input 's3' 0.6:10)
|
|
|
|
(output 's1' 7.0:17)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:6)
|
|
|
|
(input 's3' 6:10)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 7.0:17)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.6:10 0000))
|
|
|
|
(cell 2 0 (matches 0.6:10 0001))
|
|
|
|
(cell 3 0 (matches 0.6:10 0010))
|
|
|
|
(cell 4 0 (matches 0.6:10 0011))
|
|
|
|
(cell 5 0 (matches 0.6:10 0100))
|
|
|
|
(cell 6 0 (priority_match 1 (cat 1.0 2.0 3.0 4.0 5.0)))
|
|
|
|
(cell 7 0 (assignment_list 17'd0
|
|
|
|
(6.0 0:4 0.2:6)
|
|
|
|
(6.1 4:8 0.2:6)
|
|
|
|
(6.2 8:12 0.2:6)
|
|
|
|
(6.3 12:16 0.2:6)
|
|
|
|
(6.4 16:17 0.2)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_concat(self):
|
|
|
|
s1 = Signal(4)
|
|
|
|
s2 = Signal(4)
|
|
|
|
s3 = Signal(4)
|
|
|
|
s4 = Signal(12)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
Cat(s1, s2, s3).eq(s4)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3, s4])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's4' 0.2:14)
|
|
|
|
(output 's1' 0.2:6)
|
|
|
|
(output 's2' 0.6:10)
|
|
|
|
(output 's3' 0.10:14)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
2024-02-29 13:42:25 -07:00
|
|
|
(input 's4' 2:14)
|
2024-02-28 07:45:08 -07:00
|
|
|
(output 's1' 0.2:6)
|
|
|
|
(output 's2' 0.6:10)
|
|
|
|
(output 's3' 0.10:14)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_concat_narrow(self):
|
|
|
|
s1 = Signal(4)
|
|
|
|
s2 = Signal(4)
|
|
|
|
s3 = Signal(4)
|
|
|
|
s4 = Signal(signed(6))
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
Cat(s1, s2, s3).eq(s4)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3, s4])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's4' 0.2:8)
|
|
|
|
(output 's1' 0.2:6)
|
|
|
|
(output 's2' (cat 0.6:8 0.7 0.7))
|
|
|
|
(output 's3' (cat 0.7 0.7 0.7 0.7))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
2024-02-29 13:42:25 -07:00
|
|
|
(input 's4' 2:8)
|
2024-02-28 07:45:08 -07:00
|
|
|
(output 's1' 0.2:6)
|
|
|
|
(output 's2' (cat 0.6:8 0.7 0.7))
|
|
|
|
(output 's3' (cat 0.7 0.7 0.7 0.7))
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_operator(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(8)
|
|
|
|
s3 = Signal(8)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements("comb", [
|
|
|
|
s1.as_signed().eq(s3),
|
|
|
|
s2.as_unsigned().eq(s3),
|
|
|
|
])
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's3' 0.2:10)
|
|
|
|
(output 's1' 0.2:10)
|
|
|
|
(output 's2' 0.2:10)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
2024-02-29 13:42:25 -07:00
|
|
|
(input 's3' 2:10)
|
2024-02-28 07:45:08 -07:00
|
|
|
(output 's1' 0.2:10)
|
|
|
|
(output 's2' 0.2:10)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_simple_array(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(8)
|
|
|
|
s3 = Signal(8)
|
|
|
|
s4 = Signal(8)
|
|
|
|
s5 = Signal(8)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements("comb", [
|
|
|
|
Array([s1, s2, s3])[s4].eq(s5),
|
|
|
|
])
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3, s4, s5])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's4' 0.2:10)
|
|
|
|
(input 's5' 0.10:18)
|
|
|
|
(output 's1' 5.0:8)
|
|
|
|
(output 's2' 6.0:8)
|
|
|
|
(output 's3' 7.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
2024-02-29 13:42:25 -07:00
|
|
|
(input 's4' 2:10)
|
|
|
|
(input 's5' 10:18)
|
2024-02-28 07:45:08 -07:00
|
|
|
(output 's1' 5.0:8)
|
|
|
|
(output 's2' 6.0:8)
|
|
|
|
(output 's3' 7.0:8)
|
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.2:10 00000000))
|
|
|
|
(cell 2 0 (matches 0.2:10 00000001))
|
|
|
|
(cell 3 0 (matches 0.2:10 00000010))
|
|
|
|
(cell 4 0 (priority_match 1 (cat 1.0 2.0 3.0)))
|
|
|
|
(cell 5 0 (assignment_list 8'd0 (4.0 0:8 0.10:18)))
|
|
|
|
(cell 6 0 (assignment_list 8'd0 (4.1 0:8 0.10:18)))
|
|
|
|
(cell 7 0 (assignment_list 8'd0 (4.2 0:8 0.10:18)))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
2024-04-03 01:09:18 -06:00
|
|
|
def test_switchvalue(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(8)
|
|
|
|
s3 = Signal(8)
|
|
|
|
s4 = Signal(8)
|
|
|
|
s5 = Signal(8)
|
|
|
|
s6 = Signal(8)
|
|
|
|
s7 = Signal(8)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements("comb", [
|
|
|
|
SwitchValue(s5[:4], [
|
|
|
|
(1, s1),
|
|
|
|
((2, 3), s2),
|
|
|
|
((), s3),
|
|
|
|
('11--', s4),
|
|
|
|
]).eq(s6),
|
|
|
|
SwitchValue(s5[4:], [
|
|
|
|
(4, s1),
|
|
|
|
(5, s2),
|
|
|
|
(6, s3),
|
|
|
|
(None, s4),
|
|
|
|
]).eq(s7),
|
|
|
|
])
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3, s4, s5, s6, s7])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's5' 0.2:10)
|
|
|
|
(input 's6' 0.10:18)
|
|
|
|
(input 's7' 0.18:26)
|
2024-03-26 19:36:06 -06:00
|
|
|
(output 's1' 10.0:8)
|
|
|
|
(output 's2' 11.0:8)
|
2024-04-03 01:09:18 -06:00
|
|
|
(output 's3' 12.0:8)
|
2024-03-26 19:36:06 -06:00
|
|
|
(output 's4' 13.0:8)
|
2024-04-03 01:09:18 -06:00
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's5' 2:10)
|
|
|
|
(input 's6' 10:18)
|
|
|
|
(input 's7' 18:26)
|
2024-03-26 19:36:06 -06:00
|
|
|
(output 's1' 10.0:8)
|
|
|
|
(output 's2' 11.0:8)
|
2024-04-03 01:09:18 -06:00
|
|
|
(output 's3' 12.0:8)
|
2024-03-26 19:36:06 -06:00
|
|
|
(output 's4' 13.0:8)
|
2024-04-03 01:09:18 -06:00
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.2:6 0001))
|
|
|
|
(cell 2 0 (matches 0.2:6 0010 0011))
|
2024-03-26 19:36:06 -06:00
|
|
|
(cell 3 0 (matches 0.2:6 ))
|
|
|
|
(cell 4 0 (matches 0.2:6 11--))
|
|
|
|
(cell 5 0 (priority_match 1 (cat 1.0 2.0 3.0 4.0)))
|
|
|
|
(cell 6 0 (matches 0.6:10 0100))
|
|
|
|
(cell 7 0 (matches 0.6:10 0101))
|
|
|
|
(cell 8 0 (matches 0.6:10 0110))
|
|
|
|
(cell 9 0 (priority_match 1 (cat 6.0 7.0 8.0 1'd1)))
|
|
|
|
(cell 10 0 (assignment_list 8'd0 (5.0 0:8 0.10:18) (9.0 0:8 0.18:26)))
|
|
|
|
(cell 11 0 (assignment_list 8'd0 (5.1 0:8 0.10:18) (9.1 0:8 0.18:26)))
|
|
|
|
(cell 12 0 (assignment_list 8'd0 (5.2 0:8 0.10:18) (9.2 0:8 0.18:26)))
|
|
|
|
(cell 13 0 (assignment_list 8'd0 (5.3 0:8 0.10:18) (9.3 0:8 0.18:26)))
|
2024-04-03 01:09:18 -06:00
|
|
|
)
|
|
|
|
""")
|
2024-04-04 17:06:17 -06:00
|
|
|
|
|
|
|
def test_mux_en(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(8)
|
|
|
|
s3 = Signal(8)
|
|
|
|
s4 = Signal(8)
|
|
|
|
en = Signal()
|
|
|
|
m = Module()
|
|
|
|
with m.If(en):
|
|
|
|
m.d.comb += Mux(s1, s2, s3).eq(s4)
|
|
|
|
nl = build_netlist(Fragment.get(m, None), ports=[s1, s2, s3, s4, en])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's1' 0.2:10)
|
|
|
|
(input 's4' 0.10:18)
|
|
|
|
(input 'en' 0.18)
|
|
|
|
(output 's2' 6.0:8)
|
|
|
|
(output 's3' 5.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's1' 2:10)
|
|
|
|
(input 's4' 10:18)
|
|
|
|
(input 'en' 18:19)
|
|
|
|
(output 's2' 6.0:8)
|
|
|
|
(output 's3' 5.0:8)
|
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.18 1))
|
|
|
|
(cell 2 0 (priority_match 1 1.0))
|
|
|
|
(cell 3 0 (matches 0.2:10 00000000))
|
|
|
|
(cell 4 0 (priority_match 2.0 (cat 3.0 1'd1)))
|
|
|
|
(cell 5 0 (assignment_list 8'd0 (4.0 0:8 0.10:18)))
|
|
|
|
(cell 6 0 (assignment_list 8'd0 (4.1 0:8 0.10:18)))
|
|
|
|
)
|
|
|
|
""")
|
2024-04-03 01:09:18 -06:00
|
|
|
|
2024-02-28 07:45:08 -07:00
|
|
|
def test_sliced_slice(self):
|
|
|
|
s1 = Signal(12)
|
|
|
|
s2 = Signal(4)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1[1:11][2:6].eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:6)
|
|
|
|
(output 's1' 1.0:12)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:6)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 1.0:12)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (assignment_list 12'd0 (1 3:7 0.2:6)))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_sliced_concat(self):
|
|
|
|
s1 = Signal(4)
|
|
|
|
s2 = Signal(4)
|
|
|
|
s3 = Signal(4)
|
|
|
|
s4 = Signal(4)
|
|
|
|
s5 = Signal(4)
|
|
|
|
s6 = Signal(8)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
Cat(s1, s2, s3, s4, s5)[5:14].eq(s6)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3, s4, s5, s6])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's1' 0.2:6)
|
|
|
|
(input 's5' 0.6:10)
|
|
|
|
(input 's6' 0.10:18)
|
|
|
|
(output 's2' 1.0:4)
|
|
|
|
(output 's3' 0.13:17)
|
|
|
|
(output 's4' 2.0:4)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's1' 2:6)
|
|
|
|
(input 's5' 6:10)
|
|
|
|
(input 's6' 10:18)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's2' 1.0:4)
|
|
|
|
(output 's3' 0.13:17)
|
|
|
|
(output 's4' 2.0:4)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (assignment_list 4'd0 (1 1:4 0.10:13)))
|
|
|
|
(cell 2 0 (assignment_list 4'd0 (1 0:2 (cat 0.17 1'd0))))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_sliced_part(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(4)
|
|
|
|
s3 = Signal(4)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1.bit_select(s3, 6)[2:4].eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:6)
|
|
|
|
(input 's3' 0.6:10)
|
|
|
|
(output 's1' 10.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:6)
|
|
|
|
(input 's3' 6:10)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 10.0:8)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.6:10 0000))
|
|
|
|
(cell 2 0 (matches 0.6:10 0001))
|
|
|
|
(cell 3 0 (matches 0.6:10 0010))
|
|
|
|
(cell 4 0 (matches 0.6:10 0011))
|
|
|
|
(cell 5 0 (matches 0.6:10 0100))
|
|
|
|
(cell 6 0 (matches 0.6:10 0101))
|
|
|
|
(cell 7 0 (matches 0.6:10 0110))
|
|
|
|
(cell 8 0 (matches 0.6:10 0111))
|
|
|
|
(cell 9 0 (priority_match 1 (cat 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0)))
|
|
|
|
(cell 10 0 (assignment_list 8'd0
|
|
|
|
(9.0 2:4 0.2:4)
|
|
|
|
(9.1 3:5 0.2:4)
|
|
|
|
(9.2 4:6 0.2:4)
|
|
|
|
(9.3 5:7 0.2:4)
|
|
|
|
(9.4 6:8 0.2:4)
|
|
|
|
(9.5 7:8 0.2)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_sliced_part_word(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(4)
|
|
|
|
s3 = Signal(4)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1.word_select(s3, 4)[1:3].eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:6)
|
|
|
|
(input 's3' 0.6:10)
|
|
|
|
(output 's1' 4.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:6)
|
|
|
|
(input 's3' 6:10)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 4.0:8)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.6:10 0000))
|
|
|
|
(cell 2 0 (matches 0.6:10 0001))
|
|
|
|
(cell 3 0 (priority_match 1 (cat 1.0 2.0)))
|
|
|
|
(cell 4 0 (assignment_list 8'd0
|
|
|
|
(3.0 1:3 0.2:4)
|
|
|
|
(3.1 5:7 0.2:4)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_sliced_array(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(8)
|
|
|
|
s3 = Signal(8)
|
|
|
|
s4 = Signal(8)
|
|
|
|
s5 = Signal(8)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements("comb", [
|
|
|
|
Array([s1, s2, s3])[s4][2:7].eq(s5),
|
|
|
|
])
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3, s4, s5])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's4' 0.2:10)
|
|
|
|
(input 's5' 0.10:18)
|
|
|
|
(output 's1' 5.0:8)
|
|
|
|
(output 's2' 6.0:8)
|
|
|
|
(output 's3' 7.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
2024-02-29 13:42:25 -07:00
|
|
|
(input 's4' 2:10)
|
|
|
|
(input 's5' 10:18)
|
2024-02-28 07:45:08 -07:00
|
|
|
(output 's1' 5.0:8)
|
|
|
|
(output 's2' 6.0:8)
|
|
|
|
(output 's3' 7.0:8)
|
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.2:10 00000000))
|
|
|
|
(cell 2 0 (matches 0.2:10 00000001))
|
|
|
|
(cell 3 0 (matches 0.2:10 00000010))
|
|
|
|
(cell 4 0 (priority_match 1 (cat 1.0 2.0 3.0)))
|
|
|
|
(cell 5 0 (assignment_list 8'd0 (4.0 2:7 0.10:15)))
|
|
|
|
(cell 6 0 (assignment_list 8'd0 (4.1 2:7 0.10:15)))
|
|
|
|
(cell 7 0 (assignment_list 8'd0 (4.2 2:7 0.10:15)))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_part_slice(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(4)
|
|
|
|
s3 = Signal(4)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1[1:7].bit_select(s3, 4).eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:6)
|
|
|
|
(input 's3' 0.6:10)
|
|
|
|
(output 's1' 8.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:6)
|
|
|
|
(input 's3' 6:10)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 8.0:8)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.6:10 0000))
|
|
|
|
(cell 2 0 (matches 0.6:10 0001))
|
|
|
|
(cell 3 0 (matches 0.6:10 0010))
|
|
|
|
(cell 4 0 (matches 0.6:10 0011))
|
|
|
|
(cell 5 0 (matches 0.6:10 0100))
|
|
|
|
(cell 6 0 (matches 0.6:10 0101))
|
|
|
|
(cell 7 0 (priority_match 1 (cat 1.0 2.0 3.0 4.0 5.0 6.0)))
|
|
|
|
(cell 8 0 (assignment_list 8'd0
|
|
|
|
(7.0 1:5 0.2:6)
|
|
|
|
(7.1 2:6 0.2:6)
|
|
|
|
(7.2 3:7 0.2:6)
|
|
|
|
(7.3 4:7 0.2:5)
|
|
|
|
(7.4 5:7 0.2:4)
|
|
|
|
(7.5 6:7 0.2)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_sliced_part_slice(self):
|
|
|
|
s1 = Signal(12)
|
|
|
|
s2 = Signal(4)
|
|
|
|
s3 = Signal(4)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements(
|
|
|
|
"comb",
|
|
|
|
s1[3:9].bit_select(s3, 4)[1:3].eq(s2)
|
|
|
|
)
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's2' 0.2:6)
|
|
|
|
(input 's3' 0.6:10)
|
|
|
|
(output 's1' 8.0:12)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 's2' 2:6)
|
|
|
|
(input 's3' 6:10)
|
2024-02-29 13:42:25 -07:00
|
|
|
(output 's1' 8.0:12)
|
2024-02-28 07:45:08 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.6:10 0000))
|
|
|
|
(cell 2 0 (matches 0.6:10 0001))
|
|
|
|
(cell 3 0 (matches 0.6:10 0010))
|
|
|
|
(cell 4 0 (matches 0.6:10 0011))
|
|
|
|
(cell 5 0 (matches 0.6:10 0100))
|
|
|
|
(cell 6 0 (matches 0.6:10 0101))
|
|
|
|
(cell 7 0 (priority_match 1 (cat 1.0 2.0 3.0 4.0 5.0 6.0)))
|
|
|
|
(cell 8 0 (assignment_list 12'd0
|
|
|
|
(7.0 4:6 0.2:4)
|
|
|
|
(7.1 5:7 0.2:4)
|
|
|
|
(7.2 6:8 0.2:4)
|
|
|
|
(7.3 7:9 0.2:4)
|
|
|
|
(7.4 8:9 0.2)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_sliced_operator(self):
|
|
|
|
s1 = Signal(8)
|
|
|
|
s2 = Signal(8)
|
|
|
|
s3 = Signal(8)
|
|
|
|
f = Fragment()
|
|
|
|
f.add_statements("comb", [
|
|
|
|
s1.as_signed()[2:7].eq(s3),
|
|
|
|
s2.as_unsigned()[2:7].eq(s3),
|
|
|
|
])
|
|
|
|
nl = build_netlist(f, ports=[s1, s2, s3])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 's3' 0.2:10)
|
|
|
|
(output 's1' 1.0:8)
|
|
|
|
(output 's2' 2.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
2024-02-29 13:42:25 -07:00
|
|
|
(input 's3' 2:10)
|
2024-02-28 07:45:08 -07:00
|
|
|
(output 's1' 1.0:8)
|
|
|
|
(output 's2' 2.0:8)
|
|
|
|
))
|
|
|
|
(cell 1 0 (assignment_list 8'd0 (1 2:7 0.2:7)))
|
|
|
|
(cell 2 0 (assignment_list 8'd0 (1 2:7 0.2:7)))
|
|
|
|
)
|
|
|
|
""")
|
2024-02-29 13:42:25 -07:00
|
|
|
|
2024-03-05 02:34:58 -07:00
|
|
|
|
2024-02-29 13:42:25 -07:00
|
|
|
class RhsTestCase(FHDLTestCase):
|
|
|
|
def test_const(self):
|
|
|
|
o1 = Signal(8)
|
|
|
|
o2 = Signal(8)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(13)
|
|
|
|
m.d.comb += o2.eq(-13)
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [o1, o2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(output 'o1' 8'd13)
|
|
|
|
(output 'o2' 8'd243)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(output 'o1' 8'd13)
|
|
|
|
(output 'o2' 8'd243)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_operator_signed(self):
|
|
|
|
o1 = Signal(8)
|
|
|
|
o2 = Signal(8)
|
|
|
|
i1 = Signal(unsigned(4))
|
|
|
|
i2 = Signal(signed(4))
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(i1.as_signed())
|
|
|
|
m.d.comb += o2.eq(i2.as_unsigned())
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [i1, i2, o1, o2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i1' 0.2:6)
|
|
|
|
(input 'i2' 0.6:10)
|
|
|
|
(output 'o1' (cat 0.2:6 0.5 0.5 0.5 0.5))
|
|
|
|
(output 'o2' (cat 0.6:10 4'd0))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i1' 2:6)
|
|
|
|
(input 'i2' 6:10)
|
|
|
|
(output 'o1' (cat 0.2:6 0.5 0.5 0.5 0.5))
|
|
|
|
(output 'o2' (cat 0.6:10 4'd0))
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_operator_unary(self):
|
|
|
|
o1 = Signal(8)
|
|
|
|
o2 = Signal(8)
|
|
|
|
o3 = Signal(8)
|
|
|
|
o4 = Signal(8)
|
|
|
|
o5 = Signal(8)
|
|
|
|
o6 = Signal(8)
|
|
|
|
o7 = Signal(2)
|
|
|
|
o8 = Signal(2)
|
|
|
|
o9 = Signal(2)
|
|
|
|
o10 = Signal(2)
|
|
|
|
o11 = Signal(2)
|
|
|
|
o12 = Signal(2)
|
|
|
|
o13 = Signal(2)
|
|
|
|
o14 = Signal(2)
|
|
|
|
i1 = Signal(unsigned(4))
|
|
|
|
i2 = Signal(signed(4))
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(+i1)
|
|
|
|
m.d.comb += o2.eq(+i2)
|
|
|
|
m.d.comb += o3.eq(-i1)
|
|
|
|
m.d.comb += o4.eq(-i2)
|
|
|
|
m.d.comb += o5.eq(~i1)
|
|
|
|
m.d.comb += o6.eq(~i2)
|
|
|
|
m.d.comb += o7.eq(i1.all())
|
|
|
|
m.d.comb += o8.eq(i2.all())
|
|
|
|
m.d.comb += o9.eq(i1.any())
|
|
|
|
m.d.comb += o10.eq(i2.any())
|
|
|
|
m.d.comb += o11.eq(i1.xor())
|
|
|
|
m.d.comb += o12.eq(i2.xor())
|
|
|
|
m.d.comb += o13.eq(i1.bool())
|
|
|
|
m.d.comb += o14.eq(i2.bool())
|
|
|
|
nl = build_netlist(Fragment.get(m, None),
|
|
|
|
[i1, i2, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i1' 0.2:6)
|
|
|
|
(input 'i2' 0.6:10)
|
|
|
|
(output 'o1' (cat 0.2:6 4'd0))
|
|
|
|
(output 'o2' (cat 0.6:10 0.9 0.9 0.9 0.9))
|
|
|
|
(output 'o3' (cat 1.0:5 1.4 1.4 1.4))
|
|
|
|
(output 'o4' (cat 2.0:5 2.4 2.4 2.4))
|
|
|
|
(output 'o5' (cat 3.0:4 4'd0))
|
|
|
|
(output 'o6' (cat 4.0:4 4.3 4.3 4.3 4.3))
|
|
|
|
(output 'o7' (cat 5.0 1'd0))
|
|
|
|
(output 'o8' (cat 6.0 1'd0))
|
|
|
|
(output 'o9' (cat 7.0 1'd0))
|
|
|
|
(output 'o10' (cat 8.0 1'd0))
|
|
|
|
(output 'o11' (cat 9.0 1'd0))
|
|
|
|
(output 'o12' (cat 10.0 1'd0))
|
|
|
|
(output 'o13' (cat 11.0 1'd0))
|
|
|
|
(output 'o14' (cat 12.0 1'd0))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i1' 2:6)
|
|
|
|
(input 'i2' 6:10)
|
|
|
|
(output 'o1' (cat 0.2:6 4'd0))
|
|
|
|
(output 'o2' (cat 0.6:10 0.9 0.9 0.9 0.9))
|
|
|
|
(output 'o3' (cat 1.0:5 1.4 1.4 1.4))
|
|
|
|
(output 'o4' (cat 2.0:5 2.4 2.4 2.4))
|
|
|
|
(output 'o5' (cat 3.0:4 4'd0))
|
|
|
|
(output 'o6' (cat 4.0:4 4.3 4.3 4.3 4.3))
|
|
|
|
(output 'o7' (cat 5.0 1'd0))
|
|
|
|
(output 'o8' (cat 6.0 1'd0))
|
|
|
|
(output 'o9' (cat 7.0 1'd0))
|
|
|
|
(output 'o10' (cat 8.0 1'd0))
|
|
|
|
(output 'o11' (cat 9.0 1'd0))
|
|
|
|
(output 'o12' (cat 10.0 1'd0))
|
|
|
|
(output 'o13' (cat 11.0 1'd0))
|
|
|
|
(output 'o14' (cat 12.0 1'd0))
|
|
|
|
))
|
|
|
|
(cell 1 0 (- (cat 0.2:6 1'd0)))
|
|
|
|
(cell 2 0 (- (cat 0.6:10 0.9)))
|
|
|
|
(cell 3 0 (~ 0.2:6))
|
|
|
|
(cell 4 0 (~ 0.6:10))
|
|
|
|
(cell 5 0 (r& 0.2:6))
|
|
|
|
(cell 6 0 (r& 0.6:10))
|
|
|
|
(cell 7 0 (r| 0.2:6))
|
|
|
|
(cell 8 0 (r| 0.6:10))
|
|
|
|
(cell 9 0 (r^ 0.2:6))
|
|
|
|
(cell 10 0 (r^ 0.6:10))
|
|
|
|
(cell 11 0 (b 0.2:6))
|
|
|
|
(cell 12 0 (b 0.6:10))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_operator_binary_bitwise(self):
|
|
|
|
i8u = Signal(8)
|
|
|
|
i9u = Signal(9)
|
|
|
|
i8s = Signal(signed(8))
|
|
|
|
i9s = Signal(signed(9))
|
|
|
|
i1 = Signal()
|
|
|
|
o1 = Signal(12)
|
|
|
|
o2 = Signal(12)
|
|
|
|
o3 = Signal(12)
|
|
|
|
o4 = Signal(12)
|
|
|
|
o5 = Signal(12)
|
|
|
|
o6 = Signal(12)
|
|
|
|
o7 = Signal(12)
|
|
|
|
o8 = Signal(12)
|
|
|
|
o9 = Signal(12)
|
|
|
|
o10 = Signal(12)
|
|
|
|
o11 = Signal(12)
|
|
|
|
o12 = Signal(12)
|
|
|
|
o13 = Signal(12)
|
|
|
|
o14 = Signal(12)
|
|
|
|
o15 = Signal(12)
|
|
|
|
o16 = Signal(12)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(i8u & i8u)
|
|
|
|
m.d.comb += o2.eq(i8u & i9u)
|
|
|
|
m.d.comb += o3.eq(i8u & i8s)
|
|
|
|
m.d.comb += o4.eq(i8u & i9s)
|
|
|
|
m.d.comb += o5.eq(i9u | i8u)
|
|
|
|
m.d.comb += o6.eq(i9u | i9u)
|
|
|
|
m.d.comb += o7.eq(i9u | i8s)
|
|
|
|
m.d.comb += o8.eq(i9u | i9s)
|
|
|
|
m.d.comb += o9.eq(i8s ^ i8u)
|
|
|
|
m.d.comb += o10.eq(i8s ^ i9u)
|
|
|
|
m.d.comb += o11.eq(i8s ^ i8s)
|
|
|
|
m.d.comb += o12.eq(i8s ^ i9s)
|
|
|
|
m.d.comb += o13.eq(Mux(i1, i9s, i8u))
|
|
|
|
m.d.comb += o14.eq(Mux(i1, i9s, i9u))
|
|
|
|
m.d.comb += o15.eq(Mux(i1, i9s, i8s))
|
|
|
|
m.d.comb += o16.eq(Mux(i1, i9s, i9s))
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
i8u, i9u, i8s, i9s, i1,
|
|
|
|
o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15, o16,
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8u' 0.2:10)
|
|
|
|
(input 'i9u' 0.10:19)
|
|
|
|
(input 'i8s' 0.19:27)
|
|
|
|
(input 'i9s' 0.27:36)
|
|
|
|
(input 'i1' 0.36)
|
|
|
|
(output 'o1' (cat 1.0:8 4'd0))
|
|
|
|
(output 'o2' (cat 2.0:9 3'd0))
|
|
|
|
(output 'o3' (cat 3.0:9 3.8 3.8 3.8))
|
|
|
|
(output 'o4' (cat 4.0:9 4.8 4.8 4.8))
|
|
|
|
(output 'o5' (cat 5.0:9 3'd0))
|
|
|
|
(output 'o6' (cat 6.0:9 3'd0))
|
|
|
|
(output 'o7' (cat 7.0:10 7.9 7.9))
|
|
|
|
(output 'o8' (cat 8.0:10 8.9 8.9))
|
|
|
|
(output 'o9' (cat 9.0:9 9.8 9.8 9.8))
|
|
|
|
(output 'o10' (cat 10.0:10 10.9 10.9))
|
|
|
|
(output 'o11' (cat 11.0:8 11.7 11.7 11.7 11.7))
|
|
|
|
(output 'o12' (cat 12.0:9 12.8 12.8 12.8))
|
|
|
|
(output 'o13' (cat 13.0:9 13.8 13.8 13.8))
|
|
|
|
(output 'o14' (cat 14.0:10 14.9 14.9))
|
|
|
|
(output 'o15' (cat 15.0:9 15.8 15.8 15.8))
|
|
|
|
(output 'o16' (cat 16.0:9 16.8 16.8 16.8))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8u' 2:10)
|
|
|
|
(input 'i9u' 10:19)
|
|
|
|
(input 'i8s' 19:27)
|
|
|
|
(input 'i9s' 27:36)
|
|
|
|
(input 'i1' 36:37)
|
|
|
|
(output 'o1' (cat 1.0:8 4'd0))
|
|
|
|
(output 'o2' (cat 2.0:9 3'd0))
|
|
|
|
(output 'o3' (cat 3.0:9 3.8 3.8 3.8))
|
|
|
|
(output 'o4' (cat 4.0:9 4.8 4.8 4.8))
|
|
|
|
(output 'o5' (cat 5.0:9 3'd0))
|
|
|
|
(output 'o6' (cat 6.0:9 3'd0))
|
|
|
|
(output 'o7' (cat 7.0:10 7.9 7.9))
|
|
|
|
(output 'o8' (cat 8.0:10 8.9 8.9))
|
|
|
|
(output 'o9' (cat 9.0:9 9.8 9.8 9.8))
|
|
|
|
(output 'o10' (cat 10.0:10 10.9 10.9))
|
|
|
|
(output 'o11' (cat 11.0:8 11.7 11.7 11.7 11.7))
|
|
|
|
(output 'o12' (cat 12.0:9 12.8 12.8 12.8))
|
|
|
|
(output 'o13' (cat 13.0:9 13.8 13.8 13.8))
|
|
|
|
(output 'o14' (cat 14.0:10 14.9 14.9))
|
|
|
|
(output 'o15' (cat 15.0:9 15.8 15.8 15.8))
|
|
|
|
(output 'o16' (cat 16.0:9 16.8 16.8 16.8))
|
|
|
|
))
|
|
|
|
(cell 1 0 (& 0.2:10 0.2:10))
|
|
|
|
(cell 2 0 (& (cat 0.2:10 1'd0) 0.10:19))
|
|
|
|
(cell 3 0 (& (cat 0.2:10 1'd0) (cat 0.19:27 0.26)))
|
|
|
|
(cell 4 0 (& (cat 0.2:10 1'd0) 0.27:36))
|
|
|
|
(cell 5 0 (| 0.10:19 (cat 0.2:10 1'd0)))
|
|
|
|
(cell 6 0 (| 0.10:19 0.10:19))
|
|
|
|
(cell 7 0 (| (cat 0.10:19 1'd0) (cat 0.19:27 0.26 0.26)))
|
|
|
|
(cell 8 0 (| (cat 0.10:19 1'd0) (cat 0.27:36 0.35)))
|
|
|
|
(cell 9 0 (^ (cat 0.19:27 0.26) (cat 0.2:10 1'd0)))
|
|
|
|
(cell 10 0 (^ (cat 0.19:27 0.26 0.26) (cat 0.10:19 1'd0)))
|
|
|
|
(cell 11 0 (^ 0.19:27 0.19:27))
|
|
|
|
(cell 12 0 (^ (cat 0.19:27 0.26) 0.27:36))
|
|
|
|
(cell 13 0 (m 0.36 0.27:36 (cat 0.2:10 1'd0)))
|
|
|
|
(cell 14 0 (m 0.36 (cat 0.27:36 0.35) (cat 0.10:19 1'd0)))
|
|
|
|
(cell 15 0 (m 0.36 0.27:36 (cat 0.19:27 0.26)))
|
|
|
|
(cell 16 0 (m 0.36 0.27:36 0.27:36))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_operator_binary_add(self):
|
|
|
|
i8u = Signal(8)
|
|
|
|
i9u = Signal(9)
|
|
|
|
i8s = Signal(signed(8))
|
|
|
|
i9s = Signal(signed(9))
|
|
|
|
o1 = Signal(12)
|
|
|
|
o2 = Signal(12)
|
|
|
|
o3 = Signal(12)
|
|
|
|
o4 = Signal(12)
|
|
|
|
o5 = Signal(12)
|
|
|
|
o6 = Signal(12)
|
|
|
|
o7 = Signal(12)
|
|
|
|
o8 = Signal(12)
|
|
|
|
o9 = Signal(12)
|
|
|
|
o10 = Signal(12)
|
|
|
|
o11 = Signal(12)
|
|
|
|
o12 = Signal(12)
|
|
|
|
o13 = Signal(12)
|
|
|
|
o14 = Signal(12)
|
|
|
|
o15 = Signal(12)
|
|
|
|
o16 = Signal(12)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(i8u + i8u)
|
|
|
|
m.d.comb += o2.eq(i8u + i9u)
|
|
|
|
m.d.comb += o3.eq(i8u + i8s)
|
|
|
|
m.d.comb += o4.eq(i8u + i9s)
|
|
|
|
m.d.comb += o5.eq(i9u + i8u)
|
|
|
|
m.d.comb += o6.eq(i9u + i9u)
|
|
|
|
m.d.comb += o7.eq(i9u + i8s)
|
|
|
|
m.d.comb += o8.eq(i9u + i9s)
|
|
|
|
m.d.comb += o9.eq(i8s + i8u)
|
|
|
|
m.d.comb += o10.eq(i8s + i9u)
|
|
|
|
m.d.comb += o11.eq(i8s + i8s)
|
|
|
|
m.d.comb += o12.eq(i8s + i9s)
|
|
|
|
m.d.comb += o13.eq(i9s + i8u)
|
|
|
|
m.d.comb += o14.eq(i9s + i9u)
|
|
|
|
m.d.comb += o15.eq(i9s + i8s)
|
|
|
|
m.d.comb += o16.eq(i9s + i9s)
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
i8u, i9u, i8s, i9s,
|
|
|
|
o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15, o16,
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8u' 0.2:10)
|
|
|
|
(input 'i9u' 0.10:19)
|
|
|
|
(input 'i8s' 0.19:27)
|
|
|
|
(input 'i9s' 0.27:36)
|
|
|
|
(output 'o1' (cat 1.0:9 3'd0))
|
|
|
|
(output 'o2' (cat 2.0:10 2'd0))
|
|
|
|
(output 'o3' (cat 3.0:10 3.9 3.9))
|
|
|
|
(output 'o4' (cat 4.0:10 4.9 4.9))
|
|
|
|
(output 'o5' (cat 5.0:10 2'd0))
|
|
|
|
(output 'o6' (cat 6.0:10 2'd0))
|
|
|
|
(output 'o7' (cat 7.0:11 7.10))
|
|
|
|
(output 'o8' (cat 8.0:11 8.10))
|
|
|
|
(output 'o9' (cat 9.0:10 9.9 9.9))
|
|
|
|
(output 'o10' (cat 10.0:11 10.10))
|
|
|
|
(output 'o11' (cat 11.0:9 11.8 11.8 11.8))
|
|
|
|
(output 'o12' (cat 12.0:10 12.9 12.9))
|
|
|
|
(output 'o13' (cat 13.0:10 13.9 13.9))
|
|
|
|
(output 'o14' (cat 14.0:11 14.10))
|
|
|
|
(output 'o15' (cat 15.0:10 15.9 15.9))
|
|
|
|
(output 'o16' (cat 16.0:10 16.9 16.9))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8u' 2:10)
|
|
|
|
(input 'i9u' 10:19)
|
|
|
|
(input 'i8s' 19:27)
|
|
|
|
(input 'i9s' 27:36)
|
|
|
|
(output 'o1' (cat 1.0:9 3'd0))
|
|
|
|
(output 'o2' (cat 2.0:10 2'd0))
|
|
|
|
(output 'o3' (cat 3.0:10 3.9 3.9))
|
|
|
|
(output 'o4' (cat 4.0:10 4.9 4.9))
|
|
|
|
(output 'o5' (cat 5.0:10 2'd0))
|
|
|
|
(output 'o6' (cat 6.0:10 2'd0))
|
|
|
|
(output 'o7' (cat 7.0:11 7.10))
|
|
|
|
(output 'o8' (cat 8.0:11 8.10))
|
|
|
|
(output 'o9' (cat 9.0:10 9.9 9.9))
|
|
|
|
(output 'o10' (cat 10.0:11 10.10))
|
|
|
|
(output 'o11' (cat 11.0:9 11.8 11.8 11.8))
|
|
|
|
(output 'o12' (cat 12.0:10 12.9 12.9))
|
|
|
|
(output 'o13' (cat 13.0:10 13.9 13.9))
|
|
|
|
(output 'o14' (cat 14.0:11 14.10))
|
|
|
|
(output 'o15' (cat 15.0:10 15.9 15.9))
|
|
|
|
(output 'o16' (cat 16.0:10 16.9 16.9))
|
|
|
|
))
|
|
|
|
(cell 1 0 (+ (cat 0.2:10 1'd0) (cat 0.2:10 1'd0)))
|
|
|
|
(cell 2 0 (+ (cat 0.2:10 2'd0) (cat 0.10:19 1'd0)))
|
|
|
|
(cell 3 0 (+ (cat 0.2:10 2'd0) (cat 0.19:27 0.26 0.26)))
|
|
|
|
(cell 4 0 (+ (cat 0.2:10 2'd0) (cat 0.27:36 0.35)))
|
|
|
|
(cell 5 0 (+ (cat 0.10:19 1'd0) (cat 0.2:10 2'd0)))
|
|
|
|
(cell 6 0 (+ (cat 0.10:19 1'd0) (cat 0.10:19 1'd0)))
|
|
|
|
(cell 7 0 (+ (cat 0.10:19 2'd0) (cat 0.19:27 0.26 0.26 0.26)))
|
|
|
|
(cell 8 0 (+ (cat 0.10:19 2'd0) (cat 0.27:36 0.35 0.35)))
|
|
|
|
(cell 9 0 (+ (cat 0.19:27 0.26 0.26) (cat 0.2:10 2'd0)))
|
|
|
|
(cell 10 0 (+ (cat 0.19:27 0.26 0.26 0.26) (cat 0.10:19 2'd0)))
|
|
|
|
(cell 11 0 (+ (cat 0.19:27 0.26) (cat 0.19:27 0.26)))
|
|
|
|
(cell 12 0 (+ (cat 0.19:27 0.26 0.26) (cat 0.27:36 0.35)))
|
|
|
|
(cell 13 0 (+ (cat 0.27:36 0.35) (cat 0.2:10 2'd0)))
|
|
|
|
(cell 14 0 (+ (cat 0.27:36 0.35 0.35) (cat 0.10:19 2'd0)))
|
|
|
|
(cell 15 0 (+ (cat 0.27:36 0.35) (cat 0.19:27 0.26 0.26)))
|
|
|
|
(cell 16 0 (+ (cat 0.27:36 0.35) (cat 0.27:36 0.35)))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_operator_binary_sub(self):
|
|
|
|
i8u = Signal(8)
|
|
|
|
i9u = Signal(9)
|
|
|
|
i8s = Signal(signed(8))
|
|
|
|
i9s = Signal(signed(9))
|
|
|
|
o1 = Signal(12)
|
|
|
|
o2 = Signal(12)
|
|
|
|
o3 = Signal(12)
|
|
|
|
o4 = Signal(12)
|
|
|
|
o5 = Signal(12)
|
|
|
|
o6 = Signal(12)
|
|
|
|
o7 = Signal(12)
|
|
|
|
o8 = Signal(12)
|
|
|
|
o9 = Signal(12)
|
|
|
|
o10 = Signal(12)
|
|
|
|
o11 = Signal(12)
|
|
|
|
o12 = Signal(12)
|
|
|
|
o13 = Signal(12)
|
|
|
|
o14 = Signal(12)
|
|
|
|
o15 = Signal(12)
|
|
|
|
o16 = Signal(12)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(i8u - i8u)
|
|
|
|
m.d.comb += o2.eq(i8u - i9u)
|
|
|
|
m.d.comb += o3.eq(i8u - i8s)
|
|
|
|
m.d.comb += o4.eq(i8u - i9s)
|
|
|
|
m.d.comb += o5.eq(i9u - i8u)
|
|
|
|
m.d.comb += o6.eq(i9u - i9u)
|
|
|
|
m.d.comb += o7.eq(i9u - i8s)
|
|
|
|
m.d.comb += o8.eq(i9u - i9s)
|
|
|
|
m.d.comb += o9.eq(i8s - i8u)
|
|
|
|
m.d.comb += o10.eq(i8s - i9u)
|
|
|
|
m.d.comb += o11.eq(i8s - i8s)
|
|
|
|
m.d.comb += o12.eq(i8s - i9s)
|
|
|
|
m.d.comb += o13.eq(i9s - i8u)
|
|
|
|
m.d.comb += o14.eq(i9s - i9u)
|
|
|
|
m.d.comb += o15.eq(i9s - i8s)
|
|
|
|
m.d.comb += o16.eq(i9s - i9s)
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
i8u, i9u, i8s, i9s,
|
|
|
|
o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15, o16,
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8u' 0.2:10)
|
|
|
|
(input 'i9u' 0.10:19)
|
|
|
|
(input 'i8s' 0.19:27)
|
|
|
|
(input 'i9s' 0.27:36)
|
|
|
|
(output 'o1' (cat 1.0:9 1.8 1.8 1.8))
|
|
|
|
(output 'o2' (cat 2.0:10 2.9 2.9))
|
|
|
|
(output 'o3' (cat 3.0:10 3.9 3.9))
|
|
|
|
(output 'o4' (cat 4.0:10 4.9 4.9))
|
|
|
|
(output 'o5' (cat 5.0:10 5.9 5.9))
|
|
|
|
(output 'o6' (cat 6.0:10 6.9 6.9))
|
|
|
|
(output 'o7' (cat 7.0:11 7.10))
|
|
|
|
(output 'o8' (cat 8.0:11 8.10))
|
|
|
|
(output 'o9' (cat 9.0:10 9.9 9.9))
|
|
|
|
(output 'o10' (cat 10.0:11 10.10))
|
|
|
|
(output 'o11' (cat 11.0:9 11.8 11.8 11.8))
|
|
|
|
(output 'o12' (cat 12.0:10 12.9 12.9))
|
|
|
|
(output 'o13' (cat 13.0:10 13.9 13.9))
|
|
|
|
(output 'o14' (cat 14.0:11 14.10))
|
|
|
|
(output 'o15' (cat 15.0:10 15.9 15.9))
|
|
|
|
(output 'o16' (cat 16.0:10 16.9 16.9))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8u' 2:10)
|
|
|
|
(input 'i9u' 10:19)
|
|
|
|
(input 'i8s' 19:27)
|
|
|
|
(input 'i9s' 27:36)
|
|
|
|
(output 'o1' (cat 1.0:9 1.8 1.8 1.8))
|
|
|
|
(output 'o2' (cat 2.0:10 2.9 2.9))
|
|
|
|
(output 'o3' (cat 3.0:10 3.9 3.9))
|
|
|
|
(output 'o4' (cat 4.0:10 4.9 4.9))
|
|
|
|
(output 'o5' (cat 5.0:10 5.9 5.9))
|
|
|
|
(output 'o6' (cat 6.0:10 6.9 6.9))
|
|
|
|
(output 'o7' (cat 7.0:11 7.10))
|
|
|
|
(output 'o8' (cat 8.0:11 8.10))
|
|
|
|
(output 'o9' (cat 9.0:10 9.9 9.9))
|
|
|
|
(output 'o10' (cat 10.0:11 10.10))
|
|
|
|
(output 'o11' (cat 11.0:9 11.8 11.8 11.8))
|
|
|
|
(output 'o12' (cat 12.0:10 12.9 12.9))
|
|
|
|
(output 'o13' (cat 13.0:10 13.9 13.9))
|
|
|
|
(output 'o14' (cat 14.0:11 14.10))
|
|
|
|
(output 'o15' (cat 15.0:10 15.9 15.9))
|
|
|
|
(output 'o16' (cat 16.0:10 16.9 16.9))
|
|
|
|
))
|
|
|
|
(cell 1 0 (- (cat 0.2:10 1'd0) (cat 0.2:10 1'd0)))
|
|
|
|
(cell 2 0 (- (cat 0.2:10 2'd0) (cat 0.10:19 1'd0)))
|
|
|
|
(cell 3 0 (- (cat 0.2:10 2'd0) (cat 0.19:27 0.26 0.26)))
|
|
|
|
(cell 4 0 (- (cat 0.2:10 2'd0) (cat 0.27:36 0.35)))
|
|
|
|
(cell 5 0 (- (cat 0.10:19 1'd0) (cat 0.2:10 2'd0)))
|
|
|
|
(cell 6 0 (- (cat 0.10:19 1'd0) (cat 0.10:19 1'd0)))
|
|
|
|
(cell 7 0 (- (cat 0.10:19 2'd0) (cat 0.19:27 0.26 0.26 0.26)))
|
|
|
|
(cell 8 0 (- (cat 0.10:19 2'd0) (cat 0.27:36 0.35 0.35)))
|
|
|
|
(cell 9 0 (- (cat 0.19:27 0.26 0.26) (cat 0.2:10 2'd0)))
|
|
|
|
(cell 10 0 (- (cat 0.19:27 0.26 0.26 0.26) (cat 0.10:19 2'd0)))
|
|
|
|
(cell 11 0 (- (cat 0.19:27 0.26) (cat 0.19:27 0.26)))
|
|
|
|
(cell 12 0 (- (cat 0.19:27 0.26 0.26) (cat 0.27:36 0.35)))
|
|
|
|
(cell 13 0 (- (cat 0.27:36 0.35) (cat 0.2:10 2'd0)))
|
|
|
|
(cell 14 0 (- (cat 0.27:36 0.35 0.35) (cat 0.10:19 2'd0)))
|
|
|
|
(cell 15 0 (- (cat 0.27:36 0.35) (cat 0.19:27 0.26 0.26)))
|
|
|
|
(cell 16 0 (- (cat 0.27:36 0.35) (cat 0.27:36 0.35)))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_operator_binary_mul(self):
|
|
|
|
i8u = Signal(8)
|
|
|
|
i8s = Signal(signed(8))
|
|
|
|
i10u = Signal(10)
|
|
|
|
i10s = Signal(signed(10))
|
|
|
|
o1 = Signal(24)
|
|
|
|
o2 = Signal(24)
|
|
|
|
o3 = Signal(24)
|
|
|
|
o4 = Signal(24)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(i8u * i10u)
|
|
|
|
m.d.comb += o2.eq(i8u * i10s)
|
|
|
|
m.d.comb += o3.eq(i8s * i10u)
|
|
|
|
m.d.comb += o4.eq(i8s * i10s)
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
i8u, i8s, i10u, i10s,
|
|
|
|
o1, o2, o3, o4,
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8u' 0.2:10)
|
|
|
|
(input 'i8s' 0.10:18)
|
|
|
|
(input 'i10u' 0.18:28)
|
|
|
|
(input 'i10s' 0.28:38)
|
|
|
|
(output 'o1' (cat 1.0:18 6'd0))
|
|
|
|
(output 'o2' (cat 2.0:18 2.17 2.17 2.17 2.17 2.17 2.17))
|
|
|
|
(output 'o3' (cat 3.0:18 3.17 3.17 3.17 3.17 3.17 3.17))
|
|
|
|
(output 'o4' (cat 4.0:18 4.17 4.17 4.17 4.17 4.17 4.17))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8u' 2:10)
|
|
|
|
(input 'i8s' 10:18)
|
|
|
|
(input 'i10u' 18:28)
|
|
|
|
(input 'i10s' 28:38)
|
|
|
|
(output 'o1' (cat 1.0:18 6'd0))
|
|
|
|
(output 'o2' (cat 2.0:18 2.17 2.17 2.17 2.17 2.17 2.17))
|
|
|
|
(output 'o3' (cat 3.0:18 3.17 3.17 3.17 3.17 3.17 3.17))
|
|
|
|
(output 'o4' (cat 4.0:18 4.17 4.17 4.17 4.17 4.17 4.17))
|
|
|
|
))
|
|
|
|
(cell 1 0 (* (cat 0.2:10 10'd0) (cat 0.18:28 8'd0)))
|
|
|
|
(cell 2 0 (* (cat 0.2:10 10'd0) (cat 0.28:38 0.37 0.37 0.37 0.37 0.37 0.37 0.37 0.37)))
|
|
|
|
(cell 3 0 (* (cat 0.10:18 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17) (cat 0.18:28 8'd0)))
|
|
|
|
(cell 4 0 (* (cat 0.10:18 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17) (cat 0.28:38 0.37 0.37 0.37 0.37 0.37 0.37 0.37 0.37)))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_operator_binary_divmod(self):
|
|
|
|
i8u = Signal(8)
|
|
|
|
i8s = Signal(signed(8))
|
|
|
|
i6u = Signal(6)
|
|
|
|
i6s = Signal(signed(6))
|
|
|
|
m = Module()
|
|
|
|
o1 = Signal(10)
|
|
|
|
o2 = Signal(10)
|
|
|
|
o3 = Signal(10)
|
|
|
|
o4 = Signal(10)
|
|
|
|
o5 = Signal(10)
|
|
|
|
o6 = Signal(10)
|
|
|
|
o7 = Signal(10)
|
|
|
|
o8 = Signal(10)
|
|
|
|
o9 = Signal(10)
|
|
|
|
o10 = Signal(10)
|
|
|
|
o11 = Signal(10)
|
|
|
|
o12 = Signal(10)
|
|
|
|
o13 = Signal(10)
|
|
|
|
o14 = Signal(10)
|
|
|
|
o15 = Signal(10)
|
|
|
|
o16 = Signal(10)
|
|
|
|
m.d.comb += o1.eq(i8u // i6u)
|
|
|
|
m.d.comb += o2.eq(i8u % i6u)
|
|
|
|
m.d.comb += o3.eq(i8u // i6s)
|
|
|
|
m.d.comb += o4.eq(i8u % i6s)
|
|
|
|
m.d.comb += o5.eq(i8s // i6u)
|
|
|
|
m.d.comb += o6.eq(i8s % i6u)
|
|
|
|
m.d.comb += o7.eq(i8s // i6s)
|
|
|
|
m.d.comb += o8.eq(i8s % i6s)
|
|
|
|
m.d.comb += o9.eq(i6u // i8u)
|
|
|
|
m.d.comb += o10.eq(i6u % i8u)
|
|
|
|
m.d.comb += o11.eq(i6u // i8s)
|
|
|
|
m.d.comb += o12.eq(i6u % i8s)
|
|
|
|
m.d.comb += o13.eq(i6s // i8u)
|
|
|
|
m.d.comb += o14.eq(i6s % i8u)
|
|
|
|
m.d.comb += o15.eq(i6s // i8s)
|
|
|
|
m.d.comb += o16.eq(i6s % i8s)
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
i8u, i8s, i6u, i6s,
|
|
|
|
o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15, o16,
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8u' 0.2:10)
|
|
|
|
(input 'i8s' 0.10:18)
|
|
|
|
(input 'i6u' 0.18:24)
|
|
|
|
(input 'i6s' 0.24:30)
|
|
|
|
(output 'o1' (cat 1.0:8 2'd0))
|
|
|
|
(output 'o2' (cat 2.0:6 4'd0))
|
|
|
|
(output 'o3' (cat 3.0:9 3.8))
|
|
|
|
(output 'o4' (cat 4.0:6 4.5 4.5 4.5 4.5))
|
|
|
|
(output 'o5' (cat 5.0:8 5.7 5.7))
|
|
|
|
(output 'o6' (cat 6.0:6 4'd0))
|
|
|
|
(output 'o7' (cat 7.0:9 7.8))
|
|
|
|
(output 'o8' (cat 8.0:6 8.5 8.5 8.5 8.5))
|
|
|
|
(output 'o9' (cat 9.0:6 4'd0))
|
|
|
|
(output 'o10' (cat 10.0:8 2'd0))
|
|
|
|
(output 'o11' (cat 11.0:7 11.6 11.6 11.6))
|
|
|
|
(output 'o12' (cat 12.0:8 12.7 12.7))
|
|
|
|
(output 'o13' (cat 13.0:6 13.5 13.5 13.5 13.5))
|
|
|
|
(output 'o14' (cat 14.0:8 2'd0))
|
|
|
|
(output 'o15' (cat 15.0:7 15.6 15.6 15.6))
|
|
|
|
(output 'o16' (cat 16.0:8 16.7 16.7))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8u' 2:10)
|
|
|
|
(input 'i8s' 10:18)
|
|
|
|
(input 'i6u' 18:24)
|
|
|
|
(input 'i6s' 24:30)
|
|
|
|
(output 'o1' (cat 1.0:8 2'd0))
|
|
|
|
(output 'o2' (cat 2.0:6 4'd0))
|
|
|
|
(output 'o3' (cat 3.0:9 3.8))
|
|
|
|
(output 'o4' (cat 4.0:6 4.5 4.5 4.5 4.5))
|
|
|
|
(output 'o5' (cat 5.0:8 5.7 5.7))
|
|
|
|
(output 'o6' (cat 6.0:6 4'd0))
|
|
|
|
(output 'o7' (cat 7.0:9 7.8))
|
|
|
|
(output 'o8' (cat 8.0:6 8.5 8.5 8.5 8.5))
|
|
|
|
(output 'o9' (cat 9.0:6 4'd0))
|
|
|
|
(output 'o10' (cat 10.0:8 2'd0))
|
|
|
|
(output 'o11' (cat 11.0:7 11.6 11.6 11.6))
|
|
|
|
(output 'o12' (cat 12.0:8 12.7 12.7))
|
|
|
|
(output 'o13' (cat 13.0:6 13.5 13.5 13.5 13.5))
|
|
|
|
(output 'o14' (cat 14.0:8 2'd0))
|
|
|
|
(output 'o15' (cat 15.0:7 15.6 15.6 15.6))
|
|
|
|
(output 'o16' (cat 16.0:8 16.7 16.7))
|
|
|
|
))
|
|
|
|
(cell 1 0 (u// 0.2:10 (cat 0.18:24 2'd0)))
|
|
|
|
(cell 2 0 (u% 0.2:10 (cat 0.18:24 2'd0)))
|
|
|
|
(cell 3 0 (s// (cat 0.2:10 1'd0) (cat 0.24:30 0.29 0.29 0.29)))
|
|
|
|
(cell 4 0 (s% (cat 0.2:10 1'd0) (cat 0.24:30 0.29 0.29 0.29)))
|
|
|
|
(cell 5 0 (s// 0.10:18 (cat 0.18:24 2'd0)))
|
|
|
|
(cell 6 0 (s% 0.10:18 (cat 0.18:24 2'd0)))
|
|
|
|
(cell 7 0 (s// (cat 0.10:18 0.17) (cat 0.24:30 0.29 0.29 0.29)))
|
|
|
|
(cell 8 0 (s% 0.10:18 (cat 0.24:30 0.29 0.29)))
|
|
|
|
(cell 9 0 (u// (cat 0.18:24 2'd0) 0.2:10))
|
|
|
|
(cell 10 0 (u% (cat 0.18:24 2'd0) 0.2:10))
|
|
|
|
(cell 11 0 (s// (cat 0.18:24 2'd0) 0.10:18))
|
|
|
|
(cell 12 0 (s% (cat 0.18:24 2'd0) 0.10:18))
|
|
|
|
(cell 13 0 (s// (cat 0.24:30 0.29 0.29 0.29) (cat 0.2:10 1'd0)))
|
|
|
|
(cell 14 0 (s% (cat 0.24:30 0.29 0.29 0.29) (cat 0.2:10 1'd0)))
|
|
|
|
(cell 15 0 (s// (cat 0.24:30 0.29 0.29) 0.10:18))
|
|
|
|
(cell 16 0 (s% (cat 0.24:30 0.29 0.29) 0.10:18))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_operator_binary_shift(self):
|
|
|
|
i8u = Signal(8)
|
|
|
|
i8s = Signal(signed(8))
|
|
|
|
i4 = Signal(4)
|
|
|
|
o1 = Signal(32)
|
|
|
|
o2 = Signal(32)
|
|
|
|
o3 = Signal(12)
|
|
|
|
o4 = Signal(12)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(i8u << i4)
|
|
|
|
m.d.comb += o2.eq(i8s << i4)
|
|
|
|
m.d.comb += o3.eq(i8u >> i4)
|
|
|
|
m.d.comb += o4.eq(i8s >> i4)
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
i8u, i8s, i4, o1, o2, o3, o4,
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8u' 0.2:10)
|
|
|
|
(input 'i8s' 0.10:18)
|
|
|
|
(input 'i4' 0.18:22)
|
|
|
|
(output 'o1' (cat 1.0:23 9'd0))
|
|
|
|
(output 'o2' (cat 2.0:23 2.22 2.22 2.22 2.22 2.22 2.22 2.22 2.22 2.22))
|
|
|
|
(output 'o3' (cat 3.0:8 4'd0))
|
|
|
|
(output 'o4' (cat 4.0:8 4.7 4.7 4.7 4.7))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8u' 2:10)
|
|
|
|
(input 'i8s' 10:18)
|
|
|
|
(input 'i4' 18:22)
|
|
|
|
(output 'o1' (cat 1.0:23 9'd0))
|
|
|
|
(output 'o2' (cat 2.0:23 2.22 2.22 2.22 2.22 2.22 2.22 2.22 2.22 2.22))
|
|
|
|
(output 'o3' (cat 3.0:8 4'd0))
|
|
|
|
(output 'o4' (cat 4.0:8 4.7 4.7 4.7 4.7))
|
|
|
|
))
|
|
|
|
(cell 1 0 (<< (cat 0.2:10 15'd0) 0.18:22))
|
|
|
|
(cell 2 0 (<< (cat 0.10:18 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17 0.17) 0.18:22))
|
|
|
|
(cell 3 0 (u>> 0.2:10 0.18:22))
|
|
|
|
(cell 4 0 (s>> 0.10:18 0.18:22))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_operator_binary_eq(self):
|
|
|
|
i8u = Signal(8)
|
|
|
|
i9u = Signal(9)
|
|
|
|
i8s = Signal(signed(8))
|
|
|
|
i9s = Signal(signed(9))
|
|
|
|
o1 = Signal(2)
|
|
|
|
o2 = Signal(2)
|
|
|
|
o3 = Signal(2)
|
|
|
|
o4 = Signal(2)
|
|
|
|
o5 = Signal(2)
|
|
|
|
o6 = Signal(2)
|
|
|
|
o7 = Signal(2)
|
|
|
|
o8 = Signal(2)
|
|
|
|
o9 = Signal(2)
|
|
|
|
o10 = Signal(2)
|
|
|
|
o11 = Signal(2)
|
|
|
|
o12 = Signal(2)
|
|
|
|
o13 = Signal(2)
|
|
|
|
o14 = Signal(2)
|
|
|
|
o15 = Signal(2)
|
|
|
|
o16 = Signal(2)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(i8u == i8u)
|
|
|
|
m.d.comb += o2.eq(i8u != i9u)
|
|
|
|
m.d.comb += o3.eq(i8u != i8s)
|
|
|
|
m.d.comb += o4.eq(i8u == i9s)
|
|
|
|
m.d.comb += o5.eq(i9u != i8u)
|
|
|
|
m.d.comb += o6.eq(i9u == i9u)
|
|
|
|
m.d.comb += o7.eq(i9u == i8s)
|
|
|
|
m.d.comb += o8.eq(i9u != i9s)
|
|
|
|
m.d.comb += o9.eq(i8s != i8u)
|
|
|
|
m.d.comb += o10.eq(i8s == i9u)
|
|
|
|
m.d.comb += o11.eq(i8s == i8s)
|
|
|
|
m.d.comb += o12.eq(i8s != i9s)
|
|
|
|
m.d.comb += o13.eq(i9s == i8u)
|
|
|
|
m.d.comb += o14.eq(i9s != i9u)
|
|
|
|
m.d.comb += o15.eq(i9s != i8s)
|
|
|
|
m.d.comb += o16.eq(i9s == i9s)
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
i8u, i9u, i8s, i9s,
|
|
|
|
o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15, o16,
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8u' 0.2:10)
|
|
|
|
(input 'i9u' 0.10:19)
|
|
|
|
(input 'i8s' 0.19:27)
|
|
|
|
(input 'i9s' 0.27:36)
|
|
|
|
(output 'o1' (cat 1.0 1'd0))
|
|
|
|
(output 'o2' (cat 2.0 1'd0))
|
|
|
|
(output 'o3' (cat 3.0 1'd0))
|
|
|
|
(output 'o4' (cat 4.0 1'd0))
|
|
|
|
(output 'o5' (cat 5.0 1'd0))
|
|
|
|
(output 'o6' (cat 6.0 1'd0))
|
|
|
|
(output 'o7' (cat 7.0 1'd0))
|
|
|
|
(output 'o8' (cat 8.0 1'd0))
|
|
|
|
(output 'o9' (cat 9.0 1'd0))
|
|
|
|
(output 'o10' (cat 10.0 1'd0))
|
|
|
|
(output 'o11' (cat 11.0 1'd0))
|
|
|
|
(output 'o12' (cat 12.0 1'd0))
|
|
|
|
(output 'o13' (cat 13.0 1'd0))
|
|
|
|
(output 'o14' (cat 14.0 1'd0))
|
|
|
|
(output 'o15' (cat 15.0 1'd0))
|
|
|
|
(output 'o16' (cat 16.0 1'd0))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8u' 2:10)
|
|
|
|
(input 'i9u' 10:19)
|
|
|
|
(input 'i8s' 19:27)
|
|
|
|
(input 'i9s' 27:36)
|
|
|
|
(output 'o1' (cat 1.0 1'd0))
|
|
|
|
(output 'o2' (cat 2.0 1'd0))
|
|
|
|
(output 'o3' (cat 3.0 1'd0))
|
|
|
|
(output 'o4' (cat 4.0 1'd0))
|
|
|
|
(output 'o5' (cat 5.0 1'd0))
|
|
|
|
(output 'o6' (cat 6.0 1'd0))
|
|
|
|
(output 'o7' (cat 7.0 1'd0))
|
|
|
|
(output 'o8' (cat 8.0 1'd0))
|
|
|
|
(output 'o9' (cat 9.0 1'd0))
|
|
|
|
(output 'o10' (cat 10.0 1'd0))
|
|
|
|
(output 'o11' (cat 11.0 1'd0))
|
|
|
|
(output 'o12' (cat 12.0 1'd0))
|
|
|
|
(output 'o13' (cat 13.0 1'd0))
|
|
|
|
(output 'o14' (cat 14.0 1'd0))
|
|
|
|
(output 'o15' (cat 15.0 1'd0))
|
|
|
|
(output 'o16' (cat 16.0 1'd0))
|
|
|
|
))
|
|
|
|
(cell 1 0 (== 0.2:10 0.2:10))
|
|
|
|
(cell 2 0 (!= (cat 0.2:10 1'd0) 0.10:19))
|
|
|
|
(cell 3 0 (!= (cat 0.2:10 1'd0) (cat 0.19:27 0.26)))
|
|
|
|
(cell 4 0 (== (cat 0.2:10 1'd0) 0.27:36))
|
|
|
|
(cell 5 0 (!= 0.10:19 (cat 0.2:10 1'd0)))
|
|
|
|
(cell 6 0 (== 0.10:19 0.10:19))
|
|
|
|
(cell 7 0 (== (cat 0.10:19 1'd0) (cat 0.19:27 0.26 0.26)))
|
|
|
|
(cell 8 0 (!= (cat 0.10:19 1'd0) (cat 0.27:36 0.35)))
|
|
|
|
(cell 9 0 (!= (cat 0.19:27 0.26) (cat 0.2:10 1'd0)))
|
|
|
|
(cell 10 0 (== (cat 0.19:27 0.26 0.26) (cat 0.10:19 1'd0)))
|
|
|
|
(cell 11 0 (== 0.19:27 0.19:27))
|
|
|
|
(cell 12 0 (!= (cat 0.19:27 0.26) 0.27:36))
|
|
|
|
(cell 13 0 (== 0.27:36 (cat 0.2:10 1'd0)))
|
|
|
|
(cell 14 0 (!= (cat 0.27:36 0.35) (cat 0.10:19 1'd0)))
|
|
|
|
(cell 15 0 (!= 0.27:36 (cat 0.19:27 0.26)))
|
|
|
|
(cell 16 0 (== 0.27:36 0.27:36))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_operator_binary_ord(self):
|
|
|
|
i8u = Signal(8)
|
|
|
|
i9u = Signal(9)
|
|
|
|
i8s = Signal(signed(8))
|
|
|
|
i9s = Signal(signed(9))
|
|
|
|
o1 = Signal(2)
|
|
|
|
o2 = Signal(2)
|
|
|
|
o3 = Signal(2)
|
|
|
|
o4 = Signal(2)
|
|
|
|
o5 = Signal(2)
|
|
|
|
o6 = Signal(2)
|
|
|
|
o7 = Signal(2)
|
|
|
|
o8 = Signal(2)
|
|
|
|
o9 = Signal(2)
|
|
|
|
o10 = Signal(2)
|
|
|
|
o11 = Signal(2)
|
|
|
|
o12 = Signal(2)
|
|
|
|
o13 = Signal(2)
|
|
|
|
o14 = Signal(2)
|
|
|
|
o15 = Signal(2)
|
|
|
|
o16 = Signal(2)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(i8u < i8u)
|
|
|
|
m.d.comb += o2.eq(i8u < i9u)
|
|
|
|
m.d.comb += o3.eq(i8u < i8s)
|
|
|
|
m.d.comb += o4.eq(i8u < i9s)
|
|
|
|
m.d.comb += o5.eq(i9u > i8u)
|
|
|
|
m.d.comb += o6.eq(i9u > i9u)
|
|
|
|
m.d.comb += o7.eq(i9u > i8s)
|
|
|
|
m.d.comb += o8.eq(i9u > i9s)
|
|
|
|
m.d.comb += o9.eq(i8s <= i8u)
|
|
|
|
m.d.comb += o10.eq(i8s <= i9u)
|
|
|
|
m.d.comb += o11.eq(i8s <= i8s)
|
|
|
|
m.d.comb += o12.eq(i8s <= i9s)
|
|
|
|
m.d.comb += o13.eq(i9s >= i8u)
|
|
|
|
m.d.comb += o14.eq(i9s >= i9u)
|
|
|
|
m.d.comb += o15.eq(i9s >= i8s)
|
|
|
|
m.d.comb += o16.eq(i9s >= i9s)
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
i8u, i9u, i8s, i9s,
|
|
|
|
o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15, o16,
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8u' 0.2:10)
|
|
|
|
(input 'i9u' 0.10:19)
|
|
|
|
(input 'i8s' 0.19:27)
|
|
|
|
(input 'i9s' 0.27:36)
|
|
|
|
(output 'o1' (cat 1.0 1'd0))
|
|
|
|
(output 'o2' (cat 2.0 1'd0))
|
|
|
|
(output 'o3' (cat 3.0 1'd0))
|
|
|
|
(output 'o4' (cat 4.0 1'd0))
|
|
|
|
(output 'o5' (cat 5.0 1'd0))
|
|
|
|
(output 'o6' (cat 6.0 1'd0))
|
|
|
|
(output 'o7' (cat 7.0 1'd0))
|
|
|
|
(output 'o8' (cat 8.0 1'd0))
|
|
|
|
(output 'o9' (cat 9.0 1'd0))
|
|
|
|
(output 'o10' (cat 10.0 1'd0))
|
|
|
|
(output 'o11' (cat 11.0 1'd0))
|
|
|
|
(output 'o12' (cat 12.0 1'd0))
|
|
|
|
(output 'o13' (cat 13.0 1'd0))
|
|
|
|
(output 'o14' (cat 14.0 1'd0))
|
|
|
|
(output 'o15' (cat 15.0 1'd0))
|
|
|
|
(output 'o16' (cat 16.0 1'd0))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8u' 2:10)
|
|
|
|
(input 'i9u' 10:19)
|
|
|
|
(input 'i8s' 19:27)
|
|
|
|
(input 'i9s' 27:36)
|
|
|
|
(output 'o1' (cat 1.0 1'd0))
|
|
|
|
(output 'o2' (cat 2.0 1'd0))
|
|
|
|
(output 'o3' (cat 3.0 1'd0))
|
|
|
|
(output 'o4' (cat 4.0 1'd0))
|
|
|
|
(output 'o5' (cat 5.0 1'd0))
|
|
|
|
(output 'o6' (cat 6.0 1'd0))
|
|
|
|
(output 'o7' (cat 7.0 1'd0))
|
|
|
|
(output 'o8' (cat 8.0 1'd0))
|
|
|
|
(output 'o9' (cat 9.0 1'd0))
|
|
|
|
(output 'o10' (cat 10.0 1'd0))
|
|
|
|
(output 'o11' (cat 11.0 1'd0))
|
|
|
|
(output 'o12' (cat 12.0 1'd0))
|
|
|
|
(output 'o13' (cat 13.0 1'd0))
|
|
|
|
(output 'o14' (cat 14.0 1'd0))
|
|
|
|
(output 'o15' (cat 15.0 1'd0))
|
|
|
|
(output 'o16' (cat 16.0 1'd0))
|
|
|
|
))
|
|
|
|
(cell 1 0 (u< 0.2:10 0.2:10))
|
|
|
|
(cell 2 0 (u< (cat 0.2:10 1'd0) 0.10:19))
|
|
|
|
(cell 3 0 (s< (cat 0.2:10 1'd0) (cat 0.19:27 0.26)))
|
|
|
|
(cell 4 0 (s< (cat 0.2:10 1'd0) 0.27:36))
|
|
|
|
(cell 5 0 (u> 0.10:19 (cat 0.2:10 1'd0)))
|
|
|
|
(cell 6 0 (u> 0.10:19 0.10:19))
|
|
|
|
(cell 7 0 (s> (cat 0.10:19 1'd0) (cat 0.19:27 0.26 0.26)))
|
|
|
|
(cell 8 0 (s> (cat 0.10:19 1'd0) (cat 0.27:36 0.35)))
|
|
|
|
(cell 9 0 (s<= (cat 0.19:27 0.26) (cat 0.2:10 1'd0)))
|
|
|
|
(cell 10 0 (s<= (cat 0.19:27 0.26 0.26) (cat 0.10:19 1'd0)))
|
|
|
|
(cell 11 0 (s<= 0.19:27 0.19:27))
|
|
|
|
(cell 12 0 (s<= (cat 0.19:27 0.26) 0.27:36))
|
|
|
|
(cell 13 0 (s>= 0.27:36 (cat 0.2:10 1'd0)))
|
|
|
|
(cell 14 0 (s>= (cat 0.27:36 0.35) (cat 0.10:19 1'd0)))
|
|
|
|
(cell 15 0 (s>= 0.27:36 (cat 0.19:27 0.26)))
|
|
|
|
(cell 16 0 (s>= 0.27:36 0.27:36))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_operator_mux(self):
|
|
|
|
i8a = Signal(8)
|
|
|
|
i8b = Signal(8)
|
|
|
|
i1 = Signal()
|
|
|
|
i4 = Signal(4)
|
|
|
|
o1 = Signal(8)
|
|
|
|
o2 = Signal(8)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(Mux(i1, i8a, i8b))
|
|
|
|
m.d.comb += o2.eq(Mux(i4, i8a, i8b))
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [i8a, i8b, i1, i4, o1, o2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8a' 0.2:10)
|
|
|
|
(input 'i8b' 0.10:18)
|
|
|
|
(input 'i1' 0.18)
|
|
|
|
(input 'i4' 0.19:23)
|
|
|
|
(output 'o1' 1.0:8)
|
|
|
|
(output 'o2' 3.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8a' 2:10)
|
|
|
|
(input 'i8b' 10:18)
|
|
|
|
(input 'i1' 18:19)
|
|
|
|
(input 'i4' 19:23)
|
|
|
|
(output 'o1' 1.0:8)
|
|
|
|
(output 'o2' 3.0:8)
|
|
|
|
))
|
|
|
|
(cell 1 0 (m 0.18 0.2:10 0.10:18))
|
|
|
|
(cell 2 0 (b 0.19:23))
|
|
|
|
(cell 3 0 (m 2.0 0.2:10 0.10:18))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_slice(self):
|
|
|
|
i = Signal(8)
|
|
|
|
o = Signal(8)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o.eq(i[2:5])
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [i, o])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i' 0.2:10)
|
|
|
|
(output 'o' (cat 0.4:7 5'd0))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i' 2:10)
|
|
|
|
(output 'o' (cat 0.4:7 5'd0))
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_part(self):
|
|
|
|
i8u = Signal(8)
|
|
|
|
i8s = Signal(signed(8))
|
|
|
|
i4 = Signal(4)
|
|
|
|
o1 = Signal(4)
|
|
|
|
o2 = Signal(4)
|
|
|
|
o3 = Signal(4)
|
|
|
|
o4 = Signal(4)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(i8u.bit_select(i4, 3))
|
|
|
|
m.d.comb += o2.eq(i8s.bit_select(i4, 3))
|
|
|
|
m.d.comb += o3.eq(i8u.word_select(i4, 3))
|
|
|
|
m.d.comb += o4.eq(i8s.word_select(i4, 3))
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [i8u, i8s, i4, o1, o2, o3, o4])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8u' 0.2:10)
|
|
|
|
(input 'i8s' 0.10:18)
|
|
|
|
(input 'i4' 0.18:22)
|
|
|
|
(output 'o1' (cat 1.0:3 1'd0))
|
|
|
|
(output 'o2' (cat 2.0:3 1'd0))
|
|
|
|
(output 'o3' (cat 3.0:3 1'd0))
|
|
|
|
(output 'o4' (cat 4.0:3 1'd0))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8u' 2:10)
|
|
|
|
(input 'i8s' 10:18)
|
|
|
|
(input 'i4' 18:22)
|
|
|
|
(output 'o1' (cat 1.0:3 1'd0))
|
|
|
|
(output 'o2' (cat 2.0:3 1'd0))
|
|
|
|
(output 'o3' (cat 3.0:3 1'd0))
|
|
|
|
(output 'o4' (cat 4.0:3 1'd0))
|
|
|
|
))
|
|
|
|
(cell 1 0 (part 0.2:10 unsigned 0.18:22 3 1))
|
|
|
|
(cell 2 0 (part 0.10:18 signed 0.18:22 3 1))
|
|
|
|
(cell 3 0 (part 0.2:10 unsigned 0.18:22 3 3))
|
|
|
|
(cell 4 0 (part 0.10:18 signed 0.18:22 3 3))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_cat(self):
|
|
|
|
i1 = Signal()
|
|
|
|
i2 = Signal(8)
|
|
|
|
i3 = Signal(3)
|
|
|
|
o = Signal(16)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o.eq(Cat(i1, i2, i3))
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [i1, i2, i3, o])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i1' 0.2)
|
|
|
|
(input 'i2' 0.3:11)
|
|
|
|
(input 'i3' 0.11:14)
|
|
|
|
(output 'o' (cat 0.2:14 4'd0))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i1' 2:3)
|
|
|
|
(input 'i2' 3:11)
|
|
|
|
(input 'i3' 11:14)
|
|
|
|
(output 'o' (cat 0.2:14 4'd0))
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_arrayproxy(self):
|
|
|
|
i8ua = Signal(8)
|
|
|
|
i8ub = Signal(8)
|
|
|
|
i8uc = Signal(8)
|
|
|
|
i8sa = Signal(signed(8))
|
|
|
|
i8sb = Signal(signed(8))
|
|
|
|
i8sc = Signal(signed(8))
|
|
|
|
i4 = Signal(4)
|
|
|
|
o1 = Signal(10)
|
|
|
|
o2 = Signal(10)
|
|
|
|
o3 = Signal(10)
|
|
|
|
o4 = Signal(10)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(Array([i8ua, i8ub, i8uc])[i4])
|
|
|
|
m.d.comb += o2.eq(Array([i8ua, i8ub, i8sc])[i4])
|
|
|
|
m.d.comb += o3.eq(Array([i8sa, i8sb, i8sc])[i4])
|
|
|
|
m.d.comb += o4.eq(Array([i8sa, i8sb, i4])[i4])
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [i8ua, i8ub, i8uc, i8sa, i8sb, i8sc, i4, o1, o2, o3, o4])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8ua' 0.2:10)
|
|
|
|
(input 'i8ub' 0.10:18)
|
|
|
|
(input 'i8uc' 0.18:26)
|
|
|
|
(input 'i8sa' 0.26:34)
|
|
|
|
(input 'i8sb' 0.34:42)
|
|
|
|
(input 'i8sc' 0.42:50)
|
|
|
|
(input 'i4' 0.50:54)
|
2024-03-03 11:46:15 -07:00
|
|
|
(output 'o1' (cat 5.0:8 2'd0))
|
|
|
|
(output 'o2' (cat 10.0:9 10.8))
|
|
|
|
(output 'o3' (cat 15.0:8 15.7 15.7))
|
|
|
|
(output 'o4' (cat 20.0:8 20.7 20.7))
|
2024-02-29 13:42:25 -07:00
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8ua' 2:10)
|
|
|
|
(input 'i8ub' 10:18)
|
|
|
|
(input 'i8uc' 18:26)
|
|
|
|
(input 'i8sa' 26:34)
|
|
|
|
(input 'i8sb' 34:42)
|
|
|
|
(input 'i8sc' 42:50)
|
|
|
|
(input 'i4' 50:54)
|
2024-03-03 11:46:15 -07:00
|
|
|
(output 'o1' (cat 5.0:8 2'd0))
|
|
|
|
(output 'o2' (cat 10.0:9 10.8))
|
|
|
|
(output 'o3' (cat 15.0:8 15.7 15.7))
|
|
|
|
(output 'o4' (cat 20.0:8 20.7 20.7))
|
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.50:54 0000))
|
|
|
|
(cell 2 0 (matches 0.50:54 0001))
|
|
|
|
(cell 3 0 (matches 0.50:54 0010))
|
|
|
|
(cell 4 0 (priority_match 1 (cat 1.0 2.0 3.0)))
|
2024-04-03 01:09:18 -06:00
|
|
|
(cell 5 0 (assignment_list 8'd0
|
2024-03-03 11:46:15 -07:00
|
|
|
(4.0 0:8 0.2:10)
|
|
|
|
(4.1 0:8 0.10:18)
|
|
|
|
(4.2 0:8 0.18:26)
|
|
|
|
))
|
|
|
|
(cell 6 0 (matches 0.50:54 0000))
|
|
|
|
(cell 7 0 (matches 0.50:54 0001))
|
|
|
|
(cell 8 0 (matches 0.50:54 0010))
|
|
|
|
(cell 9 0 (priority_match 1 (cat 6.0 7.0 8.0)))
|
2024-04-03 01:09:18 -06:00
|
|
|
(cell 10 0 (assignment_list 9'd0
|
2024-03-03 11:46:15 -07:00
|
|
|
(9.0 0:9 (cat 0.2:10 1'd0))
|
|
|
|
(9.1 0:9 (cat 0.10:18 1'd0))
|
|
|
|
(9.2 0:9 (cat 0.42:50 0.49))
|
|
|
|
))
|
|
|
|
(cell 11 0 (matches 0.50:54 0000))
|
|
|
|
(cell 12 0 (matches 0.50:54 0001))
|
|
|
|
(cell 13 0 (matches 0.50:54 0010))
|
|
|
|
(cell 14 0 (priority_match 1 (cat 11.0 12.0 13.0)))
|
2024-04-03 01:09:18 -06:00
|
|
|
(cell 15 0 (assignment_list 8'd0
|
2024-03-03 11:46:15 -07:00
|
|
|
(14.0 0:8 0.26:34)
|
|
|
|
(14.1 0:8 0.34:42)
|
|
|
|
(14.2 0:8 0.42:50)
|
|
|
|
))
|
|
|
|
(cell 16 0 (matches 0.50:54 0000))
|
|
|
|
(cell 17 0 (matches 0.50:54 0001))
|
|
|
|
(cell 18 0 (matches 0.50:54 0010))
|
|
|
|
(cell 19 0 (priority_match 1 (cat 16.0 17.0 18.0)))
|
2024-04-03 01:09:18 -06:00
|
|
|
(cell 20 0 (assignment_list 8'd0
|
2024-03-03 11:46:15 -07:00
|
|
|
(19.0 0:8 0.26:34)
|
|
|
|
(19.1 0:8 0.34:42)
|
|
|
|
(19.2 0:8 (cat 0.50:54 4'd0))
|
2024-02-29 13:42:25 -07:00
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
2024-04-03 01:09:18 -06:00
|
|
|
def test_switchvalue(self):
|
|
|
|
i8ua = Signal(8)
|
|
|
|
i8ub = Signal(8)
|
|
|
|
i8uc = Signal(8)
|
|
|
|
i8ud = Signal(8)
|
|
|
|
i4 = Signal(4)
|
|
|
|
o1 = Signal(10)
|
|
|
|
o2 = Signal(10)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(SwitchValue(i4, [
|
|
|
|
(1, i8ua),
|
|
|
|
((2, 3), i8ub),
|
|
|
|
('11--', i8uc),
|
|
|
|
]))
|
|
|
|
m.d.comb += o2.eq(SwitchValue(i4, [
|
|
|
|
((4, 5), i8ua),
|
|
|
|
((), i8ub),
|
|
|
|
((6, 7), i8uc),
|
|
|
|
(None, i8ud),
|
|
|
|
]))
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [i8ua, i8ub, i8uc, i8ud, i4, o1, o2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i8ua' 0.2:10)
|
|
|
|
(input 'i8ub' 0.10:18)
|
|
|
|
(input 'i8uc' 0.18:26)
|
|
|
|
(input 'i8ud' 0.26:34)
|
|
|
|
(input 'i4' 0.34:38)
|
|
|
|
(output 'o1' (cat 5.0:8 2'd0))
|
2024-03-26 19:36:06 -06:00
|
|
|
(output 'o2' (cat 10.0:8 2'd0))
|
2024-04-03 01:09:18 -06:00
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i8ua' 2:10)
|
|
|
|
(input 'i8ub' 10:18)
|
|
|
|
(input 'i8uc' 18:26)
|
|
|
|
(input 'i8ud' 26:34)
|
|
|
|
(input 'i4' 34:38)
|
|
|
|
(output 'o1' (cat 5.0:8 2'd0))
|
2024-03-26 19:36:06 -06:00
|
|
|
(output 'o2' (cat 10.0:8 2'd0))
|
2024-04-03 01:09:18 -06:00
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.34:38 0001))
|
|
|
|
(cell 2 0 (matches 0.34:38 0010 0011))
|
|
|
|
(cell 3 0 (matches 0.34:38 11--))
|
|
|
|
(cell 4 0 (priority_match 1 (cat 1.0 2.0 3.0)))
|
|
|
|
(cell 5 0 (assignment_list 8'd0
|
|
|
|
(4.0 0:8 0.2:10)
|
|
|
|
(4.1 0:8 0.10:18)
|
|
|
|
(4.2 0:8 0.18:26)
|
|
|
|
))
|
|
|
|
(cell 6 0 (matches 0.34:38 0100 0101))
|
2024-03-26 19:36:06 -06:00
|
|
|
(cell 7 0 (matches 0.34:38 ))
|
|
|
|
(cell 8 0 (matches 0.34:38 0110 0111))
|
|
|
|
(cell 9 0 (priority_match 1 (cat 6.0 7.0 8.0 1'd1)))
|
|
|
|
(cell 10 0 (assignment_list 8'd0
|
|
|
|
(9.0 0:8 0.2:10)
|
|
|
|
(9.1 0:8 0.10:18)
|
|
|
|
(9.2 0:8 0.18:26)
|
|
|
|
(9.3 0:8 0.26:34)
|
2024-04-03 01:09:18 -06:00
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
2024-02-29 13:42:25 -07:00
|
|
|
def test_anyvalue(self):
|
|
|
|
o1 = Signal(12)
|
|
|
|
o2 = Signal(12)
|
|
|
|
o3 = Signal(12)
|
|
|
|
o4 = Signal(12)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(AnyConst(8))
|
|
|
|
m.d.comb += o2.eq(AnyConst(signed(8)))
|
|
|
|
m.d.comb += o3.eq(AnySeq(8))
|
|
|
|
m.d.comb += o4.eq(AnySeq(signed(8)))
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [o1, o2, o3, o4])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(output 'o1' (cat 1.0:8 4'd0))
|
|
|
|
(output 'o2' (cat 2.0:8 2.7 2.7 2.7 2.7))
|
|
|
|
(output 'o3' (cat 3.0:8 4'd0))
|
|
|
|
(output 'o4' (cat 4.0:8 4.7 4.7 4.7 4.7))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(output 'o1' (cat 1.0:8 4'd0))
|
|
|
|
(output 'o2' (cat 2.0:8 2.7 2.7 2.7 2.7))
|
|
|
|
(output 'o3' (cat 3.0:8 4'd0))
|
|
|
|
(output 'o4' (cat 4.0:8 4.7 4.7 4.7 4.7))
|
|
|
|
))
|
|
|
|
(cell 1 0 (anyconst 8))
|
|
|
|
(cell 2 0 (anyconst 8))
|
|
|
|
(cell 3 0 (anyseq 8))
|
|
|
|
(cell 4 0 (anyseq 8))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_initial(self):
|
|
|
|
o1 = Signal(12)
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += o1.eq(Initial())
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [o1])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(output 'o1' (cat 1.0 11'd0))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(output 'o1' (cat 1.0 11'd0))
|
|
|
|
))
|
|
|
|
(cell 1 0 (initial))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
2024-03-05 02:34:58 -07:00
|
|
|
|
2024-02-29 13:42:25 -07:00
|
|
|
class SwitchTestCase(FHDLTestCase):
|
|
|
|
def test_comb(self):
|
|
|
|
o1 = Signal(8)
|
|
|
|
o2 = Signal(8, init=123)
|
|
|
|
i = Signal(4)
|
|
|
|
i2 = Signal(4)
|
|
|
|
m = Module()
|
|
|
|
with m.If(i[0]):
|
|
|
|
m.d.comb += o1.eq(1)
|
|
|
|
with m.Elif(i[1]):
|
|
|
|
m.d.comb += o1[2:4].eq(2)
|
|
|
|
m.d.comb += o2.eq(3)
|
|
|
|
with m.If(i[2]):
|
|
|
|
with m.Switch(i2):
|
|
|
|
with m.Case(1):
|
|
|
|
m.d.comb += o2.eq(4)
|
|
|
|
with m.Case(2, 4):
|
|
|
|
m.d.comb += o2.eq(5)
|
|
|
|
with m.Case('11--'):
|
|
|
|
m.d.comb += o2.eq(6)
|
|
|
|
with m.If(i[3]):
|
|
|
|
m.d.comb += o1.eq(7)
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [i, i2, o1, o2])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i' 0.2:6)
|
|
|
|
(input 'i2' 0.6:10)
|
|
|
|
(output 'o1' 12.0:8)
|
|
|
|
(output 'o2' 13.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i' 2:6)
|
|
|
|
(input 'i2' 6:10)
|
|
|
|
(output 'o1' 12.0:8)
|
|
|
|
(output 'o2' 13.0:8)
|
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.2:4 -1))
|
|
|
|
(cell 2 0 (matches 0.2:4 1-))
|
|
|
|
(cell 3 0 (priority_match 1 (cat 1.0 2.0)))
|
|
|
|
(cell 4 0 (matches 0.4 1))
|
|
|
|
(cell 5 0 (priority_match 1 4.0))
|
|
|
|
(cell 6 0 (matches 0.6:10 0001))
|
|
|
|
(cell 7 0 (matches 0.6:10 0010 0100))
|
|
|
|
(cell 8 0 (matches 0.6:10 11--))
|
|
|
|
(cell 9 0 (priority_match 5.0 (cat 6.0 7.0 8.0)))
|
|
|
|
(cell 10 0 (matches 0.5 1))
|
|
|
|
(cell 11 0 (priority_match 9.2 10.0))
|
|
|
|
(cell 12 0 (assignment_list 8'd0
|
|
|
|
(3.0 0:8 8'd1)
|
|
|
|
(3.1 2:4 2'd2)
|
|
|
|
(11.0 0:8 8'd7)
|
|
|
|
))
|
|
|
|
(cell 13 0 (assignment_list 8'd123
|
|
|
|
(3.1 0:8 8'd3)
|
|
|
|
(9.0 0:8 8'd4)
|
|
|
|
(9.1 0:8 8'd5)
|
|
|
|
(9.2 0:8 8'd6)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_sync(self):
|
|
|
|
o1 = Signal(8, reset_less=True)
|
|
|
|
o2 = Signal(8, init=123)
|
|
|
|
o3 = Signal(8, init=45, reset_less=True)
|
|
|
|
o4 = Signal(8, init=67)
|
|
|
|
o5 = Signal(8, init=89)
|
|
|
|
i1 = Signal(8)
|
|
|
|
i2 = Signal()
|
|
|
|
m = Module()
|
|
|
|
m.domains.a = ClockDomain()
|
|
|
|
m.domains.b = ClockDomain(async_reset=True)
|
|
|
|
m.domains.c = ClockDomain(reset_less=True, clk_edge="neg")
|
|
|
|
with m.If(i2):
|
|
|
|
m.d.a += o1.eq(i1)
|
|
|
|
m.d.a += o2.eq(i1)
|
|
|
|
m.d.b += o3.eq(i1)
|
|
|
|
m.d.b += o4.eq(i1)
|
|
|
|
m.d.c += o5.eq(i1)
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
i1, i2, o1, o2, o3, o4, o5,
|
|
|
|
ClockSignal("a"), ResetSignal("a"),
|
|
|
|
ClockSignal("b"), ResetSignal("b"),
|
|
|
|
ClockSignal("c"),
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i1' 0.2:10)
|
|
|
|
(input 'i2' 0.10)
|
|
|
|
(input 'a_clk' 0.11)
|
|
|
|
(input 'a_rst' 0.12)
|
|
|
|
(input 'b_clk' 0.13)
|
|
|
|
(input 'b_rst' 0.14)
|
|
|
|
(input 'c_clk' 0.15)
|
2024-04-06 01:28:32 -06:00
|
|
|
(output 'o1' 4.0:8)
|
|
|
|
(output 'o2' 8.0:8)
|
|
|
|
(output 'o3' 10.0:8)
|
|
|
|
(output 'o4' 12.0:8)
|
|
|
|
(output 'o5' 14.0:8)
|
2024-02-29 13:42:25 -07:00
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i1' 2:10)
|
|
|
|
(input 'i2' 10:11)
|
|
|
|
(input 'a_clk' 11:12)
|
|
|
|
(input 'a_rst' 12:13)
|
|
|
|
(input 'b_clk' 13:14)
|
|
|
|
(input 'b_rst' 14:15)
|
|
|
|
(input 'c_clk' 15:16)
|
2024-04-06 01:28:32 -06:00
|
|
|
(output 'o1' 4.0:8)
|
|
|
|
(output 'o2' 8.0:8)
|
|
|
|
(output 'o3' 10.0:8)
|
|
|
|
(output 'o4' 12.0:8)
|
|
|
|
(output 'o5' 14.0:8)
|
2024-02-29 13:42:25 -07:00
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.10 1))
|
|
|
|
(cell 2 0 (priority_match 1 1.0))
|
2024-04-06 01:28:32 -06:00
|
|
|
(cell 3 0 (assignment_list 4.0:8 (2.0 0:8 0.2:10)))
|
|
|
|
(cell 4 0 (flipflop 3.0:8 0 pos 0.11 0))
|
|
|
|
(cell 5 0 (matches 0.12 1))
|
2024-02-29 13:42:25 -07:00
|
|
|
(cell 6 0 (priority_match 1 5.0))
|
2024-04-06 01:28:32 -06:00
|
|
|
(cell 7 0 (assignment_list 8.0:8 (2.0 0:8 0.2:10) (6.0 0:8 8'd123)))
|
|
|
|
(cell 8 0 (flipflop 7.0:8 123 pos 0.11 0))
|
|
|
|
(cell 9 0 (assignment_list 10.0:8 (2.0 0:8 0.2:10)))
|
|
|
|
(cell 10 0 (flipflop 9.0:8 45 pos 0.13 0))
|
|
|
|
(cell 11 0 (assignment_list 12.0:8 (2.0 0:8 0.2:10)))
|
|
|
|
(cell 12 0 (flipflop 11.0:8 67 pos 0.13 0.14))
|
|
|
|
(cell 13 0 (assignment_list 14.0:8 (2.0 0:8 0.2:10)))
|
|
|
|
(cell 14 0 (flipflop 13.0:8 89 neg 0.15 0))
|
2024-02-29 13:42:25 -07:00
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
2024-03-05 21:23:47 -07:00
|
|
|
def test_print(self):
|
|
|
|
m = Module()
|
|
|
|
a = Signal(6)
|
|
|
|
b = Signal(signed(8))
|
|
|
|
en = Signal()
|
|
|
|
m.domains.a = ClockDomain()
|
|
|
|
m.domains.b = ClockDomain(async_reset=True)
|
|
|
|
m.domains.c = ClockDomain(reset_less=True, clk_edge="neg")
|
|
|
|
with m.If(en):
|
|
|
|
m.d.comb += Print(a, end="")
|
|
|
|
m.d.comb += Print(b)
|
|
|
|
m.d.a += Print(a, b)
|
|
|
|
m.d.b += Print(Format("values: {:02x}, {:+d}", a, b))
|
|
|
|
m.d.c += Print("meow")
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
a, b, en,
|
|
|
|
ClockSignal("a"), ResetSignal("a"),
|
|
|
|
ClockSignal("b"), ResetSignal("b"),
|
|
|
|
ClockSignal("c"),
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'a' 0.2:8)
|
|
|
|
(input 'b' 0.8:16)
|
|
|
|
(input 'en' 0.16)
|
|
|
|
(input 'a_clk' 0.17)
|
|
|
|
(input 'a_rst' 0.18)
|
|
|
|
(input 'b_clk' 0.19)
|
|
|
|
(input 'b_rst' 0.20)
|
|
|
|
(input 'c_clk' 0.21)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'a' 2:8)
|
|
|
|
(input 'b' 8:16)
|
|
|
|
(input 'en' 16:17)
|
|
|
|
(input 'a_clk' 17:18)
|
|
|
|
(input 'a_rst' 18:19)
|
|
|
|
(input 'b_clk' 19:20)
|
|
|
|
(input 'b_rst' 20:21)
|
|
|
|
(input 'c_clk' 21:22)
|
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.16 1))
|
|
|
|
(cell 2 0 (priority_match 1 1.0))
|
|
|
|
(cell 3 0 (assignment_list 1'd0 (2.0 0:1 1'd1)))
|
|
|
|
(cell 4 0 (print 3.0 ((u 0.2:8 ''))))
|
|
|
|
(cell 5 0 (assignment_list 1'd0 (2.0 0:1 1'd1)))
|
|
|
|
(cell 6 0 (print 5.0 ((s 0.8:16 '') '\\n')))
|
2024-04-06 01:28:32 -06:00
|
|
|
(cell 7 0 (assignment_list 1'd0 (2.0 0:1 1'd1)))
|
|
|
|
(cell 8 0 (print 7.0 pos 0.17 ((u 0.2:8 '') ' ' (s 0.8:16 '') '\\n')))
|
|
|
|
(cell 9 0 (assignment_list 1'd0 (2.0 0:1 1'd1)))
|
|
|
|
(cell 10 0 (print 9.0 pos 0.19 ('values: ' (u 0.2:8 '02x') ', ' (s 0.8:16 '+d') '\\n')))
|
|
|
|
(cell 11 0 (assignment_list 1'd0 (2.0 0:1 1'd1)))
|
|
|
|
(cell 12 0 (print 11.0 neg 0.21 ('meow\\n')))
|
2024-03-05 21:23:47 -07:00
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
2024-02-29 13:42:25 -07:00
|
|
|
def test_assert(self):
|
|
|
|
m = Module()
|
|
|
|
i = Signal(6)
|
|
|
|
m.domains.a = ClockDomain()
|
|
|
|
m.domains.b = ClockDomain(async_reset=True)
|
|
|
|
m.domains.c = ClockDomain(reset_less=True, clk_edge="neg")
|
|
|
|
with m.If(i[5]):
|
|
|
|
m.d.comb += Assert(i[0])
|
2024-03-05 21:23:47 -07:00
|
|
|
m.d.comb += Assume(i[1], "aaa")
|
2024-02-29 13:42:25 -07:00
|
|
|
m.d.a += Assert(i[2])
|
2024-03-05 21:23:47 -07:00
|
|
|
m.d.b += Assume(i[3], Format("value: {}", i))
|
|
|
|
m.d.c += Cover(i[4], "c")
|
|
|
|
m.d.comb += Cover(i, "d")
|
2024-02-29 13:42:25 -07:00
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
i,
|
|
|
|
ClockSignal("a"), ResetSignal("a"),
|
|
|
|
ClockSignal("b"), ResetSignal("b"),
|
|
|
|
ClockSignal("c"),
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(input 'i' 0.2:8)
|
|
|
|
(input 'a_clk' 0.8)
|
|
|
|
(input 'a_rst' 0.9)
|
|
|
|
(input 'b_clk' 0.10)
|
|
|
|
(input 'b_rst' 0.11)
|
|
|
|
(input 'c_clk' 0.12)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(input 'i' 2:8)
|
|
|
|
(input 'a_clk' 8:9)
|
|
|
|
(input 'a_rst' 9:10)
|
|
|
|
(input 'b_clk' 10:11)
|
|
|
|
(input 'b_rst' 11:12)
|
|
|
|
(input 'c_clk' 12:13)
|
|
|
|
))
|
|
|
|
(cell 1 0 (matches 0.7 1))
|
|
|
|
(cell 2 0 (priority_match 1 1.0))
|
|
|
|
(cell 3 0 (assignment_list 1'd0 (2.0 0:1 1'd1)))
|
2024-03-05 21:23:47 -07:00
|
|
|
(cell 4 0 (assert 0.2 3.0 None))
|
2024-02-29 13:42:25 -07:00
|
|
|
(cell 5 0 (assignment_list 1'd0 (2.0 0:1 1'd1)))
|
2024-03-05 21:23:47 -07:00
|
|
|
(cell 6 0 (assume 0.3 5.0 ('aaa')))
|
2024-02-29 13:42:25 -07:00
|
|
|
(cell 7 0 (b 0.2:8))
|
|
|
|
(cell 8 0 (assignment_list 1'd0 (2.0 0:1 1'd1)))
|
2024-03-05 21:23:47 -07:00
|
|
|
(cell 9 0 (cover 7.0 8.0 ('d')))
|
2024-04-06 01:28:32 -06:00
|
|
|
(cell 10 0 (assignment_list 1'd0 (2.0 0:1 1'd1)))
|
|
|
|
(cell 11 0 (assert 0.4 10.0 pos 0.8 None))
|
|
|
|
(cell 12 0 (assignment_list 1'd0 (2.0 0:1 1'd1)))
|
|
|
|
(cell 13 0 (assume 0.5 12.0 pos 0.10 ('value: ' (u 0.2:8 ''))))
|
|
|
|
(cell 14 0 (assignment_list 1'd0 (2.0 0:1 1'd1)))
|
|
|
|
(cell 15 0 (cover 0.6 14.0 neg 0.12 ('c')))
|
2024-02-29 13:42:25 -07:00
|
|
|
)
|
|
|
|
""")
|
2024-03-15 15:27:59 -06:00
|
|
|
|
2024-03-05 02:34:58 -07:00
|
|
|
|
2024-03-15 15:27:59 -06:00
|
|
|
class ConflictTestCase(FHDLTestCase):
|
|
|
|
def test_domain_conflict(self):
|
|
|
|
s = Signal()
|
|
|
|
m = Module()
|
|
|
|
m.d.sync += s.eq(1)
|
|
|
|
m1 = Module()
|
|
|
|
m1.d.comb += s.eq(2)
|
|
|
|
m.submodules.m1 = m1
|
|
|
|
with self.assertRaisesRegex(DriverConflict,
|
|
|
|
r"^Signal \(sig s\) driven from domain comb at "
|
|
|
|
r".*test_hdl_ir.py:\d+ and domain sync at "
|
|
|
|
r".*test_hdl_ir.py:\d+$"):
|
|
|
|
build_netlist(Fragment.get(m, None), [])
|
|
|
|
|
|
|
|
def test_module_conflict(self):
|
|
|
|
s = Signal()
|
|
|
|
m = Module()
|
|
|
|
m.d.sync += s.eq(1)
|
|
|
|
m1 = Module()
|
|
|
|
m1.d.sync += s.eq(2)
|
|
|
|
m.submodules.m1 = m1
|
|
|
|
with self.assertRaisesRegex(DriverConflict,
|
|
|
|
r"^Signal \(sig s\) driven from module top\.m1 at "
|
|
|
|
r".*test_hdl_ir.py:\d+ and module top at "
|
|
|
|
r".*test_hdl_ir.py:\d+$"):
|
|
|
|
build_netlist(Fragment.get(m, None), [])
|
|
|
|
|
|
|
|
def test_instance_conflict(self):
|
|
|
|
s = Signal()
|
|
|
|
m = Module()
|
|
|
|
m.d.sync += s.eq(1)
|
|
|
|
m.submodules.t = Instance("tt", o_s=s)
|
|
|
|
with self.assertRaisesRegex(DriverConflict,
|
|
|
|
r"^Bit 0 of signal \(sig s\) has multiple drivers: "
|
|
|
|
r".*test_hdl_ir.py:\d+ and .*test_hdl_ir.py:\d+$"):
|
|
|
|
build_netlist(Fragment.get(m, None), [])
|
2024-03-05 02:34:58 -07:00
|
|
|
|
|
|
|
|
|
|
|
class UndrivenTestCase(FHDLTestCase):
|
|
|
|
def test_undriven(self):
|
|
|
|
o = Signal(8)
|
|
|
|
m = Module()
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
("o", o, PortDirection.Output),
|
|
|
|
])
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(output 'o' 8'd0)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(output 'o' 8'd0)
|
|
|
|
))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_undef_to_ff(self):
|
|
|
|
o = Signal(8, init=0x55)
|
|
|
|
m = Module()
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
("o", o, PortDirection.Output),
|
|
|
|
], all_undef_to_ff=True)
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(output 'o' 1.0:8)
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(output 'o' 1.0:8)
|
|
|
|
))
|
|
|
|
(cell 1 0 (flipflop 1.0:8 85 pos 0 0))
|
|
|
|
)
|
|
|
|
""")
|
|
|
|
|
|
|
|
def test_undef_to_ff_partial(self):
|
|
|
|
o = Signal(8, init=0x55)
|
|
|
|
m = Module()
|
|
|
|
m.submodules.inst = Instance("t", o_o=o[2])
|
|
|
|
nl = build_netlist(Fragment.get(m, None), [
|
|
|
|
("o", o, PortDirection.Output),
|
|
|
|
], all_undef_to_ff=True)
|
|
|
|
self.assertRepr(nl, """
|
|
|
|
(
|
|
|
|
(module 0 None ('top')
|
|
|
|
(output 'o' (cat 2.0:2 1.0 3.0:5))
|
|
|
|
)
|
|
|
|
(cell 0 0 (top
|
|
|
|
(output 'o' (cat 2.0:2 1.0 3.0:5))
|
|
|
|
))
|
|
|
|
(cell 1 0 (instance 't' 'inst' (output 'o' 0:1)))
|
|
|
|
(cell 2 0 (flipflop 2.0:2 1 pos 0 0))
|
|
|
|
(cell 3 0 (flipflop 3.0:5 10 pos 0 0))
|
|
|
|
)
|
|
|
|
""")
|
2024-04-11 11:53:49 -06:00
|
|
|
|
|
|
|
|
|
|
|
class FieldsTestCase(FHDLTestCase):
|
|
|
|
def test_fields(self):
|
|
|
|
class MyEnum(enum.Enum, shape=unsigned(2)):
|
|
|
|
A = 0
|
|
|
|
B = 1
|
|
|
|
C = 2
|
|
|
|
l = data.StructLayout({"a": MyEnum, "b": signed(3)})
|
|
|
|
s1 = Signal(l)
|
|
|
|
s2 = Signal(MyEnum)
|
|
|
|
s3 = Signal(signed(3))
|
|
|
|
s4 = Signal(unsigned(4))
|
|
|
|
nl = build_netlist(Fragment.get(Module(), None), [
|
|
|
|
s1.as_value(), s2.as_value(), s3, s4,
|
|
|
|
])
|
|
|
|
self.assertEqual(nl.signal_fields[s1.as_value()], {
|
|
|
|
(): SignalField(nl.signals[s1.as_value()], signed=False),
|
|
|
|
('a',): SignalField(nl.signals[s1.as_value()][0:2], signed=False, enum_name="MyEnum", enum_variants={
|
|
|
|
0: "A",
|
|
|
|
1: "B",
|
|
|
|
2: "C",
|
|
|
|
}),
|
|
|
|
('b',): SignalField(nl.signals[s1.as_value()][2:5], signed=True)
|
|
|
|
})
|
|
|
|
self.assertEqual(nl.signal_fields[s2.as_value()], {
|
|
|
|
(): SignalField(nl.signals[s2.as_value()], signed=False, enum_name="MyEnum", enum_variants={
|
|
|
|
0: "A",
|
|
|
|
1: "B",
|
|
|
|
2: "C",
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
self.assertEqual(nl.signal_fields[s3], {
|
|
|
|
(): SignalField(nl.signals[s3], signed=True),
|
|
|
|
})
|
|
|
|
self.assertEqual(nl.signal_fields[s4], {
|
|
|
|
(): SignalField(nl.signals[s4], signed=False),
|
|
|
|
})
|
2024-04-13 05:38:47 -06:00
|
|
|
|
|
|
|
|
|
|
|
class CycleTestCase(FHDLTestCase):
|
|
|
|
def test_cycle(self):
|
|
|
|
a = Signal()
|
|
|
|
b = Signal()
|
|
|
|
m = Module()
|
|
|
|
m.d.comb += [
|
|
|
|
a.eq(~b),
|
|
|
|
b.eq(~a),
|
|
|
|
]
|
|
|
|
with self.assertRaisesRegex(CombinationalCycle,
|
|
|
|
r"^Combinational cycle detected, path:\n"
|
|
|
|
r".*test_hdl_ir.py:\d+: operator ~ bit 0\n"
|
|
|
|
r".*test_hdl_ir.py:\d+: signal b bit 0\n"
|
|
|
|
r".*test_hdl_ir.py:\d+: operator ~ bit 0\n"
|
|
|
|
r".*test_hdl_ir.py:\d+: signal a bit 0\n"
|
|
|
|
r"$"):
|
|
|
|
build_netlist(Fragment.get(m, None), [])
|