
This function was added in commit 20553b14
in the wrong place, with
the wrong name, and without tests. Fix all that.
159 lines
5 KiB
Python
159 lines
5 KiB
Python
from abc import abstractproperty
|
|
|
|
from ..hdl import *
|
|
from ..lib.cdc import ResetSynchronizer
|
|
from ..build import *
|
|
|
|
|
|
__all__ = ["QuicklogicPlatform"]
|
|
|
|
|
|
class QuicklogicPlatform(TemplatedPlatform):
|
|
"""
|
|
Symbiflow toolchain
|
|
-------------------
|
|
|
|
Required tools:
|
|
* ``symbiflow_synth``
|
|
* ``symbiflow_pack``
|
|
* ``symbiflow_place``
|
|
* ``symbiflow_route``
|
|
* ``symbiflow_write_fasm``
|
|
* ``symbiflow_write_bitstream``
|
|
|
|
The environment is populated by running the script specified in the environment variable
|
|
``NMIGEN_ENV_QLSymbiflow``, if present.
|
|
|
|
Available overrides:
|
|
* ``add_constraints``: inserts commands in XDC file.
|
|
"""
|
|
|
|
device = abstractproperty()
|
|
package = abstractproperty()
|
|
|
|
# Since the QuickLogic version of SymbiFlow toolchain is not upstreamed yet
|
|
# we should distinguish the QuickLogic version from mainline one.
|
|
# QuickLogic toolchain: https://github.com/QuickLogic-Corp/quicklogic-fpga-toolchain/releases
|
|
toolchain = "QLSymbiflow"
|
|
|
|
required_tools = [
|
|
"symbiflow_synth",
|
|
"symbiflow_pack",
|
|
"symbiflow_place",
|
|
"symbiflow_route",
|
|
"symbiflow_write_fasm",
|
|
"symbiflow_write_bitstream"
|
|
]
|
|
file_templates = {
|
|
**TemplatedPlatform.build_script_templates,
|
|
"{{name}}.v": r"""
|
|
/* {{autogenerated}} */
|
|
{{emit_verilog()}}
|
|
""",
|
|
"{{name}}.debug.v": r"""
|
|
/* {{autogenerated}} */
|
|
{{emit_debug_verilog()}}
|
|
""",
|
|
"{{name}}.pcf": r"""
|
|
# {{autogenerated}}
|
|
{% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
|
|
set_io {{port_name}} {{pin_name}}
|
|
{% endfor %}
|
|
""",
|
|
"{{name}}.xdc": r"""
|
|
# {{autogenerated}}
|
|
{% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
|
|
{% for attr_name, attr_value in attrs.items() -%}
|
|
set_property {{attr_name}} {{attr_value}} [get_ports {{port_name|tcl_escape}} }]
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
|
|
""",
|
|
"{{name}}.sdc": r"""
|
|
# {{autogenerated}}
|
|
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
|
|
{% if port_signal is not none -%}
|
|
create_clock -period {{100000000/frequency}} {{port_signal.name|ascii_escape}}
|
|
{% endif %}
|
|
{% endfor %}
|
|
"""
|
|
}
|
|
command_templates = [
|
|
r"""
|
|
{{invoke_tool("symbiflow_synth")}}
|
|
-t {{name}}
|
|
-v {% for file in platform.iter_files(".v", ".sv", ".vhd", ".vhdl") -%} {{file}} {% endfor %} {{name}}.v
|
|
-d {{platform.device}}
|
|
-p {{name}}.pcf
|
|
-P {{platform.package}}
|
|
-x {{name}}.xdc
|
|
""",
|
|
r"""
|
|
{{invoke_tool("symbiflow_pack")}}
|
|
-e {{name}}.eblif
|
|
-d {{platform.device}}
|
|
-s {{name}}.sdc
|
|
""",
|
|
r"""
|
|
{{invoke_tool("symbiflow_place")}}
|
|
-e {{name}}.eblif
|
|
-d {{platform.device}}
|
|
-p {{name}}.pcf
|
|
-n {{name}}.net
|
|
-P {{platform.package}}
|
|
-s {{name}}.sdc
|
|
""",
|
|
r"""
|
|
{{invoke_tool("symbiflow_route")}}
|
|
-e {{name}}.eblif
|
|
-d {{platform.device}}
|
|
-s {{name}}.sdc
|
|
""",
|
|
r"""
|
|
{{invoke_tool("symbiflow_write_fasm")}}
|
|
-e {{name}}.eblif
|
|
-d {{platform.device}}
|
|
-s {{name}}.sdc
|
|
""",
|
|
r"""
|
|
{{invoke_tool("symbiflow_write_bitstream")}}
|
|
-f {{name}}.fasm
|
|
-d {{platform.device}}
|
|
-P {{platform.package}}
|
|
-b {{name}}.bit
|
|
"""
|
|
]
|
|
|
|
# Common logic
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def add_clock_constraint(self, clock, frequency):
|
|
super().add_clock_constraint(clock, frequency)
|
|
clock.attrs["keep"] = "TRUE"
|
|
|
|
def create_missing_domain(self, name):
|
|
if name == "sync" and self.default_clk is not None:
|
|
m = Module()
|
|
if self.default_clk == "sys_clk0":
|
|
clk_i = Signal()
|
|
sys_clk0 = Signal()
|
|
m.submodules += Instance("qlal4s3b_cell_macro",
|
|
o_Sys_Clk0=sys_clk0)
|
|
m.submodules += Instance("gclkbuff",
|
|
o_A=sys_clk0,
|
|
o_Z=clk_i)
|
|
else:
|
|
clk_i = self.request(self.default_clk).i
|
|
|
|
if self.default_rst is not None:
|
|
rst_i = self.request(self.default_rst).i
|
|
else:
|
|
rst_i = Const(0)
|
|
|
|
m.domains += ClockDomain("sync")
|
|
m.d.comb += ClockSignal("sync").eq(clk_i)
|
|
m.submodules.reset_sync = ResetSynchronizer(rst_i, domain="sync")
|
|
return m
|