vendor: `yosys` is not a required tool for proprietary toolchains.
[nmigen.git] / nmigen / vendor / lattice_ecp5.py
index c1140630fbb28c95a1061b66a3d0e41816410fbc..c1a1366148903e3ac3d0deaf8bbf691681cecfc7 100644 (file)
@@ -71,15 +71,13 @@ class LatticeECP5Platform(TemplatedPlatform):
     # Trellis templates
 
     _nextpnr_device_options = {
-        "LFE5U-12F":    "--25k",
+        "LFE5U-12F":    "--12k",
         "LFE5U-25F":    "--25k",
         "LFE5U-45F":    "--45k",
         "LFE5U-85F":    "--85k",
-        "LFE5UM-12F":   "--um-25k",
         "LFE5UM-25F":   "--um-25k",
         "LFE5UM-45F":   "--um-45k",
         "LFE5UM-85F":   "--um-85k",
-        "LFE5UM5G-12F": "--um5g-25k",
         "LFE5UM5G-25F": "--um5g-25k",
         "LFE5UM5G-45F": "--um5g-45k",
         "LFE5UM5G-85F": "--um5g-85k",
@@ -110,10 +108,13 @@ class LatticeECP5Platform(TemplatedPlatform):
         "{{name}}.ys": r"""
             # {{autogenerated}}
             {% for file in platform.iter_extra_files(".v") -%}
-                read_verilog {{get_override("read_opts")|options}} {{file}}
+                read_verilog {{get_override("read_verilog_opts")|options}} {{file}}
             {% endfor %}
             {% for file in platform.iter_extra_files(".sv") -%}
-                read_verilog -sv {{get_override("read_opts")|options}} {{file}}
+                read_verilog -sv {{get_override("read_verilog_opts")|options}} {{file}}
+            {% endfor %}
+            {% for file in platform.iter_extra_files(".il") -%}
+                read_ilang {{file}}
             {% endfor %}
             read_ilang {{name}}.il
             {{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
@@ -125,15 +126,19 @@ 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 signal, frequency in platform.iter_clock_constraints() -%}
-                FREQUENCY NET "{{signal|hierarchy(".")}}" {{frequency}} HZ;
+            {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
+                {% if port_signal is not none -%}
+                    FREQUENCY PORT "{{port_signal.name}}" {{frequency}} HZ;
+                {% else -%}
+                    FREQUENCY NET "{{net_signal|hierarchy(".")}}" {{frequency}} HZ;
+                {% endif %}
             {% endfor %}
             {{get_override("add_preferences")|default("# (add_preferences placeholder)")}}
         """
@@ -171,7 +176,6 @@ class LatticeECP5Platform(TemplatedPlatform):
     # Diamond templates
 
     _diamond_required_tools = [
-        "yosys",
         "pnmainc",
         "ddtcmd"
     ]
@@ -201,7 +205,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}}
@@ -212,7 +216,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"""
@@ -224,14 +228,15 @@ class LatticeECP5Platform(TemplatedPlatform):
                 IOBUF PORT "{{port_name}}"
                     {%- for key, value in extras.items() %} {{key}}={{value}}{% endfor %};
             {% endfor %}
-            {% for signal, frequency in platform.iter_clock_constraints() -%}
-                FREQUENCY NET "{{signal|hierarchy("/")}}" {{frequency/1000000}} MHZ;
-            {% endfor %}
             {{get_override("add_preferences")|default("# (add_preferences placeholder)")}}
         """,
         "{{name}}.sdc": r"""
-            {% for signal, frequency in platform.iter_clock_constraints() -%}
-                create_clock -period {{1000000000/frequency}} [get_nets {{signal|hierarchy("/")}}]
+            {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
+                {% if port_signal is not none -%}
+                    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|tcl_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_escape}}]
+                {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
         """,
@@ -286,6 +291,12 @@ class LatticeECP5Platform(TemplatedPlatform):
             return self._diamond_command_templates
         assert False
 
+    @property
+    def default_clk_constraint(self):
+        if self.default_clk == "OSCG":
+            return Clock(310e6 / self.oscg_div)
+        return super().default_clk_constraint
+
     def create_missing_domain(self, name):
         # Lattice ECP5 devices have two global set/reset signals: PUR, which is driven at startup
         # by the configuration logic and unconditionally resets every storage element, and GSR,
@@ -294,7 +305,19 @@ class LatticeECP5Platform(TemplatedPlatform):
         # network, its deassertion may violate a setup/hold constraint with relation to a user
         # clock. To avoid this, a GSR/SGSR instance should be driven synchronized to user clock.
         if name == "sync" and self.default_clk is not None:
-            clk_i = self.request(self.default_clk).i
+            m = Module()
+            if self.default_clk == "OSCG":
+                if not hasattr(self, "oscg_div"):
+                    raise ValueError("OSCG divider (oscg_div) must be an integer between 2 "
+                                     "and 128")
+                if not isinstance(self.oscg_div, int) or self.oscg_div < 2 or self.oscg_div > 128:
+                    raise ValueError("OSCG divider (oscg_div) must be an integer between 2 "
+                                     "and 128, not {!r}"
+                                     .format(self.oscg_div))
+                clk_i = Signal()
+                m.submodules += Instance("OSCG", p_DIV=self.oscg_div, o_OSC=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:
@@ -302,7 +325,6 @@ class LatticeECP5Platform(TemplatedPlatform):
 
             gsr0 = Signal()
             gsr1 = Signal()
-            m = Module()
             # There is no end-of-startup signal on ECP5, but PUR is released after IOB enable, so
             # a simple reset synchronizer (with PUR as the asynchronous reset) does the job.
             m.submodules += [