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_VCC)
X(PLL)
X(CLKIN_T)
X(CLKIN_C)
X(FB_T)
X(FB_C)
X(BOTTOM_IO_PORT_A)
X(BOTTOM_IO_PORT_B)
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
// ==========================================
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 {
int32_t class_id;
int16_t io16_x_off;

View File

@ -157,6 +157,20 @@ class ChipExtraData(BBAStruct):
self.bottom_io.serialise(f"{context}_bottom_io", bba)
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
class TypeDesc:
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
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...
_tbrlre = re.compile(r"IO([TBRL])(\d+)(\w)")
def create_packages(chip: Chip, db: chipdb):
@ -953,6 +976,8 @@ def create_packages(chip: Chip, db: chipdb):
pad_func = pad_func.rstrip('/')
bank = int(db.pin_bank[io_loc])
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
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
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();
size_t len = ctx->package_info->pads.ssize();
@ -45,6 +45,25 @@ IdStringList GowinUtils::get_pin_funcs(BelId bel)
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)
{
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);
// 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
bool is_simple_io_bel(BelId bel);

View File

@ -2624,6 +2624,8 @@ struct GowinPacker
{
log_info("Pack PLL...\n");
pool<BelId> used_pll_bels;
for (auto &cell : ctx->cells) {
auto &ci = *cell.second;
@ -2639,6 +2641,26 @@ struct GowinPacker
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"));
}
}
}
}
}
}