fhdl.xfrm: implement DomainRenamer.
This commit is contained in:
parent
8963ab5d9f
commit
9bee90f1bd
|
@ -573,7 +573,7 @@ class ClockSignal(Value):
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
domain : str
|
domain : str
|
||||||
Clock domain to obtain a clock signal for. Defaults to `"sync"`.
|
Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
|
||||||
"""
|
"""
|
||||||
def __init__(self, domain="sync"):
|
def __init__(self, domain="sync"):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -588,13 +588,13 @@ class ClockSignal(Value):
|
||||||
class ResetSignal(Value):
|
class ResetSignal(Value):
|
||||||
"""Reset signal for a given clock domain
|
"""Reset signal for a given clock domain
|
||||||
|
|
||||||
`ResetSignal` s for a given clock domain can be retrieved multiple
|
``ResetSignal`` s for a given clock domain can be retrieved multiple
|
||||||
times. They all ultimately refer to the same signal.
|
times. They all ultimately refer to the same signal.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
domain : str
|
domain : str
|
||||||
Clock domain to obtain a reset signal for. Defaults to `"sync"`.
|
Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
|
||||||
"""
|
"""
|
||||||
def __init__(self, domain="sync"):
|
def __init__(self, domain="sync"):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -603,7 +603,7 @@ class ResetSignal(Value):
|
||||||
self.domain = domain
|
self.domain = domain
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "(reset {})".format(self.domain)
|
return "(rst {})".format(self.domain)
|
||||||
|
|
||||||
|
|
||||||
class _StatementList(list):
|
class _StatementList(list):
|
||||||
|
|
|
@ -4,7 +4,8 @@ from .ast import *
|
||||||
from .ir import *
|
from .ir import *
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["ValueTransformer", "StatementTransformer", "ResetInserter", "CEInserter"]
|
__all__ = ["ValueTransformer", "StatementTransformer", "FragmentTransformer",
|
||||||
|
"DomainRenamer", "ResetInserter", "CEInserter"]
|
||||||
|
|
||||||
|
|
||||||
class ValueTransformer:
|
class ValueTransformer:
|
||||||
|
@ -116,6 +117,30 @@ class FragmentTransformer:
|
||||||
return self.on_fragment(value)
|
return self.on_fragment(value)
|
||||||
|
|
||||||
|
|
||||||
|
class DomainRenamer(FragmentTransformer, ValueTransformer, StatementTransformer):
|
||||||
|
def __init__(self, domains):
|
||||||
|
if isinstance(domains, str):
|
||||||
|
domains = {"sync": domains}
|
||||||
|
self.domains = OrderedDict(domains)
|
||||||
|
|
||||||
|
def on_ClockSignal(self, value):
|
||||||
|
if value.domain in self.domains:
|
||||||
|
return ClockSignal(self.domains[value.domain])
|
||||||
|
return value
|
||||||
|
|
||||||
|
def on_ResetSignal(self, value):
|
||||||
|
if value.domain in self.domains:
|
||||||
|
return ResetSignal(self.domains[value.domain])
|
||||||
|
return value
|
||||||
|
|
||||||
|
def map_drivers(self, fragment, new_fragment):
|
||||||
|
for cd_name, signals in fragment.iter_domains():
|
||||||
|
if cd_name in self.domains:
|
||||||
|
cd_name = self.domains[cd_name]
|
||||||
|
for signal in signals:
|
||||||
|
new_fragment.drive(signal, cd_name)
|
||||||
|
|
||||||
|
|
||||||
class _ControlInserter(FragmentTransformer):
|
class _ControlInserter(FragmentTransformer):
|
||||||
def __init__(self, controls):
|
def __init__(self, controls):
|
||||||
if isinstance(controls, Value):
|
if isinstance(controls, Value):
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import re
|
|
||||||
import unittest
|
import unittest
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
from nmigen.fhdl.ast import *
|
from ..fhdl.ast import *
|
||||||
from nmigen.fhdl.dsl import *
|
from ..fhdl.dsl import *
|
||||||
|
from .tools import *
|
||||||
|
|
||||||
|
|
||||||
class DSLTestCase(unittest.TestCase):
|
class DSLTestCase(FHDLTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.s1 = Signal()
|
self.s1 = Signal()
|
||||||
self.s2 = Signal()
|
self.s2 = Signal()
|
||||||
|
@ -24,13 +24,6 @@ class DSLTestCase(unittest.TestCase):
|
||||||
# WTF? unittest.assertRaises is completely broken.
|
# WTF? unittest.assertRaises is completely broken.
|
||||||
self.assertEqual(str(cm.exception), msg)
|
self.assertEqual(str(cm.exception), msg)
|
||||||
|
|
||||||
def assertRepr(self, obj, repr_str):
|
|
||||||
obj = Statement.wrap(obj)
|
|
||||||
repr_str = re.sub(r"\s+", " ", repr_str)
|
|
||||||
repr_str = re.sub(r"\( (?=\()", "(", repr_str)
|
|
||||||
repr_str = re.sub(r"\) (?=\))", ")", repr_str)
|
|
||||||
self.assertEqual(repr(obj), repr_str.strip())
|
|
||||||
|
|
||||||
def test_d_comb(self):
|
def test_d_comb(self):
|
||||||
m = Module()
|
m = Module()
|
||||||
m.d.comb += self.c1.eq(1)
|
m.d.comb += self.c1.eq(1)
|
||||||
|
|
|
@ -355,4 +355,4 @@ class ResetSignalTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
s1 = ResetSignal()
|
s1 = ResetSignal()
|
||||||
self.assertEqual(repr(s1), "(reset sync)")
|
self.assertEqual(repr(s1), "(rst sync)")
|
|
@ -1,25 +1,72 @@
|
||||||
import re
|
import re
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from nmigen.fhdl.ast import *
|
from ..fhdl.ast import *
|
||||||
from nmigen.fhdl.ir import *
|
from ..fhdl.ir import *
|
||||||
from nmigen.fhdl.xfrm import *
|
from ..fhdl.xfrm import *
|
||||||
|
from .tools import *
|
||||||
|
|
||||||
|
|
||||||
class ResetInserterTestCase(unittest.TestCase):
|
class DomainRenamerTestCase(FHDLTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.s1 = Signal()
|
||||||
|
self.s2 = Signal()
|
||||||
|
self.s3 = Signal()
|
||||||
|
self.s4 = Signal()
|
||||||
|
self.s5 = Signal()
|
||||||
|
self.c1 = Signal()
|
||||||
|
|
||||||
|
def test_rename_signals(self):
|
||||||
|
f = Fragment()
|
||||||
|
f.add_statements(
|
||||||
|
self.s1.eq(ClockSignal()),
|
||||||
|
ResetSignal().eq(self.s2),
|
||||||
|
self.s3.eq(0),
|
||||||
|
self.s4.eq(ClockSignal("other")),
|
||||||
|
self.s5.eq(ResetSignal("other")),
|
||||||
|
)
|
||||||
|
f.drive(self.s1, None)
|
||||||
|
f.drive(self.s2, None)
|
||||||
|
f.drive(self.s3, "sync")
|
||||||
|
|
||||||
|
f = DomainRenamer("pix")(f)
|
||||||
|
self.assertRepr(f.statements, """
|
||||||
|
(
|
||||||
|
(eq (sig s1) (clk pix))
|
||||||
|
(eq (rst pix) (sig s2))
|
||||||
|
(eq (sig s3) (const 0'd0))
|
||||||
|
(eq (sig s4) (clk other))
|
||||||
|
(eq (sig s5) (rst other))
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
self.assertEqual(f.drivers, {
|
||||||
|
None: ValueSet((self.s1, self.s2)),
|
||||||
|
"pix": ValueSet((self.s3,)),
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_rename_multi(self):
|
||||||
|
f = Fragment()
|
||||||
|
f.add_statements(
|
||||||
|
self.s1.eq(ClockSignal()),
|
||||||
|
self.s2.eq(ResetSignal("other")),
|
||||||
|
)
|
||||||
|
|
||||||
|
f = DomainRenamer({"sync": "pix", "other": "pix2"})(f)
|
||||||
|
self.assertRepr(f.statements, """
|
||||||
|
(
|
||||||
|
(eq (sig s1) (clk pix))
|
||||||
|
(eq (sig s2) (rst pix2))
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
class ResetInserterTestCase(FHDLTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.s1 = Signal()
|
self.s1 = Signal()
|
||||||
self.s2 = Signal(reset=1)
|
self.s2 = Signal(reset=1)
|
||||||
self.s3 = Signal(reset=1, reset_less=True)
|
self.s3 = Signal(reset=1, reset_less=True)
|
||||||
self.c1 = Signal()
|
self.c1 = Signal()
|
||||||
|
|
||||||
def assertRepr(self, obj, repr_str):
|
|
||||||
obj = Statement.wrap(obj)
|
|
||||||
repr_str = re.sub(r"\s+", " ", repr_str)
|
|
||||||
repr_str = re.sub(r"\( (?=\()", "(", repr_str)
|
|
||||||
repr_str = re.sub(r"\) (?=\))", ")", repr_str)
|
|
||||||
self.assertEqual(repr(obj), repr_str.strip())
|
|
||||||
|
|
||||||
def test_reset_default(self):
|
def test_reset_default(self):
|
||||||
f = Fragment()
|
f = Fragment()
|
||||||
f.add_statements(
|
f.add_statements(
|
||||||
|
@ -92,20 +139,13 @@ class ResetInserterTestCase(unittest.TestCase):
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
class CEInserterTestCase(unittest.TestCase):
|
class CEInserterTestCase(FHDLTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.s1 = Signal()
|
self.s1 = Signal()
|
||||||
self.s2 = Signal()
|
self.s2 = Signal()
|
||||||
self.s3 = Signal()
|
self.s3 = Signal()
|
||||||
self.c1 = Signal()
|
self.c1 = Signal()
|
||||||
|
|
||||||
def assertRepr(self, obj, repr_str):
|
|
||||||
obj = Statement.wrap(obj)
|
|
||||||
repr_str = re.sub(r"\s+", " ", repr_str)
|
|
||||||
repr_str = re.sub(r"\( (?=\()", "(", repr_str)
|
|
||||||
repr_str = re.sub(r"\) (?=\))", ")", repr_str)
|
|
||||||
self.assertEqual(repr(obj), repr_str.strip())
|
|
||||||
|
|
||||||
def test_ce_default(self):
|
def test_ce_default(self):
|
||||||
f = Fragment()
|
f = Fragment()
|
||||||
f.add_statements(
|
f.add_statements(
|
||||||
|
|
16
nmigen/test/tools.py
Normal file
16
nmigen/test/tools.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import re
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from ..fhdl.ast import *
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["FHDLTestCase"]
|
||||||
|
|
||||||
|
|
||||||
|
class FHDLTestCase(unittest.TestCase):
|
||||||
|
def assertRepr(self, obj, repr_str):
|
||||||
|
obj = Statement.wrap(obj)
|
||||||
|
repr_str = re.sub(r"\s+", " ", repr_str)
|
||||||
|
repr_str = re.sub(r"\( (?=\()", "(", repr_str)
|
||||||
|
repr_str = re.sub(r"\) (?=\))", ")", repr_str)
|
||||||
|
self.assertEqual(repr(obj), repr_str.strip())
|
Loading…
Reference in a new issue