2015-04-13 14:54:19 -04:00
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
import sys
|
2013-02-07 16:07:30 -05:00
|
|
|
|
2013-05-26 12:07:26 -04:00
|
|
|
from migen.fhdl.std import *
|
2013-08-11 17:07:07 -04:00
|
|
|
from migen.fhdl.structure import _Fragment
|
2013-02-07 16:07:30 -05:00
|
|
|
|
|
|
|
from mibuild.generic_platform import *
|
2015-02-26 06:10:41 -05:00
|
|
|
from mibuild import tools
|
|
|
|
from mibuild.xilinx import common
|
2013-02-07 16:07:30 -05:00
|
|
|
|
2015-04-13 14:45:35 -04:00
|
|
|
|
2013-02-07 16:07:30 -05:00
|
|
|
def _format_constraint(c):
|
2015-04-13 14:07:07 -04:00
|
|
|
if isinstance(c, Pins):
|
|
|
|
return "LOC=" + c.identifiers[0]
|
|
|
|
elif isinstance(c, IOStandard):
|
|
|
|
return "IOSTANDARD=" + c.name
|
|
|
|
elif isinstance(c, Drive):
|
|
|
|
return "DRIVE=" + str(c.strength)
|
|
|
|
elif isinstance(c, Misc):
|
|
|
|
return c.misc
|
2013-02-07 16:07:30 -05:00
|
|
|
|
2015-04-13 14:45:35 -04:00
|
|
|
|
2013-02-07 16:07:30 -05:00
|
|
|
def _format_ucf(signame, pin, others, resname):
|
2015-04-13 14:07:07 -04:00
|
|
|
fmt_c = []
|
|
|
|
for c in [Pins(pin)] + others:
|
|
|
|
fc = _format_constraint(c)
|
|
|
|
if fc is not None:
|
|
|
|
fmt_c.append(fc)
|
|
|
|
fmt_r = resname[0] + ":" + str(resname[1])
|
|
|
|
if resname[2] is not None:
|
|
|
|
fmt_r += "." + resname[2]
|
|
|
|
return "NET \"" + signame + "\" " + " | ".join(fmt_c) + "; # " + fmt_r + "\n"
|
2013-02-07 16:07:30 -05:00
|
|
|
|
2015-04-13 14:45:35 -04:00
|
|
|
|
2013-02-07 16:07:30 -05:00
|
|
|
def _build_ucf(named_sc, named_pc):
|
2015-04-13 14:07:07 -04:00
|
|
|
r = ""
|
|
|
|
for sig, pins, others, resname in named_sc:
|
|
|
|
if len(pins) > 1:
|
|
|
|
for i, p in enumerate(pins):
|
|
|
|
r += _format_ucf(sig + "(" + str(i) + ")", p, others, resname)
|
|
|
|
else:
|
|
|
|
r += _format_ucf(sig, pins[0], others, resname)
|
|
|
|
if named_pc:
|
|
|
|
r += "\n" + "\n\n".join(named_pc)
|
|
|
|
return r
|
2013-02-07 16:07:30 -05:00
|
|
|
|
2015-04-13 14:45:35 -04:00
|
|
|
|
2013-12-12 17:17:51 -05:00
|
|
|
def _build_xst_files(device, sources, vincpaths, build_name, xst_opt):
|
2015-04-13 14:07:07 -04:00
|
|
|
prj_contents = ""
|
2015-04-16 07:07:28 -04:00
|
|
|
for filename, language, library in sources:
|
|
|
|
prj_contents += language + " " + library + " " + filename + "\n"
|
2015-04-13 14:07:07 -04:00
|
|
|
tools.write_to_file(build_name + ".prj", prj_contents)
|
2013-02-07 16:07:30 -05:00
|
|
|
|
2015-04-13 14:07:07 -04:00
|
|
|
xst_contents = """run
|
2013-12-06 02:51:03 -05:00
|
|
|
-ifn {build_name}.prj
|
2015-04-25 08:29:08 -04:00
|
|
|
-use_new_parser yes
|
2013-02-07 16:07:30 -05:00
|
|
|
-top top
|
2013-12-06 02:51:03 -05:00
|
|
|
{xst_opt}
|
|
|
|
-ofn {build_name}.ngc
|
2013-12-12 17:17:51 -05:00
|
|
|
-p {device}
|
|
|
|
""".format(build_name=build_name, xst_opt=xst_opt, device=device)
|
2015-04-13 14:07:07 -04:00
|
|
|
for path in vincpaths:
|
|
|
|
xst_contents += "-vlgincdir " + path + "\n"
|
|
|
|
tools.write_to_file(build_name + ".xst", xst_contents)
|
2013-02-07 16:07:30 -05:00
|
|
|
|
2015-04-13 14:45:35 -04:00
|
|
|
|
2013-12-12 17:17:51 -05:00
|
|
|
def _run_yosys(device, sources, vincpaths, build_name):
|
2015-04-13 14:07:07 -04:00
|
|
|
ys_contents = ""
|
|
|
|
incflags = ""
|
|
|
|
for path in vincpaths:
|
|
|
|
incflags += " -I" + path
|
|
|
|
for filename, language in sources:
|
|
|
|
ys_contents += "read_{}{} {}\n".format(language, incflags, filename)
|
|
|
|
|
|
|
|
if device[:2] == "xc":
|
|
|
|
archcode = device[2:4]
|
|
|
|
else:
|
|
|
|
archcode = device[0:2]
|
|
|
|
arch = {
|
|
|
|
"6s": "spartan6",
|
|
|
|
"7a": "artix7",
|
|
|
|
"7k": "kintex7",
|
|
|
|
"7v": "virtex7",
|
|
|
|
"7z": "zynq7000"
|
|
|
|
}[archcode]
|
|
|
|
|
|
|
|
ys_contents += """hierarchy -check -top top
|
2013-12-01 11:07:48 -05:00
|
|
|
proc; memory; opt; fsm; opt
|
|
|
|
synth_xilinx -arch {arch} -top top -edif {build_name}.edif""".format(arch=arch, build_name=build_name)
|
2014-10-17 05:08:37 -04:00
|
|
|
|
2015-04-13 14:07:07 -04:00
|
|
|
ys_name = build_name + ".ys"
|
|
|
|
tools.write_to_file(ys_name, ys_contents)
|
|
|
|
r = subprocess.call(["yosys", ys_name])
|
|
|
|
if r != 0:
|
|
|
|
raise OSError("Subprocess failed")
|
2013-12-01 11:07:48 -05:00
|
|
|
|
2015-04-13 14:45:35 -04:00
|
|
|
|
2013-12-06 02:51:03 -05:00
|
|
|
def _run_ise(build_name, ise_path, source, mode, ngdbuild_opt,
|
2015-04-13 14:07:07 -04:00
|
|
|
bitgen_opt, ise_commands, map_opt, par_opt, ver=None):
|
|
|
|
if sys.platform == "win32" or sys.platform == "cygwin":
|
|
|
|
source = False
|
|
|
|
build_script_contents = "# Autogenerated by mibuild\nset -e\n"
|
|
|
|
if source:
|
|
|
|
settings = common.settings(ise_path, ver, "ISE_DS")
|
|
|
|
build_script_contents += "source " + settings + "\n"
|
|
|
|
if mode == "edif":
|
|
|
|
ext = "edif"
|
|
|
|
else:
|
|
|
|
ext = "ngc"
|
|
|
|
build_script_contents += """
|
2014-07-27 21:30:08 -04:00
|
|
|
xst -ifn {build_name}.xst
|
|
|
|
"""
|
2013-12-06 05:49:44 -05:00
|
|
|
|
2015-04-13 14:07:07 -04:00
|
|
|
build_script_contents += """
|
2013-12-06 05:49:44 -05:00
|
|
|
ngdbuild {ngdbuild_opt} -uc {build_name}.ucf {build_name}.{ext} {build_name}.ngd
|
2014-04-04 00:19:29 -04:00
|
|
|
map {map_opt} -o {build_name}_map.ncd {build_name}.ngd {build_name}.pcf
|
|
|
|
par {par_opt} {build_name}_map.ncd {build_name}.ncd {build_name}.pcf
|
|
|
|
bitgen {bitgen_opt} {build_name}.ncd {build_name}.bit
|
2013-08-07 18:15:35 -04:00
|
|
|
"""
|
2015-04-13 14:07:07 -04:00
|
|
|
build_script_contents = build_script_contents.format(build_name=build_name,
|
|
|
|
ngdbuild_opt=ngdbuild_opt, bitgen_opt=bitgen_opt, ext=ext,
|
|
|
|
par_opt=par_opt, map_opt=map_opt)
|
|
|
|
build_script_contents += ise_commands.format(build_name=build_name)
|
|
|
|
build_script_file = "build_" + build_name + ".sh"
|
|
|
|
tools.write_to_file(build_script_file, build_script_contents, force_unix=True)
|
2013-02-07 16:07:30 -05:00
|
|
|
|
2015-04-13 14:07:07 -04:00
|
|
|
r = subprocess.call(["bash", build_script_file])
|
|
|
|
if r != 0:
|
|
|
|
raise OSError("Subprocess failed")
|
2013-02-07 16:07:30 -05:00
|
|
|
|
2015-04-13 14:45:35 -04:00
|
|
|
|
2015-03-13 18:17:45 -04:00
|
|
|
class XilinxISEToolchain:
|
2015-04-13 14:07:07 -04:00
|
|
|
def __init__(self):
|
|
|
|
self.xst_opt = """-ifmt MIXED
|
2013-12-06 02:51:03 -05:00
|
|
|
-opt_mode SPEED
|
|
|
|
-register_balancing yes"""
|
2015-04-13 14:07:07 -04:00
|
|
|
self.map_opt = "-ol high -w"
|
|
|
|
self.par_opt = "-ol high -w"
|
|
|
|
self.ngdbuild_opt = ""
|
|
|
|
self.bitgen_opt = "-g LCK_cycle:6 -g Binary:Yes -w"
|
|
|
|
self.ise_commands = ""
|
|
|
|
|
|
|
|
def build(self, platform, fragment, build_dir="build", build_name="top",
|
|
|
|
ise_path="/opt/Xilinx", source=True, run=True, mode="xst"):
|
|
|
|
tools.mkdir_noerror(build_dir)
|
|
|
|
os.chdir(build_dir)
|
|
|
|
|
|
|
|
if not isinstance(fragment, _Fragment):
|
|
|
|
fragment = fragment.get_fragment()
|
|
|
|
platform.finalize(fragment)
|
|
|
|
|
|
|
|
ngdbuild_opt = self.ngdbuild_opt
|
|
|
|
|
|
|
|
vns = None
|
|
|
|
|
|
|
|
if mode == "xst" or mode == "yosys":
|
|
|
|
v_output = platform.get_verilog(fragment)
|
|
|
|
vns = v_output.ns
|
|
|
|
named_sc, named_pc = platform.resolve_signals(vns)
|
|
|
|
v_file = build_name + ".v"
|
|
|
|
v_output.write(v_file)
|
2015-04-16 07:07:28 -04:00
|
|
|
sources = platform.sources | {(v_file, "verilog", "work")}
|
2015-04-13 14:07:07 -04:00
|
|
|
if mode == "xst":
|
|
|
|
_build_xst_files(platform.device, sources, platform.verilog_include_paths, build_name, self.xst_opt)
|
|
|
|
isemode = "xst"
|
|
|
|
else:
|
|
|
|
_run_yosys(platform.device, sources, platform.verilog_include_paths, build_name)
|
|
|
|
isemode = "edif"
|
|
|
|
ngdbuild_opt += "-p " + platform.device
|
|
|
|
|
|
|
|
if mode == "mist":
|
|
|
|
from mist import synthesize
|
|
|
|
synthesize(fragment, platform.constraint_manager.get_io_signals())
|
|
|
|
|
|
|
|
if mode == "edif" or mode == "mist":
|
|
|
|
e_output = platform.get_edif(fragment)
|
|
|
|
vns = e_output.ns
|
|
|
|
named_sc, named_pc = platform.resolve_signals(vns)
|
|
|
|
e_file = build_name + ".edif"
|
|
|
|
e_output.write(e_file)
|
|
|
|
isemode = "edif"
|
|
|
|
|
|
|
|
tools.write_to_file(build_name + ".ucf", _build_ucf(named_sc, named_pc))
|
|
|
|
if run:
|
|
|
|
_run_ise(build_name, ise_path, source, isemode,
|
|
|
|
ngdbuild_opt, self.bitgen_opt, self.ise_commands,
|
|
|
|
self.map_opt, self.par_opt)
|
|
|
|
|
|
|
|
os.chdir("..")
|
|
|
|
|
|
|
|
return vns
|
|
|
|
|
|
|
|
def add_period_constraint(self, platform, clk, period):
|
|
|
|
platform.add_platform_command("""NET "{clk}" TNM_NET = "GRP{clk}";
|
2014-05-19 05:27:08 -04:00
|
|
|
TIMESPEC "TS{clk}" = PERIOD "GRP{clk}" """+str(period)+""" ns HIGH 50%;""", clk=clk)
|