Skip to content

Commit

Permalink
gowin: Himbaechel. Unify the creation of tail types
Browse files Browse the repository at this point in the history
A single mechanism for creating a new type of tile if special functions
are found in the chip database that depend on the coordinates of the
tile.

Signed-off-by: YRabbit <[email protected]>
  • Loading branch information
yrabbit authored and gatecat committed Aug 31, 2023
1 parent 87ae77f commit a823543
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 88 deletions.
177 changes: 104 additions & 73 deletions himbaechel/uarch/gowin/gowin_arch_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,13 @@ def serialise(self, context: str, bba: BBAWriter):
self.bottom_io.serialise(f"{context}_bottom_io", bba)
bba.slice(f"{context}_diff_io_types", len(self.diff_io_types))

# { ttyp : {}}
# Unique features of the tiletype
class TypeDesc:
def __init__(self, dups, tiletype = '', extra_func = None, sfx = 0):
self.tiletype = tiletype
self.extra_func = extra_func
self.dups = dups
self.sfx = sfx
created_tiletypes = {}

# u-turn at the rim
Expand Down Expand Up @@ -225,56 +231,106 @@ def get_wire_type(name):
tt.create_pip(src, dst)

def create_hclk_switch_matrix(tt: TileType, db: chipdb, x: int, y: int):
if (y, x) not in db.hclk_pips:
return
# hclk wires
for dst, srcs in db.hclk_pips[(y, x)].items():
for dst, srcs in db.hclk_pips[y, x].items():
if not tt.has_wire(dst):
tt.create_wire(dst, "HCLK")
for src in srcs.keys():
if not tt.has_wire(src):
tt.create_wire(src, "HCLK")
tt.create_pip(src, dst)

extra_type_cnt = 1
def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
if (y, x) not in db.extra_func:
return
for func, desc in db.extra_func[(y, x)].items():
if func == 'osc':
osc_type = desc['type']
portmap = db.grid[y][x].bels[osc_type].portmap
for port, wire in portmap.items():
tt.create_wire(wire, port)
bel = tt.create_bel(osc_type, osc_type, z = OSC_Z)
for port, wire in portmap.items():
if 'OUT' in port:
tt.add_bel_pin(bel, port, wire, PinType.OUTPUT)
else:
tt.add_bel_pin(bel, port, wire, PinType.INPUT)
elif func == 'gsr':
wire = desc['wire']
tt.create_wire(wire, "GSRI")
bel = tt.create_bel("GSR", "GSR", z = GSR_Z)
tt.add_bel_pin(bel, "GSRI", wire, PinType.INPUT)

def create_tiletype(create_func, chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
global extra_type_cnt
create_hclk_pips = False

# HCLK wires can be different in the same types of tiles, so if necessary, create a new type
if ttyp in created_tiletypes:
# check if we have HCLK pips
if (y, x) in db.hclk_pips and created_tiletypes[ttyp]['hclk_pips'] != db.hclk_pips[y, x]:
create_hclk_pips = True
ttyp = 100 * ttyp + extra_type_cnt
extra_type_cnt += 1
has_extra_func = (y, x) in db.extra_func

# (found, TypeDesc)
def find_or_make_dup():
for d in created_tiletypes[ttyp].dups:
if has_extra_func and d.extra_func == db.extra_func[(y, x)]:
return (True, d)
elif not has_extra_func and not d.extra_func:
return (True, d)
sfx = len(created_tiletypes[ttyp].dups) + 1
if has_extra_func:
tdesc = TypeDesc(extra_func = db.extra_func[(y, x)], sfx = sfx, dups = [])
else:
tdesc = TypeDesc(sfx = sfx, dups = [])
created_tiletypes[ttyp].dups.append(tdesc)
return (False, tdesc)

old_type = False
if ttyp not in created_tiletypes:
# new type
if has_extra_func:
tdesc = TypeDesc(extra_func = db.extra_func[(y, x)], dups = [])
else:
chip.set_tile_type(x, y, created_tiletypes[ttyp]['tiletype'])
return
elif (y, x) in db.hclk_pips:
create_hclk_pips = True
tdesc = TypeDesc(dups = [])
created_tiletypes.update({ttyp: tdesc})
else:
created_tiletypes[ttyp] = {}
if create_hclk_pips:
created_tiletypes.setdefault(ttyp, {}).update({'hclk_pips': db.hclk_pips[y, x]})
# find similar
if has_extra_func:
if created_tiletypes[ttyp].extra_func == db.extra_func[(y, x)]:
tdesc = created_tiletypes[ttyp]
old_type = True
else:
old_type, tdesc = find_or_make_dup()
elif not created_tiletypes[ttyp].extra_func:
tdesc = created_tiletypes[ttyp]
old_type = True
else:
old_type, tdesc = find_or_make_dup()

if old_type:
chip.set_tile_type(x, y, tdesc.tiletype)
return

tiletype, tt = create_func(chip, db, x, y, ttyp)
tt = create_func(chip, db, x, y, ttyp, tdesc)
print(ttyp, tdesc.tiletype)

if create_hclk_pips:
create_hclk_switch_matrix(tt, db, x, y)
create_extra_funcs(tt, db, x, y)
create_hclk_switch_matrix(tt, db, x, y)
create_switch_matrix(tt, db, x, y)
chip.set_tile_type(x, y, tiletype)
created_tiletypes.setdefault(ttyp, {}).update({'tiletype': tiletype})
chip.set_tile_type(x, y, tdesc.tiletype)

def create_null_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
def create_null_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tdesc: TypeDesc):
typename = "NULL"
tiletype = f"{typename}_{ttyp}"
if tdesc.sfx != 0:
tiletype += f"_{tdesc.sfx}"
tt = chip.create_tile_type(tiletype)
tt.extra_data = TileExtraData(chip.strs.id(typename))
return (tiletype, tt)
tdesc.tiletype = tiletype
return tt

