build.dsl: require a dict for extras instead of a stringly array.
authorwhitequark <whitequark@whitequark.org>
Sun, 2 Jun 2019 23:36:21 +0000 (23:36 +0000)
committerwhitequark <whitequark@whitequark.org>
Sun, 2 Jun 2019 23:36:21 +0000 (23:36 +0000)
Fixes #72.

nmigen/build/dsl.py
nmigen/test/test_build_dsl.py
nmigen/test/test_build_res.py
nmigen/vendor/ice40_hx1k_blink_evn.py
nmigen/vendor/icestick.py
nmigen/vendor/tinyfpga_bx.py

index f27a312b2d31e93f446d3fd7fcedf5cc0a76c76f..7b3c38d1c8d057a0c41fb9cad7b15a55b7e67b9f 100644 (file)
@@ -47,7 +47,7 @@ class DiffPairs:
 
 
 class Subsignal:
-    def __init__(self, name, *io, extras=()):
+    def __init__(self, name, *io, extras=None):
         self.name = name
 
         if not io:
@@ -67,25 +67,35 @@ class Subsignal:
                     raise TypeError("A Subsignal can only be followed by more Subsignals, but "
                                     "{!r} is followed by {!r}"
                                     .format(io[0], c))
-        self.io = io
-
-        for c in extras:
-            if not isinstance(c, str):
-                raise TypeError("Extra constraint must be a string, not {!r}".format(c))
-        self.extras = list(extras)
+        self.io     = io
+        self.extras = {}
+
+        if extras is not None:
+            if not isinstance(extras, dict):
+                raise TypeError("Extra constraints must be a dict, not {!r}"
+                                .format(extras))
+            for extra_key, extra_value in extras.items():
+                if not isinstance(extra_key, str):
+                    raise TypeError("Extra constraint key must be a string, not {!r}"
+                                    .format(extra_key))
+                if not isinstance(extra_value, str):
+                    raise TypeError("Extra constraint value must be a string, not {!r}"
+                                    .format(extra_value))
+                self.extras[extra_key] = extra_value
 
         if isinstance(self.io[0], Subsignal):
             for sub in self.io:
-                sub.extras += self.extras
+                sub.extras.update(self.extras)
 
     def __repr__(self):
         return "(subsignal {} {} {})".format(self.name,
                                              " ".join(map(repr, self.io)),
-                                             " ".join(self.extras))
+                                             " ".join("{}={}".format(k, v)
+                                                      for k, v in self.extras.items()))
 
 
 class Resource(Subsignal):
-    def __init__(self, name, number, *io, extras=()):
+    def __init__(self, name, number, *io, extras=None):
         super().__init__(name, *io, extras=extras)
 
         self.number = number
@@ -93,4 +103,5 @@ class Resource(Subsignal):
     def __repr__(self):
         return "(resource {} {} {} {})".format(self.name, self.number,
                                                " ".join(map(repr, self.io)),
-                                               " ".join(self.extras))
+                                               " ".join("{}={}".format(k, v)
+                                                        for k, v in self.extras.items()))
index 6a1c1cc7753e1c7532225d26e590b4039c1f8509..15ef9ad34f334139b690c4aa835f9fbe66ccc344 100644 (file)
@@ -45,7 +45,7 @@ class DiffPairsTestCase(FHDLTestCase):
 
 class SubsignalTestCase(FHDLTestCase):
     def test_basic_pins(self):
-        s = Subsignal("a", Pins("A0"), extras=["IOSTANDARD=LVCMOS33"])
+        s = Subsignal("a", Pins("A0"), extras={"IOSTANDARD": "LVCMOS33"})
         self.assertEqual(repr(s), "(subsignal a (pins io A0) IOSTANDARD=LVCMOS33)")
 
     def test_basic_diffpairs(self):
@@ -62,11 +62,11 @@ class SubsignalTestCase(FHDLTestCase):
     def test_extras(self):
         s = Subsignal("a",
                 Subsignal("b", Pins("A0")),
-                Subsignal("c", Pins("A0"), extras=["SLEW=FAST"]),
-                extras=["IOSTANDARD=LVCMOS33"])
-        self.assertEqual(s.extras, ["IOSTANDARD=LVCMOS33"])
-        self.assertEqual(s.io[0].extras, ["IOSTANDARD=LVCMOS33"])
-        self.assertEqual(s.io[1].extras, ["SLEW=FAST", "IOSTANDARD=LVCMOS33"])
+                Subsignal("c", Pins("A0"), extras={"SLEW": "FAST"}),
+                extras={"IOSTANDARD": "LVCMOS33"})
+        self.assertEqual(s.extras, {"IOSTANDARD": "LVCMOS33"})
+        self.assertEqual(s.io[0].extras, {"IOSTANDARD": "LVCMOS33"})
+        self.assertEqual(s.io[1].extras, {"SLEW": "FAST", "IOSTANDARD": "LVCMOS33"})
 
     def test_empty_io(self):
         with self.assertRaises(TypeError, msg="Missing I/O constraints"):
