build: merge with migen.build 27beffe7
This commit is contained in:
parent
0edfd9b901
commit
64e4e1ce84
|
@ -6,8 +6,7 @@ from litex.build.generic_programmer import GenericProgrammer
|
||||||
class USBBlaster(GenericProgrammer):
|
class USBBlaster(GenericProgrammer):
|
||||||
needs_bitreverse = False
|
needs_bitreverse = False
|
||||||
|
|
||||||
def load_bitstream(self, bitstream_file, port=0):
|
def load_bitstream(self, bitstream_file, cable_suffix=""):
|
||||||
usb_port = "[USB-{}]".format(port)
|
|
||||||
subprocess.call(["quartus_pgm", "-m", "jtag", "-c",
|
subprocess.call(["quartus_pgm", "-m", "jtag", "-c",
|
||||||
"USB-Blaster{}".format(usb_port), "-o",
|
"USB-Blaster{}".format(cable_suffix), "-o",
|
||||||
"p;{}".format(bitstream_file)])
|
"p;{}".format(bitstream_file)])
|
||||||
|
|
|
@ -366,6 +366,12 @@ class GenericPlatform:
|
||||||
self.constraint_manager.get_io_signals(),
|
self.constraint_manager.get_io_signals(),
|
||||||
create_clock_domains=False, **kwargs)
|
create_clock_domains=False, **kwargs)
|
||||||
|
|
||||||
|
def get_edif(self, fragment, cell_library, vendor, device, **kwargs):
|
||||||
|
return edif.convert(
|
||||||
|
fragment,
|
||||||
|
self.constraint_manager.get_io_signals(),
|
||||||
|
cell_library, vendor, device, **kwargs)
|
||||||
|
|
||||||
def build(self, fragment):
|
def build(self, fragment):
|
||||||
raise NotImplementedError("GenericPlatform.build must be overloaded")
|
raise NotImplementedError("GenericPlatform.build must be overloaded")
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,7 @@ class GenericProgrammer:
|
||||||
fullname = os.path.join(fulldir, self.flash_proxy_basename)
|
fullname = os.path.join(fulldir, self.flash_proxy_basename)
|
||||||
if os.path.exists(fullname):
|
if os.path.exists(fullname):
|
||||||
return fullname
|
return fullname
|
||||||
raise OSError(
|
raise OSError("Failed to find flash proxy bitstream")
|
||||||
"Failed to find flash proxy bitstream %s, searched:\n %s\n" % (
|
|
||||||
self.flash_proxy_basename,
|
|
||||||
"\n ".join(self.flash_proxy_dirs)))
|
|
||||||
|
|
||||||
# must be overloaded by specific programmer
|
# must be overloaded by specific programmer
|
||||||
def load_bitstream(self, bitstream_file):
|
def load_bitstream(self, bitstream_file):
|
||||||
|
|
|
@ -36,13 +36,11 @@ def _build_pcf(named_sc, named_pc):
|
||||||
def _run_icestorm(source, build_template, build_name, pnr_pkg_opts,
|
def _run_icestorm(source, build_template, build_name, pnr_pkg_opts,
|
||||||
icetime_pkg_opts, icetime_constraint):
|
icetime_pkg_opts, icetime_constraint):
|
||||||
if sys.platform == "win32" or sys.platform == "cygwin":
|
if sys.platform == "win32" or sys.platform == "cygwin":
|
||||||
source_cmd = "call "
|
|
||||||
script_ext = ".bat"
|
script_ext = ".bat"
|
||||||
shell = ["cmd", "/c"]
|
shell = ["cmd", "/c"]
|
||||||
build_script_contents = "@echo off\nrem Autogenerated by LiteX\n"
|
build_script_contents = "@echo off\nrem Autogenerated by LiteX\n"
|
||||||
fail_stmt = " || exit /b"
|
fail_stmt = " || exit /b"
|
||||||
else:
|
else:
|
||||||
source_cmd = "source "
|
|
||||||
script_ext = ".sh"
|
script_ext = ".sh"
|
||||||
shell = ["bash"]
|
shell = ["bash"]
|
||||||
build_script_contents = "# Autogenerated by LiteX\nset -e\n"
|
build_script_contents = "# Autogenerated by LiteX\nset -e\n"
|
||||||
|
@ -159,12 +157,13 @@ class LatticeIceStormToolchain:
|
||||||
"lp8k": ["cm81", "cm81:4k", "cm121", "cm121:4k", "cm225",
|
"lp8k": ["cm81", "cm81:4k", "cm121", "cm121:4k", "cm225",
|
||||||
"cm225:4k"],
|
"cm225:4k"],
|
||||||
"hx8k": ["cb132", "cb132:4k", "tq144:4k", "cm225", "ct256"],
|
"hx8k": ["cb132", "cb132:4k", "tq144:4k", "cm225", "ct256"],
|
||||||
|
"up5k": ["sg48"],
|
||||||
}
|
}
|
||||||
|
|
||||||
(family, series_size, package) = device_str.split("-")
|
(family, series_size, package) = device_str.split("-")
|
||||||
if family not in ["ice40"]:
|
if family not in ["ice40"]:
|
||||||
raise ValueError("Unknown device family")
|
raise ValueError("Unknown device family")
|
||||||
if series_size not in ["lp384", "lp1k", "hx1k", "lp8k", "hx8k"]:
|
if series_size not in ["lp384", "lp1k", "hx1k", "lp8k", "hx8k", "up5k"]:
|
||||||
raise ValueError("Invalid device series/size")
|
raise ValueError("Invalid device series/size")
|
||||||
if package not in valid_packages[series_size]:
|
if package not in valid_packages[series_size]:
|
||||||
raise ValueError("Invalid device package")
|
raise ValueError("Invalid device package")
|
||||||
|
|
|
@ -19,9 +19,6 @@ def write_to_file(filename, contents, force_unix=False):
|
||||||
newline = None
|
newline = None
|
||||||
if force_unix:
|
if force_unix:
|
||||||
newline = "\n"
|
newline = "\n"
|
||||||
if os.path.exists(filename):
|
|
||||||
if open(filename, "r", newline=newline).read() == contents:
|
|
||||||
return
|
|
||||||
with open(filename, "w", newline=newline) as f:
|
with open(filename, "w", newline=newline) as f:
|
||||||
f.write(contents)
|
f.write(contents)
|
||||||
|
|
||||||
|
@ -41,23 +38,20 @@ def versions(path):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
def sub_rules(lines, rules, max_matches=1):
|
def sub_rules(line, rules, max_matches=1):
|
||||||
for line in lines:
|
|
||||||
n = max_matches
|
|
||||||
for pattern, color in rules:
|
for pattern, color in rules:
|
||||||
line, m = re.subn(pattern, color, line, n)
|
line, matches = re.subn(pattern, color, line, max_matches)
|
||||||
n -= m
|
max_matches -= matches
|
||||||
if not n:
|
if not max_matches:
|
||||||
break
|
break
|
||||||
yield line
|
return line
|
||||||
|
|
||||||
|
|
||||||
def subprocess_call_filtered(command, rules, *, max_matches=1, **kwargs):
|
def subprocess_call_filtered(command, rules, *, max_matches=1, **kwargs):
|
||||||
proc = subprocess.Popen(command, stdout=subprocess.PIPE,
|
with subprocess.Popen(command, stdout=subprocess.PIPE,
|
||||||
universal_newlines=True, bufsize=1,
|
universal_newlines=True, bufsize=1,
|
||||||
**kwargs)
|
**kwargs) as proc:
|
||||||
with proc:
|
with open(proc.stdout.fileno(), errors="ignore", closefd=False) as stdout:
|
||||||
for line in sub_rules(iter(proc.stdout.readline, ""),
|
for line in stdout:
|
||||||
rules, max_matches):
|
print(sub_rules(line, rules, max_matches), end="")
|
||||||
sys.stdout.write(line)
|
return proc.wait()
|
||||||
return proc.returncode
|
|
||||||
|
|
|
@ -2,11 +2,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
try:
|
try:
|
||||||
import colorama
|
import colorama
|
||||||
# install escape sequence translation on Windows
|
colorama.init() # install escape sequence translation on Windows
|
||||||
if os.getenv("COLORAMA", "") == "force":
|
|
||||||
colorama.init(strip=False)
|
|
||||||
else:
|
|
||||||
colorama.init()
|
|
||||||
_have_colorama = True
|
_have_colorama = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_have_colorama = False
|
_have_colorama = False
|
||||||
|
@ -35,54 +31,43 @@ if _have_colorama:
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def settings(path, name=None, ver=None, first=None):
|
def settings(path, ver=None, sub=None):
|
||||||
if first == "version":
|
if ver is None:
|
||||||
if not ver:
|
vers = list(tools.versions(path))
|
||||||
vers = tools.versions(path)
|
if not vers:
|
||||||
ver = max(vers)
|
raise OSError("no version directory for Xilinx tools found in "
|
||||||
|
+ path)
|
||||||
full = os.path.join(path, str(ver), name)
|
|
||||||
|
|
||||||
elif first == "name":
|
|
||||||
path = os.path.join(path, name)
|
|
||||||
|
|
||||||
if not ver:
|
|
||||||
vers = tools.versions(path)
|
|
||||||
ver = max(vers)
|
ver = max(vers)
|
||||||
|
|
||||||
full = os.path.join(path, str(ver))
|
full = os.path.join(path, str(ver))
|
||||||
|
if sub:
|
||||||
if not vers:
|
full = os.path.join(full, sub)
|
||||||
raise OSError(
|
|
||||||
"no version directory for Xilinx tools found in {}".format(
|
|
||||||
path))
|
|
||||||
|
|
||||||
search = [64, 32]
|
search = [64, 32]
|
||||||
if tools.arch_bits() == 32:
|
if tools.arch_bits() == 32:
|
||||||
search = [32]
|
search.reverse()
|
||||||
|
|
||||||
if sys.platform == "win32" or sys.platform == "cygwin":
|
if sys.platform == "win32" or sys.platform == "cygwin":
|
||||||
script_ext = "bat"
|
script_ext = "bat"
|
||||||
else:
|
else:
|
||||||
script_ext = "sh"
|
script_ext = "sh"
|
||||||
|
|
||||||
searched_in = []
|
|
||||||
for b in search:
|
for b in search:
|
||||||
settings = os.path.join(full, "settings{0}.{1}".format(b, script_ext))
|
settings = os.path.join(full, "settings{0}.{1}".format(b, script_ext))
|
||||||
if os.path.exists(settings):
|
if os.path.exists(settings):
|
||||||
return settings
|
return settings
|
||||||
searched_in.append(settings)
|
|
||||||
|
|
||||||
raise OSError(
|
raise OSError("no Xilinx tools settings file found")
|
||||||
"no Xilinx tools settings file found.\n"
|
|
||||||
"Looked in:\n"
|
|
||||||
" " +
|
|
||||||
"\n ".join(searched_in))
|
|
||||||
|
|
||||||
|
|
||||||
class XilinxMultiRegImpl(MultiRegImpl):
|
class XilinxMultiRegImpl(MultiRegImpl):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
MultiRegImpl.__init__(self, *args, **kwargs)
|
MultiRegImpl.__init__(self, *args, **kwargs)
|
||||||
|
i = self.i
|
||||||
|
if not hasattr(i, "attr"):
|
||||||
|
i0, i = i, Signal()
|
||||||
|
self.comb += i.eq(i0)
|
||||||
|
self.regs[0].attr.add("mr_ff")
|
||||||
for r in self.regs:
|
for r in self.regs:
|
||||||
r.attr.add("async_reg")
|
r.attr.add("async_reg")
|
||||||
r.attr.add("no_shreg_extract")
|
r.attr.add("no_shreg_extract")
|
||||||
|
@ -103,12 +88,11 @@ class XilinxAsyncResetSynchronizerImpl(Module):
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("FDPE", p_INIT=1, i_D=0, i_PRE=async_reset,
|
Instance("FDPE", p_INIT=1, i_D=0, i_PRE=async_reset,
|
||||||
i_CE=1, i_C=cd.clk, o_Q=rst_meta,
|
i_CE=1, i_C=cd.clk, o_Q=rst_meta,
|
||||||
attr={"async_reg", "ars_ff"}),
|
attr={"async_reg", "ars_ff1"}),
|
||||||
Instance("FDPE", p_INIT=1, i_D=rst_meta, i_PRE=async_reset,
|
Instance("FDPE", p_INIT=1, i_D=rst_meta, i_PRE=async_reset,
|
||||||
i_CE=1, i_C=cd.clk, o_Q=cd.rst,
|
i_CE=1, i_C=cd.clk, o_Q=cd.rst,
|
||||||
attr={"async_reg", "ars_ff"})
|
attr={"async_reg", "ars_ff2"})
|
||||||
]
|
]
|
||||||
async_reset.attr.add("ars_false_path")
|
|
||||||
|
|
||||||
|
|
||||||
class XilinxAsyncResetSynchronizer:
|
class XilinxAsyncResetSynchronizer:
|
||||||
|
@ -139,27 +123,31 @@ class XilinxDifferentialOutput:
|
||||||
return XilinxDifferentialOutputImpl(dr.i, dr.o_p, dr.o_n)
|
return XilinxDifferentialOutputImpl(dr.i, dr.o_p, dr.o_n)
|
||||||
|
|
||||||
|
|
||||||
class XilinxDDROutputImpl(Module):
|
xilinx_special_overrides = {
|
||||||
|
MultiReg: XilinxMultiReg,
|
||||||
|
AsyncResetSynchronizer: XilinxAsyncResetSynchronizer,
|
||||||
|
DifferentialInput: XilinxDifferentialInput,
|
||||||
|
DifferentialOutput: XilinxDifferentialOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class XilinxDDROutputImplS6(Module):
|
||||||
def __init__(self, i1, i2, o, clk):
|
def __init__(self, i1, i2, o, clk):
|
||||||
self.specials += Instance("ODDR2",
|
self.specials += Instance("ODDR2",
|
||||||
p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC",
|
p_DDR_ALIGNMENT="C0", p_INIT=0, p_SRTYPE="SYNC",
|
||||||
i_C0=clk, i_C1=~clk, i_CE=1, i_S=0, i_R=0,
|
i_C0=clk, i_C1=~clk, i_CE=1, i_S=0, i_R=0,
|
||||||
i_D0=i1, i_D1=i2, o_Q=o,
|
i_D0=i1, i_D1=i2, o_Q=o,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class XilinxDDROutput:
|
class XilinxDDROutputS6:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def lower(dr):
|
def lower(dr):
|
||||||
return XilinxDDROutputImpl(dr.i1, dr.i2, dr.o, dr.clk)
|
return XilinxDDROutputImplS6(dr.i1, dr.i2, dr.o, dr.clk)
|
||||||
|
|
||||||
|
|
||||||
xilinx_special_overrides = {
|
xilinx_s6_special_overrides = {
|
||||||
MultiReg: XilinxMultiReg,
|
DDROutput: XilinxDDROutputS6
|
||||||
AsyncResetSynchronizer: XilinxAsyncResetSynchronizer,
|
|
||||||
DifferentialInput: XilinxDifferentialInput,
|
|
||||||
DifferentialOutput: XilinxDifferentialOutput,
|
|
||||||
DDROutput: XilinxDDROutput
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -178,6 +166,60 @@ class XilinxDDROutputS7:
|
||||||
return XilinxDDROutputImplS7(dr.i1, dr.i2, dr.o, dr.clk)
|
return XilinxDDROutputImplS7(dr.i1, dr.i2, dr.o, dr.clk)
|
||||||
|
|
||||||
|
|
||||||
|
class XilinxDDRInputImplS7(Module):
|
||||||
|
def __init__(self, i, o1, o2, clk):
|
||||||
|
self.specials += Instance("IDDR",
|
||||||
|
p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED",
|
||||||
|
i_C=clk, i_CE=1, i_S=0, i_R=0,
|
||||||
|
o_D=i, i_Q1=o1, i_Q2=o2,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class XilinxDDRInputS7:
|
||||||
|
@staticmethod
|
||||||
|
def lower(dr):
|
||||||
|
return XilinxDDRInputImplS7(dr.i, dr.o1, dr.o2, dr.clk)
|
||||||
|
|
||||||
|
|
||||||
xilinx_s7_special_overrides = {
|
xilinx_s7_special_overrides = {
|
||||||
DDROutput: XilinxDDROutputS7
|
DDROutput: XilinxDDROutputS7,
|
||||||
|
DDRInput: XilinxDDRInputS7
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class XilinxDDROutputImplKU(Module):
|
||||||
|
def __init__(self, i1, i2, o, clk):
|
||||||
|
self.specials += Instance("ODDRE1",
|
||||||
|
i_C=clk, i_SR=0,
|
||||||
|
i_D1=i1, i_D2=i2, o_Q=o,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class XilinxDDROutputKU:
|
||||||
|
@staticmethod
|
||||||
|
def lower(dr):
|
||||||
|
return XilinxDDROutputImplKU(dr.i1, dr.i2, dr.o, dr.clk)
|
||||||
|
|
||||||
|
|
||||||
|
class XilinxDDRInputImplKU(Module):
|
||||||
|
def __init__(self, i, o1, o2, clk):
|
||||||
|
self.specials += Instance("IDDRE1",
|
||||||
|
p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED",
|
||||||
|
p_IS_C_INVERTED=0,
|
||||||
|
i_D=i,
|
||||||
|
o_Q1=o1, o_Q2=o2,
|
||||||
|
i_C=clk, i_CB=~clk,
|
||||||
|
i_R=0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class XilinxDDRInputKU:
|
||||||
|
@staticmethod
|
||||||
|
def lower(dr):
|
||||||
|
return XilinxDDRInputImplKU(dr.i, dr.o1, dr.o2, dr.clk)
|
||||||
|
|
||||||
|
|
||||||
|
xilinx_ku_special_overrides = {
|
||||||
|
DDROutput: XilinxDDROutputKU,
|
||||||
|
DDRInput: XilinxDDRInputKU
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ synth_xilinx -top top -edif {build_name}.edif""".format(build_name=build_name)
|
||||||
|
|
||||||
|
|
||||||
def _run_ise(build_name, ise_path, source, mode, ngdbuild_opt,
|
def _run_ise(build_name, ise_path, source, mode, ngdbuild_opt,
|
||||||
bitgen_opt, ise_commands, map_opt, par_opt, ver=None):
|
toolchain, platform, ver=None):
|
||||||
if sys.platform == "win32" or sys.platform == "cygwin":
|
if sys.platform == "win32" or sys.platform == "cygwin":
|
||||||
source_cmd = "call "
|
source_cmd = "call "
|
||||||
script_ext = ".bat"
|
script_ext = ".bat"
|
||||||
|
@ -107,14 +107,24 @@ xst -ifn {build_name}.xst{fail_stmt}
|
||||||
|
|
||||||
build_script_contents += """
|
build_script_contents += """
|
||||||
ngdbuild {ngdbuild_opt} -uc {build_name}.ucf {build_name}.{ext} {build_name}.ngd{fail_stmt}
|
ngdbuild {ngdbuild_opt} -uc {build_name}.ucf {build_name}.{ext} {build_name}.ngd{fail_stmt}
|
||||||
|
"""
|
||||||
|
if mode == "cpld":
|
||||||
|
build_script_contents += """
|
||||||
|
cpldfit -ofmt verilog {par_opt} -p {device} {build_name}.ngd{fail_stmt}
|
||||||
|
taengine -f {build_name}.vm6 -detail -iopath -l {build_name}.tim{fail_stmt}
|
||||||
|
hprep6 -s IEEE1532 -i {build_name}.vm6{fail_stmt}
|
||||||
|
"""
|
||||||
|
else:
|
||||||
|
build_script_contents += """
|
||||||
map {map_opt} -o {build_name}_map.ncd {build_name}.ngd {build_name}.pcf{fail_stmt}
|
map {map_opt} -o {build_name}_map.ncd {build_name}.ngd {build_name}.pcf{fail_stmt}
|
||||||
par {par_opt} {build_name}_map.ncd {build_name}.ncd {build_name}.pcf{fail_stmt}
|
par {par_opt} {build_name}_map.ncd {build_name}.ncd {build_name}.pcf{fail_stmt}
|
||||||
bitgen {bitgen_opt} {build_name}.ncd {build_name}.bit{fail_stmt}
|
bitgen {bitgen_opt} {build_name}.ncd {build_name}.bit{fail_stmt}
|
||||||
"""
|
"""
|
||||||
build_script_contents = build_script_contents.format(build_name=build_name,
|
build_script_contents = build_script_contents.format(build_name=build_name,
|
||||||
ngdbuild_opt=ngdbuild_opt, bitgen_opt=bitgen_opt, ext=ext,
|
ngdbuild_opt=ngdbuild_opt, bitgen_opt=toolchain.bitgen_opt, ext=ext,
|
||||||
par_opt=par_opt, map_opt=map_opt, fail_stmt=fail_stmt)
|
par_opt=toolchain.par_opt, map_opt=toolchain.map_opt,
|
||||||
build_script_contents += ise_commands.format(build_name=build_name)
|
device=platform.device, fail_stmt=fail_stmt)
|
||||||
|
build_script_contents += toolchain.ise_commands.format(build_name=build_name)
|
||||||
build_script_file = "build_" + build_name + script_ext
|
build_script_file = "build_" + build_name + script_ext
|
||||||
tools.write_to_file(build_script_file, build_script_contents, force_unix=False)
|
tools.write_to_file(build_script_file, build_script_contents, force_unix=False)
|
||||||
command = shell + [build_script_file]
|
command = shell + [build_script_file]
|
||||||
|
@ -128,8 +138,9 @@ class XilinxISEToolchain:
|
||||||
"keep": ("keep", "true"),
|
"keep": ("keep", "true"),
|
||||||
"no_retiming": ("register_balancing", "no"),
|
"no_retiming": ("register_balancing", "no"),
|
||||||
"async_reg": None,
|
"async_reg": None,
|
||||||
"ars_ff": None,
|
"mr_ff": None,
|
||||||
"ars_false_path": None,
|
"ars_ff1": None,
|
||||||
|
"ars_ff2": None,
|
||||||
"no_shreg_extract": ("shreg_extract", "no")
|
"no_shreg_extract": ("shreg_extract", "no")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +156,7 @@ class XilinxISEToolchain:
|
||||||
self.ise_commands = ""
|
self.ise_commands = ""
|
||||||
|
|
||||||
def build(self, platform, fragment, build_dir="build", build_name="top",
|
def build(self, platform, fragment, build_dir="build", build_name="top",
|
||||||
toolchain_path=None, source=None, run=True, mode="xst", **kwargs):
|
toolchain_path=None, source=True, run=True, mode="xst", **kwargs):
|
||||||
if not isinstance(fragment, _Fragment):
|
if not isinstance(fragment, _Fragment):
|
||||||
fragment = fragment.get_fragment()
|
fragment = fragment.get_fragment()
|
||||||
if toolchain_path is None:
|
if toolchain_path is None:
|
||||||
|
@ -155,8 +166,6 @@ class XilinxISEToolchain:
|
||||||
toolchain_path = "/cygdrive/c/Xilinx"
|
toolchain_path = "/cygdrive/c/Xilinx"
|
||||||
else:
|
else:
|
||||||
toolchain_path = "/opt/Xilinx"
|
toolchain_path = "/opt/Xilinx"
|
||||||
if source is None:
|
|
||||||
source = sys.platform != "win32"
|
|
||||||
|
|
||||||
platform.finalize(fragment)
|
platform.finalize(fragment)
|
||||||
ngdbuild_opt = self.ngdbuild_opt
|
ngdbuild_opt = self.ngdbuild_opt
|
||||||
|
@ -166,31 +175,46 @@ class XilinxISEToolchain:
|
||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
os.chdir(build_dir)
|
os.chdir(build_dir)
|
||||||
try:
|
try:
|
||||||
if mode == "xst" or mode == "yosys":
|
if mode in ("xst", "yosys", "cpld"):
|
||||||
v_output = platform.get_verilog(fragment, name=build_name, **kwargs)
|
v_output = platform.get_verilog(fragment, name=build_name, **kwargs)
|
||||||
vns = v_output.ns
|
vns = v_output.ns
|
||||||
named_sc, named_pc = platform.resolve_signals(vns)
|
named_sc, named_pc = platform.resolve_signals(vns)
|
||||||
v_file = build_name + ".v"
|
v_file = build_name + ".v"
|
||||||
v_output.write(v_file)
|
v_output.write(v_file)
|
||||||
sources = platform.sources | {(v_file, "verilog", "work")}
|
sources = platform.sources | {(v_file, "verilog", "work")}
|
||||||
if mode == "xst":
|
if mode in ("xst", "cpld"):
|
||||||
_build_xst_files(platform.device, sources, platform.verilog_include_paths, build_name, self.xst_opt)
|
_build_xst_files(platform.device, sources, platform.verilog_include_paths, build_name, self.xst_opt)
|
||||||
isemode = "xst"
|
isemode = mode
|
||||||
else:
|
else:
|
||||||
_run_yosys(platform.device, sources, platform.verilog_include_paths, build_name)
|
_run_yosys(platform.device, sources, platform.verilog_include_paths, build_name)
|
||||||
isemode = "edif"
|
isemode = "edif"
|
||||||
ngdbuild_opt += "-p " + platform.device
|
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))
|
tools.write_to_file(build_name + ".ucf", _build_ucf(named_sc, named_pc))
|
||||||
if run:
|
if run:
|
||||||
_run_ise(build_name, toolchain_path, source, isemode,
|
_run_ise(build_name, toolchain_path, source, isemode,
|
||||||
ngdbuild_opt, self.bitgen_opt, self.ise_commands,
|
ngdbuild_opt, self, platform)
|
||||||
self.map_opt, self.par_opt)
|
|
||||||
finally:
|
finally:
|
||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
|
|
||||||
return vns
|
return vns
|
||||||
|
|
||||||
|
# ISE is broken and you must use *separate* TNM_NET objects for period
|
||||||
|
# constraints and other constraints otherwise it will be unable to trace
|
||||||
|
# them through clock objects like DCM and PLL objects.
|
||||||
|
|
||||||
def add_period_constraint(self, platform, clk, period):
|
def add_period_constraint(self, platform, clk, period):
|
||||||
platform.add_platform_command(
|
platform.add_platform_command(
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import os
|
|
||||||
|
|
||||||
from litex.build.generic_platform import GenericPlatform
|
from litex.build.generic_platform import GenericPlatform
|
||||||
from litex.build.xilinx import common, vivado, ise
|
from litex.build.xilinx import common, vivado, ise
|
||||||
|
|
||||||
|
@ -22,12 +20,18 @@ class XilinxPlatform(GenericPlatform):
|
||||||
|
|
||||||
def get_verilog(self, *args, special_overrides=dict(), **kwargs):
|
def get_verilog(self, *args, special_overrides=dict(), **kwargs):
|
||||||
so = dict(common.xilinx_special_overrides)
|
so = dict(common.xilinx_special_overrides)
|
||||||
|
if self.device[:3] == "xc6":
|
||||||
|
so.update(common.xilinx_s6_special_overrides)
|
||||||
if self.device[:3] == "xc7":
|
if self.device[:3] == "xc7":
|
||||||
so.update(common.xilinx_s7_special_overrides)
|
so.update(common.xilinx_s7_special_overrides)
|
||||||
|
if self.device[:4] == "xcku":
|
||||||
|
so.update(common.xilinx_ku_special_overrides)
|
||||||
so.update(special_overrides)
|
so.update(special_overrides)
|
||||||
return GenericPlatform.get_verilog(self, *args,
|
return GenericPlatform.get_verilog(self, *args,
|
||||||
special_overrides=so, attr_translate=self.toolchain.attr_translate, **kwargs)
|
special_overrides=so, attr_translate=self.toolchain.attr_translate, **kwargs)
|
||||||
|
|
||||||
|
def get_edif(self, fragment, **kwargs):
|
||||||
|
return GenericPlatform.get_edif(self, fragment, "UNISIMS", "Xilinx", self.device, **kwargs)
|
||||||
|
|
||||||
def build(self, *args, **kwargs):
|
def build(self, *args, **kwargs):
|
||||||
return self.toolchain.build(self, *args, **kwargs)
|
return self.toolchain.build(self, *args, **kwargs)
|
||||||
|
|
|
@ -6,6 +6,42 @@ from litex.build.generic_programmer import GenericProgrammer
|
||||||
from litex.build.xilinx import common
|
from litex.build.xilinx import common
|
||||||
|
|
||||||
|
|
||||||
|
def _run_urjtag(cmds):
|
||||||
|
with subprocess.Popen("jtag", stdin=subprocess.PIPE) as process:
|
||||||
|
process.stdin.write(cmds.encode("ASCII"))
|
||||||
|
process.communicate()
|
||||||
|
|
||||||
|
|
||||||
|
class UrJTAG(GenericProgrammer):
|
||||||
|
needs_bitreverse = True
|
||||||
|
|
||||||
|
def __init__(self, cable, flash_proxy_basename=None):
|
||||||
|
GenericProgrammer.__init__(self, flash_proxy_basename)
|
||||||
|
self.cable = cable
|
||||||
|
|
||||||
|
def load_bitstream(self, bitstream_file):
|
||||||
|
cmds = """cable {cable}
|
||||||
|
detect
|
||||||
|
pld load {bitstream}
|
||||||
|
quit
|
||||||
|
""".format(bitstream=bitstream_file, cable=self.cable)
|
||||||
|
_run_urjtag(cmds)
|
||||||
|
|
||||||
|
def flash(self, address, data_file):
|
||||||
|
flash_proxy = self.find_flash_proxy()
|
||||||
|
cmds = """cable {cable}
|
||||||
|
detect
|
||||||
|
pld load "{flash_proxy}"
|
||||||
|
initbus fjmem opcode=000010
|
||||||
|
frequency 6000000
|
||||||
|
detectflash 0
|
||||||
|
endian big
|
||||||
|
flashmem "{address}" "{data_file}" noverify
|
||||||
|
""".format(flash_proxy=flash_proxy, address=address, data_file=data_file,
|
||||||
|
cable=self.cable)
|
||||||
|
_run_urjtag(cmds)
|
||||||
|
|
||||||
|
|
||||||
class XC3SProg(GenericProgrammer):
|
class XC3SProg(GenericProgrammer):
|
||||||
needs_bitreverse = False
|
needs_bitreverse = False
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,9 @@ class XilinxVivadoToolchain:
|
||||||
"keep": ("dont_touch", "true"),
|
"keep": ("dont_touch", "true"),
|
||||||
"no_retiming": ("dont_touch", "true"),
|
"no_retiming": ("dont_touch", "true"),
|
||||||
"async_reg": ("async_reg", "true"),
|
"async_reg": ("async_reg", "true"),
|
||||||
"ars_ff": ("ars_ff", "true"), # user-defined attribute
|
"mr_ff": ("mr_ff", "true"), # user-defined attribute
|
||||||
"ars_false_path": ("ars_false_path", "true"), # user-defined attribute
|
"ars_ff1": ("ars_ff1", "true"), # user-defined attribute
|
||||||
|
"ars_ff2": ("ars_ff2", "true"), # user-defined attribute
|
||||||
"no_shreg_extract": None
|
"no_shreg_extract": None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,8 +95,7 @@ class XilinxVivadoToolchain:
|
||||||
|
|
||||||
def _build_batch(self, platform, sources, edifs, build_name):
|
def _build_batch(self, platform, sources, edifs, build_name):
|
||||||
tcl = []
|
tcl = []
|
||||||
tcl.append("create_property ars_ff cell")
|
tcl.append("create_project -force -name {} -part {}".format(build_name, platform.device))
|
||||||
tcl.append("create_property ars_false_path net")
|
|
||||||
for filename, language, library in sources:
|
for filename, language, library in sources:
|
||||||
filename_tcl = "{" + filename + "}"
|
filename_tcl = "{" + filename + "}"
|
||||||
tcl.append("add_files " + filename_tcl)
|
tcl.append("add_files " + filename_tcl)
|
||||||
|
@ -111,7 +111,6 @@ class XilinxVivadoToolchain:
|
||||||
tcl.append("synth_design -top {} -part {} -include_dirs {{{}}}".format(build_name, platform.device, " ".join(platform.verilog_include_paths)))
|
tcl.append("synth_design -top {} -part {} -include_dirs {{{}}}".format(build_name, platform.device, " ".join(platform.verilog_include_paths)))
|
||||||
else:
|
else:
|
||||||
tcl.append("synth_design -top {} -part {}".format(build_name, platform.device))
|
tcl.append("synth_design -top {} -part {}".format(build_name, platform.device))
|
||||||
tcl.append("write_checkpoint -force {}_synth.dcp".format(build_name))
|
|
||||||
tcl.append("report_timing_summary -file {}_timing_synth.rpt".format(build_name))
|
tcl.append("report_timing_summary -file {}_timing_synth.rpt".format(build_name))
|
||||||
tcl.append("report_utilization -hierarchical -file {}_utilization_hierarchical_synth.rpt".format(build_name))
|
tcl.append("report_utilization -hierarchical -file {}_utilization_hierarchical_synth.rpt".format(build_name))
|
||||||
tcl.append("report_utilization -file {}_utilization_synth.rpt".format(build_name))
|
tcl.append("report_utilization -file {}_utilization_synth.rpt".format(build_name))
|
||||||
|
@ -119,11 +118,9 @@ class XilinxVivadoToolchain:
|
||||||
tcl.append("place_design")
|
tcl.append("place_design")
|
||||||
if self.with_phys_opt:
|
if self.with_phys_opt:
|
||||||
tcl.append("phys_opt_design -directive AddRetime")
|
tcl.append("phys_opt_design -directive AddRetime")
|
||||||
tcl.append("write_checkpoint -force {}_place.dcp".format(build_name))
|
|
||||||
tcl.append("report_utilization -hierarchical -file {}_utilization_hierarchical_place.rpt".format(build_name))
|
tcl.append("report_utilization -hierarchical -file {}_utilization_hierarchical_place.rpt".format(build_name))
|
||||||
tcl.append("report_utilization -file {}_utilization_place.rpt".format(build_name))
|
tcl.append("report_utilization -file {}_utilization_place.rpt".format(build_name))
|
||||||
tcl.append("report_io -file {}_io.rpt".format(build_name))
|
tcl.append("report_io -file {}_io.rpt".format(build_name))
|
||||||
tcl.append("write_csv -force {}_tracelength.csv".format(build_name))
|
|
||||||
tcl.append("report_control_sets -verbose -file {}_control_sets.rpt".format(build_name))
|
tcl.append("report_control_sets -verbose -file {}_control_sets.rpt".format(build_name))
|
||||||
tcl.append("report_clock_utilization -file {}_clock_utilization.rpt".format(build_name))
|
tcl.append("report_clock_utilization -file {}_clock_utilization.rpt".format(build_name))
|
||||||
tcl.append("route_design")
|
tcl.append("route_design")
|
||||||
|
@ -147,12 +144,11 @@ class XilinxVivadoToolchain:
|
||||||
" [get_nets {clk}]", clk=clk)
|
" [get_nets {clk}]", clk=clk)
|
||||||
for from_, to in sorted(self.false_paths,
|
for from_, to in sorted(self.false_paths,
|
||||||
key=lambda x: (x[0].duid, x[1].duid)):
|
key=lambda x: (x[0].duid, x[1].duid)):
|
||||||
if (from_ not in self.clocks
|
|
||||||
or to not in self.clocks):
|
|
||||||
raise ValueError("Vivado requires period "
|
|
||||||
"constraints on all clocks used in false paths")
|
|
||||||
platform.add_platform_command(
|
platform.add_platform_command(
|
||||||
"set_false_path -from [get_clocks {from_}] -to [get_clocks {to}]",
|
"set_clock_groups "
|
||||||
|
"-group [get_clocks -include_generated_clocks -of [get_nets {from_}]] "
|
||||||
|
"-group [get_clocks -include_generated_clocks -of [get_nets {to}]] "
|
||||||
|
"-asynchronous",
|
||||||
from_=from_, to=to)
|
from_=from_, to=to)
|
||||||
|
|
||||||
# make sure add_*_constraint cannot be used again
|
# make sure add_*_constraint cannot be used again
|
||||||
|
@ -160,30 +156,30 @@ class XilinxVivadoToolchain:
|
||||||
del self.false_paths
|
del self.false_paths
|
||||||
|
|
||||||
def _constrain(self, platform):
|
def _constrain(self, platform):
|
||||||
|
# The asynchronous input to a MultiReg is a false path
|
||||||
|
platform.add_platform_command(
|
||||||
|
"set_false_path -quiet "
|
||||||
|
"-to [get_nets -filter {{mr_ff == TRUE}}]"
|
||||||
|
)
|
||||||
# The asychronous reset input to the AsyncResetSynchronizer is a false
|
# The asychronous reset input to the AsyncResetSynchronizer is a false
|
||||||
# path
|
# path
|
||||||
platform.add_platform_command(
|
platform.add_platform_command(
|
||||||
"set_false_path -quiet "
|
"set_false_path -quiet "
|
||||||
"-through [get_nets -hier -filter {{ars_false_path==true}}] "
|
"-to [get_pins -filter {{REF_PIN_NAME == PRE}} "
|
||||||
"-to [get_cells -hier -filter {{ars_ff==true}}]"
|
"-of [get_cells -filter {{ars_ff1 == TRUE || ars_ff2 == TRUE}}]]"
|
||||||
)
|
)
|
||||||
# clock_period-2ns to resolve metastability on the wire between the
|
# clock_period-2ns to resolve metastability on the wire between the
|
||||||
# AsyncResetSynchronizer FFs
|
# AsyncResetSynchronizer FFs
|
||||||
platform.add_platform_command(
|
platform.add_platform_command(
|
||||||
"set_max_delay 2 -quiet "
|
"set_max_delay 2 -quiet "
|
||||||
"-from [get_cells -hier -filter {{ars_ff==true}}] "
|
"-from [get_pins -filter {{REF_PIN_NAME == Q}} "
|
||||||
"-to [get_cells -hier -filter {{ars_ff==true}}]"
|
"-of [get_cells -filter {{ars_ff1 == TRUE}}]] "
|
||||||
|
"-to [get_pins -filter {{REF_PIN_NAME == D}} "
|
||||||
|
"-of [get_cells -filter {{ars_ff2 == TRUE}}]]"
|
||||||
)
|
)
|
||||||
|
|
||||||
def build(self, platform, fragment, build_dir="build", build_name="top",
|
def build(self, platform, fragment, build_dir="build", build_name="top",
|
||||||
toolchain_path=None, source=True, run=True, **kwargs):
|
toolchain_path="/opt/Xilinx/Vivado", source=True, run=True, **kwargs):
|
||||||
if toolchain_path is None:
|
|
||||||
if sys.platform == "win32":
|
|
||||||
toolchain_path = "C:\\Xilinx"
|
|
||||||
elif sys.platform == "cygwin":
|
|
||||||
toolchain_path = "/cygdrive/c/Xilinx"
|
|
||||||
else:
|
|
||||||
toolchain_path = "/opt/Xilinx"
|
|
||||||
os.makedirs(build_dir, exist_ok=True)
|
os.makedirs(build_dir, exist_ok=True)
|
||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
os.chdir(build_dir)
|
os.chdir(build_dir)
|
||||||
|
@ -214,4 +210,5 @@ class XilinxVivadoToolchain:
|
||||||
self.clocks[clk] = period
|
self.clocks[clk] = period
|
||||||
|
|
||||||
def add_false_path_constraint(self, platform, from_, to):
|
def add_false_path_constraint(self, platform, from_, to):
|
||||||
|
if (to, from_) not in self.false_paths:
|
||||||
self.false_paths.add((from_, to))
|
self.false_paths.add((from_, to))
|
||||||
|
|
Loading…
Reference in New Issue