# responsible nodes, there will be IO banks, configuration, etc.
def create_corner_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
def create_corner_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tdesc: TypeDesc):
typename = "CORNER"
tiletype = f"{typename}_{ttyp}"
if tdesc.sfx != 0:
tiletype += f"_{tdesc.sfx}"
tt = chip.create_tile_type(tiletype)
tt.extra_data = TileExtraData(chip.strs.id(typename))

Expand All @@ -287,46 +343,17 @@ def create_corner_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
tt.create_wire('VCC', 'VCC')
gnd = tt.create_bel('VCC', 'VCC', z = VCC_Z)
tt.add_bel_pin(gnd, "V", "VCC", PinType.OUTPUT)
# also here may be GSR
if 'GSR' in db.grid[y][x].bels:
portmap = db.grid[y][x].bels['GSR'].portmap
tt.create_wire(portmap['GSRI'], "GSRI")
io = tt.create_bel("GSR", "GSR", z = GSR_Z)
tt.add_bel_pin(io, "GSRI", portmap['GSRI'], PinType.INPUT)
if (y, x) in db.extra_cell_func:
funcs = db.extra_cell_func[(y, x)]
if 'osc' in funcs:
osc_type = funcs['osc']['type']
portmap = db.grid[y][x].bels[osc_type].portmap
for port, wire in portmap.items():
tt.create_wire(wire, port)
io = tt.create_bel(osc_type, osc_type, z = OSC_Z)
for port, wire in portmap.items():
if 'OUT' in port:
tt.add_bel_pin(io, port, wire, PinType.OUTPUT)
else:
tt.add_bel_pin(io, port, wire, PinType.INPUT)

return (tiletype, tt)

# Global set/reset. GW2A series has special cell for it
def create_gsr_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
typename = "GSR"
tiletype = f"{typename}_{ttyp}"
tt = chip.create_tile_type(tiletype)
tt.extra_data = TileExtraData(chip.strs.id(typename))

portmap = db.grid[y][x].bels['GSR'].portmap
tt.create_wire(portmap['GSRI'], "GSRI")
io = tt.create_bel("GSR", "GSR", z = GSR_Z)
tt.add_bel_pin(io, "GSRI", portmap['GSRI'], PinType.INPUT)
tdesc.tiletype = tiletype
return tt

return (tiletype, tt)

# IO
def create_io_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
def create_io_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tdesc: TypeDesc):
typename = "IO"
tiletype = f"{typename}_{ttyp}"
if tdesc.sfx != 0:
tiletype += f"_{tdesc.sfx}"
tt = chip.create_tile_type(tiletype)
tt.extra_data = TileExtraData(chip.strs.id(typename))

Expand Down Expand Up @@ -376,12 +403,15 @@ def create_io_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
tt.add_bel_pin(iol, port, wire, PinType.OUTPUT)
else:
tt.add_bel_pin(iol, port, wire, PinType.INPUT)
return (tiletype, tt)
tdesc.tiletype = tiletype
return tt

# logic: luts, dffs, alu etc
def create_logic_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
def create_logic_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tdesc: TypeDesc):
typename = "LOGIC"
tiletype = f"{typename}_{ttyp}"
if tdesc.sfx != 0:
tiletype += f"_{tdesc.sfx}"
tt = chip.create_tile_type(tiletype)
tt.extra_data = TileExtraData(chip.strs.id(typename))

Expand Down Expand Up @@ -471,11 +501,12 @@ def create_logic_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
tt.add_bel_pin(ff, "O", f"OF7", PinType.OUTPUT)
tt.add_bel_pin(ff, "S0", f"SEL7", PinType.INPUT)

