Gowin. Add pin configurations bel/cell.

Prior to the 5A series, pin functions (GPIO/SSPI/JTAG/DONE/etc) were
switched using fuses. This was done during the binary image formation
stage for loading into the FPGA using the command line keys of the
gowin_pack program.

The 5A series features certain ports that connect to VCC or GND
depending on whether the pin is used as SSPI or GPIO, for example. This
mechanism exists in parallel with fuses, but it is not described
anywhere, nor is there a corresponding primitive.

To generate working images, we have no choice but to simulate this thing
at the nextpnr stage, since VCC/GND routing is required.

For now, two flags are added, responsible for the SSPI and I2C pin
functions.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
YRabbit 2025-08-08 07:10:18 +10:00 committed by Lofty
parent 8ce9918405
commit 0be6173064
6 changed files with 70 additions and 0 deletions

View File

@ -1011,6 +1011,11 @@ X(GSRI)
X(BANDGAP) X(BANDGAP)
X(BGEN) X(BGEN)
// pin function config
X(PINCFG)
X(SSPI)
X(I2C)
// inverter // inverter
X(INV) X(INV)

View File

@ -196,6 +196,7 @@ NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
static constexpr int32_t HAS_BANDGAP = 16; static constexpr int32_t HAS_BANDGAP = 16;
static constexpr int32_t HAS_PLL_HCLK = 32; static constexpr int32_t HAS_PLL_HCLK = 32;
static constexpr int32_t HAS_CLKDIV_HCLK = 64; static constexpr int32_t HAS_CLKDIV_HCLK = 64;
static constexpr int32_t HAS_PINCFG = 128;
}); });
} // namespace } // namespace
@ -243,6 +244,8 @@ enum
DLLDLY_Z = 303, // : 305 reserve for 2 DLLDLYs DLLDLY_Z = 303, // : 305 reserve for 2 DLLDLYs
PINCFG_Z = 400,
// The two least significant bits encode Z for 9-bit adders and // The two least significant bits encode Z for 9-bit adders and
// multipliers, if they are equal to 0, then we get Z of their common // multipliers, if they are equal to 0, then we get Z of their common
// 18-bit equivalent. // 18-bit equivalent.

View File

@ -22,6 +22,7 @@ CHIP_NEED_BLKSEL_FIX = 0x8
CHIP_HAS_BANDGAP = 0x10 CHIP_HAS_BANDGAP = 0x10
CHIP_HAS_PLL_HCLK = 0x20 CHIP_HAS_PLL_HCLK = 0x20
CHIP_HAS_CLKDIV_HCLK = 0x40 CHIP_HAS_CLKDIV_HCLK = 0x40
CHIP_HAS_PINCFG = 0x80
# Tile flags # Tile flags
TILE_I3C_CAPABLE_IO = 0x1 TILE_I3C_CAPABLE_IO = 0x1
@ -67,6 +68,8 @@ MIPIIBUF_Z = 302
DLLDLY_Z = 303 # : 305 reserve for 2 DLLDLYs DLLDLY_Z = 303 # : 305 reserve for 2 DLLDLYs
PINCFG_Z = 400 #
DSP_Z = 509 DSP_Z = 509
DSP_0_Z = 511 # DSP macro 0 DSP_0_Z = 511 # DSP macro 0
@ -755,6 +758,13 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
if not tt.has_wire(wire): if not tt.has_wire(wire):
tt.create_wire(wire, "EMCU_OUT") tt.create_wire(wire, "EMCU_OUT")
tt.add_bel_pin(bel, port, wire, PinType.OUTPUT) tt.add_bel_pin(bel, port, wire, PinType.OUTPUT)
elif func == 'pincfg':
bel = tt.create_bel("PINCFG", "PINCFG", PINCFG_Z)
portmap = desc['ins']
for port, wire in portmap.items():
if not tt.has_wire(wire):
tt.create_wire(wire, "PINCFG_IN")
tt.add_bel_pin(bel, port, wire, PinType.INPUT)
def create_tiletype(create_func, chip: Chip, db: chipdb, x: int, y: int, ttyp: int): def create_tiletype(create_func, chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
has_extra_func = (y, x) in db.extra_func has_extra_func = (y, x) in db.extra_func
@ -1566,6 +1576,8 @@ def main():
chip_flags |= CHIP_HAS_PLL_HCLK; chip_flags |= CHIP_HAS_PLL_HCLK;
if "HAS_CLKDIV_HCLK" in db.chip_flags: if "HAS_CLKDIV_HCLK" in db.chip_flags:
chip_flags |= CHIP_HAS_CLKDIV_HCLK; chip_flags |= CHIP_HAS_CLKDIV_HCLK;
if "HAS_PINCFG" in db.chip_flags:
chip_flags |= CHIP_HAS_PINCFG;
X = db.cols; X = db.cols;
Y = db.rows; Y = db.rows;

View File

@ -330,6 +330,12 @@ bool GowinUtils::has_BANDGAP(void)
return extra->chip_flags & Extra_chip_data_POD::HAS_BANDGAP; return extra->chip_flags & Extra_chip_data_POD::HAS_BANDGAP;
} }
bool GowinUtils::has_PINCFG(void)
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->chip_flags & Extra_chip_data_POD::HAS_PINCFG;
}
bool GowinUtils::has_SP32(void) bool GowinUtils::has_SP32(void)
{ {
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get()); const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());

View File

@ -96,6 +96,9 @@ struct GowinUtils
// Power saving // Power saving
bool has_BANDGAP(void); bool has_BANDGAP(void);
// Pin function configuration via wires
bool has_PINCFG(void);
// DSP // DSP
inline int get_dsp_18_z(int z) const { return z & (~3); } inline int get_dsp_18_z(int z) const { return z & (~3); }
inline int get_dsp_9_idx(int z) const { return z & 3; } inline int get_dsp_9_idx(int z) const { return z & 3; }

View File

@ -3681,6 +3681,44 @@ struct GowinPacker
} }
} }
// ===================================
// Pin function configuration via wires
// ===================================
void pack_pincfg(void)
{
if (!gwu.has_PINCFG()) {
return;
}
log_info("Pack PINCFG...\n");
auto pincfg_cell = std::make_unique<CellInfo>(ctx, id_PINCFG, id_PINCFG);
for (int i = 0; i < 5; ++i) {
IdString port = ctx->idf("UNK%d_VCC", i);
pincfg_cell->addInput(port);
pincfg_cell->connectPort(port, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
}
const ArchArgs &args = ctx->getArchArgs();
pincfg_cell->addInput(id_SSPI);
if (args.options.count("sspi_as_gpio")) {
pincfg_cell->connectPort(id_SSPI, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
pincfg_cell->setParam(id_SSPI, 1);
} else {
pincfg_cell->connectPort(id_SSPI, ctx->nets.at(ctx->id("$PACKER_GND")).get());
}
pincfg_cell->addInput(id_I2C);
if (args.options.count("i2c_as_gpio")) {
pincfg_cell->connectPort(id_I2C, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
pincfg_cell->setParam(id_I2C, 1);
} else {
pincfg_cell->connectPort(id_I2C, ctx->nets.at(ctx->id("$PACKER_GND")).get());
}
ctx->cells[pincfg_cell->name] = std::move(pincfg_cell);
}
// =================================== // ===================================
// Global power regulator // Global power regulator
// =================================== // ===================================
@ -4245,6 +4283,9 @@ struct GowinPacker
pack_gsr(); pack_gsr();
ctx->check(); ctx->check();
pack_pincfg();
ctx->check();
pack_hclk(); pack_hclk();
ctx->check(); ctx->check();