def write_posp(f): belre = re.compile(r"R(\d+)C(\d+)_(SLICE|IOB)(\w)") namere = re.compile(r"\W+") for name, cell in ctx.cells: row, col, typ, idx = belre.match(cell.bel).groups() row = int(row) col = int(col) name = namere.sub('_', name) if typ == 'SLICE': idx = int(idx) cls = idx // 2 side = ['A', 'B'][idx % 2] lutname = name + "_LUT" f.write(f"{lutname} PLACE_R{row}C{col}[{cls}][{side}]\n") lut = codegen.Primitive("LUT4", lutname) #lut.params["INIT"] = f"16'b{val:016b}" lut.portmap['F'] = f"R{row}C{col}_F{idx}" lut.portmap['I0'] = f"R{row}C{col}_A{idx}" lut.portmap['I1'] = f"R{row}C{col}_B{idx}" lut.portmap['I2'] = f"R{row}C{col}_C{idx}" lut.portmap['I3'] = f"R{row}C{col}_D{idx}" mod.wires.update(lut.portmap.values()) mod.primitives[lutname] = lut if int(cell.params['FF_USED'], 2): dffname = name + "_DFF" f.write(f"{dffname} PLACE_R{row}C{col}[{cls}][{side}]\n") lut = codegen.Primitive("DFF", dffname) lut.portmap['D'] = f"R{row}C{col}_F{idx}" lut.portmap['Q'] = f"R{row}C{col}_Q{idx}" lut.portmap['CLK'] = f"R{row}C{col}_CLK{idx}" mod.wires.update(lut.portmap.values()) mod.primitives[dffname] = lut elif typ == 'IOB': if row == 1: edge = 'T' num = col elif col == 1: edge = 'L' 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
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, {}
def make_muxes(row, col, idx, db, mod): name = f"R{row}C{col}_MUX2_LUT50" if name in mod.primitives.keys(): return # one MUX8 if col < db.cols : name = f"R{row}C{col}_MUX2_LUT80" mux2 = codegen.Primitive("MUX2", name) mux2.portmap['I0'] = f"R{row}C{col + 1}_OF3" mux2.portmap['I1'] = f"R{row}C{col}_OF3" mux2.portmap['O'] = f"R{row}C{col}_OF7" mux2.portmap['S0'] = f"R{row}C{col}_SEL7" mod.wires.update(mux2.portmap.values()) mod.primitives[name] = mux2 # one MUX7 name = f"R{row}C{col}_MUX2_LUT70" mux2 = codegen.Primitive("MUX2", name) mux2.portmap['I0'] = f"R{row}C{col}_OF5" mux2.portmap['I1'] = f"R{row}C{col}_OF1" mux2.portmap['O'] = f"R{row}C{col}_OF3" mux2.portmap['S0'] = f"R{row}C{col}_SEL3" mod.wires.update(mux2.portmap.values()) mod.primitives[name] = mux2 # two MUX6 for i in range(2): name = f"R{row}C{col}_MUX2_LUT6{i}" mux2 = codegen.Primitive("MUX2", name) mux2.portmap['I0'] = f"R{row}C{col}_OF{i * 4 + 2}" mux2.portmap['I1'] = f"R{row}C{col}_OF{i * 4}" mux2.portmap['O'] = f"R{row}C{col}_OF{i * 4 + 1}" mux2.portmap['S0'] = f"R{row}C{col}_SEL{i * 4 + 1}" mod.wires.update(mux2.portmap.values()) mod.primitives[name] = mux2 # four MUX5 for i in range(4): name = f"R{row}C{col}_MUX2_LUT5{i}" mux2 = codegen.Primitive("MUX2", name) mux2.portmap['I0'] = f"R{row}C{col}_F{i * 2}" mux2.portmap['I1'] = f"R{row}C{col}_F{i * 2 + 1}" mux2.portmap['O'] = f"R{row}C{col}_OF{i * 2}" mux2.portmap['S0'] = f"R{row}C{col}_SEL{i * 2}" mod.wires.update(mux2.portmap.values()) mod.primitives[name] = mux2
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)
def dff(mod, cst, row, col, clk=None): "make a dff with optional clock" name = tiled_fuzzer.make_name("DFF", "DFF") dff = codegen.Primitive("DFF", name) dff.portmap['CLK'] = clk if clk else name + "_CLK" dff.portmap['D'] = name + "_D" dff.portmap['Q'] = name + "_Q" mod.wires.update(dff.portmap.values()) mod.primitives[name] = dff cst.cells[name] = (row, col, 0, 'A') # f"R{row}C{col}" return dff.portmap['CLK']
def ibuf(mod, cst, loc, clk=None): "make an ibuf with optional clock" name = tiled_fuzzer.make_name("IOB", "IBUF") iob = codegen.Primitive("IBUF", name) iob.portmap["I"] = name + "_I" iob.portmap["O"] = clk if clk else name + "_O" mod.wires.update([iob.portmap["O"]]) mod.inputs.update([iob.portmap["I"]]) mod.primitives[name] = iob cst.ports[name] = loc return iob.portmap["O"]
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
def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, db): # db is 0-based, floorplanner is 1-based row = dbrow + 1 col = dbcol + 1 aliases = db.grid[dbrow][dbcol].aliases for dest, src in chain(pips.items(), aliases.items(), clock_pips.items()): srcg = chipdb.wire2global(row, col, db, src) destg = chipdb.wire2global(row, col, db, dest) mod.wires.update({srcg, destg}) mod.assigns.append((destg, srcg)) belre = re.compile(r"(IOB|LUT|DFF|BANK|CFG)(\w*)") for bel, flags in bels.items(): typ, idx = belre.match(bel).groups() if typ == "LUT": val = sum(1 << f for f in flags) name = f"R{row}C{col}_LUT4_{idx}" lut = codegen.Primitive("LUT4", name) lut.params["INIT"] = f"16'b{val:016b}" lut.portmap['F'] = f"R{row}C{col}_F{idx}" lut.portmap['I0'] = f"R{row}C{col}_A{idx}" lut.portmap['I1'] = f"R{row}C{col}_B{idx}" lut.portmap['I2'] = f"R{row}C{col}_C{idx}" lut.portmap['I3'] = f"R{row}C{col}_D{idx}" mod.wires.update(lut.portmap.values()) mod.primitives[name] = lut elif typ == "DFF": kind, = flags # DFF only have one flag idx = int(idx) port = dffmap[kind] name = f"R{row}C{col}_{typ}E_{idx}" dff = codegen.Primitive(kind + "E", name) dff.portmap['CLK'] = f"R{row}C{col}_CLK{idx//2}" dff.portmap['D'] = f"R{row}C{col}_F{idx}" dff.portmap['Q'] = f"R{row}C{col}_Q{idx}" dff.portmap['CE'] = f"R{row}C{col}_CE{idx//2}" if port: dff.portmap[port] = f"R{row}C{col}_LSR{idx//2}" mod.wires.update(dff.portmap.values()) mod.primitives[name] = dff elif typ == "IOB": try: kind, = flags.intersection(iobmap.keys()) except ValueError: continue portmap = db.grid[dbrow][dbcol].bels[bel].portmap name = f"R{row}C{col}_{kind}_{idx}" wires = set(iobmap[kind]['wires']) ports = set(chain.from_iterable(iobmap[kind].values())) - wires iob = codegen.Primitive(kind, name) for port in wires: wname = portmap[port] iob.portmap[port] = f"R{row}C{col}_{wname}" for port in ports: iob.portmap[port] = f"R{row}C{col}_{port}{idx}" for wires in iobmap[kind]['wires']: wnames = [f"R{row}C{col}_{portmap[w]}" for w in wires] mod.wires.update(wnames) for direction in ['inputs', 'outputs', 'inouts']: for wires in iobmap[kind].get(direction, []): wnames = [f"R{row}C{col}_{w}{idx}" for w in wires] getattr(mod, direction).update(wnames) mod.primitives[name] = iob # gnd = codegen.Primitive("GND", "mygnd") # gnd.portmap["G"] = "VSS" # mod.primitives["mygnd"] = gnd # vcc = codegen.Primitive("VCC", "myvcc") # vcc.portmap["V"] = "VCC" # mod.primitives["myvcc"] = vcc mod.assigns.append(("VCC", "1")) mod.assigns.append(("GND", "0"))
def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cfg, cst, db): # db is 0-based, floorplanner is 1-based row = dbrow+1 col = dbcol+1 aliases = db.grid[dbrow][dbcol].aliases for dest, src in chain(pips.items(), aliases.items(), clock_pips.items()): srcg = chipdb.wire2global(row, col, db, src) destg = chipdb.wire2global(row, col, db, dest) mod.wires.update({srcg, destg}) mod.assigns.append((destg, srcg)) belre = re.compile(r"(IOB|LUT|DFF|BANK|CFG|ALU|RAM16)(\w*)") for bel, flags in bels.items(): typ, idx = belre.match(bel).groups() if typ == "LUT": val = 0xffff - sum(1<<f for f in flags) if val == 0: mod.assigns.append((f"R{row}C{col}_F{idx}", "VSS")) else: name = f"R{row}C{col}_LUT4_{idx}" lut = codegen.Primitive("LUT4", name) lut.params["INIT"] = f"16'b{val:016b}" lut.portmap['F'] = f"R{row}C{col}_F{idx}" lut.portmap['I0'] = f"R{row}C{col}_A{idx}" lut.portmap['I1'] = f"R{row}C{col}_B{idx}" lut.portmap['I2'] = f"R{row}C{col}_C{idx}" lut.portmap['I3'] = f"R{row}C{col}_D{idx}" mod.wires.update(lut.portmap.values()) mod.primitives[name] = lut cst.cells[name] = (row, col, int(idx) // 2, _sides[int(idx) % 2]) make_muxes(row, col, idx, db, mod) elif typ == "ALU": #print(flags) kind, = flags # ALU only have one flag idx = int(idx) name = f"R{row}C{col}_ALU_{idx}" if kind in "012346789": # main ALU alu = codegen.Primitive("ALU", name) alu.params["ALU_MODE"] = kind alu.portmap['SUM'] = f"R{row}C{col}_F{idx}" alu.portmap['CIN'] = f"R{row}C{col}_CIN{idx}" if idx != 5: alu.portmap['COUT'] = f"R{row}C{col}_CIN{idx+1}" else: alu.portmap['COUT'] = f"R{row}C{col + 1}_CIN{0}" if kind in "2346789": alu.portmap['I0'] = f"R{row}C{col}_A{idx}" alu.portmap['I1'] = f"R{row}C{col}_B{idx}" if kind in "28": alu.portmap['I3'] = f"R{row}C{col}_D{idx}" elif kind == "0": alu.portmap['I0'] = f"R{row}C{col}_B{idx}" alu.portmap['I1'] = f"R{row}C{col}_D{idx}" else: alu.portmap['I0'] = f"R{row}C{col}_A{idx}" alu.portmap['I1'] = f"R{row}C{col}_D{idx}" mod.wires.update(alu.portmap.values()) mod.primitives[name] = alu elif typ == "RAM16": val0 = sum(1<<x for x in range(0,16) if not x in flags) val1 = sum(1<<(x-16) for x in range(16,32) if not x in flags) val2 = sum(1<<(x-32) for x in range(32,48) if not x in flags) val3 = sum(1<<(x-48) for x in range(48,64) if not x in flags) name = f"R{row}C{col}_RAM16" ram16 = codegen.Primitive("RAM16SDP4", name) ram16.params["INIT_0"] = f"16'b{val0:016b}" ram16.params["INIT_1"] = f"16'b{val1:016b}" ram16.params["INIT_2"] = f"16'b{val2:016b}" ram16.params["INIT_3"] = f"16'b{val3:016b}" ram16.portmap['DI'] = [f"R{row}C{col}_{x}5" for x in "ABCD"] ram16.portmap['CLK'] = f"R{row}C{col}_CLK2" ram16.portmap['WRE'] = f"R{row}C{col}_LSR2" ram16.portmap['WAD'] = [f"R{row}C{col}_{x}4" for x in "ABCD"] ram16.portmap['RAD'] = [f"R{row}C{col}_{x}0" for x in "ABCD"] ram16.portmap['DO'] = [f"R{row}C{col}_F{x}" for x in range(4)] mod.wires.update(chain.from_iterable([x if isinstance(x, list) else [x] for x in ram16.portmap.values()])) mod.primitives[name] = ram16 elif typ == "DFF": #print(flags) kind, = flags # DFF only have one flag idx = int(idx) port = dffmap[kind] name = f"R{row}C{col}_{typ}E_{idx}" dff = codegen.Primitive(kind+"E", name) dff.portmap['CLK'] = f"R{row}C{col}_CLK{idx//2}" dff.portmap['D'] = f"R{row}C{col}_F{idx}" dff.portmap['Q'] = f"R{row}C{col}_Q{idx}" dff.portmap['CE'] = f"R{row}C{col}_CE{idx//2}" if port: dff.portmap[port] = f"R{row}C{col}_LSR{idx//2}" mod.wires.update(dff.portmap.values()) mod.primitives[name] = dff cst.cells[name] = (row, col, int(idx) // 2, _sides[int(idx) % 2]) elif typ == "IOB": try: kind, = flags.intersection(iobmap.keys()) except ValueError: continue flags.remove(kind) portmap = db.grid[dbrow][dbcol].bels[bel].portmap name = f"R{row}C{col}_{kind}_{idx}" wires = set(iobmap[kind]['wires']) ports = set(chain.from_iterable(iobmap[kind].values())) - wires iob = codegen.Primitive(kind, name) for port in wires: wname = portmap[port] iob.portmap[portname(port)] = f"R{row}C{col}_{wname}" for port in ports: iob.portmap[port] = f"R{row}C{col}_{port}{idx}" wnames = [f"R{row}C{col}_{portmap[w]}" for w in iobmap[kind]['wires']] mod.wires.update(wnames) for direction in ['inputs', 'outputs', 'inouts']: wnames = [f"R{row}C{col}_{w}{idx}" for w in iobmap[kind].get(direction, [])] getattr(mod, direction).update(wnames) mod.primitives[name] = iob # constraints pos = chipdb.loc2pin_name(db, dbrow, dbcol) bank = chipdb.loc2bank(db, dbrow, dbcol) cst.ports[name] = f"{pos}{idx}" iostd = _banks.get(bank) if iostd: cst.attrs.setdefault(name, {}).update({"IO_TYPE" : iostd}) for flg in flags: name_val = flg.split('=') cst.attrs.setdefault(name, {}).update({name_val[0] : name_val[1]}) elif typ == "CFG": for flag in flags: for name in cfg.settings.keys(): if name.startswith(flag): cfg.settings[name] = 'true' # gnd = codegen.Primitive("GND", "mygnd") # gnd.portmap["G"] = "VSS" # mod.primitives["mygnd"] = gnd # vcc = codegen.Primitive("VCC", "myvcc") # vcc.portmap["V"] = "VCC" # mod.primitives["myvcc"] = vcc mod.assigns.append(("VCC", "1")) mod.assigns.append(("VSS", "0"))