--- /dev/null
+from migen.fhdl.structure import *
+
+class CRG:
+ def get_clock_domains(self):
+ r = dict()
+ for k, v in self.__dict__.items():
+ if isinstance(v, ClockDomain):
+ r[v.name] = v
+ return r
+
+ def get_fragment(self):
+ return Fragment()
+
+class SimpleCRG(CRG):
+ def __init__(self, platform, clk_name, rst_name):
+ self.cd = ClockDomain("sys")
+ platform.request(clk_name, None, self.cd.clk)
+ platform.request(rst_name, None, self.cd.rst)
--- /dev/null
+from copy import copy
+
+from migen.fhdl.structure import *
+from migen.corelogic.record import Record
+from migen.fhdl import verilog
+
+class ConstraintError(Exception):
+ pass
+
+class Pins:
+ def __init__(self, *identifiers):
+ self.identifiers = identifiers
+
+class IOStandard:
+ def __init__(self, name):
+ self.name = name
+
+class Drive:
+ def __init__(self, strength):
+ self.strength = strength
+
+class Misc:
+ def __init__(self, misc):
+ self.misc = misc
+
+class Subsignal:
+ def __init__(self, name, *constraints):
+ self.name = name
+ self.constraints = list(constraints)
+
+def _lookup(description, name, number):
+ for resource in description:
+ if resource[0] == name and (number is None or resource[1] == number):
+ return resource
+ return ConstraintError("Resource not found")
+
+def _resource_type(resource):
+ t = None
+ for element in resource[2:]:
+ if isinstance(element, Pins):
+ assert(t is None)
+ t = len(element.identifiers)
+ 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
+
+def _match(description, requests):
+ available = list(description)
+ matched = []
+
+ # 1. Match requests for a specific number
+ for request in requests:
+ if request[1] is not None:
+ resource = _lookup(available, request[0], request[1])
+ available.remove(resource)
+ matched.append((resource, request[2]))
+
+ # 2. Match requests for no specific number
+ for request in requests:
+ if request[1] is None:
+ resource = _lookup(available, request[0], request[1])
+ available.remove(resource)
+ matched.append((resource, request[2]))
+
+ return matched
+
+def _separate_pins(constraints):
+ pins = None
+ others = []
+ for c in constraints:
+ if isinstance(c, Pins):
+ assert(pins is None)
+ pins = c.identifiers
+ else:
+ others.append(c)
+ return pins, others
+
+class ConstraintManager:
+ def __init__(self, description):
+ self.description = description
+ self.requests = []
+ self.platform_commands = []
+
+ def request(self, name, number=None, obj=None):
+ r = _lookup(self.description, name, number)
+ t = _resource_type(r)
+
+ # If obj is None, then create it.
+ # If it already exists, do some sanity checking.
+ if obj is None:
+ if isinstance(t, int):
+ obj = Signal(t, name_override=r[0])
+ else:
+ obj = Record(t)
+ else:
+ if isinstance(t, int):
+ assert(isinstance(obj, Signal) and obj.nbits == t)
+ else:
+ for e in t:
+ sig = getattr(obj, e[0])
+ assert(isinstance(sig, Signal) and sig.nbits == e[1])
+
+ # Register the request
+ self.requests.append((name, number, obj))
+
+ return obj
+
+ def add_platform_command(self, command, **signals):
+ self.platform_commands.append((command, signals))
+
+ def get_io_signals(self):
+ s = set()
+ for req in self.requests:
+ obj = req[2]
+ if isinstance(obj, Signal):
+ s.add(obj)
+ else:
+ for k in obj.__dict__:
+ p = getattr(obj, k)
+ if isinstance(p, Signal):
+ s.add(p)
+ return s
+
+ def get_sig_constraints(self):
+ r = []
+ matched = _match(self.description, self.requests)
+ for resource, obj in matched:
+ name = resource[0]
+ number = resource[1]
+ has_subsignals = False
+ top_constraints = []
+ for element in resource[2:]:
+ if isinstance(element, Subsignal):
+ 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)
+ r.append((sig, pins, others, (name, number, element.name)))
+ else:
+ pins, others = _separate_pins(top_constraints)
+ r.append((obj, pins, others, (name, number, None)))
+ return r
+
+ def get_platform_commands(self):
+ return self.platform_commands
+
+ def save(self):
+ return copy(self.requests), copy(self.platform_commands)
+
+ def restore(self, backup):
+ self.request, self.platform_commands = backup
+
+class GenericPlatform:
+ def __init__(self, device, io, default_crg_factory=None):
+ self.device = device
+ self.constraint_manager = ConstraintManager(io)
+ self.default_crg_factory = default_crg_factory
+
+ def request(self, *args, **kwargs):
+ return self.constraint_manager.request(*args, **kwargs)
+
+ def add_platform_command(self, *args, **kwargs):
+ return self.constraint_manager.add_platform_command(*args, **kwargs)
+
+ def get_verilog(self, fragment, clock_domains=None):
+ # We may create a temporary clock/reset generator that would request pins.
+ # Save the constraint manager state so that such pin requests disappear
+ # at the end of this function.
+ backup = self.constraint_manager.save()
+ try:
+ # if none exists, create a default clock domain and drive it
+ if clock_domains is None:
+ if self.default_crg_factory is None:
+ raise NotImplementedError("No clock/reset generator defined by either platform or user")
+ crg = self.default_crg_factory(self)
+ frag = fragment + crg.get_fragment()
+ clock_domains = crg.get_clock_domains()
+ else:
+ frag = fragment
+ # generate Verilog
+ src, vns = verilog.convert(frag, self.constraint_manager.get_io_signals(),
+ clock_domains=clock_domains, return_ns=True)
+ # 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]
+ # 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))
+ finally:
+ self.constraint_manager.restore(backup)
+ return src, named_sc, named_pc
+
+ def build(self, fragment, clock_domains=None):
+ raise NotImplementedError("GenericPlatform.build must be overloaded")
--- /dev/null
+from mibuild.generic_platform import *
+from mibuild.xilinx_ise import XilinxISEPlatform, CRG_DS
+
+_io = [
+ ("user_led", 0, Pins("Y3")),
+ ("user_led", 1, Pins("Y1")),
+ ("user_led", 2, Pins("W2")),
+ ("user_led", 3, Pins("W1")),
+ ("user_led", 4, Pins("V3")),
+ ("user_led", 5, Pins("V1")),
+ ("user_led", 6, Pins("U2")),
+ ("user_led", 7, Pins("U1")),
+
+ ("clk100", 0,
+ Subsignal("p", Pins("B14"), IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE")),
+ Subsignal("n", Pins("A14"), IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE"))
+ ),
+
+ ("gpio", 0, Pins("R8")),
+
+ ("gpmc", 0,
+ Subsignal("clk", Pins("R26")),
+ Subsignal("a", Pins("N17", "N18", "L23", "L24", "N19", "N20", "N21", "N22", "P17", "P19")),
+ Subsignal("d", Pins("N23", "N24", "R18", "R19", "P21", "P22", "R20", "R21", "P24", "P26", "R23", "R24", "T22", "T23", "U23", "R25")),
+ Subsignal("we_n", Pins("W26")),
+ Subsignal("oe_n", Pins("AA25")),
+ Subsignal("ale_n", Pins("AA26")),
+ IOStandard("LVCMOS33")),
+ # Warning: CS are numbered 1-7 on ARM side and 0-6 on FPGA side.
+ # Numbers here are given on the FPGA side.
+ ("gpmc_ce_n", 0, Pins("V23"), IOStandard("LVCMOS33")), # nCS0
+ ("gpmc_ce_n", 1, Pins("U25"), IOStandard("LVCMOS33")), # nCS1
+ ("gpmc_ce_n", 2, Pins("W25"), IOStandard("LVCMOS33")), # nCS6
+ ("gpmc_dmareq_n", 0, Pins("T24"), IOStandard("LVCMOS33")), # nCS2
+ ("gpmc_dmareq_n", 1, Pins("T26"), IOStandard("LVCMOS33")), # nCS3
+ ("gpmc_dmareq_n", 2, Pins("V24"), IOStandard("LVCMOS33")), # nCS4
+ ("gpmc_dmareq_n", 3, Pins("V26"), IOStandard("LVCMOS33")), # nCS5
+
+ # FMC150
+ ("fmc150_ctrl", 0,
+ Subsignal("spi_sclk", Pins("AE5")),
+ Subsignal("spi_data", Pins("AF5")),
+
+ Subsignal("adc_sdo", Pins("U13")),
+ Subsignal("adc_en_n", Pins("AA15")),
+ Subsignal("adc_reset", Pins("V13")),
+
+ Subsignal("cdce_sdo", Pins("AA8")),
+ Subsignal("cdce_en_n", Pins("Y9")),
+ Subsignal("cdce_reset_n", Pins("AB7")),
+ Subsignal("cdce_pd_n", Pins("AC6")),
+ Subsignal("cdce_pll_status", Pins("W7")),
+ Subsignal("cdce_ref_en", Pins("W8")),
+
+ Subsignal("dac_sdo", Pins("W9")),
+ Subsignal("dac_en_n", Pins("W10")),
+
+ Subsignal("mon_sdo", Pins("AC5")),
+ Subsignal("mon_en_n", Pins("AD6")),
+ Subsignal("mon_reset_n", Pins("AF6")),
+ Subsignal("mon_int_n", Pins("AD5")),
+
+ Subsignal("pg_c2m", Pins("AA23"), IOStandard("LVCMOS33"))
+ ),
+ ("ti_dac", 0, # DAC3283
+ Subsignal("dat_p", Pins("AA10", "AA9", "V11", "Y11", "W14", "Y12", "AD14", "AE13"), IOStandard("LVDS_25")),
+ Subsignal("dat_n", Pins("AB11", "AB9", "V10", "AA11", "Y13", "AA12", "AF14", "AF13"), IOStandard("LVDS_25")),
+ Subsignal("frame_p", Pins("AB13"), IOStandard("LVDS_25")),
+ Subsignal("frame_n", Pins("AA13"), IOStandard("LVDS_25")),
+ Subsignal("txenable", Pins("AB15"), IOStandard("LVCMOS25"))
+ ),
+ ("ti_adc", 0, # ADS62P49
+ Subsignal("dat_a_p", Pins("AB14", "Y21", "W20", "AB22", "V18", "W17", "AA21")),
+ Subsignal("dat_a_n", Pins("AC14", "AA22", "Y20", "AC22", "W19", "W18", "AB21")),
+ Subsignal("dat_b_p", Pins("Y17", "U15", "AA19", "W16", "AA18", "Y15", "V14")),
+ Subsignal("dat_b_n", Pins("AA17", "V16", "AB19", "Y16", "AB17", "AA16", "V15")),
+ IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE")
+ ),
+ ("fmc150_clocks", 0,
+ Subsignal("dac_clk_p", Pins("V12"), IOStandard("LVDS_25")),
+ Subsignal("dac_clk_n", Pins("W12"), IOStandard("LVDS_25")),
+ Subsignal("adc_clk_p", Pins("AE15"), IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE")),
+ Subsignal("adc_clk_n", Pins("AF15"), IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE")),
+ Subsignal("clk_to_fpga", Pins("W24"), IOStandard("LVCMOS25"))
+ ),
+
+ ("fmc150_ext_trigger", 0, Pins("U26")),
+
+ # Vermeer radar testbed
+ # TX path
+ ("pe43602", 0,
+ Subsignal("d", Pins("H8")),
+ Subsignal("clk", Pins("B3")),
+ Subsignal("le", Pins("F7")),
+ IOStandard("LVCMOS33")
+ ),
+ ("rfmd2081", 0,
+ Subsignal("enx", Pins("E5")),
+ Subsignal("sclk", Pins("G6")),
+ Subsignal("sdata", Pins("F5")),
+ Subsignal("sdatao", Pins("E6")),
+ IOStandard("LVCMOS33")
+ ),
+ # RX path
+ ("lmh6521", 0,
+ Subsignal("scsb", Pins("C5")),
+ Subsignal("sclk", Pins("G10")),
+ Subsignal("sdi", Pins("D5")),
+ Subsignal("sdo", Pins("F9")),
+ IOStandard("LVCMOS33")
+ ),
+ ("lmh6521", 1,
+ Subsignal("scsb", Pins("E10")),
+ Subsignal("sclk", Pins("A4")),
+ Subsignal("sdi", Pins("B4")),
+ Subsignal("sdo", Pins("H10")),
+ IOStandard("LVCMOS33")
+ ),
+ ("rffc5071", 0,
+ Subsignal("enx", Pins("A2")),
+ Subsignal("sclk", Pins("G9")),
+ Subsignal("sdata", Pins("H9")),
+ Subsignal("sdatao", Pins("A3")),
+ IOStandard("LVCMOS33")
+ )
+]
+
+class Platform(XilinxISEPlatform):
+ def __init__(self):
+ XilinxISEPlatform.__init__(self, "xc6slx150t-fgg676-3", _io,
+ lambda p: CRG_DS(p, "clk100", "gpio", 10.0))
--- /dev/null
+import os
+
+def mkdir_noerror(d):
+ try:
+ os.mkdir(d)
+ except OSError:
+ pass
+
+def write_to_file(filename, contents):
+ f = open(filename, "w")
+ f.write(contents)
+ f.close()
--- /dev/null
+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(device, sources, named_sc, named_pc, build_name, xilinx_install_path):
+ tools.write_to_file(build_name + ".ucf", _build_ucf(named_sc, named_pc))
+
+ prj_contents = ""
+ for s in sources:
+ prj_contents += s["type"] + " work " + s["path"] + "\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 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"):
+ 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 = [{"type": "verilog", "path": v_file}]
+ _build(self.device, sources, named_sc, named_pc, build_name, xilinx_install_path)
+
+ os.chdir("..")