mirror of https://github.com/YosysHQ/nextpnr.git
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:
parent
8ce9918405
commit
0be6173064
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue