From 6b7723e4c1be110a98f28c9ab7ad47bb1a61bb54 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sun, 7 Apr 2024 21:47:23 +1000 Subject: [PATCH] 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 --- himbaechel/uarch/gowin/constids.inc | 4 ++++ himbaechel/uarch/gowin/gowin.h | 6 ++++++ himbaechel/uarch/gowin/gowin_arch_gen.py | 25 ++++++++++++++++++++++++ himbaechel/uarch/gowin/gowin_utils.cc | 23 ++++++++++++++++++++-- himbaechel/uarch/gowin/gowin_utils.h | 5 ++++- himbaechel/uarch/gowin/pack.cc | 22 +++++++++++++++++++++ 6 files changed, 82 insertions(+), 3 deletions(-) diff --git a/himbaechel/uarch/gowin/constids.inc b/himbaechel/uarch/gowin/constids.inc index b3568720..78ddb1fb 100644 --- a/himbaechel/uarch/gowin/constids.inc +++ b/himbaechel/uarch/gowin/constids.inc @@ -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) diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index aa3dcd08..abff9031 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -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; diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index 3ba94c52..2aab88f6 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -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): diff --git a/himbaechel/uarch/gowin/gowin_utils.cc b/himbaechel/uarch/gowin/gowin_utils.cc index df255527..3aba699d 100644 --- a/himbaechel/uarch/gowin/gowin_utils.cc +++ b/himbaechel/uarch/gowin/gowin_utils.cc @@ -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(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; diff --git a/himbaechel/uarch/gowin/gowin_utils.h b/himbaechel/uarch/gowin/gowin_utils.h index ea466b11..ce6b8d9f 100644 --- a/himbaechel/uarch/gowin/gowin_utils.h +++ b/himbaechel/uarch/gowin/gowin_utils.h @@ -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); diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index ad85fce1..c28a9eea 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -2624,6 +2624,8 @@ struct GowinPacker { log_info("Pack PLL...\n"); + pool 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")); + } + } + } } } }