litex/mibuild/xilinx_ise.py

126 lines
4.0 KiB
Python

import os, struct, subprocess
from decimal import Decimal
from migen.fhdl.structure import *
from mibuild.generic_platform import *
from mibuild.crg import CRG, SimpleCRG
from mibuild import tools
def _add_period_constraint(platform, clk, period):
platform.add_platform_command("""NET "{clk}" TNM_NET = "GRPclk";
TIMESPEC "TSclk" = PERIOD "GRPclk" """+str(period)+""" ns HIGH 50%;""", clk=clk)
class CRG_SE(SimpleCRG):
def __init__(self, platform, clk_name, rst_name, period):
SimpleCRG.__init__(self, platform, clk_name, rst_name)
_add_period_constraint(platform, self.cd.clk, period)
class CRG_DS(CRG):
def __init__(self, platform, clk_name, rst_name, period):
self.cd = ClockDomain("sys")
self._clk = platform.request(clk_name)
platform.request(rst_name, None, self.cd.rst)
_add_period_constraint(platform, self._clk.p, period)
def get_fragment(self):
ibufg = Instance("IBUFGDS",
Instance.Input("I", self._clk.p),
Instance.Input("IB", self._clk.n),
Instance.Output("O", self.cd.clk)
)
return Fragment(instances=[ibufg])
def _format_constraint(c):
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
def _format_ucf(signame, pin, others, resname):
fmt_c = [_format_constraint(c) for c in ([Pins(pin)] + others)]
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"
def _build_ucf(named_sc, named_pc):
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
def _build_files(device, sources, named_sc, named_pc, build_name):
tools.write_to_file(build_name + ".ucf", _build_ucf(named_sc, named_pc))
prj_contents = ""
for filename, language in sources:
prj_contents += language + " work " + filename + "\n"
tools.write_to_file(build_name + ".prj", prj_contents)
xst_contents = """run
-ifn %s.prj
-top top
-ifmt MIXED
-opt_mode SPEED
-reduce_control_sets auto
-ofn %s.ngc
-p %s""" % (build_name, build_name, device)
tools.write_to_file(build_name + ".xst", xst_contents)
def _run_ise(build_name, xilinx_install_path):
def is_valid_version(v):
try:
Decimal(v)
return os.path.isdir(os.path.join(xilinx_install_path, v))
except:
return False
vers = [ver for ver in os.listdir(xilinx_install_path) if is_valid_version(ver)]
tools_version = max(vers)
bits = struct.calcsize("P")*8
xilinx_settings_file = '%s/%s/ISE_DS/settings%d.sh' % (xilinx_install_path, tools_version, bits)
build_script_contents = """# Autogenerated by mibuild
set -e
source {xilinx_settings_file}
xst -ifn {build_name}.xst
ngdbuild -uc {build_name}.ucf {build_name}.ngc
map -ol high -w {build_name}.ngd
par -ol high -w {build_name}.ncd {build_name}-routed.ncd
bitgen -g Binary:Yes -w {build_name}-routed.ncd {build_name}.bit
""".format(build_name=build_name, xilinx_settings_file=xilinx_settings_file)
build_script_file = "build_" + build_name + ".sh"
tools.write_to_file(build_script_file, build_script_contents)
r = subprocess.call(["bash", build_script_file])
if r != 0:
raise OSError("Subprocess failed")
class XilinxISEPlatform(GenericPlatform):
def build(self, fragment, clock_domains=None, build_dir="build", build_name="top",
xilinx_install_path="/opt/Xilinx", run=True):
tools.mkdir_noerror(build_dir)
os.chdir(build_dir)
v_src, named_sc, named_pc = self.get_verilog(fragment, clock_domains)
v_file = build_name + ".v"
tools.write_to_file(v_file, v_src)
sources = self.sources + [(v_file, "verilog")]
_build_files(self.device, sources, named_sc, named_pc, build_name)
if run:
_run_ise(build_name, xilinx_install_path)
os.chdir("..")