class USBBlaster(GenericProgrammer):
needs_bitreverse = False
- def load_bitstream(self, bitstream_file, port=0):
- usb_port = "[USB-{}]".format(port)
+ def load_bitstream(self, bitstream_file, cable_suffix=""):
subprocess.call(["quartus_pgm", "-m", "jtag", "-c",
- "USB-Blaster{}".format(usb_port), "-o",
+ "USB-Blaster{}".format(cable_suffix), "-o",
"p;{}".format(bitstream_file)])
self.constraint_manager.get_io_signals(),
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):
raise NotImplementedError("GenericPlatform.build must be overloaded")
fullname = os.path.join(fulldir, self.flash_proxy_basename)
if os.path.exists(fullname):
return fullname
- raise OSError(
- "Failed to find flash proxy bitstream %s, searched:\n %s\n" % (
- self.flash_proxy_basename,
- "\n ".join(self.flash_proxy_dirs)))
+ raise OSError("Failed to find flash proxy bitstream")
# must be overloaded by specific programmer
def load_bitstream(self, bitstream_file):
def _run_icestorm(source, build_template, build_name, pnr_pkg_opts,
icetime_pkg_opts, icetime_constraint):
if sys.platform == "win32" or sys.platform == "cygwin":
- source_cmd = "call "
script_ext = ".bat"
shell = ["cmd", "/c"]
build_script_contents = "@echo off\nrem Autogenerated by LiteX\n"
fail_stmt = " || exit /b"
else:
- source_cmd = "source "
script_ext = ".sh"
shell = ["bash"]
build_script_contents = "# Autogenerated by LiteX\nset -e\n"
"lp8k": ["cm81", "cm81:4k", "cm121", "cm121:4k", "cm225",
"cm225:4k"],
"hx8k": ["cb132", "cb132:4k", "tq144:4k", "cm225", "ct256"],
+ "up5k": ["sg48"],
}
(family, series_size, package) = device_str.split("-")
if family not in ["ice40"]:
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")
if package not in valid_packages[series_size]:
raise ValueError("Invalid device package")
newline = None
if force_unix:
newline = "\n"
- if os.path.exists(filename):
- if open(filename, "r", newline=newline).read() == contents:
- return
with open(filename, "w", newline=newline) as f:
f.write(contents)
continue
-def sub_rules(lines, rules, max_matches=1):
- for line in lines:
- n = max_matches
- for pattern, color in rules:
- line, m = re.subn(pattern, color, line, n)
- n -= m
- if not n:
- break
- yield line
+def sub_rules(line, rules, max_matches=1):
+ for pattern, color in rules:
+ line, matches = re.subn(pattern, color, line, max_matches)
+ max_matches -= matches
+ if not max_matches:
+ break
+ return line
def subprocess_call_filtered(command, rules, *, max_matches=1, **kwargs):
- proc = subprocess.Popen(command, stdout=subprocess.PIPE,
- universal_newlines=True, bufsize=1,
- **kwargs)
- with proc:
- for line in sub_rules(iter(proc.stdout.readline, ""),
- rules, max_matches):
- sys.stdout.write(line)
- return proc.returncode
+ with subprocess.Popen(command, stdout=subprocess.PIPE,
+ universal_newlines=True, bufsize=1,
+ **kwargs) as proc:
+ with open(proc.stdout.fileno(), errors="ignore", closefd=False) as stdout:
+ for line in stdout:
+ print(sub_rules(line, rules, max_matches), end="")
+ return proc.wait()
import sys
try:
import colorama
- # install escape sequence translation on Windows
- if os.getenv("COLORAMA", "") == "force":
- colorama.init(strip=False)
- else:
- colorama.init()
+ colorama.init() # install escape sequence translation on Windows
_have_colorama = True
except ImportError:
_have_colorama = False
]
-def settings(path, name=None, ver=None, first=None):
- if first == "version":
- if not ver:
- vers = tools.versions(path)
- ver = max(vers)
-
- full = os.path.join(path, str(ver), name)
-
- elif first == "name":
- path = os.path.join(path, name)
+def settings(path, ver=None, sub=None):
+ if ver is None:
+ vers = list(tools.versions(path))
+ if not vers:
+ raise OSError("no version directory for Xilinx tools found in "
+ + path)
+ ver = max(vers)
- if not ver:
- vers = tools.versions(path)
- ver = max(vers)
-
- full = os.path.join(path, str(ver))
-
- if not vers:
- raise OSError(
- "no version directory for Xilinx tools found in {}".format(
- path))
+ full = os.path.join(path, str(ver))
+ if sub:
+ full = os.path.join(full, sub)
search = [64, 32]
if tools.arch_bits() == 32:
- search = [32]
+ search.reverse()
if sys.platform == "win32" or sys.platform == "cygwin":
script_ext = "bat"
else:
script_ext = "sh"
- searched_in = []
for b in search:
settings = os.path.join(full, "settings{0}.{1}".format(b, script_ext))
if os.path.exists(settings):
return settings
- searched_in.append(settings)
- raise OSError(
- "no Xilinx tools settings file found.\n"
- "Looked in:\n"
- " " +
- "\n ".join(searched_in))
+ raise OSError("no Xilinx tools settings file found")
class XilinxMultiRegImpl(MultiRegImpl):
def __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:
r.attr.add("async_reg")
r.attr.add("no_shreg_extract")
self.specials += [
Instance("FDPE", p_INIT=1, i_D=0, i_PRE=async_reset,
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,
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:
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):
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_D0=i1, i_D1=i2, o_Q=o,
)
-class XilinxDDROutput:
+class XilinxDDROutputS6:
@staticmethod
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 = {
- MultiReg: XilinxMultiReg,
- AsyncResetSynchronizer: XilinxAsyncResetSynchronizer,
- DifferentialInput: XilinxDifferentialInput,
- DifferentialOutput: XilinxDifferentialOutput,
- DDROutput: XilinxDDROutput
+xilinx_s6_special_overrides = {
+ DDROutput: XilinxDDROutputS6
}
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 = {
- 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
}
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":
source_cmd = "call "
script_ext = ".bat"
build_script_contents += """
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}
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}
"""
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, fail_stmt=fail_stmt)
- build_script_contents += ise_commands.format(build_name=build_name)
+ ngdbuild_opt=ngdbuild_opt, bitgen_opt=toolchain.bitgen_opt, ext=ext,
+ par_opt=toolchain.par_opt, map_opt=toolchain.map_opt,
+ 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
tools.write_to_file(build_script_file, build_script_contents, force_unix=False)
command = shell + [build_script_file]
"keep": ("keep", "true"),
"no_retiming": ("register_balancing", "no"),
"async_reg": None,
- "ars_ff": None,
- "ars_false_path": None,
+ "mr_ff": None,
+ "ars_ff1": None,
+ "ars_ff2": None,
"no_shreg_extract": ("shreg_extract", "no")
}
self.ise_commands = ""
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):
fragment = fragment.get_fragment()
if toolchain_path is None:
toolchain_path = "/cygdrive/c/Xilinx"
else:
toolchain_path = "/opt/Xilinx"
- if source is None:
- source = sys.platform != "win32"
platform.finalize(fragment)
ngdbuild_opt = self.ngdbuild_opt
cwd = os.getcwd()
os.chdir(build_dir)
try:
- if mode == "xst" or mode == "yosys":
+ if mode in ("xst", "yosys", "cpld"):
v_output = platform.get_verilog(fragment, name=build_name, **kwargs)
vns = v_output.ns
named_sc, named_pc = platform.resolve_signals(vns)
v_file = build_name + ".v"
v_output.write(v_file)
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)
- isemode = "xst"
+ isemode = mode
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, toolchain_path, source, isemode,
- ngdbuild_opt, self.bitgen_opt, self.ise_commands,
- self.map_opt, self.par_opt)
+ ngdbuild_opt, self, platform)
finally:
os.chdir(cwd)
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):
platform.add_platform_command(
"""
-import os
-
from litex.build.generic_platform import GenericPlatform
from litex.build.xilinx import common, vivado, ise
def get_verilog(self, *args, special_overrides=dict(), **kwargs):
so = dict(common.xilinx_special_overrides)
+ if self.device[:3] == "xc6":
+ so.update(common.xilinx_s6_special_overrides)
if self.device[:3] == "xc7":
so.update(common.xilinx_s7_special_overrides)
+ if self.device[:4] == "xcku":
+ so.update(common.xilinx_ku_special_overrides)
so.update(special_overrides)
return GenericPlatform.get_verilog(self, *args,
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):
return self.toolchain.build(self, *args, **kwargs)
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):
needs_bitreverse = False
"keep": ("dont_touch", "true"),
"no_retiming": ("dont_touch", "true"),
"async_reg": ("async_reg", "true"),
- "ars_ff": ("ars_ff", "true"), # user-defined attribute
- "ars_false_path": ("ars_false_path", "true"), # user-defined attribute
+ "mr_ff": ("mr_ff", "true"), # user-defined attribute
+ "ars_ff1": ("ars_ff1", "true"), # user-defined attribute
+ "ars_ff2": ("ars_ff2", "true"), # user-defined attribute
"no_shreg_extract": None
}
def _build_batch(self, platform, sources, edifs, build_name):
tcl = []
- tcl.append("create_property ars_ff cell")
- tcl.append("create_property ars_false_path net")
+ tcl.append("create_project -force -name {} -part {}".format(build_name, platform.device))
for filename, language, library in sources:
filename_tcl = "{" + filename + "}"
tcl.append("add_files " + filename_tcl)
tcl.append("synth_design -top {} -part {} -include_dirs {{{}}}".format(build_name, platform.device, " ".join(platform.verilog_include_paths)))
else:
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_utilization -hierarchical -file {}_utilization_hierarchical_synth.rpt".format(build_name))
tcl.append("report_utilization -file {}_utilization_synth.rpt".format(build_name))
tcl.append("place_design")
if self.with_phys_opt:
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 -file {}_utilization_place.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_clock_utilization -file {}_clock_utilization.rpt".format(build_name))
tcl.append("route_design")
" [get_nets {clk}]", clk=clk)
for from_, to in sorted(self.false_paths,
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(
- "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)
# make sure add_*_constraint cannot be used again
del self.false_paths
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
# path
platform.add_platform_command(
"set_false_path -quiet "
- "-through [get_nets -hier -filter {{ars_false_path==true}}] "
- "-to [get_cells -hier -filter {{ars_ff==true}}]"
+ "-to [get_pins -filter {{REF_PIN_NAME == PRE}} "
+ "-of [get_cells -filter {{ars_ff1 == TRUE || ars_ff2 == TRUE}}]]"
)
# clock_period-2ns to resolve metastability on the wire between the
# AsyncResetSynchronizer FFs
platform.add_platform_command(
"set_max_delay 2 -quiet "
- "-from [get_cells -hier -filter {{ars_ff==true}}] "
- "-to [get_cells -hier -filter {{ars_ff==true}}]"
+ "-from [get_pins -filter {{REF_PIN_NAME == Q}} "
+ "-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",
- toolchain_path=None, 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"
+ toolchain_path="/opt/Xilinx/Vivado", source=True, run=True, **kwargs):
os.makedirs(build_dir, exist_ok=True)
cwd = os.getcwd()
os.chdir(build_dir)
self.clocks[clk] = period
def add_false_path_constraint(self, platform, from_, to):
- self.false_paths.add((from_, to))
+ if (to, from_) not in self.false_paths:
+ self.false_paths.add((from_, to))