vendor.intel: add Mistral toolchain support.
authorOlivier Galibert <galibert@pobox.com>
Thu, 14 Oct 2021 16:02:22 +0000 (18:02 +0200)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 31 Dec 2021 19:48:54 +0000 (19:48 +0000)
nmigen/vendor/intel.py

index e72a082a1806b322dbd61cd516235c6b3db876af..b7863931d898d003a6d77492521a2ad9a540d6eb 100644 (file)
@@ -9,6 +9,9 @@ __all__ = ["IntelPlatform"]
 
 class IntelPlatform(TemplatedPlatform):
     """
+    Quartus toolchain
+    -----------------
+
     Required tools:
         * ``quartus_map``
         * ``quartus_fit``
@@ -31,15 +34,36 @@ class IntelPlatform(TemplatedPlatform):
         * ``*.rpt``: toolchain reports.
         * ``{{name}}.sof``: bitstream as SRAM object file.
         * ``{{name}}.rbf``: bitstream as raw binary file.
+
+
+    Mistral toolchain
+    -----------------
+
+    Required tools:
+        * ``yosys``
+        * ``nextpnr-mistral``
+
+    The environment is populated by running the script specified in the environment variable
+    ``NMIGEN_ENV_Mistral``, if present.
+
+        * ``verbose``: enables logging of informational messages to standard error.
+        * ``read_verilog_opts``: adds options for ``read_verilog`` Yosys command.
+        * ``synth_opts``: adds options for ``synth_intel_alm`` Yosys command.
+        * ``script_after_read``: inserts commands after ``read_ilang`` in Yosys script.
+        * ``script_after_synth``: inserts commands after ``synth_intel_alm`` in Yosys script.
+        * ``yosys_opts``: adds extra options for ``yosys``.
+        * ``nextpnr_opts``: adds extra options for ``nextpnr-mistral``.
     """
 
-    toolchain = "Quartus"
+    toolchain = None # selected when creating platform
 
     device  = abstractproperty()
     package = abstractproperty()
     speed   = abstractproperty()
     suffix  = ""
 
+    # Quartus templates
+
     quartus_suppressed_warnings = [
         10264,  # All case item expressions in this case statement are onehot
         10270,  # Incomplete Verilog case statement has no default case item
@@ -51,14 +75,14 @@ class IntelPlatform(TemplatedPlatform):
         292013, # Feature is only available with a valid subscription license
     ]
 
-    required_tools = [
+    quartus_required_tools = [
         "quartus_map",
         "quartus_fit",
         "quartus_asm",
         "quartus_sta",
     ]
 
-    file_templates = {
+    quartus_file_templates = {
         **TemplatedPlatform.build_script_templates,
         "build_{{name}}.sh": r"""
             # {{autogenerated}}
@@ -124,7 +148,7 @@ class IntelPlatform(TemplatedPlatform):
             {% endfor %}
         """,
     }
-    command_templates = [
+    quartus_command_templates = [
         r"""
         {{invoke_tool("quartus_map")}}
             {{get_override("quartus_map_opts")|options}}
@@ -147,6 +171,104 @@ class IntelPlatform(TemplatedPlatform):
         """,
     ]
 
+
+    # Mistral templates
+
+    mistral_required_tools = [
+        "yosys",
+        "nextpnr-mistral"
+    ]
+    mistral_file_templates = {
+        **TemplatedPlatform.build_script_templates,
+        "{{name}}.il": r"""
+            # {{autogenerated}}
+            {{emit_rtlil()}}
+        """,
+        "{{name}}.debug.v": r"""
+            /* {{autogenerated}} */
+            {{emit_debug_verilog()}}
+        """,
+        "{{name}}.ys": r"""
+            # {{autogenerated}}
+            {% for file in platform.iter_files(".v") -%}
+                read_verilog {{get_override("read_verilog_opts")|options}} {{file}}
+            {% endfor %}
+            {% for file in platform.iter_files(".sv") -%}
+                read_verilog -sv {{get_override("read_verilog_opts")|options}} {{file}}
+            {% endfor %}
+            {% for file in platform.iter_files(".il") -%}
+                read_ilang {{file}}
+            {% endfor %}
+            read_ilang {{name}}.il
+            delete w:$verilog_initial_trigger
+            {{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
+            synth_intel_alm {{get_override("synth_opts")|options}} -top {{name}}
+            {{get_override("script_after_synth")|default("# (script_after_synth placeholder)")}}
+            write_json {{name}}.json
+        """,
+        "{{name}}.qsf": r"""
+            # {{autogenerated}}
+            {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
+                set_location_assignment -to {{port_name|tcl_quote}} PIN_{{pin_name}}
+                {% for key, value in attrs.items() -%}
+                    set_instance_assignment -to {{port_name|tcl_quote}} -name {{key}} {{value|tcl_quote}}
+                {% endfor %}
+            {% endfor %}
+        """,
+
+    }
+    mistral_command_templates = [
+        r"""
+        {{invoke_tool("yosys")}}
+            {{quiet("-q")}}
+            {{get_override("yosys_opts")|options}}
+            -l {{name}}.rpt
+            {{name}}.ys
+        """,
+        r"""
+        {{invoke_tool("nextpnr-mistral")}}
+            {{quiet("--quiet")}}
+            {{get_override("nextpnr_opts")|options}}
+            --log {{name}}.tim
+            --device {{platform.device}}{{platform.package}}{{platform.speed}}{{platform.suffix}}
+            --json {{name}}.json
+            --qsf {{name}}.qsf
+            --rbf {{name}}.rbf
+        """
+    ]
+
+    # Common logic
+
+    def __init__(self, *, toolchain="Quartus"):
+        super().__init__()
+
+        assert toolchain in ("Quartus", "Mistral")
+        self.toolchain = toolchain
+
+    @property
+    def required_tools(self):
+        if self.toolchain == "Quartus":
+            return self.quartus_required_tools
+        if self.toolchain == "Mistral":
+            return self.mistral_required_tools
+        assert False
+
+    @property
+    def file_templates(self):
+        if self.toolchain == "Quartus":
+            return self.quartus_file_templates
+        if self.toolchain == "Mistral":
+            return self.mistral_file_templates
+        assert False
+
+    @property
+    def command_templates(self):
+        if self.toolchain == "Quartus":
+            return self.quartus_command_templates
+        if self.toolchain == "Mistral":
+            return self.mistral_command_templates
+        assert False
+
     def add_clock_constraint(self, clock, frequency):
         super().add_clock_constraint(clock, frequency)
         clock.attrs["keep"] = "true"