Ejemplo n.º 1
0
def quadrants():
    mod = codegen.Module()
    cst = codegen.Constraints()
    ibuf(mod, cst, true_pins[2], clk="myclk")
    pnr = tiled_fuzzer.run_pnr(mod, cst, {})

    modules = []
    constrs = []
    idxes = []
    for i in range(2, db.cols):
        for j in [2, db.rows - 3]:  # avoid bram
            if "DFF0" not in db.grid[j - 1][i - 1].bels:
                print(i, j)
                continue
            mod = codegen.Module()
            cst = codegen.Constraints()

            ibuf(mod, cst, true_pins[0], clk="myclk")
            dff(mod, cst, j, i, clk="myclk")

            modules.append(mod)
            constrs.append(cst)
            idxes.append((j, i))

    for i in [2, db.cols - 2]:
        for j in range(2, db.rows):
            if "DFF0" not in db.grid[j - 1][i - 1].bels:
                print(i, j)
                continue
            mod = codegen.Module()
            cst = codegen.Constraints()

            ibuf(mod, cst, true_pins[0], clk="myclk")
            dff(mod, cst, j, i, clk="myclk")

            modules.append(mod)
            constrs.append(cst)
            idxes.append((j, i))

    pnr_res = pool.map(lambda param: tiled_fuzzer.run_pnr(*param, {}),
                       zip(modules, constrs))

    res = {}
    for (row, col), (mybs, *_) in zip(idxes, pnr_res):
        sweep_tiles = fuse_h4x.tile_bitmap(fse, mybs ^ pnr.bitmap)

        # find which tap was used
        taps = [
            r for (r, c, typ), t in sweep_tiles.items()
            if typ in {13, 14, 15, 16, 18, 19}
        ]

        # find which center tile was used
        t8x = [(r, c) for (r, c, typ), t in sweep_tiles.items()
               if typ >= 80 and typ < 90]
        rows, cols, _ = res.setdefault(t8x[0], (set(), set(), taps[0]))
        rows.add(row - 1)
        cols.add(col - 1)

    return res
Ejemplo n.º 2
0
def center_muxes(ct, rows, cols):
    "Find which mux drives which spine, and maps their inputs to clock pins"

    fr = min(rows)
    dff_locs = [(fr + 1, c + 1) for c in cols][:len(true_pins)]

    mod = codegen.Module()
    cst = codegen.Constraints()

    ibufs = [ibuf(mod, cst, p) for p in true_pins]
    dffs = [dff(mod, cst, row, col) for row, col in dff_locs]

    pnr = tiled_fuzzer.run_pnr(mod, cst, {})

    modules = []
    constrs = []
    for i, pin in enumerate(true_pins):
        mod = codegen.Module()
        cst = codegen.Constraints()
        ibufs = [ibuf(mod, cst, p) for p in true_pins]
        dffs = [dff(mod, cst, row, col) for row, col in dff_locs]
        mod.assigns = list(zip(dffs, ibufs))[:i + 1]

        modules.append(mod)
        constrs.append(cst)

    pnr_res = pool.map(lambda param: tiled_fuzzer.run_pnr(*param, {}),
                       zip(modules, constrs))

    gb_sources = {}
    gb_destinations = {}
    src_seen = set()
    dst_seen = set()

    base = pnr.bitmap
    for i, (bs_sweep, *_) in enumerate(pnr_res):
        pin = true_pins[i]
        new = base ^ bs_sweep
        tiles = chipdb.tile_bitmap(db, new)

        try:
            _, _, clk_pips = gowin_unpack.parse_tile_(db,
                                                      ct[0],
                                                      ct[1],
                                                      tiles[ct],
                                                      noalias=True)
            dest, = set(clk_pips.keys()) - dst_seen
            dst_seen.add(dest)
            src, = set(clk_pips.values()) - src_seen
            src_seen.add(src)
        except ValueError:
            # it seems this uses a dynamically configurable mux routed to VCC/VSS
            continue
        print(i, pin, src, dest)
        gb_destinations[(ct[1], i)] = dest
        gb_sources[src] = pin

    return gb_sources, gb_destinations
