Gowin. Add PLL pads.

If the CLKIN input of the PLL is connected to a special pin, then it
makes sense to try to place the PLL so that it uses a direct implicit
non-switched connection to this pin.

The transfer of information about pins for various purposes has been
implemented (clock input signal, feedback, etc), but so far only CLKIN
is used.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
YRabbit 2024-04-07 21:47:23 +10:00 committed by myrtle
parent 9bb46b98b4
commit 6b7723e4c1
6 changed files with 82 additions and 3 deletions

View File

@ -1140,6 +1140,10 @@ X(router)
X(GOWIN_GND) X(GOWIN_GND)
X(GOWIN_VCC) X(GOWIN_VCC)
X(PLL) X(PLL)
X(CLKIN_T)
X(CLKIN_C)
X(FB_T)
X(FB_C)
X(BOTTOM_IO_PORT_A) X(BOTTOM_IO_PORT_A)
X(BOTTOM_IO_PORT_B) X(BOTTOM_IO_PORT_B)
X(IOLOGIC_DUMMY) X(IOLOGIC_DUMMY)

View File

@ -65,6 +65,12 @@ inline bool is_dsp(const CellInfo *cell) { return type_is_dsp(cell->type); }
// ========================================== // ==========================================
// extra data in the chip db // extra data in the chip db
// ========================================== // ==========================================
NPNR_PACKED_STRUCT(struct Pad_extra_data_POD {
int32_t pll_tile;
int32_t pll_bel;
int32_t pll_type;
});
NPNR_PACKED_STRUCT(struct Tile_extra_data_POD { NPNR_PACKED_STRUCT(struct Tile_extra_data_POD {
int32_t class_id; int32_t class_id;
int16_t io16_x_off; int16_t io16_x_off;

View File

@ -157,6 +157,20 @@ class ChipExtraData(BBAStruct):
self.bottom_io.serialise(f"{context}_bottom_io", bba) self.bottom_io.serialise(f"{context}_bottom_io", bba)
bba.slice(f"{context}_diff_io_types", len(self.diff_io_types)) bba.slice(f"{context}_diff_io_types", len(self.diff_io_types))
@dataclass
class PadExtraData(BBAStruct):
# Which PLL does this pad belong to.
pll_tile: IdString
pll_bel: IdString
pll_type: IdString
def serialise_lists(self, context: str, bba: BBAWriter):
pass
def serialise(self, context: str, bba: BBAWriter):
bba.u32(self.pll_tile.index)
bba.u32(self.pll_bel.index)
bba.u32(self.pll_type.index)
# Unique features of the tiletype # Unique features of the tiletype
class TypeDesc: class TypeDesc:
def __init__(self, dups, tiletype = '', extra_func = None, sfx = 0): def __init__(self, dups, tiletype = '', extra_func = None, sfx = 0):
@ -917,6 +931,15 @@ def create_pll_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tdesc
tdesc.tiletype = tiletype tdesc.tiletype = tiletype
return tt return tt
# add Pll's bel to the pad
def add_pll(chip: Chip, db: chipdb, pad: PadInfo, ioloc: str):
try:
if ioloc in db.pad_pll:
row, col, ttyp, bel_name = db.pad_pll[ioloc]
pad.extra_data = PadExtraData(chip.strs.id(f'X{col}Y{row}'), chip.strs.id(bel_name), chip.strs.id(ttyp))
except:
return
# pinouts, packages... # pinouts, packages...
_tbrlre = re.compile(r"IO([TBRL])(\d+)(\w)") _tbrlre = re.compile(r"IO([TBRL])(\d+)(\w)")
def create_packages(chip: Chip, db: chipdb): def create_packages(chip: Chip, db: chipdb):
@ -953,6 +976,8 @@ def create_packages(chip: Chip, db: chipdb):
pad_func = pad_func.rstrip('/') pad_func = pad_func.rstrip('/')
bank = int(db.pin_bank[io_loc]) bank = int(db.pin_bank[io_loc])
pad = pkg.create_pad(pinno, tile, bel, pad_func, bank) pad = pkg.create_pad(pinno, tile, bel, pad_func, bank)
# add PLL if any is connected
add_pll(chip, db, pad, io_loc)
# Extra chip data # Extra chip data
def create_extra_data(chip: Chip, db: chipdb, chip_flags: int): def create_extra_data(chip: Chip, db: chipdb, chip_flags: int):

View File

@ -30,9 +30,9 @@ Loc GowinUtils::get_tile_io16_offs(int x, int y)
} }
// pin functions: GCLKT_4, SSPI_CS, READY etc // pin functions: GCLKT_4, SSPI_CS, READY etc
IdStringList GowinUtils::get_pin_funcs(BelId bel) IdStringList GowinUtils::get_pin_funcs(BelId io_bel)
{ {
IdStringList bel_name = ctx->getBelName(bel); IdStringList bel_name = ctx->getBelName(io_bel);
const PadInfoPOD *pins = ctx->package_info->pads.get(); const PadInfoPOD *pins = ctx->package_info->pads.get();
size_t len = ctx->package_info->pads.ssize(); size_t len = ctx->package_info->pads.ssize();
@ -45,6 +45,25 @@ IdStringList GowinUtils::get_pin_funcs(BelId bel)
return IdStringList(); return IdStringList();
} }
// PLL pads
BelId GowinUtils::get_pll_bel(BelId io_bel, IdString type)
{
IdStringList bel_name = ctx->getBelName(io_bel);
const PadInfoPOD *pins = ctx->package_info->pads.get();
size_t len = ctx->package_info->pads.ssize();
for (size_t i = 0; i < len; i++) {
const PadInfoPOD *pin = &pins[i];
if (IdString(pin->tile) == bel_name[0] && IdString(pin->bel) == bel_name[1]) {
const Pad_extra_data_POD *extra = reinterpret_cast<const Pad_extra_data_POD *>(pin->extra_data.get());
if (extra != nullptr && IdString(extra->pll_type) == type) {
return ctx->getBelByName(IdStringList::concat(IdString(extra->pll_tile), IdString(extra->pll_bel)));
}
}
}
return BelId();
}
bool GowinUtils::is_simple_io_bel(BelId bel) bool GowinUtils::is_simple_io_bel(BelId bel)
{ {
return chip_bel_info(ctx->chip_info, bel).flags & BelFlags::FLAG_SIMPLE_IO; return chip_bel_info(ctx->chip_info, bel).flags & BelFlags::FLAG_SIMPLE_IO;

View File

@ -24,7 +24,10 @@ struct GowinUtils
Loc get_tile_io16_offs(int x, int y); Loc get_tile_io16_offs(int x, int y);
// pin functions: GCLKT_4, SSPI_CS, READY etc // pin functions: GCLKT_4, SSPI_CS, READY etc
IdStringList get_pin_funcs(BelId bel); IdStringList get_pin_funcs(BelId io_bel);
// PLL pads (type - CLKIN, FeedBack, etc)
BelId get_pll_bel(BelId io_bel, IdString type);
// Bels and pips // Bels and pips
bool is_simple_io_bel(BelId bel); bool is_simple_io_bel(BelId bel);

View File

@ -2624,6 +2624,8 @@ struct GowinPacker
{ {
log_info("Pack PLL...\n"); log_info("Pack PLL...\n");
pool<BelId> used_pll_bels;
for (auto &cell : ctx->cells) { for (auto &cell : ctx->cells) {
auto &ci = *cell.second; auto &ci = *cell.second;
@ -2639,6 +2641,26 @@ struct GowinPacker
ci.renamePort(ctx->idf("FDLY[%d]", i), ctx->idf("FDLY%d", i)); ci.renamePort(ctx->idf("FDLY[%d]", i), ctx->idf("FDLY%d", i));
} }
} }
// If CLKIN is connected to a special pin, then it makes sense
// to try to place the PLL so that it uses a direct connection
// to this pin.
if (ci.bel == BelId()) {
NetInfo *ni = ci.getPort(id_CLKIN);
if (ni && ni->driver.cell) {
BelId pll_bel = gwu.get_pll_bel(ni->driver.cell->bel, id_CLKIN_T);
if (ctx->debug) {
log_info("PLL clkin driver:%s at %s, PLL bel:%s\n", ctx->nameOf(ni->driver.cell),
ctx->getBelName(ni->driver.cell->bel).str(ctx).c_str(),
pll_bel != BelId() ? ctx->getBelName(pll_bel).str(ctx).c_str() : "NULL");
}
if (pll_bel != BelId() && used_pll_bels.count(pll_bel) == 0) {
used_pll_bels.insert(pll_bel);
ctx->bindBel(pll_bel, &ci, PlaceStrength::STRENGTH_LOCKED);
ci.disconnectPort(id_CLKIN);
ci.setParam(id_INSEL, std::string("CLKIN0"));
}
}
}
} }
} }
} }