hdl.{ast,cd,dsl,xfrm}: reject inappropriately used comb domain.
authorwhitequark <cz@m-labs.hk>
Mon, 8 Jul 2019 10:26:49 +0000 (10:26 +0000)
committerwhitequark <cz@m-labs.hk>
Mon, 8 Jul 2019 10:26:49 +0000 (10:26 +0000)
Fixes #125.

nmigen/hdl/ast.py
nmigen/hdl/cd.py
nmigen/hdl/dsl.py
nmigen/hdl/xfrm.py
nmigen/test/test_hdl_ast.py
nmigen/test/test_hdl_cd.py
nmigen/test/test_hdl_dsl.py
nmigen/test/test_hdl_xfrm.py

index bf09077552c9675636a502f8470bdb666bce9f17..949a82516ad77b449e9040946c357adeb4557d3a 100644 (file)
@@ -693,6 +693,8 @@ class ClockSignal(Value):
         super().__init__(src_loc_at=src_loc_at)
         if not isinstance(domain, str):
             raise TypeError("Clock domain name must be a string, not '{!r}'".format(domain))
+        if domain == "comb":
+            raise ValueError("Domain '{}' does not have a clock".format(domain))
         self.domain = domain
 
     def shape(self):
@@ -727,6 +729,8 @@ class ResetSignal(Value):
         super().__init__(src_loc_at=src_loc_at)
         if not isinstance(domain, str):
             raise TypeError("Clock domain name must be a string, not '{!r}'".format(domain))
+        if domain == "comb":
+            raise ValueError("Domain '{}' does not have a reset".format(domain))
         self.domain = domain
         self.allow_reset_less = allow_reset_less
 
index 4d2a33bd879afc41c6bdcfae0152130f3c93e5f6..06f8d790fa89ce99a7e9e2fc5eb379586431f7ee 100644 (file)
@@ -50,6 +50,8 @@ class ClockDomain:
                 raise ValueError("Clock domain name must be specified explicitly")
         if name.startswith("cd_"):
             name = name[3:]
+        if name == "comb":
+            raise ValueError("Domain '{}' may not be clocked".format(name))
         self.name = name
 
         self.clk = Signal(name=self._name_for(name, "clk"), src_loc_at=1)
index bd6399a36692c8de9e1e9b94dab9cc377b593f17..f154ed3305e2f9f2ff7cdef9e6137e330a43eb2c 100644 (file)
@@ -261,6 +261,8 @@ class Module(_ModuleBuilderRoot, Elaboratable):
     @contextmanager
     def FSM(self, reset=None, domain="sync", name="fsm"):
         self._check_context("FSM", context=None)
+        if domain == "comb":
+            raise ValueError("FSM may not be driven by the '{}' domain".format(domain))
         fsm_data = self._set_ctrl("FSM", {
             "name":     name,
             "signal":   Signal(name="{}_state".format(name), src_loc_at=2),
index 9448c0ca30608a43fa7e8999974902ac75b5996f..434067665a52f04d9c96bfa7b6692b229502b37b 100644 (file)
@@ -326,6 +326,11 @@ class DomainRenamer(FragmentTransformer, ValueTransformer, StatementTransformer)
     def __init__(self, domain_map):
         if isinstance(domain_map, str):
             domain_map = {"sync": domain_map}
+        for src, dst in domain_map.items():
+            if src == "comb":
+                raise ValueError("Domain '{}' may not be renamed".format(src))
+            if dst == "comb":
+                raise ValueError("Domain '{}' may not be renamed to '{}'".format(src, dst))
         self.domain_map = OrderedDict(domain_map)
 
     def on_ClockSignal(self, value):
index 6ef1193c39336c0bb322f35006bc5e0559808f88..54824b1d9ed80e07a5ec248ba39df3d93c76ab77 100644 (file)
@@ -515,6 +515,11 @@ class ClockSignalTestCase(FHDLTestCase):
         s1 = ClockSignal()
         self.assertEqual(repr(s1), "(clk sync)")
 
+    def test_wrong_name_comb(self):
+        with self.assertRaises(ValueError,
+                msg="Domain 'comb' does not have a clock"):
+            ClockSignal("comb")
+
 
 class ResetSignalTestCase(FHDLTestCase):
     def test_domain(self):
@@ -534,6 +539,11 @@ class ResetSignalTestCase(FHDLTestCase):
         s1 = ResetSignal()
         self.assertEqual(repr(s1), "(rst sync)")
 
+    def test_wrong_name_comb(self):
+        with self.assertRaises(ValueError,
+                msg="Domain 'comb' does not have a reset"):
+            ResetSignal("comb")
+
 
 class MockUserValue(UserValue):
     def __init__(self, lowered):
index 43619f8d171e0e89389254a382aad525a46f18c7..23c4637801449ccaa42979baf56fd9850a77fcb3 100644 (file)
@@ -55,3 +55,8 @@ class ClockDomainTestCase(FHDLTestCase):
         sync.rename("pix")
         self.assertEqual(sync.name, "pix")
         self.assertEqual(sync.clk.name, "pix_clk")
+
+    def test_wrong_name_comb(self):
+        with self.assertRaises(ValueError,
+                msg="Domain 'comb' may not be clocked"):
+            comb = ClockDomain()
index 43f83d28813cd88065074dfbd2b7060d9c1b8122..9af7038afc2f62ccc10d0621559ff55e8b754854 100644 (file)
@@ -458,6 +458,13 @@ class DSLTestCase(FHDLTestCase):
         ()
         """)
 
+    def test_FSM_wrong_domain(self):
+        m = Module()
+        with self.assertRaises(ValueError,
+                msg="FSM may not be driven by the 'comb' domain"):
+            with m.FSM(domain="comb"):
+                pass
+
     def test_FSM_wrong_redefined(self):
         m = Module()
         with m.FSM():
index 389229923e5b1a9533c43046a4256cb31adc3e0e..fcf77c11009620c65b3de279b98300847f83fd96 100644 (file)
@@ -88,6 +88,16 @@ class DomainRenamerTestCase(FHDLTestCase):
             "pix": cd_pix,
         })
 
+    def test_rename_wrong_to_comb(self):
+        with self.assertRaises(ValueError,
+                msg="Domain 'sync' may not be renamed to 'comb'"):
+            DomainRenamer("comb")
+
+    def test_rename_wrong_from_comb(self):
+        with self.assertRaises(ValueError,
+                msg="Domain 'comb' may not be renamed"):
+            DomainRenamer({"comb": "sync"})
+
 
 class DomainLowererTestCase(FHDLTestCase):
     def setUp(self):