build/lattice/trellis: fix spimode typo.
[litex.git] / litex / build / lattice / trellis.py
index a02e49a9a3aab296253d1ed0805d2d414d8e45af..df7559f2ec029940db9e0971c3744c7262a7ee11 100644 (file)
@@ -49,7 +49,10 @@ def _build_lpf(named_sc, named_pc, build_name):
 # Yosys/Nextpnr Helpers/Templates ------------------------------------------------------------------
 
 _yosys_template = [
+    "verilog_defaults -push",
+    "verilog_defaults -add -defer",
     "{read_files}",
+    "verilog_defaults -pop",
     "attrmap -tocase keep -imap keep=\"true\" keep=1 -imap keep=\"false\" keep=0 -remove keep=0",
     "synth_ecp5 -abc9 {nwl} -json {build_name}.json -top {build_name}",
 ]
@@ -74,7 +77,30 @@ def _build_yosys(template, platform, nowidelut, build_name):
         ))
     tools.write_to_file(build_name + ".ys", "\n".join(ys))
 
+def nextpnr_ecp5_parse_device(device):
+    device      = device.lower()
+    family      = device.split("-")[0]
+    size        = device.split("-")[1]
+    speed_grade = device.split("-")[2][0]
+    if speed_grade not in ["6", "7", "8"]:
+       raise ValueError("Invalid speed grade {}".format(speed_grade))
+    package     = device.split("-")[2][1:]
+    if "256" in package:
+        package = "CABGA256"
+    elif "285" in package:
+        package = "CSFBGA285"
+    elif "381" in package:
+        package = "CABGA381"
+    elif "554" in package:
+        package = "CABGA554"
+    elif "756" in package:
+        package = "CABGA756"
+    else:
+       raise ValueError("Invalid package {}".format(package))
+    return (family, size, speed_grade, package)
+
 nextpnr_ecp5_architectures = {
+    "lfe5u-12f"   : "12k",
     "lfe5u-25f"   : "25k",
     "lfe5u-45f"   : "45k",
     "lfe5u-85f"   : "85k",
@@ -86,29 +112,16 @@ nextpnr_ecp5_architectures = {
     "lfe5um5g-85f": "um5g-85k",
 }
 
-def nextpnr_ecp5_package(package):
-    if "256" in package:
-        return "CABGA256"
-    elif "285" in package:
-        return "CSFBGA285"
-    elif "381" in package:
-        return "CABGA381"
-    elif "554" in package:
-        return "CABGA554"
-    elif "756" in package:
-        return "CABGA756"
-    raise ValueError("Unknown package {}".format(package))
-
 # Script -------------------------------------------------------------------------------------------
 
 _build_template = [
-    "yosys -q -l {build_name}.rpt {build_name}.ys",
+    "yosys -l {build_name}.rpt {build_name}.ys",
     "nextpnr-ecp5 --json {build_name}.json --lpf {build_name}.lpf --textcfg {build_name}.config  \
-    --{architecture} --package {package} --freq {freq_constraint} {timefailarg}",
-    "ecppack {build_name}.config --svf {build_name}.svf --bit {build_name}.bit"
+    --{architecture} --package {package} --speed {speed_grade} {timefailarg} {ignoreloops} --seed {seed}",
+    "ecppack {build_name}.config --svf {build_name}.svf --bit {build_name}.bit --bootaddr {bootaddr} --spimode {spimode}"
 ]
 
-def _build_script(source, build_template, build_name, architecture, package, freq_constraint, timingstrict):
+def _build_script(source, build_template, build_name, architecture, package, speed_grade, timingstrict, ignoreloops, bootaddr, seed, spimode):
     if sys.platform in ("win32", "cygwin"):
         script_ext = ".bat"
         script_contents = "@echo off\nrem Autogenerated by LiteX / git: " + tools.get_litex_git_revision() + "\n\n"
@@ -124,9 +137,13 @@ def _build_script(source, build_template, build_name, architecture, package, fre
             build_name      = build_name,
             architecture    = architecture,
             package         = package,
-            freq_constraint = freq_constraint,
+            speed_grade     = speed_grade,
             timefailarg     = "--timing-allow-fail" if not timingstrict else "",
-            fail_stmt       = fail_stmt)
+            ignoreloops     = "--ignore-loops" if ignoreloops else "",
+            bootaddr        = bootaddr,
+            fail_stmt       = fail_stmt,
+            seed            = seed,
+            spimode         = spimode)
 
     script_file = "build_" + build_name + script_ext
     tools.write_to_file(script_file, script_contents, force_unix=False)
