105 lines
3.7 KiB
Python
105 lines
3.7 KiB
Python
# This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
|
|
# License: BSD
|
|
|
|
import os
|
|
import subprocess
|
|
import shutil
|
|
|
|
from migen.fhdl.structure import _Fragment
|
|
from mibuild.generic_platform import *
|
|
|
|
from mibuild import tools
|
|
from mibuild.lattice import common
|
|
|
|
|
|
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 \"{}\" -impl \"implementation\" -dev {} -synthesis \"synplify\"".format(build_name, device))
|
|
for path in vincpaths:
|
|
tcl.append("prj_impl option {include path} {\"" + path + "\"}")
|
|
for filename, language, library in sources:
|
|
tcl.append("prj_src add \"" + filename + "\" -work " + library)
|
|
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 LatticeDiamondToolchain:
|
|
def build(self, platform, 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()
|
|
platform.finalize(fragment)
|
|
|
|
v_output = platform.get_verilog(fragment)
|
|
named_sc, named_pc = platform.resolve_signals(v_output.ns)
|
|
v_file = build_name + ".v"
|
|
v_output.write(v_file)
|
|
sources = platform.sources | {(v_file, "verilog", "work")}
|
|
_build_files(platform.device, sources, platform.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 v_output.ns
|
|
|
|
def add_period_constraint(self, platform, clk, period):
|
|
# TODO: handle differential clk
|
|
platform.add_platform_command("""FREQUENCY PORT "{clk}" {freq} MHz;""".format(freq=str(float(1/period)*1000), clk="{clk}"), clk=clk)
|