From 0a32f0ecdf3a367377fcc88b44042602e7ea52ad Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 13 Dec 2018 08:57:14 +0000 Subject: [PATCH] fhdl.xfrm: implement DomainRenamer. --- nmigen/fhdl/ast.py | 8 +- nmigen/fhdl/xfrm.py | 27 ++++++- nmigen/test/test_fhdl_dsl.py | 15 +--- ...test_fhdl_values.py => test_fhdl_value.py} | 2 +- nmigen/test/test_fhdl_xfrm.py | 78 ++++++++++++++----- nmigen/test/tools.py | 16 ++++ 6 files changed, 110 insertions(+), 36 deletions(-) rename nmigen/test/{test_fhdl_values.py => test_fhdl_value.py} (99%) create mode 100644 nmigen/test/tools.py diff --git a/nmigen/fhdl/ast.py b/nmigen/fhdl/ast.py index 604bb9e..9d3af7d 100644 --- a/nmigen/fhdl/ast.py +++ b/nmigen/fhdl/ast.py @@ -573,7 +573,7 @@ class ClockSignal(Value): Parameters ---------- 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"): super().__init__() @@ -588,13 +588,13 @@ class ClockSignal(Value): class ResetSignal(Value): """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. Parameters ---------- 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"): super().__init__() @@ -603,7 +603,7 @@ class ResetSignal(Value): self.domain = domain def __repr__(self): - return "(reset {})".format(self.domain) + return "(rst {})".format(self.domain) class _StatementList(list): diff --git a/nmigen/fhdl/xfrm.py b/nmigen/fhdl/xfrm.py index 8a20aab..4277af6 100644 --- a/nmigen/fhdl/xfrm.py +++ b/nmigen/fhdl/xfrm.py @@ -4,7 +4,8 @@ from .ast import * from .ir import * -__all__ = ["ValueTransformer", "StatementTransformer", "ResetInserter", "CEInserter"] +__all__ = ["ValueTransformer", "StatementTransformer", "FragmentTransformer", + "DomainRenamer", "ResetInserter", "CEInserter"] class ValueTransformer: @@ -116,6 +117,30 @@ class FragmentTransformer: 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): def __init__(self, controls): if isinstance(controls, Value): diff --git a/nmigen/test/test_fhdl_dsl.py b/nmigen/test/test_fhdl_dsl.py index 22019b1..7da25cf 100644 --- a/nmigen/test/test_fhdl_dsl.py +++ b/nmigen/test/test_fhdl_dsl.py @@ -1,12 +1,12 @@ -import re import unittest from contextlib import contextmanager -from nmigen.fhdl.ast import * -from nmigen.fhdl.dsl import * +from ..fhdl.ast import * +from ..fhdl.dsl import * +from .tools import * -class DSLTestCase(unittest.TestCase): +class DSLTestCase(FHDLTestCase): def setUp(self): self.s1 = Signal() self.s2 = Signal() @@ -24,13 +24,6 @@ class DSLTestCase(unittest.TestCase): # WTF? unittest.assertRaises is completely broken. 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): m = Module() m.d.comb += self.c1.eq(1) diff --git a/nmigen/test/test_fhdl_values.py b/nmigen/test/test_fhdl_value.py similarity index 99% rename from nmigen/test/test_fhdl_values.py rename to nmigen/test/test_fhdl_value.py index 16e0970..9c7dbde 100644 --- a/nmigen/test/test_fhdl_values.py +++ b/nmigen/test/test_fhdl_value.py @@ -355,4 +355,4 @@ class ResetSignalTestCase(unittest.TestCase): def test_repr(self): s1 = ResetSignal() - self.assertEqual(repr(s1), "(reset sync)") + self.assertEqual(repr(s1), "(rst sync)") diff --git a/nmigen/test/test_fhdl_xfrm.py b/nmigen/test/test_fhdl_xfrm.py index b569601..aad4525 100644 --- a/nmigen/test/test_fhdl_xfrm.py +++ b/nmigen/test/test_fhdl_xfrm.py @@ -1,25 +1,72 @@ import re import unittest -from nmigen.fhdl.ast import * -from nmigen.fhdl.ir import * -from nmigen.fhdl.xfrm import * +from ..fhdl.ast import * +from ..fhdl.ir 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): self.s1 = Signal() self.s2 = Signal(reset=1) self.s3 = Signal(reset=1, reset_less=True) 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): f = Fragment() f.add_statements( @@ -92,20 +139,13 @@ class ResetInserterTestCase(unittest.TestCase): """) -class CEInserterTestCase(unittest.TestCase): +class CEInserterTestCase(FHDLTestCase): def setUp(self): self.s1 = Signal() self.s2 = Signal() self.s3 = 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): f = Fragment() f.add_statements( diff --git a/nmigen/test/tools.py b/nmigen/test/tools.py new file mode 100644 index 0000000..9e3a8f0 --- /dev/null +++ b/nmigen/test/tools.py @@ -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()) -- 2.30.2