diff --git a/mibuild/altera/platform.py b/mibuild/altera/platform.py index 7023581f9..1cbf2a193 100644 --- a/mibuild/altera/platform.py +++ b/mibuild/altera/platform.py @@ -15,7 +15,8 @@ class AlteraPlatform(GenericPlatform): def get_verilog(self, *args, special_overrides=dict(), **kwargs): so = dict(common.altera_special_overrides) so.update(special_overrides) - return GenericPlatform.get_verilog(self, *args, special_overrides=so, **kwargs) + return GenericPlatform.get_verilog(self, *args, special_overrides=so, + **kwargs) def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) diff --git a/mibuild/altera/programmer.py b/mibuild/altera/programmer.py index e2e2cae50..77a24cc0d 100644 --- a/mibuild/altera/programmer.py +++ b/mibuild/altera/programmer.py @@ -7,5 +7,7 @@ class USBBlaster(GenericProgrammer): needs_bitreverse = False def load_bitstream(self, bitstream_file, port=0): - usb_port = "[USB-"+str(port) + "]" - subprocess.call(["quartus_pgm", "-m", "jtag", "-c", "USB-Blaster" + usb_port, "-o", "p;" + bitstream_file]) + usb_port = "[USB-{}]".format(port) + subprocess.call(["quartus_pgm", "-m", "jtag", "-c", + "USB-Blaster{}".format(usb_port), "-o", + "p;{}".format(bitstream_file)]) diff --git a/mibuild/altera/quartus.py b/mibuild/altera/quartus.py index 9e29f6f3f..ad5f50b1b 100644 --- a/mibuild/altera/quartus.py +++ b/mibuild/altera/quartus.py @@ -5,60 +5,90 @@ import os import subprocess from migen.fhdl.structure import _Fragment -from mibuild.generic_platform import * +from mibuild.generic_platform import (Pins, IOStandard, Misc) from mibuild import tools -from mibuild.xilinx import common -def _format_constraint(c): +def _format_constraint(c, signame, fmt_r): if isinstance(c, Pins): - return "set_location_assignment PIN_" + c.identifiers[0] + return "set_location_assignment -comment \"{name}\" " \ + "-to {signame} Pin_{pin}".format( + signame=signame, + name=fmt_r, + pin=c.identifiers[0]) elif isinstance(c, IOStandard): - return "set_instance_assignment -name IO_STANDARD " + "\"" + c.name + "\"" + return "set_instance_assignment -name io_standard " \ + "-comment \"{name}\" \"{std}\" -to {signame}".format( + signame=signame, + name=fmt_r, + std=c.name) elif isinstance(c, Misc): - return c.misc + if not isinstance(c.misc, str) and len(c.misc) == 2: + return "set_instance_assignment -comment \"{name}\" " \ + "-name {misc[0]} \"{misc[1]}\" -to {signame}".format( + signame=signame, + name=fmt_r, + misc=c.misc) + else: + return "set_instance_assignment -comment \"{name}\" " \ + "-name {misc} " \ + "-to {signame}".format( + signame=signame, + name=fmt_r, + misc=c.misc) def _format_qsf(signame, pin, others, resname): - fmt_c = [_format_constraint(c) for c in ([Pins(pin)] + others)] - fmt_r = resname[0] + ":" + str(resname[1]) + fmt_r = "{}:{}".format(*resname[:2]) if resname[2] is not None: fmt_r += "." + resname[2] - r = "" - for c in fmt_c: - r += c + " -to " + signame + " # " + fmt_r + "\n" - return r + + fmt_c = [_format_constraint(c, signame, fmt_r) for c in + ([Pins(pin)] + others)] + + return '\n'.join(fmt_c) def _build_qsf(named_sc, named_pc): - r = "" + lines = [] for sig, pins, others, resname in named_sc: if len(pins) > 1: for i, p in enumerate(pins): - r += _format_qsf(sig + "[" + str(i) + "]", p, others, resname) + lines.append( + _format_qsf("{}[{}]".format(sig, i), p, others, resname)) else: - r += _format_qsf(sig, pins[0], others, resname) + lines.append(_format_qsf(sig, pins[0], others, resname)) + if named_pc: - r += "\n" + "\n\n".join(named_pc) - r += "set_global_assignment -name top_level_entity top\n" - return r + lines.append("") + lines.append("\n\n".join(named_pc)) + + lines.append("set_global_assignment -name top_level_entity top") + return "\n".join(lines) def _build_files(device, sources, vincpaths, named_sc, named_pc, build_name): - qsf_contents = "" + lines = [] for filename, language, library in sources: - # Enforce use of SystemVerilog (Quartus does not support global parameters in Verilog) + # Enforce use of SystemVerilog + # (Quartus does not support global parameters in Verilog) if language == "verilog": language = "systemverilog" - qsf_contents += "set_global_assignment -name " + language.upper() + "_FILE " + filename + " -library " + library + " \n" + lines.append( + "set_global_assignment -name {lang}_FILE {path} " + "-library {lib}".format( + lang=language.upper(), + path=filename.replace("\\", "/"), + lib=library)) for path in vincpaths: - qsf_contents += "set_global_assignment -name SEARCH_PATH " + path + "\n" + lines.append("set_global_assignment -name SEARCH_PATH {}".format( + path.replace("\\", "/"))) - qsf_contents += _build_qsf(named_sc, named_pc) - qsf_contents += "set_global_assignment -name DEVICE " + device - tools.write_to_file(build_name + ".qsf", qsf_contents) + lines.append(_build_qsf(named_sc, named_pc)) + lines.append("set_global_assignment -name DEVICE {}".format(device)) + tools.write_to_file("{}.qsf".format(build_name), "\n".join(lines)) def _run_quartus(build_name, quartus_path): @@ -69,18 +99,19 @@ quartus_fit --read_settings_files=off --write_settings_files=off {build_name} -c quartus_asm --read_settings_files=off --write_settings_files=off {build_name} -c {build_name} quartus_sta {build_name} -c {build_name} -""".format(build_name=build_name) +""".format(build_name=build_name) # noqa build_script_file = "build_" + build_name + ".sh" - tools.write_to_file(build_script_file, build_script_contents, force_unix=True) + tools.write_to_file(build_script_file, + build_script_contents, + force_unix=True) - r = subprocess.call(["bash", build_script_file]) - if r != 0: + if subprocess.call(["bash", build_script_file]): raise OSError("Subprocess failed") class AlteraQuartusToolchain: def build(self, platform, fragment, build_dir="build", build_name="top", - quartus_path="/opt/Altera", run=True): + quartus_path="/opt/Altera", run=True): tools.mkdir_noerror(build_dir) os.chdir(build_dir) @@ -93,7 +124,12 @@ class AlteraQuartusToolchain: 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, named_sc, named_pc, build_name) + _build_files(platform.device, + sources, + platform.verilog_include_paths, + named_sc, + named_pc, + build_name) if run: _run_quartus(build_name, quartus_path) @@ -103,5 +139,11 @@ class AlteraQuartusToolchain: def add_period_constraint(self, platform, clk, period): # TODO: handle differential clk - platform.add_platform_command("""set_global_assignment -name DUTY_CYCLE 50 -section_id {clk}""", clk=clk) - platform.add_platform_command("""set_global_assignment -name FMAX_REQUIREMENT "{freq} MHz" -section_id {clk}\n""".format(freq=str(float(1/period)*1000), clk="{clk}"), clk=clk) + platform.add_platform_command( + "set_global_assignment -name duty_cycle 50 -section_id {clk}", + clk=clk) + platform.add_platform_command( + "set_global_assignment -name fmax_requirement \"{freq} MHz\" " + "-section_id {clk}".format(freq=(1. / period) * 1000, + clk="{clk}"), + clk=clk) diff --git a/mibuild/generic_platform.py b/mibuild/generic_platform.py index 0e50e11a1..04d4b3b4a 100644 --- a/mibuild/generic_platform.py +++ b/mibuild/generic_platform.py @@ -1,8 +1,7 @@ import os import sys -from migen.fhdl.std import * -from migen.fhdl.structure import _Fragment +from migen.fhdl.std import Signal from migen.genlib.record import Record from migen.genlib.io import CRG from migen.fhdl import verilog, edif @@ -21,38 +20,60 @@ class Pins: for i in identifiers: self.identifiers += i.split() + def __repr__(self): + return "{}('{}')".format(self.__class__.__name__, + " ".join(self.identifiers)) + class IOStandard: def __init__(self, name): self.name = name + def __repr__(self): + return "{}('{}')".format(self.__class__.__name__, self.name) + class Drive: def __init__(self, strength): self.strength = strength + def __repr__(self): + return "{}('{}')".format(self.__class__.__name__, self.strength) + class Misc: def __init__(self, misc): self.misc = misc + def __repr__(self): + return "{}({})".format(self.__class__.__name__, repr(self.misc)) + class Subsignal: def __init__(self, name, *constraints): self.name = name self.constraints = list(constraints) + def __repr__(self): + return "{}('{}', {})".format( + self.__class__.__name__, + self.name, + ", ".join([repr(constr) for constr in self.constraints])) + class PlatformInfo: def __init__(self, info): self.info = info + def __repr__(self): + return "{}({})".format(self.__class__.__name__, repr(self.info)) + def _lookup(description, name, number): for resource in description: if resource[0] == name and (number is None or resource[1] == number): return resource - raise ConstraintError("Resource not found: " + name + ":" + str(number)) + raise ConstraintError("Resource not found: {}:{}".format(name, number)) def _resource_type(resource): @@ -64,13 +85,16 @@ def _resource_type(resource): elif isinstance(element, Subsignal): if t is None: t = [] + assert(isinstance(t, list)) n_bits = None for c in element.constraints: if isinstance(c, Pins): assert(n_bits is None) n_bits = len(c.identifiers) + t.append((element.name, n_bits)) + return t @@ -89,9 +113,11 @@ class ConnectorManager: pin_list = connector[1] else: raise ValueError("Unsupported pin list type {} for connector" - " {}".format(type(connector[1]), conn_name)) + " {}".format(type(connector[1]), conn_name)) if conn_name in self.connector_table: - raise ValueError("Connector specified more than once: "+conn_name) + raise ValueError( + "Connector specified more than once: {}".format(conn_name)) + self.connector_table[conn_name] = pin_list def resolve_identifiers(self, identifiers): @@ -101,9 +127,11 @@ class ConnectorManager: conn, pn = identifier.split(":") if pn.isdigit(): pn = int(pn) + r.append(self.connector_table[conn][pn]) else: r.append(identifier) + return r @@ -116,6 +144,7 @@ def _separate_pins(constraints): pins = c.identifiers else: others.append(c) + return pins, others @@ -136,19 +165,23 @@ class ConstraintManager: obj = Signal(rt, name_override=resource[0]) else: obj = Record(rt, name=resource[0]) + for element in resource[2:]: if isinstance(element, PlatformInfo): obj.platform_info = element.info break + self.available.remove(resource) self.matched.append((resource, obj)) return obj def lookup_request(self, name, number=None): for resource, obj in self.matched: - if resource[0] == name and (number is None or resource[1] == number): + if resource[0] == name and (number is None or + resource[1] == number): return obj - raise ConstraintError("Resource not found: " + name + ":" + str(number)) + + raise ConstraintError("Resource not found: {}:{}".format(name, number)) def add_platform_command(self, command, **signals): self.platform_commands.append((command, signals)) @@ -160,6 +193,7 @@ class ConstraintManager: r.add(obj) else: r.update(obj.flatten()) + return r def get_sig_constraints(self): @@ -174,17 +208,21 @@ class ConstraintManager: has_subsignals = True else: top_constraints.append(element) + if has_subsignals: for element in resource[2:]: if isinstance(element, Subsignal): sig = getattr(obj, element.name) - pins, others = _separate_pins(top_constraints + element.constraints) + pins, others = _separate_pins(top_constraints + + element.constraints) pins = self.connector_manager.resolve_identifiers(pins) - r.append((sig, pins, others, (name, number, element.name))) + r.append((sig, pins, others, + (name, number, element.name))) else: pins, others = _separate_pins(top_constraints) pins = self.connector_manager.resolve_identifiers(pins) r.append((obj, pins, others, (name, number, None))) + return r def get_platform_commands(self): @@ -223,27 +261,35 @@ class GenericPlatform: # if none exists, create a default clock domain and drive it if not fragment.clock_domains: if not hasattr(self, "default_clk_name"): - raise NotImplementedError("No default clock and no clock domain defined") + raise NotImplementedError( + "No default clock and no clock domain defined") crg = CRG(self.request(self.default_clk_name)) fragment += crg.get_fragment() + self.do_finalize(fragment, *args, **kwargs) self.finalized = True def do_finalize(self, fragment, *args, **kwargs): - """overload this and e.g. add_platform_command()'s after the modules had their say""" + """overload this and e.g. add_platform_command()'s after the modules + had their say""" if hasattr(self, "default_clk_period"): try: - self.add_period_constraint(self.lookup_request(self.default_clk_name), self.default_clk_period) + self.add_period_constraint( + self.lookup_request(self.default_clk_name), + self.default_clk_period) except ConstraintError: pass def add_source(self, filename, language=None, library=None): if language is None: language = tools.language_by_filename(filename) + if language is None: language = "verilog" # default to Verilog + if library is None: library = "work" # default to work + filename = os.path.abspath(filename) if sys.platform == "win32" or sys.platform == "cygwin": filename = filename.replace("\\", "/") @@ -277,20 +323,28 @@ class GenericPlatform: def resolve_signals(self, vns): # resolve signal names in constraints sc = self.constraint_manager.get_sig_constraints() - named_sc = [(vns.get_name(sig), pins, others, resource) for sig, pins, others, resource in sc] + named_sc = [(vns.get_name(sig), pins, others, resource) + for sig, pins, others, resource in sc] # resolve signal names in platform commands pc = self.constraint_manager.get_platform_commands() named_pc = [] for template, args in pc: name_dict = dict((k, vns.get_name(sig)) for k, sig in args.items()) named_pc.append(template.format(**name_dict)) + return named_sc, named_pc def get_verilog(self, fragment, **kwargs): - return verilog.convert(fragment, self.constraint_manager.get_io_signals(), create_clock_domains=False, **kwargs) + return verilog.convert( + fragment, + 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) + 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") @@ -298,9 +352,10 @@ class GenericPlatform: def build_cmdline(self, *args, **kwargs): arg = sys.argv[1:] if len(arg) % 2: - print("Missing value for option: "+sys.argv[-1]) + print("Missing value for option: {}".format(sys.argv[-1])) sys.exit(1) - argdict = dict((k, autotype(v)) for k, v in zip(*[iter(arg)]*2)) + + argdict = dict((k, autotype(v)) for k, v in zip(*[iter(arg)] * 2)) kwargs.update(argdict) self.build(*args, **kwargs)