plat, vendor: systematically escape net and file names in Tcl.

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.
This commit is contained in:
whitequark 2020-05-02 10:41:18 +00:00
parent 6e29fbcc61
commit 6cee280407
7 changed files with 50 additions and 37 deletions

View 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

View 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 %}
""",

View 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)")}}

View 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)")}}

View 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)")}}

View 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)")}}

View 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)")}}