@@ -98,8 +98,14 @@ class SubsignalTestCase(FHDLTestCase):
 
     def test_wrong_extras(self):
         with self.assertRaises(TypeError,
-                msg="Extra constraint must be a string, not (pins io B0)"):
+                msg="Extra constraints must be a dict, not [(pins io B0)]"):
             s = Subsignal("a", Pins("A0"), extras=[Pins("B0")])
+        with self.assertRaises(TypeError,
+                msg="Extra constraint key must be a string, not 1"):
+            s = Subsignal("a", Pins("A0"), extras={1: 2})
+        with self.assertRaises(TypeError,
+                msg="Extra constraint value must be a string, not 2"):
+            s = Subsignal("a", Pins("A0"), extras={"1": 2})
 
 
 class ResourceTestCase(FHDLTestCase):
@@ -107,7 +113,7 @@ class ResourceTestCase(FHDLTestCase):
         r = Resource("serial", 0,
                 Subsignal("tx", Pins("A0", dir="o")),
                 Subsignal("rx", Pins("A1", dir="i")),
-                extras=["IOSTANDARD=LVCMOS33"])
+                extras={"IOSTANDARD": "LVCMOS33"})
         self.assertEqual(repr(r), "(resource serial 0"
                                   " (subsignal tx (pins o A0) IOSTANDARD=LVCMOS33)"
                                   " (subsignal rx (pins i A1) IOSTANDARD=LVCMOS33)"
index dac5ad577bfa6c5a006c680e31617fb0cc525bab..5ffdac8e6485c5de7251990d38e04b8a6196c9ab 100644 (file)
@@ -66,7 +66,7 @@ class ConstraintManagerTestCase(FHDLTestCase):
         self.assertEqual(len(ports), 1)
 
         self.assertEqual(list(self.cm.iter_port_constraints()), [
-            ("user_led_0_io", ["A0"], [])
+            ("user_led_0_io", ["A0"], {})
         ])
 
     def test_request_with_dir(self):
@@ -90,8 +90,8 @@ class ConstraintManagerTestCase(FHDLTestCase):
             (i2c.sda, sda),
         ])
         self.assertEqual(list(self.cm.iter_port_constraints()), [
-            ("i2c_0__scl_io", ["N10"], []),
-            ("i2c_0__sda_io", ["N11"], [])
+            ("i2c_0__scl_io", ["N10"], {}),
+            ("i2c_0__sda_io", ["N11"], {})
         ])
 
     def test_request_diffpairs(self):
@@ -112,8 +112,8 @@ class ConstraintManagerTestCase(FHDLTestCase):
             (clk100, p, n),
         ])
         self.assertEqual(list(self.cm.iter_port_constraints()), [
-            ("clk100_0_p", ["H1"], []),
-            ("clk100_0_n", ["H2"], [])
+            ("clk100_0_p", ["H1"], {}),
+            ("clk100_0_n", ["H2"], {})
         ])
 
     def test_add_clock(self):
