def pnr(netlist, cfgfile, outfile, top="top"): _logger.info("Starting Place-and-route") with open(cfgfile, "r") as f: cfg = yaml.safe_load(f) try: netlist = Netlist(netlist, top) try: gal = _devices[cfg["device"]](cfg["mode"]) except KeyError: _logger.error("Supported devices: %s", ",".join(_devices.keys())) raise PnrError("Invalid target: {}".format(target)) gal.pnr(netlist, cfg["pins"]) _logger.info("Place-and-route succeed") except PnrError as exc: _logger.error(exc) return False with open(outfile, "w+") as f: _logger.info("Producing JEDEC file to {}".format(outfile)) gal.write_jedec(f) return True
def set_registered(self, clock, pins): _logger.info("Configure macro cell %s in registered mode (clock: %s)", self.outpad, clock) if self.gal_mode != "registered": raise PnrError("GAL_DFF can only be synthesized in registered mode" " (current GAL mode: {})".format(self.gal_mode)) sysclk = None for netname, pin in pins.items(): if pin == 1: sysclk = netname if clock != sysclk: raise PnrError("{} is not mapped to a clock input " "(currently mapped to {} signal)".format( clock, sysclk)) self.fuse_ac1 = 0
def get_driver(self, bit): for cell_name, cell in self.top["cells"].items(): for connection_name, bits in cell["connections"].items(): if bit in bits and \ cell["port_directions"][connection_name] == "output": _logger.debug("Found driver for bit %d: %s", bit, cell_name) return cell raise PnrError("Cannot find a driver for bit {}".format(bit))
def _connect_input(self, netname, pins, table): _logger.info("Connecting input %s to macro cell %d", netname, self.outpad) try: inpad = pins[netname] except KeyError: raise PnrError("No IO assigned for netname {}".format(netname)) try: index_input = self.inputs.index(inpad) except ValueError: raise PnrError("Pad {} cannot be assigned as input".format(inpad)) _logger.debug("Position of netname %s: %d", netname, index_input) for i in range(self.depth - int(self.has_oe())): idx = (i + int(self.has_oe())) * self.width + (index_input * 2) self.fuses_and_array[idx] = table[i * 2] ^ 1 self.fuses_and_array[idx + 1] = table[i * 2 + 1] ^ 1
def configure(self, netlist, bit, pins): _logger.info("Configuring macro cell %s", self.outpad) self.fuse_xor = 1 if type(bit) is int: driver = netlist.get_driver(bit) if driver["type"] == "GAL_DFF": clock = netlist.get_netname(driver["connections"]["C"][0]) self.set_registered(clock, pins) driver = netlist.get_driver(driver["connections"]["D"][0]) if driver["type"] == "GAL_XOR": self.invert() driver = netlist.get_driver(driver["connections"]["A"][0]) if driver["type"] == "GAL_SOP": if driver["parameters"]["WIDTH"] == 1: upstream = driver["connections"]["I0"][0] if netlist.get_netname(upstream) not in pins.keys(): _logger.info("Inverter SOP detected: %s", upstream) self.invert() driver = netlist.get_driver(upstream) if driver["type"] == "GAL_SOP": self.configure_and_array(netlist, driver, pins) else: raise PnrError("Unknown cell type: {}".format(driver["type"])) elif bit == "1": self.invert() elif bit != "0": raise PnrError("Cannot assign value {} to outpad {}".format( bit, self.outpad)) self.used = True
def pnr(self, netlist, pins): for netname, pin, direction in netlist.get_ios(pins): if direction == "output": cell = self.get_cell(pin) if cell.used: raise PnrError("Cell {} is already used".format(pin)) bit = netlist.get_bit(netname) cell.configure(netlist, bit, pins) else: try: cell = self.get_cell(pin) except KeyError: pass else: cell.configure_as_input()
def _get_input_table(self, sop, index): sop_table = sop["parameters"]["TABLE"] sop_depth = sop["parameters"]["DEPTH"] sop_width = sop["parameters"]["WIDTH"] if sop_depth > self.get_useable_depth(): raise PnrError( "Pin {}: sum-of-product cannot fit in the macro-cell. " "(Depth: {}, Max: {})".format(self.outpad, sop_depth, self.get_useable_depth())) if isinstance(sop_table, str): sop_table = int(sop_table, 2) table = [] for i in range(index * 2, self.depth * sop_width * 2, sop_width * 2): table.append((sop_table >> (i + 1) & 1)) table.append((sop_table >> i & 1)) _logger.debug("Input table %d: %s", index, table) return table
def get_netname(self, bit): for name, netname in self.top["netnames"].items(): if bit in netname["bits"]: return name raise PnrError("Cannot find netname for bit {}".format(bit))
def get_bit(self, netname): bits = self.get_bits(netname) if len(bits) != 1: raise PnrError("Wire {} must be exactly 1 bit (is {})".format( netname, len(bits))) return bits[0]