From f7bfa13144d11f26ad5eed7fd74ac26a43317434 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 16 Mar 2015 12:01:27 +0100 Subject: [PATCH] mibuild: add initial Lattice Diamond support (with ECP3 Versa board platform skeleton) --- mibuild/lattice/__init__.py | 0 mibuild/lattice/diamond.py | 93 +++++++++++++++++++++++++++++++++++ mibuild/lattice/programmer.py | 51 +++++++++++++++++++ mibuild/platforms/versa.py | 34 +++++++++++++ 4 files changed, 178 insertions(+) create mode 100644 mibuild/lattice/__init__.py create mode 100644 mibuild/lattice/diamond.py create mode 100644 mibuild/lattice/programmer.py create mode 100644 mibuild/platforms/versa.py diff --git a/mibuild/lattice/__init__.py b/mibuild/lattice/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mibuild/lattice/diamond.py b/mibuild/lattice/diamond.py new file mode 100644 index 00000000..f39ddd32 --- /dev/null +++ b/mibuild/lattice/diamond.py @@ -0,0 +1,93 @@ +# This file is Copyright (c) 2015 Florent Kermarrec +# License: BSD + +import os, subprocess, shutil + +from migen.fhdl.structure import _Fragment +from mibuild.generic_platform import * +from mibuild import tools + +def _format_constraint(c): + if isinstance(c, Pins): + return ("LOCATE COMP ", " SITE " + "\"" + c.identifiers[0] + "\"") + elif isinstance(c, IOStandard): + return ("IOBUF PORT ", " IO_TYPE=" + c.name) + elif isinstance(c, Misc): + return c.misc + +def _format_lpf(signame, pin, others, resname): + fmt_c = [_format_constraint(c) for c in ([Pins(pin)] + others)] + r = "" + for pre, suf in fmt_c: + r += pre + "\""+ signame +"\"" + suf + ";\n" + return r + +def _build_lpf(named_sc, named_pc): + r = "BLOCK RESETPATHS;\n" + r += "BLOCK ASYNCPATHS;\n" + for sig, pins, others, resname in named_sc: + if len(pins) > 1: + for i, p in enumerate(pins): + r += _format_lpf(sig + "[" + str(i) + "]", p, others, resname) + else: + r += _format_lpf(sig, pins[0], others, resname) + if named_pc: + r += "\n" + "\n\n".join(named_pc) + return r + +def _build_files(device, sources, vincpaths, build_name): + tcl = [] + tcl.append("prj_project new -name \"%s\" -impl \"implementation\" -dev %s -synthesis \"synplify\"" %(build_name, device)) + for filename, language in sources: + tcl.append("prj_src add \"" + filename.replace("\\", "/") + "\"") + tcl.append("prj_run Synthesis -impl implementation -forceOne") + tcl.append("prj_run Translate -impl implementation") + tcl.append("prj_run Map -impl implementation") + tcl.append("prj_run PAR -impl implementation") + tcl.append("prj_run Export -impl implementation -task Bitgen") + tools.write_to_file(build_name + ".tcl", "\n".join(tcl)) + +def _run_diamond(build_name, source, ver=None): + if sys.platform == "win32" or sys.platform == "cygwin": + build_script_contents = "REM Autogenerated by mibuild\n" + build_script_contents = "pnmainc " + build_name + ".tcl\n" + build_script_file = "build_" + build_name + ".bat" + tools.write_to_file(build_script_file, build_script_contents) + r = subprocess.call([build_script_file]) + shutil.copy(os.path.join("implementation", build_name + "_implementation.bit"), build_name + ".bit") + else: + raise NotImplementedError() + + if r != 0: + raise OSError("Subprocess failed") + +class LatticeDiamondPlatform(GenericPlatform): + bitstream_ext = ".bit" + def build(self, fragment, build_dir="build", build_name="top", + diamond_path="/opt/Diamond", run=True): + tools.mkdir_noerror(build_dir) + os.chdir(build_dir) + + if not isinstance(fragment, _Fragment): + fragment = fragment.get_fragment() + self.finalize(fragment) + + v_src, vns = self.get_verilog(fragment) + named_sc, named_pc = self.resolve_signals(vns) + v_file = build_name + ".v" + tools.write_to_file(v_file, v_src) + sources = self.sources + [(v_file, "verilog")] + _build_files(self.device, sources, self.verilog_include_paths, build_name) + + tools.write_to_file(build_name + ".lpf", _build_lpf(named_sc, named_pc)) + + if run: + _run_diamond(build_name, diamond_path) + + os.chdir("..") + + return vns + + def add_period_constraint(self, clk, period): + # TODO: handle differential clk + self.add_platform_command("""FREQUENCY PORT "{clk}" {freq} MHz;""".format(freq=str(float(1/period)*1000), clk="{clk}"), clk=clk) \ No newline at end of file diff --git a/mibuild/lattice/programmer.py b/mibuild/lattice/programmer.py new file mode 100644 index 00000000..726e5e12 --- /dev/null +++ b/mibuild/lattice/programmer.py @@ -0,0 +1,51 @@ +import os, subprocess + +from mibuild.generic_programmer import GenericProgrammer +from mibuild import tools + +# XXX Lattice programmer need an .xcf file, will need clean up and support for more parameters +_xcf_template = """ + + + + + + JTAG + + + 1 + Lattice + LatticeECP3 + LFE3-35EA + {bitstream_file} + Fast Program + + + + SEQUENTIAL + ENTIRED CHAIN + No Override + TLR + TLR + + + + USB2 + FTUSB-0 + Dual RS232-HS A Location 0000 Serial A + + TRST ABSENT; + ISPEN ABSENT; + + + +""" + +class LatticeProgrammer(GenericProgrammer): + needs_bitreverse = False + + def load_bitstream(self, bitstream_file): + xcf_file = bitstream_file.replace(".bit", ".xcf") + xcf_content = _xcf_template.format(bitstream_file=bitstream_file) + tools.write_to_file(xcf_file, xcf_content) + subprocess.call(["pgrcmd", "-infile", xcf_file]) diff --git a/mibuild/platforms/versa.py b/mibuild/platforms/versa.py new file mode 100644 index 00000000..6cd58bf9 --- /dev/null +++ b/mibuild/platforms/versa.py @@ -0,0 +1,34 @@ +# This file is Copyright (c) 2013 Florent Kermarrec +# License: BSD + +from mibuild.generic_platform import * +from mibuild.lattice.diamond import LatticeDiamondPlatform +from mibuild.lattice.programmer import LatticeProgrammer + +_io = [ + ("clk100", 0, Pins("L5"), IOStandard("LVDS25")), + + ("user_led", 0, Pins("Y20"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("AA21"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("U18"), IOStandard("LVCMOS33")), + ("user_led", 3, Pins("U19"), IOStandard("LVCMOS33")), + ("user_led", 4, Pins("W19"), IOStandard("LVCMOS33")), + ("user_led", 5, Pins("V19"), IOStandard("LVCMOS33")), + ("user_led", 6, Pins("AB20"), IOStandard("LVCMOS33")), + ("user_led", 7, Pins("AA20"), IOStandard("LVCMOS33")), + + ("serial", 0, + Subsignal("tx", Pins("B11"), IOStandard("LVCMOS33")), # X4 IO0 + Subsignal("rx", Pins("B12"), IOStandard("LVCMOS33")), # X4 IO1 + ), +] + +class Platform(LatticeDiamondPlatform): + default_clk_name = "clk100" + default_clk_period = 10 + + def __init__(self): + LatticeDiamondPlatform.__init__(self, "LFE3-35EA-6FN484C", _io) + + def create_programmer(self): + return LatticeProgrammer() -- 2.30.2