plat, vendor: systematically escape net and file names in Tcl.
authorwhitequark <whitequark@whitequark.org>
Sat, 2 May 2020 10:41:18 +0000 (10:41 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 31 Dec 2021 13:30:17 +0000 (13:30 +0000)
Before this commit, there was only occasional quoting of some names
used in any Tcl files. (I'm not sure what I was thinking.)

After this commit, any substs that may include Tcl special characters
are escaped. This does not include build names (which are explicitly
restricted to ASCII to avoid this problem), or attribute names (which
are chosen from a predefined set). Ideally we'd use a more principled
approach but Jinja2 does not support custom escaping mechanisms.

Note that Vivado restricts clock names to a more restrictive set that
forbids using Tcl special characters even when escaped.

Fixes #375.

nmigen/build/plat.py
nmigen/vendor/intel.py
nmigen/vendor/lattice_ecp5.py
nmigen/vendor/lattice_ice40.py
nmigen/vendor/lattice_machxo2.py
nmigen/vendor/xilinx_7series.py
nmigen/vendor/xilinx_ultrascale.py

index d9f2ab2a9daedf5b48387aabd3a4bccf7be08c1e..17f147baff21513412e33a01814a81e04eb473c7 100644 (file)
@@ -368,6 +368,17 @@ class TemplatedPlatform(Platform):
         def hierarchy(signal, separator):
             return separator.join(name_map[signal][1:])
 
+        def ascii_escape(string):
+            def escape_one(match):
+                if match.group(1) is None:
+                    return match.group(2)
+                else:
+                    return "_{:02x}_".format(ord(match.group(1)[0]))
+            return "".join(escape_one(m) for m in re.finditer(r"([^A-Za-z0-9_])|(.)", string))
+
+        def tcl_escape(string):
+            return "{" + re.sub(r"([{}\\])", r"\\\1", string) + "}"
+
         def verbose(arg):
             if "NMIGEN_verbose" in os.environ:
                 return arg
@@ -387,6 +398,8 @@ class TemplatedPlatform(Platform):
                     trim_blocks=True, lstrip_blocks=True, undefined=jinja2.StrictUndefined)
                 compiled.environment.filters["options"] = options
                 compiled.environment.filters["hierarchy"] = hierarchy
+                compiled.environment.filters["ascii_escape"] = ascii_escape
+                compiled.environment.filters["tcl_escape"] = tcl_escape
             except jinja2.TemplateSyntaxError as e:
                 e.args = ("{} (at {}:{})".format(e.message, origin, e.lineno),)
                 raise
index 2f0c81f4a80711b65fed5c170a1d0094287e0ddc..07ee95bc9d1b12e998034aca5495828fdac20716 100644 (file)
@@ -85,22 +85,22 @@ class IntelPlatform(TemplatedPlatform):
             {% endif %}
 
             {% for file in platform.iter_extra_files(".v") -%}
-                set_global_assignment -name VERILOG_FILE "{{file}}"
+                set_global_assignment -name VERILOG_FILE {{file|tcl_escape}}
             {% endfor %}
             {% for file in platform.iter_extra_files(".sv") -%}
-                set_global_assignment -name SYSTEMVERILOG_FILE "{{file}}"
+                set_global_assignment -name SYSTEMVERILOG_FILE {{file|tcl_escape}}
             {% endfor %}
             {% for file in platform.iter_extra_files(".vhd", ".vhdl") -%}
-                set_global_assignment -name VHDL_FILE "{{file}}"
+                set_global_assignment -name VHDL_FILE {{file|tcl_escape}}
             {% endfor %}
             set_global_assignment -name VERILOG_FILE {{name}}.v
             set_global_assignment -name TOP_LEVEL_ENTITY {{name}}
 
             set_global_assignment -name DEVICE {{platform.device}}{{platform.package}}{{platform.speed}}{{platform.suffix}}
-            {% for port_name, pin_name, extras in platform.iter_port_constraints_bits() -%}
-                set_location_assignment -to "{{port_name}}" PIN_{{pin_name}}
-                {% for key, value in extras.items() -%}
-                    set_instance_assignment -to "{{port_name}}" -name {{key}} "{{value}}"
+            {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
+                set_location_assignment -to {{port_name|tcl_escape}} PIN_{{pin_name}}
+                {% for key, value in attrs.items() -%}
+                    set_instance_assignment -to {{port_name|tcl_escape}} -name {{key}} {{value|tcl_escape}}
                 {% endfor %}
             {% endfor %}
 
@@ -109,9 +109,9 @@ class IntelPlatform(TemplatedPlatform):
         "{{name}}.sdc": r"""
             {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
                 {% if port_signal is not none -%}
-                    create_clock -name {{port_signal.name}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                    create_clock -name {{port_signal.name|tcl_escape}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_escape}}]
                 {% else -%}
-                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("|")}}]
+                    create_clock -name {{net_signal.name|tcl_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("|")|tcl_escape}}]
                 {% endif %}
             {% endfor %}
         """,
index 53e1626d248d805227f5261c5d0e8d27fc03b9d0..cfa20eea22b88a0e969ad6f168c0b501592402be 100644 (file)
@@ -126,11 +126,11 @@ class LatticeECP5Platform(TemplatedPlatform):
             # {{autogenerated}}
             BLOCK ASYNCPATHS;
             BLOCK RESETPATHS;
-            {% for port_name, pin_name, extras in platform.iter_port_constraints_bits() -%}
+            {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
                 LOCATE COMP "{{port_name}}" SITE "{{pin_name}}";
-                {% if extras -%}
+                {% if attrs -%}
                 IOBUF PORT "{{port_name}}"
-                    {%- for key, value in extras.items() %} {{key}}={{value}}{% endfor %};
+                    {%- for key, value in attrs.items() %} {{key}}={{value}}{% endfor %};
                 {% endif %}
             {% endfor %}
             {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
@@ -206,7 +206,7 @@ class LatticeECP5Platform(TemplatedPlatform):
                 -lpf {{name}}.lpf \
                 -synthesis synplify
             {% for file in platform.iter_extra_files(".v", ".sv", ".vhd", ".vhdl") -%}
-                prj_src add "{{file}}"
+                prj_src add {{file|tcl_escape}}
             {% endfor %}
             prj_src add {{name}}.v
             prj_impl option top {{name}}
@@ -217,7 +217,7 @@ class LatticeECP5Platform(TemplatedPlatform):
             prj_run Translate -impl impl -forceAll
             prj_run Map -impl impl -forceAll
             prj_run PAR -impl impl -forceAll
-            prj_run Export -impl "impl" -forceAll -task Bitgen
+            prj_run Export -impl impl -forceAll -task Bitgen
             {{get_override("script_after_export")|default("# (script_after_export placeholder)")}}
         """,
         "{{name}}.lpf": r"""
@@ -234,9 +234,9 @@ class LatticeECP5Platform(TemplatedPlatform):
         "{{name}}.sdc": r"""
             {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
                 {% if port_signal is not none -%}
-                    create_clock -name {{port_signal.name}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                    create_clock -name {{port_signal.name|tcl_escape}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_escape}}]
                 {% else -%}
-                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
+                    create_clock -name {{net_signal.name|tcl_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_escape}}]
                 {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
index 94dd02afc91ba836eb8cfb724e495a4a2258e694..4617d0374b8a389f8e6626faa7e183e61543ef4b 100644 (file)
@@ -224,7 +224,7 @@ class LatticeICE40Platform(TemplatedPlatform):
         "{{name}}_syn.prj": r"""
             # {{autogenerated}}
             {% for file in platform.iter_extra_files(".v", ".sv", ".vhd", ".vhdl") -%}
-                add_file -verilog {{file}}
+                add_file -verilog {{file|tcl_escape}}
             {% endfor %}
             add_file -verilog {{name}}.v
             add_file -constraint {{name}}.sdc
@@ -246,9 +246,9 @@ class LatticeICE40Platform(TemplatedPlatform):
             # {{autogenerated}}
             {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
                 {% if port_signal is not none -%}
-                    create_clock -name {{port_signal.name}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                    create_clock -name {{port_signal.name|tcl_escape}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_escape}}]
                 {% else -%}
-                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
+                    create_clock -name {{net_signal.name|tcl_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_escape}}]
                 {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
index 962994b5fbded365a011572ab7d526481a4f7d4d..3ce9962852b116fa3b2b131695665fb55c727ac5 100644 (file)
@@ -66,7 +66,7 @@ class LatticeMachXO2Platform(TemplatedPlatform):
                 -lpf {{name}}.lpf \
                 -synthesis synplify
             {% for file in platform.iter_extra_files(".v", ".sv", ".vhd", ".vhdl") -%}
-                prj_src add "{{file}}"
+                prj_src add {{file|tcl_escape}}
             {% endfor %}
             prj_src add {{name}}.v
             prj_impl option top {{name}}
@@ -84,11 +84,11 @@ class LatticeMachXO2Platform(TemplatedPlatform):
             # {{autogenerated}}
             BLOCK ASYNCPATHS;
             BLOCK RESETPATHS;
-            {% for port_name, pin_name, extras in platform.iter_port_constraints_bits() -%}
+            {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
                 LOCATE COMP "{{port_name}}" SITE "{{pin_name}}";
-                {% if extras -%}
+                {% if attrs -%}
                 IOBUF PORT "{{port_name}}"
-                    {%- for key, value in extras.items() %} {{key}}={{value}}{% endfor %};
+                    {%- for key, value in attrs.items() %} {{key}}={{value}}{% endfor %};
                 {% endif %}
             {% endfor %}
             {{get_override("add_preferences")|default("# (add_preferences placeholder)")}}
@@ -96,9 +96,9 @@ class LatticeMachXO2Platform(TemplatedPlatform):
         "{{name}}.sdc": r"""
             {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
                 {% if port_signal is not none -%}
-                    create_clock -name {{port_signal.name}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                    create_clock -name {{port_signal.name|tcl_escape}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_escape}}]
                 {% else -%}
-                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
+                    create_clock -name {{net_signal.name|tcl_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_escape}}]
                 {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
index 128035d203e17a88cc09e7faf417fd7629c4e6f7..5da57a69fa2375027868f772814a4207f1791e39 100644 (file)
@@ -78,12 +78,12 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
             # {{autogenerated}}
             create_project -force -name {{name}} -part {{platform.device}}{{platform.package}}-{{platform.speed}}{{"-" + platform.grade if platform.grade else ""}}
             {% for file in platform.iter_extra_files(".v", ".sv", ".vhd", ".vhdl") -%}
-                add_files {{file}}
+                add_files {{file|tcl_escape}}
             {% endfor %}
             add_files {{name}}.v
             read_xdc {{name}}.xdc
             {% for file in platform.iter_extra_files(".xdc") -%}
-                read_xdc {{file}}
+                read_xdc {{file|tcl_escape}}
             {% endfor %}
             {{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
             synth_design -top {{name}}
@@ -128,16 +128,16 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
         "{{name}}.xdc": r"""
             # {{autogenerated}}
             {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
-                set_property LOC {{pin_name}} [get_ports {{port_name}}]
+                set_property LOC {{pin_name}} [get_ports {{port_name|tcl_escape}}]
                 {% for attr_name, attr_value in attrs.items() -%}
-                    set_property {{attr_name}} {{attr_value}} [get_ports {{port_name}}]
+                    set_property {{attr_name}} {{attr_value|tcl_escape}} [get_ports {{port_name|tcl_escape}}]
                 {% endfor %}
             {% endfor %}
             {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
                 {% if port_signal is not none -%}
-                    create_clock -name {{port_signal.name}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                    create_clock -name {{port_signal.name|ascii_escape}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_escape}}]
                 {% else -%}
-                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
+                    create_clock -name {{net_signal.name|ascii_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_escape}}]
                 {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
index 113753c313713ccb0a6c1b9edfc4b70960bf7055..d4136fb9a950ee89acb86dbadef2123ebe671ad6 100644 (file)
@@ -78,12 +78,12 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
             # {{autogenerated}}
             create_project -force -name {{name}} -part {{platform.device}}-{{platform.package}}-{{platform.speed}}{{"-" + platform.grade if platform.grade else ""}}
             {% for file in platform.iter_extra_files(".v", ".sv", ".vhd", ".vhdl") -%}
-                add_files {{file}}
+                add_files {{file|tcl_escape}}
             {% endfor %}
             add_files {{name}}.v
             read_xdc {{name}}.xdc
             {% for file in platform.iter_extra_files(".xdc") -%}
-                read_xdc {{file}}
+                read_xdc {{file|tcl_escape}}
             {% endfor %}
             {{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
             synth_design -top {{name}}
@@ -128,16 +128,16 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
         "{{name}}.xdc": r"""
             # {{autogenerated}}
             {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
-                set_property LOC {{pin_name}} [get_ports {{port_name}}]
+                set_property LOC {{pin_name}} [get_ports {{port_name|tcl_escape}}]
                 {% for attr_name, attr_value in attrs.items() -%}
-                    set_property {{attr_name}} {{attr_value}} [get_ports {{port_name}}]
+                    set_property {{attr_name}} {{attr_value|tcl_escape}} [get_ports {{port_name|tcl_escape}}]
                 {% endfor %}
             {% endfor %}
             {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
                 {% if port_signal is not none -%}
-                    create_clock -name {{port_signal.name}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                    create_clock -name {{port_signal.name|ascii_escape}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_escape}}]
                 {% else -%}
-                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
+                    create_clock -name {{net_signal.name|ascii_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_escape}}]
                 {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}