Skip to content

Commit

Permalink
mibuild: add initial Lattice Diamond support (with ECP3 Versa board p…
Browse files Browse the repository at this point in the history
…latform skeleton)
  • Loading branch information
enjoy-digital committed Mar 16, 2015
1 parent beeaefc commit f7bfa13
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 0 deletions.
Empty file added mibuild/lattice/__init__.py
Empty file.
93 changes: 93 additions & 0 deletions mibuild/lattice/diamond.py
@@ -0,0 +1,93 @@
# 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)
51 changes: 51 additions & 0 deletions 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 = """
<?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])
34 changes: 34 additions & 0 deletions mibuild/platforms/versa.py
@@ -0,0 +1,34 @@
# 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()

0 comments on commit f7bfa13

Please sign in to comment.