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))
Beispiel #2
0
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))
Beispiel #4
0
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
Beispiel #5
0
    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]
Beispiel #6
0
def main():
    parsed = parse_sdf.parse_sdf_file(sys.argv[1])
    with open(sys.argv[2], "wb") as pickled:
        pickle.dump(parsed, pickled)