def process_design(picklef, sdf): with open(picklef, "rb") as pf: parsed = pickle.load(pf) arc2pips = parsed["arc2pips"] wire_fanout = parsed["wire_fanout"] # Correlate with interconnect delays in the Tcl, and build equations parsed_sdf = parse_sdf_file(sdf).cells["top"] for from_pin, to_pin in sorted(parsed_sdf.interconnect.keys()): src = conv_sdf_port(from_pin) dst = conv_sdf_port(to_pin) if (src, dst) not in arc2pips: continue dly = parsed_sdf.interconnect[from_pin, to_pin] coeff = {} for pip in arc2pips[src, dst]: pipcls = get_pip_class(pip) if pipcls is None or pipcls in zero_delay_classes: continue base_var = get_base_variable(pipcls) if base_var is not None: coeff[base_var] = coeff.get(base_var, 0) + 1 fan_var = get_fanout_adder_variable(pipcls) if fan_var is not None: fanout = wire_fanout.get(pip[0], 1) max_cls_fanout[pipcls] = max(max_cls_fanout.get(pipcls, 0), fanout) coeff[fan_var] = coeff.get(fan_var, 0) + fanout # AFAICS all Nexus delays are the same for rising and falling, so don't bother solving both rhs = ( min(dly.rising.minv, dly.falling.minv), max(dly.rising.typv, dly.falling.typv), max(dly.rising.maxv, dly.falling.maxv), ) eqn_rows.append((tuple(sorted(coeff.items())), rhs))
def add_sdf_to_database(dbfile, sdffile, include_cell_predicate=include_cell, rewrite_cell_func=rewrite_celltype, rewrite_pin_func=rewrite_pin): db = load_database(dbfile) sdf = parse_sdf.parse_sdf_file(sdffile) for instname, cell in sdf.cells.items(): if not include_cell_predicate(cell.inst, cell.type): continue celltype = rewrite_cell_func(cell.inst, cell.type) if celltype not in db: db[celltype] = set() for entry in cell.entries: if type(entry) is parse_sdf.IOPath: db[celltype].add( tupleise( dict(type="IOPath", from_pin=rewrite_pin_func(cell.inst, cell.type, entry.from_pin), to_pin=rewrite_pin_func(cell.inst, cell.type, entry.to_pin), rising=delay_tuple(entry.rising), falling=delay_tuple(entry.falling)))) elif type(entry) is parse_sdf.SetupHoldCheck: db[celltype].add( tupleise( dict(type="SetupHold", pin=rewrite_pin_func(cell.inst, cell.type, entry.pin), clock=rewrite_pin_func(cell.inst, cell.type, entry.clock), setup=delay_tuple(entry.setup), hold=delay_tuple(entry.hold)))) elif type(entry) is parse_sdf.WidthCheck: db[celltype].add( tupleise( dict(type="Width", clock=rewrite_pin_func(cell.inst, cell.type, entry.clock), width=delay_tuple(entry.width)))) else: assert False save_database(dbfile, db)
def main(): with open(sys.argv[1], "r") as jf: modules = json.load(jf) sdf = parse_sdf_file(sys.argv[2]) paths = set() for cell in sdf.cells.values(): celltype = unescape_sdf_name(cell.type) for path in cell.entries: if isinstance(path, IOPath): from_port = path.from_pin[1] if isinstance(path.from_pin, tuple) else path.from_pin rewritten = rewrite_path(modules, celltype, from_port, path.to_pin) if rewritten is None: continue paths.add((rewritten[0], rewritten[1], rewritten[2], min(path.rising.minv, path.falling.minv), max(path.rising.typv, path.falling.typv), max(path.rising.maxv, path.falling.maxv), )) for path in sorted(paths): print("{:60s} {:10s} {:10s} {:4d} {:4d} {:4d}".format(*path))
def solve_pip_delays(ncl, sdf, debug=False): path_pip_classes, wire_fanout = design_pip_classes.get_equations(ncl) sdf_data = parse_sdf.parse_sdf_file(sdf) top_ic = None for cell in sdf_data.cells: if len(sdf_data.cells[cell].interconnect) != 0: top_ic = sdf_data.cells[cell].interconnect break assert top_ic is not None variables = {} for path in sorted(path_pip_classes.values()): for wire, pipclass in path: if (pipclass, "delay") not in variables and not pip_classes.force_zero_delay_pip(pipclass): vid = len(variables) variables[pipclass, "delay"] = vid if not pip_classes.force_zero_fanout_pip(pipclass): if (pipclass, "fanout") not in variables: vid = len(variables) variables[pipclass, "fanout"] = vid kfid = len(variables) data = {} corners = "min", "typ", "max" i = 0 A = numpy.zeros((len(path_pip_classes), len(variables))) for arc, path in sorted(path_pip_classes.items()): for wire, pipclass in path: if not pip_classes.force_zero_delay_pip(pipclass): A[i, variables[pipclass, "delay"]] += 1 if not pip_classes.force_zero_fanout_pip(pipclass): A[i, variables[pipclass, "fanout"]] += wire_fanout[wire, pipclass] if pipclass not in data: data[pipclass] = { "delay": [0, 0, 0], "fanout": [0, 0, 0], } i += 1 for corner in corners: b = numpy.zeros((len(path_pip_classes), )) i = 0 for arc, path in sorted(path_pip_classes.items()): src, dest = arc srcname = "{}/{}".format(src[0].replace('/', '\\/').replace('.', '\\.'), src[1]) destname = "{}/{}".format(dest[0].replace('/', '\\/').replace('.', '\\.'), dest[1]) b[i] = getattr(top_ic[srcname, destname].rising, corner + "v") i += 1 print("Starting least squares solver!") x, rnorm = optimize.nnls(A, b) for var, j in sorted(variables.items()): pipclass, vartype = var data[pipclass][vartype][corners.index(corner)] = x[j] if debug: error = numpy.matmul(A, x) - b i = 0 worst = 0 sqsum = 0 for arc, path in sorted(path_pip_classes.items()): src, dest = arc rel_error = error[i] / b[i] print("error {}.{} -> {}.{} = {:.01f} ps ({:.01f} %)".format(src[0], src[1], dest[0], dest[1], error[i], rel_error * 100)) worst = max(worst, abs(error[i])) sqsum += error[i]**2 i = i + 1 with open("error.csv", "w") as f: print("actual, percent", file=f) for i in range(len(path_pip_classes)): rel_error = error[i] / b[i] print("{}, {}".format(b[i], rel_error * 100), file=f) for var, j in sorted(variables.items()): print("{}_{} = {:.01f} ps".format(var[0], var[1], x[j])) print("Error: {:.01f} ps max, {:.01f} ps RMS".format(worst, math.sqrt(sqsum / len(path_pip_classes)))) return data
def get_tile_type_data(tiletype): if tiletype not in tile_type_cache: td = TileData(tiletype) # Import wires and pips tj = read_tile_type_json(tiletype) for wire, wire_data in sorted(tj["wires"].items()): wire_id = len(td.wires) wd = WireData(index=wire_id, name=wire, tied_value=None) # FIXME: tied_value wd.intent = get_wire_intent(tiletype, wire) if wire_data is not None: if "res" in wire_data: wd.resistance = float(wire_data["res"]) if "cap" in wire_data: wd.capacitance = float(wire_data["cap"]) td.wires.append(wd) td.wires_by_name[wire] = wd for pip, pipdata in sorted(tj["pips"].items()): # FIXME: pip/wire delays pip_id = len(td.pips) pd = PIPData( index=pip_id, from_wire=td.wires_by_name[pipdata["src_wire"]].index, to_wire=td.wires_by_name[pipdata["dst_wire"]].index, is_bidi=(not bool(int(pipdata["is_directional"]))), is_route_thru=bool(int(pipdata["is_pseudo"]))) if "is_pass_transistor" in pipdata: pd.is_buffered = (not bool( int(pipdata["is_pass_transistor"]))) if "src_to_dst" in pipdata: s2d = pipdata["src_to_dst"] if "delay" in s2d and s2d["delay"] is not None: pd.min_delay = min(float(s2d["delay"][0]), float(s2d["delay"][1])) pd.max_delay = max(float(s2d["delay"][2]), float(s2d["delay"][3])) if "res" in s2d and s2d["res"] is not None: pd.resistance = float(s2d["res"]) if "in_cap" in s2d and s2d["in_cap"] is not None: pd.capacitance = float(s2d["in_cap"]) td.pips.append(pd) for sitedata in tj["sites"]: rel_xy = parse_xy(sitedata["name"]) sitetype = sitedata["type"] for sitepin, pindata in sorted(sitedata["site_pins"].items()): if pindata is None: tspd = TileSitePinData(None) else: pinwire = td.wires_by_name[pindata["wire"]].index tspd = TileSitePinData(pinwire) if "delay" in pindata: tspd.min_delay = min(float(pindata["delay"][0]), float(pindata["delay"][1])) tspd.max_delay = max(float(pindata["delay"][2]), float(pindata["delay"][3])) if "res" in pindata: tspd.resistance = float(pindata["res"]) if "cap" in pindata: tspd.capacitance = float(pindata["cap"]) td.sitepin_data[(sitetype, rel_xy, sitepin)] = tspd if os.path.exists(prjxray_root + "/timings/" + tiletype + ".sdf"): td.cell_timing = parse_sdf_file(prjxray_root + "/timings/" + tiletype + ".sdf") tile_type_cache[tiletype] = td return tile_type_cache[tiletype]
def main(): parsed = parse_sdf.parse_sdf_file(sys.argv[1]) with open(sys.argv[2], "wb") as pickled: pickle.dump(parsed, pickled)