diff --git a/litex/build/gowin/__init__.py b/litex/build/gowin/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/litex/build/gowin/common.py b/litex/build/gowin/common.py new file mode 100644 index 000000000..3d428dea3 --- /dev/null +++ b/litex/build/gowin/common.py @@ -0,0 +1,8 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2020 Pepijn de Vos +# Copyright (c) 2015-2018 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +gowin_special_overrides = {} diff --git a/litex/build/gowin/gowin.py b/litex/build/gowin/gowin.py new file mode 100644 index 000000000..ea486a187 --- /dev/null +++ b/litex/build/gowin/gowin.py @@ -0,0 +1,122 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2020 Pepijn de Vos +# Copyright (c) 2015-2018 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os +import subprocess + +from migen.fhdl.structure import _Fragment + +from litex.build.generic_platform import Pins, IOStandard, Misc +from litex.build import tools + +def _build_cst(named_sc, named_pc): + lines = [] + + flat_sc = [] + for name, pins, other, resource in named_sc: + if len(pins) > 1: + for i, p in enumerate(pins): + flat_sc.append((f"{name}[{i}]", p, other)) + else: + flat_sc.append((name, pins[0], other)) + + for name, pin, other in flat_sc: + lines.append(f"IO_LOC \"{name}\" {pin};") + + for c in other: + if isinstance(c, IOStandard): + lines.append(f"IO_PORT \"{name}\" IO_TYPE={c.name};") + elif isinstance(c, Misc): + lines.append(f"IO_PORT \"{name}\" {c.misc};") + + if named_pc: + lines.extend(named_pc) + + cst = "\n".join(lines) + with open("top.cst", "w") as f: + f.write(cst) + +def _build_script(name, partnumber, files, options): + lines = [ + f"set_device -name {name} {partnumber}", + "add_file top.cst", + ] + + for f, typ, lib in files: + lines.append(f"add_file {f}") + + for opt, val in options.items(): + lines.append(f"set_option -{opt} {val}") + + lines.append("run all") + + tcl = "\n".join(lines) + with open("run.tcl", "w") as f: + f.write(tcl) + +class GowinToolchain(): + + attr_translate = { + "keep": None, + "no_retiming": None, + "async_reg": None, + "mr_ff": None, + "mr_false_path": None, + "ars_ff1": None, + "ars_ff2": None, + "ars_false_path": None, + "no_shreg_extract": None + } + + def __init__(self): + self.options = {} + + def build(self, platform, fragment, + build_dir = "build", + build_name = "top", + run = True, + **kwargs): + + # Create build directory + cwd = os.getcwd() + os.makedirs(build_dir, exist_ok=True) + os.chdir(build_dir) + + # Finalize design + if not isinstance(fragment, _Fragment): + fragment = fragment.get_fragment() + platform.finalize(fragment) + + # Generate verilog + v_output = platform.get_verilog(fragment, name=build_name, **kwargs) + named_sc, named_pc = platform.resolve_signals(v_output.ns) + v_file = build_name + ".v" + v_output.write(v_file) + platform.add_source(v_file) + + if platform.verilog_include_paths: + self.options['include_path'] = '{' + ';'.join(platform.verilog_include_paths) + '}' + + # Generate constraints file (.cst) + _build_cst( + named_sc = named_sc, + named_pc = named_pc) + + # Generate TCL build script + script = _build_script( + name = platform.devicename, + partnumber = platform.device, + files = platform.sources, + options = self.options) + + # Run + if run: + subprocess.run(["gw_sh", "run.tcl"]) + + os.chdir(cwd) + + return v_output.ns diff --git a/litex/build/gowin/platform.py b/litex/build/gowin/platform.py new file mode 100644 index 000000000..8ac93ebdb --- /dev/null +++ b/litex/build/gowin/platform.py @@ -0,0 +1,40 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2020 Pepijn de Vos +# Copyright (c) 2015-2018 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os + +from litex.build.generic_platform import GenericPlatform +from litex.build.gowin import common, gowin + +# GowinPlatform ----------------------------------------------------------------------------------- + +class GowinPlatform(GenericPlatform): + bitstream_ext = ".fs" + + def __init__(self, device, *args, toolchain="gowin", devicename=None, **kwargs): + GenericPlatform.__init__(self, device, *args, **kwargs) + if not devicename: + idx = device.find('-') + likely_name = f"{device[:idx]}-{device[idx+3]}" + raise ValueError(f"devicename not provided, maybe {likely_name}?") + self.devicename = devicename + if toolchain == "gowin": + self.toolchain = gowin.GowinToolchain() + elif toolchain == "apicula": + raise ValueError("Apicula toolchain needs more work") + else: + raise ValueError("Unknown toolchain") + + def get_verilog(self, *args, special_overrides=dict(), **kwargs): + so = dict(common.gowin_special_overrides) + so.update(special_overrides) + return GenericPlatform.get_verilog(self, *args, special_overrides=so, + attr_translate=self.toolchain.attr_translate, + **kwargs) + + def build(self, *args, **kwargs): + return self.toolchain.build(self, *args, **kwargs) diff --git a/litex/build/openfpgaloader.py b/litex/build/openfpgaloader.py index 8189be13f..1d845505c 100644 --- a/litex/build/openfpgaloader.py +++ b/litex/build/openfpgaloader.py @@ -17,5 +17,8 @@ class OpenFPGALoader(GenericProgrammer): def __init__(self, board): self.board = board - def load_bitstream(self, bitstream_file): - subprocess.call(["openFPGALoader", "--board", self.board, bitstream_file]) + def load_bitstream(self, bitstream_file, flash=False): + cmd = ["openFPGALoader", "--board", self.board, "--bitstream", bitstream_file] + if flash: + cmd.append("--write-flash") + subprocess.call(cmd)