@@ -158,26 +175,25 @@ class LatticeTrellisToolchain:
         "no_shreg_extract": None
     }
 
-    special_overrides = common.lattice_ecpx_trellis_special_overrides
+    special_overrides = common.lattice_ecp5_trellis_special_overrides
 
     def __init__(self):
         self.yosys_template   = _yosys_template
         self.build_template   = _build_template
-        self.freq_constraints = dict()
+        self.false_paths = set() # FIXME: use it
 
     def build(self, platform, fragment,
         build_dir      = "build",
         build_name     = "top",
-        toolchain_path = None,
         run            = True,
         nowidelut      = False,
         timingstrict   = False,
+        ignoreloops    = False,
+        bootaddr       = 0,
+        seed           = 1,
+        spimode        = "fast-read",
         **kwargs):
 
-        # Get default toolchain path (if not specified)
-        if toolchain_path is None:
-            toolchain_path = "/usr/share/trellis/"
-
         # Create build directory
         os.makedirs(build_dir, exist_ok=True)
         cwd = os.getcwd()
@@ -188,7 +204,7 @@ class LatticeTrellisToolchain:
             fragment = fragment.get_fragment()
         platform.finalize(fragment)
 
-         # Generate verilog
+        # Generate verilog
         v_output = platform.get_verilog(fragment, name=build_name, **kwargs)
         named_sc, named_pc = platform.resolve_signals(v_output.ns)
         top_file = build_name + ".v"
@@ -201,17 +217,13 @@ class LatticeTrellisToolchain:
         # Generate Yosys script
         _build_yosys(self.yosys_template, platform, nowidelut, build_name)
 
-        # Translate device to Nextpnr architecture/package
-        (family, size, package) = platform.device.split("-")
-        architecture = nextpnr_ecp5_architectures[(family + "-" + size).lower()]
-        package      = nextpnr_ecp5_package(package)
-
-        freq_constraint = str(max(self.freq_constraints.values(), default=0.0))
+        # Translate device to Nextpnr architecture/package/speed_grade
+        (family, size, speed_grade, package) = nextpnr_ecp5_parse_device(platform.device)
+        architecture = nextpnr_ecp5_architectures[(family + "-" + size)]
 
         # Generate build script
         script = _build_script(False, self.build_template, build_name, architecture, package,
-            freq_constraint, timingstrict)
-
+                               speed_grade, timingstrict, ignoreloops, bootaddr, seed, spimode)
         # Run
         if run:
             _run_script(script)
@@ -220,21 +232,36 @@ class LatticeTrellisToolchain:
 
         return v_output.ns
 
-    # Until nextpnr-ecp5 can handle multiple clock domains, use the same
-    # approach as the icestorm and use the fastest clock for timing
-    # constraints.
     def add_period_constraint(self, platform, clk, period):
         platform.add_platform_command("""FREQUENCY PORT "{clk}" {freq} MHz;""".format(
             freq=str(float(1/period)*1000), clk="{clk}"), clk=clk)
 
+    def add_false_path_constraint(self, platform, from_, to):
+        from_.attr.add("keep")
+        to.attr.add("keep")
+        if (to, from_) not in self.false_paths:
+            self.false_paths.add((from_, to))
+
 def trellis_args(parser):
     parser.add_argument("--yosys-nowidelut", action="store_true",
                         help="pass '-nowidelut' to yosys synth_ecp5")
     parser.add_argument("--nextpnr-timingstrict", action="store_true",
                         help="fail if timing not met, i.e., do NOT pass '--timing-allow-fail' to nextpnr")
+    parser.add_argument("--nextpnr-ignoreloops", action="store_true",
+                        help="ignore combinational loops in timing analysis, i.e. pass '--ignore-loops' to nextpnr")
+    parser.add_argument("--ecppack-bootaddr", default=0,
+                        help="Set boot address for next image, i.e. pass '--bootaddr xxx' to ecppack")
+    parser.add_argument("--ecppack-spimode", default="fast-read",
+                        help="Set slave SPI programming mode")
+    parser.add_argument("--nextpnr-seed", default=1, type=int,
+                        help="seed to pass to nextpnr")
 
 def trellis_argdict(args):
     return {
         "nowidelut":    args.yosys_nowidelut,
         "timingstrict": args.nextpnr_timingstrict,
+        "ignoreloops":  args.nextpnr_ignoreloops,
+        "bootaddr":     args.ecppack_bootaddr,
+        "spimode":      args.ecppack_spimode,
+        "seed":         args.nextpnr_seed,
     }