Ejemplo n.º 3
0
def iob(locations):
    for iostd in iostandards:
        for ttyp, tiles in locations.items():  # for each tile of this type
            locs = tiles.copy()
            mod = codegen.Module()
            cst = codegen.Constraints()
            # get bels in this ttyp
            bels = {name[-1] for loc in tiles.values() for name in loc}
            for pin in bels:  # [A, B, C, D, ...]
                for attr, attr_values in iobattrs.items(
                ):  # each IOB attribute
                    # XXX remove
                    if iostd == "PCI33" and attr == "SINGLE_RESISTOR":
                        continue
                    attr_vals = attr_values.values
                    if attr_vals == None:
                        attr_vals = attr_values.table[iostd]
                    for attr_val in attr_vals:  # each value of the attribute
                        for typ, conn in iobmap.items():
                            # skip illegal atributesa for mode
                            if typ not in attr_values.allowed_modes:
                                continue
                            # find the next location that has pin
                            # or make a new module
                            loc = find_next_loc(pin, locs)
                            if (loc == None):
                                yield Fuzzer(ttyp, mod, cst, {}, iostd)
                                locs = tiles.copy()
                                mod = codegen.Module()
                                cst = codegen.Constraints()
                                loc = find_next_loc(pin, locs)

                            # special pins
                            if is_illegal(iostd, loc, attr):
                                continue
                            name = make_name("IOB", typ)
                            iob = codegen.Primitive(typ, name)
                            for port in chain.from_iterable(conn.values()):
                                iob.portmap[port] = name + "_" + port

                            for direction, wires in conn.items():
                                wnames = [name + "_" + w for w in wires]
                                getattr(mod, direction).update(wnames)
                            mod.primitives[name] = iob
                            cst.ports[name] = loc
                            # complex iob. connect OEN and O
                            if typ == "IOBUF":
                                iob.portmap["OEN"] = name + "_O"
                            if attr_val:
                                # port attribute value
                                cst.attrs[name] = {attr: attr_val}
                            if iostd:
                                cst.attrs.setdefault(name, {}).update(
                                    {"IO_TYPE": iostd})
            yield Fuzzer(ttyp, mod, cst, {}, iostd)
Ejemplo n.º 4
0
def iob(locations, corners):
    cnt = Counter()  # keep track of how many runs are needed
    for ttyp, tiles in locations.items():  # for each tile of this type
        mod = codegen.Module()
        cst = codegen.Constraints()
        # get bels in this ttyp
        bels = {name[-1] for loc in tiles.values() for name in loc}
        locs = tiles.copy()
        for pin in bels:  # [A, B, C, D, ...]
            for typ, conn in iobmap.items():
                # find the next location that has pin
                # or make a new module
                for tile, names in locs.items():
                    name = tile + pin
                    if name in names:
                        del locs[tile]
                        loc = name
                        break
                else:  # no usable tiles
                    yield ttyp, mod, cst, {}
                    cnt[ttyp] += 1
                    locs = tiles.copy()
                    mod = codegen.Module()
                    cst = codegen.Constraints()
                    for tile, names in locs.items():
                        name = tile + pin
                        if name in names:
                            del locs[tile]
                            loc = name
                            break

                name = make_name("IOB", typ)
                iob = codegen.Primitive(typ, name)
                for port in chain.from_iterable(conn.values()):
                    iob.portmap[port] = name + "_" + port

                for direction, wires in conn.items():
                    wnames = [name + "_" + w for w in wires]
                    getattr(mod, direction).update(wnames)
                mod.primitives[name] = iob
                cst.ports[name] = loc

            yield ttyp, mod, cst, {}
            cnt[ttyp] += 1
    # insert dummie in the corners to detect the bank enable bits
    runs = cnt.most_common(1)[0][1]
    for _ in range(runs):
        for ttyp in corners:
            mod = codegen.Module()
            cst = codegen.Constraints()
            cfg = {}
            yield ttyp, mod, cst, cfg