return (tiletype, tt)
tdesc.tiletype = tiletype
return tt

def create_ssram_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
def create_ssram_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tdesc: TypeDesc):
# SSRAM is LUT based, so it's logic-like
tiletype, tt = create_logic_tiletype(chip, db, x, y, ttyp)
tt = create_logic_tiletype(chip, db, x, y, ttyp, tdesc)

lut_inputs = ['A', 'B', 'C', 'D']
ff = tt.create_bel(f"RAM16SDP4", "RAM16SDP4", z = RAMW_Z)
Expand All @@ -491,7 +522,7 @@ def create_ssram_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
tt.add_bel_pin(ff, f"CLK", "CLK2", PinType.INPUT)
tt.add_bel_pin(ff, f"CE", "CE2", PinType.INPUT)
tt.add_bel_pin(ff, f"WRE", "LSR2", PinType.INPUT)
return (tiletype, tt)
return tt

# PLL main tile
_pll_inputs = {'CLKFB', 'FBDSEL0', 'FBDSEL1', 'FBDSEL2', 'FBDSEL3',
Expand All @@ -501,9 +532,11 @@ def create_ssram_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
'PSDA2', 'PSDA3', 'DUTYDA0', 'DUTYDA1', 'DUTYDA2', 'DUTYDA3',
'FDLY0', 'FDLY1', 'FDLY2', 'FDLY3', 'CLKIN'}
_pll_outputs = {'CLKOUT', 'LOCK', 'CLKOUTP', 'CLKOUTD', 'CLKOUTD3'}
def create_pll_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
def create_pll_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tdesc: TypeDesc):
typename = "PLL"
tiletype = f"{typename}_{ttyp}"
if tdesc.sfx != 0:
tiletype += f"_{tdesc.sfx}"
tt = chip.create_tile_type(tiletype)
tt.extra_data = TileExtraData(chip.strs.id(typename))

Expand All @@ -525,7 +558,8 @@ def create_pll_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
assert pin in _pll_outputs, f"Unknown PLL pin {pin}"
tt.create_wire(wire, "PLL_O")
tt.add_bel_pin(pll, pin, wire, PinType.OUTPUT)
return (tiletype, tt)
tdesc.tiletype = tiletype
return tt

# pinouts, packages...
_tbrlre = re.compile(r"IO([TBRL])(\d+)(\w)")
Expand Down Expand Up @@ -601,7 +635,6 @@ def main():
logic_tiletypes = db.tile_types['C']
io_tiletypes = db.tile_types['I']
ssram_tiletypes = db.tile_types['M']
gsr_tiletypes = {1}
pll_tiletypes = db.tile_types['P']

# Setup tile grid
Expand All @@ -612,8 +645,6 @@ def main():
assert ttyp not in created_tiletypes, "Duplication of corner types"
create_tiletype(create_corner_tiletype, ch, db, x, y, ttyp)
continue
if ttyp in gsr_tiletypes:
create_tiletype(create_gsr_tiletype, ch, db, x, y, ttyp)
elif ttyp in logic_tiletypes:
create_tiletype(create_logic_tiletype, ch, db, x, y, ttyp)
elif ttyp in ssram_tiletypes:
Expand Down
25 changes: 10 additions & 15 deletions himbaechel/uarch/gowin/pack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1070,22 +1070,17 @@ struct GowinPacker
}
}
if (!user_gsr) {
bool have_gsr_bel = false;
auto bels = ctx->getBels();
for (auto bid : bels) {
if (ctx->getBelType(bid) == id_GSR) {
have_gsr_bel = true;
break;
}
}
if (have_gsr_bel) {
// make default GSR
auto gsr_cell = std::make_unique<CellInfo>(ctx, id_GSR, id_GSR);
gsr_cell->addInput(id_GSRI);
gsr_cell->connectPort(id_GSRI, ctx->nets[ctx->id("$PACKER_VCC")].get());
ctx->cells[gsr_cell->name] = std::move(gsr_cell);
// make default GSR
auto gsr_cell = std::make_unique<CellInfo>(ctx, id_GSR, id_GSR);
gsr_cell->addInput(id_GSRI);
gsr_cell->connectPort(id_GSRI, ctx->nets[ctx->id("$PACKER_VCC")].get());
ctx->cells[gsr_cell->name] = std::move(gsr_cell);
}
if (ctx->verbose) {
if (user_gsr) {
log_info("Have user GSR\n");
} else {
log_info("No GSR in the chip base\n");
log_info("No user GSR. Make one.\n");
}
}
}
Expand Down

0 comments on commit a823543

Please sign in to comment.