amaranth/nmigen/vendor/quicklogic.py
Jan Kowalewski 8fe319f065 vendor.quicklogic: utilize internal SoC clock in EOS-S3
Signed-off-by: Jan Kowalewski <jkowalewski@antmicro.com>
2020-10-30 18:11:25 +00:00

156 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()
part = 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_extra_files(".v", ".sv", ".vhd", ".vhdl") -%} {{file}} {% endfor %} {{name}}.v
-d {{platform.device}}
-p {{name}}.pcf
-P {{platform.part}}
-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.part}}
-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.part}}
-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