Ejemplo n.º 5
0
def dff(locations):
    for ttyp in range(12, 18):  # for each tile type
        mod = codegen.Module()
        cst = codegen.Constraints()
        try:
            # get all tiles of this type
            # iter causes the loop to not repeat the same locs per cls
            locs = iter(locations[ttyp])
        except KeyError:
            continue

        for cls in range(3):  # for each cls
            for side in ["A", "B"]:
                for typ, port in dffmap.items():  # for each bel type
                    try:
                        loc = next(locs)  # get the next unused tile
                    except StopIteration:
                        yield ttyp, mod, cst, {}
                        locs = iter(locations[ttyp])
                        loc = next(locs)
                        mod = codegen.Module()
                        cst = codegen.Constraints()

                    lutname = make_name("DUMMY", "LUT4")
                    lut = codegen.Primitive("LUT4", lutname)
                    lut.params["INIT"] = "16'hffff"
                    lut.portmap['F'] = lutname + "_F"
                    lut.portmap['I0'] = lutname + "_I0"
                    lut.portmap['I1'] = lutname + "_I1"
                    lut.portmap['I2'] = lutname + "_I2"
                    lut.portmap['I3'] = lutname + "_I3"

                    mod.wires.update(lut.portmap.values())
                    mod.primitives[lutname] = lut
                    name = make_name("DFF", typ)
                    dff = codegen.Primitive(typ, name)
                    dff.portmap['CLK'] = name + "_CLK"
                    dff.portmap['D'] = lutname + "_F"
                    dff.portmap['Q'] = name + "_Q"
                    if port:
                        dff.portmap[port] = name + "_" + port
                    mod.wires.update(dff.portmap.values())
                    mod.primitives[name] = dff

                    row = loc[0] + 1
                    col = loc[1] + 1
                    cst.cells[lutname] = f"R{row}C{col}[{cls}][{side}]"
                    cst.cells[name] = f"R{row}C{col}[{cls}][{side}]"
        yield ttyp, mod, cst, {}
Ejemplo n.º 6
0
def main():
    parser = argparse.ArgumentParser(description='Unpack Gowin bitstream')
    parser.add_argument('bitstream')
    parser.add_argument('-d', '--device', required=True)
    parser.add_argument('-o', '--output', default='unpack.v')

    args = parser.parse_args()

    with importlib.resources.open_binary("apycula", f"{args.device}.pickle") as f:
        db = pickle.load(f)
    bitmap = read_bitstream(args.bitstream)[0]
    bm = chipdb.tile_bitmap(db, bitmap)
    mod = codegen.Module()

    for dest, src in db.aliases.items():
        mod.wires.update({src, dest})
        mod.assigns.append((dest, src))

    for idx, t in bm.items():
        row, col = idx
        print(idx)
        #for bitrow in t:
        #    print(*bitrow, sep='')
        #if idx == (5, 0):
        #    from fuse_h4x import *
        #    fse = readFse(open("/home/pepijn/bin/gowin/IDE/share/device/GW1N-1/GW1N-1.fse", 'rb'))
        #    breakpoint()
        bels, pips, clock_pips = parse_tile_(db, row, col, t)
        print(bels)
        #print(pips)
        print(clock_pips)
        tile2verilog(row, col, bels, pips, clock_pips, mod, db)
    with open(args.output, 'w') as f:
        mod.write(f)
Ejemplo n.º 7
0
def dualmode(ttyp):
    for pin in dualmode_pins:
        mod = codegen.Module()
        cst = codegen.Constraints()
        cfg = {pin: "0"}
        # modules with different ttyp can be combined, so in theory it could happen
        # that there is an IOB in the module, which claims the dual-purpose pin.
        # P&R will not be able to place it and the fuzzling result will be misleading.
        # Non-optimal: prohibit combining with anything.
        yield Fuzzer(ttyp, mod, cst, cfg, 'dual_mode_fuzzing')
Ejemplo n.º 8
0
def dualmode(ttyp):
    for pin in dualmode_pins:
        mod = codegen.Module()
        cst = codegen.Constraints()
        cfg = {pin: 'false'}
        yield ttyp, mod, cst, cfg