index ee7c5f65af29694a79e9aed4c1aaa5aef5c517aa..1f4488291fb13499efbc3ef1d814c0cf0eacb600 100644 (file)
@@ -12,15 +12,15 @@ class ICE40HX1KBlinkEVNPlatform(IceBurnProgrammerMixin, LatticeICE40Platform):
         ("clk3p3", 3.3e6),
     ]
     resources = [
-        Resource("clk3p3", 0, Pins("13", dir="i"), extras=["IO_STANDARD=SB_LVCMOS33"]),
+        Resource("clk3p3", 0, Pins("13", dir="i"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
 
-        Resource("user_led", 0, Pins("59", dir="o"), extras=["IO_STANDARD=SB_LVCMOS33"]),
-        Resource("user_led", 1, Pins("56", dir="o"), extras=["IO_STANDARD=SB_LVCMOS33"]),
-        Resource("user_led", 2, Pins("53", dir="o"), extras=["IO_STANDARD=SB_LVCMOS33"]),
-        Resource("user_led", 3, Pins("51", dir="o"), extras=["IO_STANDARD=SB_LVCMOS33"]),
+        Resource("user_led", 0, Pins("59", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
+        Resource("user_led", 1, Pins("56", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
+        Resource("user_led", 2, Pins("53", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
+        Resource("user_led", 3, Pins("51", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
 
-        Resource("user_btn", 0, Pins("60"), extras=["IO_STANDARD=SB_LVCMOS33"]),
-        Resource("user_btn", 1, Pins("57"), extras=["IO_STANDARD=SB_LVCMOS33"]),
-        Resource("user_btn", 2, Pins("54"), extras=["IO_STANDARD=SB_LVCMOS33"]),
-        Resource("user_btn", 3, Pins("52"), extras=["IO_STANDARD=SB_LVCMOS33"]),
+        Resource("user_btn", 0, Pins("60"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
+        Resource("user_btn", 1, Pins("57"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
+        Resource("user_btn", 2, Pins("54"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
+        Resource("user_btn", 3, Pins("52"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
     ]
index 5827baa3bd1209d11d35c5c9dbe111c29893dac3..4d1ecfdcd10c7a55adf6c422053e1696205111d4 100644 (file)
@@ -12,13 +12,13 @@ class ICEStickPlatform(IceStormProgrammerMixin, LatticeICE40Platform):
         ("clk12", 12e6),
     ]
     resources = [
-        Resource("clk12", 0, Pins("21", dir="i"), extras=["IO_STANDARD=SB_LVCMOS33"]),
+        Resource("clk12", 0, Pins("21", dir="i"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
 
-        Resource("user_led", 0, Pins("99", dir="o"), extras=["IO_STANDARD=SB_LVCMOS33"]),
-        Resource("user_led", 1, Pins("98", dir="o"), extras=["IO_STANDARD=SB_LVCMOS33"]),
-        Resource("user_led", 2, Pins("97", dir="o"), extras=["IO_STANDARD=SB_LVCMOS33"]),
-        Resource("user_led", 3, Pins("96", dir="o"), extras=["IO_STANDARD=SB_LVCMOS33"]),
-        Resource("user_led", 4, Pins("95", dir="o"), extras=["IO_STANDARD=SB_LVCMOS33"]),
+        Resource("user_led", 0, Pins("99", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
+        Resource("user_led", 1, Pins("98", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
+        Resource("user_led", 2, Pins("97", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
+        Resource("user_led", 3, Pins("96", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
+        Resource("user_led", 4, Pins("95", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
 
         Resource("serial", 0,
             Subsignal("rx",  Pins("9", dir="i")),
@@ -28,14 +28,14 @@ class ICEStickPlatform(IceStormProgrammerMixin, LatticeICE40Platform):
             Subsignal("dtr", Pins("3", dir="o")),
             Subsignal("dsr", Pins("2", dir="i")),
             Subsignal("dcd", Pins("1", dir="i")),
-            extras=["IO_STANDARD=SB_LVTTL", "PULLUP=1"],
+            extras={"IO_STANDARD": "SB_LVTTL", "PULLUP": "1"}
         ),
 
         Resource("irda", 0,
             Subsignal("rx", Pins("106", dir="i")),
             Subsignal("tx", Pins("105", dir="o")),
             Subsignal("sd", Pins("107", dir="o")),
-            extras=["IO_STANDARD=SB_LVCMOS33"]
+            extras={"IO_STANDARD": "SB_LVCMOS33"}
         ),
 
         Resource("spiflash", 0,
@@ -43,7 +43,7 @@ class ICEStickPlatform(IceStormProgrammerMixin, LatticeICE40Platform):
             Subsignal("clk",  Pins("70", dir="o")),
             Subsignal("mosi", Pins("67", dir="io")),
             Subsignal("miso", Pins("68", dir="io")),
-            extras=["IO_STANDARD=SB_LVCMOS33"]
+            extras={"IO_STANDARD": "SB_LVCMOS33"}
         ),
     ]
     prog_mode = "flash"
index ccaa2b34ea5afcdc6ac31375d6bf0240b7822fc6..50ced5d9b00a5bb3003cf5f605a61df7fa6235f9 100644 (file)
@@ -12,15 +12,15 @@ class TinyFPGABXPlatform(TinyProgrammerMixin, LatticeICE40Platform):
         ("clk16", 16e6),
     ]
     resources = [
-        Resource("clk16", 0, Pins("B2", dir="i"), extras=["IO_STANDARD=SB_LVCMOS33"]),
+        Resource("clk16", 0, Pins("B2", dir="i"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
 
-        Resource("user_led", 0, Pins("B3", dir="o"), extras=["IO_STANDARD=SB_LVCMOS33"]),
+        Resource("user_led", 0, Pins("B3", dir="o"), extras={"IO_STANDARD": "SB_LVCMOS33"}),
 
         Resource("usb", 0,
-            Subsignal("d_p", Pins("B4", dir="io")),
-            Subsignal("d_n", Pins("A4", dir="io")),
+            Subsignal("d_p",     Pins("B4", dir="io")),
+            Subsignal("d_n",     Pins("A4", dir="io")),
             Subsignal("pull_up", Pins("A3", dir="o")),
-            extras=["IO_STANDARD=SB_LVCMOS33"]
+            extras={"IO_STANDARD": "SB_LVCMOS33"}
         ),
 
         Resource("spiflash", 0,
@@ -28,6 +28,6 @@ class TinyFPGABXPlatform(TinyProgrammerMixin, LatticeICE40Platform):
             Subsignal("clk",  Pins("G7", dir="o")),
             Subsignal("mosi", Pins("G6", dir="io")),
             Subsignal("miso", Pins("H7", dir="io")),
-            extras=["IO_STANDARD=SB_LVCMOS33"]
+            extras={"IO_STANDARD": "SB_LVCMOS33"}
         ),
     ]