def main(): parser = argparse.ArgumentParser(description='Pack Gowin bitstream') parser.add_argument('netlist') parser.add_argument('-d', '--device', required=True) parser.add_argument('-o', '--output', default='pack.fs') parser.add_argument('-c', '--compress', default=False, action='store_true') parser.add_argument('--png') 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) if m: luts = m.group(3) device = f"GW1N-{luts}" with importlib.resources.open_binary("apycula", f"{device}.pickle") as f: db = pickle.load(f) with open(args.netlist) as f: pnr = json.load(f) tilemap = chipdb.tile_bitmap(db, db.template, empty=True) bels = get_bels(pnr) place(db, tilemap, bels) pips = get_pips(pnr) route(db, tilemap, pips) res = chipdb.fuse_bitmap(db, tilemap) header_footer(db, res, args.compress) if args.png: bslib.display(args.png, res) bslib.write_bitstream(args.output, res, db.cmd_hdr, db.cmd_ftr, args.compress)
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)
def main(): parser = argparse.ArgumentParser(description='Unpack Gowin bitstream') parser.add_argument('netlist') parser.add_argument('-d', '--device', required=True) parser.add_argument('-o', '--output', default='pack.fs') parser.add_argument('--png') args = parser.parse_args() with importlib.resources.open_binary("apycula", f"{args.device}.pickle") as f: db = pickle.load(f) with open(args.netlist) as f: pnr = json.load(f) tilemap = chipdb.tile_bitmap(db, db.template, empty=True) bels = get_bels(pnr) place(db, tilemap, bels) pips = get_pips(pnr) route(db, tilemap, pips) res = chipdb.fuse_bitmap(db, tilemap) header_footer(db, res) if args.png: bslib.display(args.png, res) bslib.write_bitstream(args.output, res, db.cmd_hdr, db.cmd_ftr)
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
def main(): parser = argparse.ArgumentParser(description='Pack Gowin bitstream') parser.add_argument('netlist') parser.add_argument('-d', '--device', required=True) parser.add_argument('-o', '--output', default='pack.fs') parser.add_argument('-c', '--compress', default=False, action='store_true') parser.add_argument('-s', '--cst', default=None) parser.add_argument('--allow_pinless_io', action='store_true') parser.add_argument('--jtag_as_gpio', action='store_true') parser.add_argument('--sspi_as_gpio', action='store_true') parser.add_argument('--mspi_as_gpio', action='store_true') parser.add_argument('--ready_as_gpio', action='store_true') parser.add_argument('--done_as_gpio', action='store_true') parser.add_argument('--reconfign_as_gpio', action='store_true') parser.add_argument('--png') args = parser.parse_args() device = args.device # For tool integration it is allowed to pass a full part number 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) with open(args.netlist) as f: pnr = json.load(f) tilemap = chipdb.tile_bitmap(db, db.template, empty=True) cst = codegen.Constraints() bels = get_bels(pnr) place(db, tilemap, bels, cst, args) pips = get_pips(pnr) route(db, tilemap, pips) dualmode_pins(db, tilemap, args) res = chipdb.fuse_bitmap(db, tilemap) header_footer(db, res, args.compress) if args.png: bslib.display(args.png, res) bslib.write_bitstream(args.output, res, db.cmd_hdr, db.cmd_ftr, args.compress) if args.cst: with open(args.cst, "w") as f: cst.write(f)
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)
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
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