Ejemplo n.º 9
0
        iob(pin_locations, [
            fse['header']['grid'][61][0][0],
            fse['header']['grid'][61][-1][0],
            fse['header']['grid'][61][0][-1],
            fse['header']['grid'][61][-1][-1],
        ]),
        dff(locations),
        dualmode(fse['header']['grid'][61][0][0]),
    )
    for ttyp, mod, cst, cfg in fuzzers:
        modmap.setdefault(ttyp, []).append(mod)
        cstmap.setdefault(ttyp, []).append(cst)
        cfgmap.setdefault(ttyp, []).append(cfg)

    modules = [
        reduce(lambda a, b: a + b, m, codegen.Module())
        for m in zip_longest(*modmap.values(), fillvalue=codegen.Module())
    ]
    constrs = [
        reduce(lambda a, b: a + b, c, codegen.Constraints())
        for c in zip_longest(*cstmap.values(), fillvalue=codegen.Constraints())
    ]
    configs = [
        reduce(lambda a, b: {
            **a,
            **b
        }, c, {}) for c in zip_longest(*cfgmap.values(), fillvalue={})
    ]

    type_re = re.compile(r"inst\d+_([A-Z]+)_([A-Z]+)")
Ejemplo n.º 10
0
        iob(pin_locations, [
            fse['header']['grid'][61][0][0],
            fse['header']['grid'][61][-1][0],
            fse['header']['grid'][61][0][-1],
            fse['header']['grid'][61][-1][-1],
        ]),
        dff(locations),
        dualmode(fse['header']['grid'][61][0][0]),
    )
    for ttyp, mod, cst, cfg in fuzzers:
        modmap.setdefault(ttyp, []).append(mod)
        cstmap.setdefault(ttyp, []).append(cst)
        cfgmap.setdefault(ttyp, []).append(cfg)

    modules = [
        reduce(lambda a, b: a + b, m, codegen.Module())
        for m in zip_longest(*modmap.values(), fillvalue=codegen.Module())
    ]
    constrs = [
        reduce(lambda a, b: a + b, c, codegen.Constraints())
        for c in zip_longest(*cstmap.values(), fillvalue=codegen.Constraints())
    ]
    configs = [
        reduce(lambda a, b: {
            **a,
            **b
        }, c, {}) for c in zip_longest(*cfgmap.values(), fillvalue={})
    ]

    type_re = re.compile(r"inst\d+_([A-Z]+)_([A-Z]+)")
Ejemplo n.º 11
0
                num = row
            elif col == 47:  #TODO parameterize
                edge = 'R'
                num = row
            else:
                edge = 'B'
                num = col
            f.write(f"{name} PLACE_IO{edge}{num}[{idx}]\n")

            iob = codegen.Primitive("IOBUF", name)
            iob.portmap['I'] = f"R{row}C{col}_I{idx}"
            iob.portmap['O'] = f"R{row}C{col}_O{idx}"
            iob.portmap['IO'] = f"R{row}C{col}_IO{idx}"
            iob.portmap['OEN'] = f"R{row}C{col}_OEN{idx}"
            mod.wires.update(iob.portmap.values())
            mod.inouts.add(f"R{row}C{col}_IO{idx}")
            mod.primitives[name] = iob


with open("blinky.fasm", "w") as f:
    write_fasm(ctx, param_map, f)

mod = codegen.Module()
with open("blinky.posp", "w") as f:
    write_posp(f)

with open("blinky.vm", "w") as f:
    mod.write(f)

