--- /dev/null
+# This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
+# 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
--- /dev/null
+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 = """
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE ispXCF SYSTEM "IspXCF.dtd" >
+<ispXCF version="3.4.1">
+ <Comment></Comment>
+ <Chain>
+ <Comm>JTAG</Comm>
+ <Device>
+ <SelectedProg value="TRUE"/>
+ <Pos>1</Pos>
+ <Vendor>Lattice</Vendor>
+ <Family>LatticeECP3</Family>
+ <Name>LFE3-35EA</Name>
+ <File>{bitstream_file}</File>
+ <Operation>Fast Program</Operation>
+ </Device>
+ </Chain>
+ <ProjectOptions>
+ <Program>SEQUENTIAL</Program>
+ <Process>ENTIRED CHAIN</Process>
+ <OperationOverride>No Override</OperationOverride>
+ <StartTAP>TLR</StartTAP>
+ <EndTAP>TLR</EndTAP>
+ <VerifyUsercode value="FALSE"/>
+ </ProjectOptions>
+ <CableOptions>
+ <CableName>USB2</CableName>
+ <PortAdd>FTUSB-0</PortAdd>
+ <USBID>Dual RS232-HS A Location 0000 Serial A</USBID>
+ <JTAGPinSetting>
+ TRST ABSENT;
+ ISPEN ABSENT;
+ </JTAGPinSetting>
+ </CableOptions>
+</ispXCF>
+"""
+
+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])
--- /dev/null
+# This file is Copyright (c) 2013 Florent Kermarrec <florent@enjoy-digital.fr>
+# 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()