#code.interact(local=locals())
Ejemplo n.º 12
0
def main():
    parser = argparse.ArgumentParser(description='Unpack Gowin bitstream')
    parser.add_argument('bitstream')
    parser.add_argument('-d', '--device', required=True)
    parser.add_argument('-o', '--output', default='unpack.v')
    parser.add_argument('-c', '--config', default=None)
    parser.add_argument('-s', '--cst', default=None)
    parser.add_argument('--noalu', metavar='N', type = int,
                        default = 0, help = '0 - detect the ALU')

    args = parser.parse_args()

    device = args.device
    # For tool integration it is allowed to pass a full part number
    m = re.match("GW1N([A-Z]*)-(LV|UV|UX)([0-9])C?([A-Z]{2}[0-9]+)(C[0-9]/I[0-9])", device)
    m = re.match("GW1N(S?)[A-Z]*-(LV|UV|UX)([0-9])C?([A-Z]{2}[0-9]+P?)(C[0-9]/I[0-9])", device)
    if m:
        mods = m.group(1)
        luts = m.group(3)
        device = f"GW1N{mods}-{luts}"

    with importlib.resources.open_binary("apycula", f"{device}.pickle") as f:
        db = pickle.load(f)

    bitmap = read_bitstream(args.bitstream)[0]
    bm = chipdb.tile_bitmap(db, bitmap)
    mod = codegen.Module()
    cfg = codegen.DeviceConfig(default_device_config())
    cst = codegen.Constraints()

    for (drow, dcol, dname), (srow, scol, sname) in db.aliases.items():
        src = f"R{srow+1}C{scol+1}_{sname}"
        dest = f"R{drow+1}C{dcol+1}_{dname}"
        mod.wires.update({src, dest})
        mod.assigns.append((dest, src))

    # banks first: need to know iostandards
    for pos in db.corners.keys():
        row, col = pos
        try:
            t = bm[(row, col)]
        except KeyError:
            continue
        bels, pips, clock_pips = parse_tile_(db, row, col, t)
        tile2verilog(row, col, bels, pips, clock_pips, mod, cfg, cst, db)

    for idx, t in bm.items():
        row, col = idx
        # skip banks & dual pisn
        if (row, col) in db.corners:
            continue
        #for bitrow in t:
        #    print(*bitrow, sep='')
        #if idx == (5, 0):
        #    from fuse_h4x import *
        #    fse = readFse(open("/home/pepijn/bin/gowin/IDE/share/device/GW1N-1/GW1N-1.fse", 'rb'))
        #    breakpoint()
        bels, pips, clock_pips = parse_tile_(db, row, col, t, noiostd = False)
        #print(bels)
        #print(pips)
        #print(clock_pips)
        if args.noalu:
            removeALUs(bels)
        else:
            removeLUTs(bels)
        ram16_remove_bels(bels)
        tile2verilog(row, col, bels, pips, clock_pips, mod, cfg, cst, db)

    with open(args.output, 'w') as f:
        mod.write(f)

    if args.config:
        with open(args.config, 'w') as f:
            cfg.write(f)

    if args.cst:
        with open(args.cst, 'w') as f:
            cst.write(f)
Ejemplo n.º 13
0
def taps(rows, cols):
    "Find which colunm is driven by which tap"
    # conver to sorted list of 1-indexed vendor constraints
    rows = [row + 1 for row in sorted(rows)]
    cols = [col + 1 for col in sorted(cols)]

    modules = []
    constrs = []
    locs = []

    # use a different row for each clock
    # row by row, column by column, hook up the clock to the dff
    # in the old IDE row 1 always used clock 1 and so forth
    for col in cols:
        for gclk, row in enumerate(rows[:len(true_pins)]):
            mod = codegen.Module()
            cst = codegen.Constraints()

            clks = [ibuf(mod, cst, p) for p in true_pins]
            for i, clk in zip(rows, clks):
                flop = dff(mod, cst, i, col)
                if i <= row:
                    mod.assigns.append((flop, clk))

            modules.append(mod)
            constrs.append(cst)
            locs.append((gclk, col - 1))

    pnr_res = pool.map(lambda param: tiled_fuzzer.run_pnr(*param, {}),
                       zip(modules, constrs))

    last_dffcol = None
    seen_primary_taps = set()
    seen_secondary_taps = set()
    seen_spines = set()
    clks = {}
    for (gclk, dff_col), (sweep_bs, *_) in zip(locs, pnr_res):
        sweep_tiles = chipdb.tile_bitmap(db, sweep_bs)
        if dff_col != last_dffcol:
            seen_primary_taps = set()
            seen_secondary_taps = set()
            seen_spines = set()
            last_dffcol = dff_col

        tap = None
        print("#" * 80)
        print("gclk", gclk, "dff_col", dff_col)
        for loc, tile in sweep_tiles.items():
            row, col = loc
            _, _, clk_pips = gowin_unpack.parse_tile_(db,
                                                      row,
                                                      col,
                                                      tile,
                                                      noalias=True)
            spines = set(s for s in clk_pips.keys() if s.startswith("SPINE"))
            new_spines = spines - seen_spines
            seen_spines.update(spines)
            print(clk_pips.keys())
            if "GT00" in clk_pips and col not in seen_primary_taps:
                tap = col
                seen_primary_taps.add(col)
            if "GT10" in clk_pips and col not in seen_secondary_taps:
                tap = col
                seen_secondary_taps.add(col)
            print("loc", row, col, "tap", tap, "new spines", new_spines)
        # if tap == None: breakpoint()
        clks.setdefault(gclk, {}).setdefault(tap, set()).add(dff_col)
        print(clks)

    return clks
Ejemplo n.º 14
0
    pnr_data = {}
    for fuzzer in fuzzers:
        pnr_data.setdefault(fuzzer.iostd, DataForPnr({}, {}, {}))
        pnr_data[fuzzer.iostd].modmap.setdefault(fuzzer.ttyp,
                                                 []).append(fuzzer.mod)
        pnr_data[fuzzer.iostd].cstmap.setdefault(fuzzer.ttyp,
                                                 []).append(fuzzer.cst)
        pnr_data[fuzzer.iostd].cfgmap.setdefault(fuzzer.ttyp,
                                                 []).append(fuzzer.cfg)

    modules = []
    constrs = []
    configs = []
    for data in pnr_data.values():
        modules += [
            reduce(lambda a, b: a + b, m, codegen.Module())
            for m in zip_longest(*data.modmap.values(),
                                 fillvalue=codegen.Module())
        ]
        constrs += [
            reduce(lambda a, b: a + b, c, codegen.Constraints())
            for c in zip_longest(*data.cstmap.values(),
                                 fillvalue=codegen.Constraints())
        ]
        configs += [
            reduce(lambda a, b: {
                **a,
                **b
            }, c, {}) for c in zip_longest(*data.cfgmap.values(), fillvalue={})
        ]
Ejemplo n.º 15
0
def taps(rows, cols):
    "Find which colunm is driven by which tap"
    mod = codegen.Module()
    cst = codegen.Constraints()

    clks = [ibuf(mod, cst, p) for p in true_pins]

    # conver to sorted list of 1-indexed vendor constraints
    rows = [row + 1 for row in sorted(rows)]
    cols = [col + 1 for col in sorted(cols)]
    for row in rows[:len(true_pins)]:
        for col in cols:
            flop = dff(mod, cst, row, col)

    bs_base, _, _, _, _ = tiled_fuzzer.run_pnr(mod, cst, {})

    modules = []
    constrs = []
    locs = []
    for gclk, row in enumerate(rows[:len(true_pins)]):
        for col in cols:
            mod = codegen.Module()
            cst = codegen.Constraints()

            clks = [ibuf(mod, cst, p) for p in true_pins]
            for i, clk in zip(rows, clks):
                for j in cols:
                    flop = dff(mod, cst, i, j)
                    if i < row:
                        mod.assigns.append((flop, clk))
                    elif i == row and j == col:
                        mod.assigns.append((flop, clk))

            modules.append(mod)
            constrs.append(cst)
            locs.append((gclk, col - 1))

    pnr_res = pool.map(lambda param: tiled_fuzzer.run_pnr(*param, {}),
                       zip(modules, constrs))

    clks = {}
    complete_taps = set()
    last_gclk = None
    for (gclk, dff_col), (sweep_bs, *_) in zip(locs, pnr_res):
        sweep_tiles = chipdb.tile_bitmap(db, sweep_bs ^ bs_base)

        tap = None
        if last_gclk != None and gclk != last_gclk:
            complete_taps.update(clks[last_gclk].keys())
        last_gclk = gclk
        if gclk == 4:  # secondary taps
            complete_taps = set()
        # print("#"*80)
        # print("gclk", gclk, "dff_col", dff_col)
        for loc, tile in sweep_tiles.items():
            row, col = loc
            _, _, clk_pips = gowin_unpack.parse_tile_(db,
                                                      row,
                                                      col,
                                                      tile,
                                                      noalias=True)
            # print("loc", row, col, "pips", clk_pips)
            if ("GT00" in clk_pips and gclk < 4) or \
               ("GT10" in clk_pips and gclk >= 4):
                # print("tap", col)
                if col not in complete_taps:
                    tap = col
        clks.setdefault(gclk, {}).setdefault(tap, set()).add(dff_col)
        # print(complete_taps, clks)
        #if not tap: break

    return clks