Gowin. Implement power saving primitive

As the board on the GW1N-1 chip becomes a rarity, its replacement is the
Tangnano1k board with the GW1NZ-1 chip. This chip has a unique mechanism
for turning off power to important things such as OSC, PLL, etc.

Here we introduce a primitive that allows energy saving to be controlled
dynamically.

We also bring the names of some functions to uniformity.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
YRabbit 2024-07-06 19:14:43 +10:00 committed by myrtle
parent ba293437e0
commit 7dd4a8c1d5
7 changed files with 69 additions and 7 deletions

View File

@ -987,6 +987,10 @@ X(GSR)
X(GSR0)
X(GSRI)
// power saving
X(BANDGAP)
X(BGEN)
// inverter
X(INV)

View File

@ -259,7 +259,7 @@ void GowinImpl::adjust_dsp_pin_mapping(void)
void GowinImpl::prePlace() { assign_cell_info(); }
void GowinImpl::postPlace()
{
gwu.have_SP32();
gwu.has_SP32();
if (ctx->debug) {
log_info("================== Final Placement ===================\n");
for (auto &cell : ctx->cells) {

View File

@ -99,6 +99,7 @@ NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
static constexpr int32_t NEED_SP_FIX = 2;
static constexpr int32_t NEED_BSRAM_OUTREG_FIX = 4;
static constexpr int32_t NEED_BLKSEL_FIX = 8;
static constexpr int32_t HAS_BANDGAP = 16;
});
} // namespace
@ -131,6 +132,7 @@ enum
GSR_Z = 276,
VCC_Z = 277,
VSS_Z = 278,
BANDGAP_Z = 279,
// 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

View File

@ -19,6 +19,7 @@ CHIP_HAS_SP32 = 0x1
CHIP_NEED_SP_FIX = 0x2
CHIP_NEED_BSRAM_OUTREG_FIX = 0x4
CHIP_NEED_BLKSEL_FIX = 0x8
CHIP_HAS_BANDGAP = 0x10
# Z of the bels
# sync with C++ part!
@ -46,6 +47,7 @@ PLL_Z = 275
GSR_Z = 276
VCC_Z = 277
GND_Z = 278
BANDGAP_Z = 279
DSP_Z = 509
@ -338,6 +340,11 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
tt.create_wire(wire, "GSRI")
bel = tt.create_bel("GSR", "GSR", z = GSR_Z)
tt.add_bel_pin(bel, "GSRI", wire, PinType.INPUT)
elif func == 'bandgap':
wire = desc['wire']
tt.create_wire(wire, "BGEN")
bel = tt.create_bel("BANDGAP", "BANDGAP", z = BANDGAP_Z)
tt.add_bel_pin(bel, "BGEN", wire, PinType.INPUT)
if func == 'io16':
role = desc['role']
if role == 'MAIN':
@ -1024,6 +1031,8 @@ def main():
chip_flags |= CHIP_NEED_BSRAM_OUTREG_FIX;
if "NEED_BLKSEL_FIX" in db.chip_flags:
chip_flags |= CHIP_NEED_BLKSEL_FIX;
if "HAS_BANDGAP" in db.chip_flags:
chip_flags |= CHIP_HAS_BANDGAP;
X = db.cols;
Y = db.rows;

View File

@ -94,7 +94,7 @@ bool GowinUtils::is_diff_io_supported(IdString type)
return false;
}
bool GowinUtils::have_bottom_io_cnds(void)
bool GowinUtils::has_bottom_io_cnds(void)
{
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
return extra->bottom_io.conditions.size() != 0;
@ -112,7 +112,13 @@ IdString GowinUtils::get_bottom_io_wire_b_net(int8_t condition)
return IdString(extra->bottom_io.conditions[condition].wire_b_net);
}
bool GowinUtils::have_SP32(void)
bool GowinUtils::has_BANDGAP(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_BANDGAP;
}
bool GowinUtils::has_SP32(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_SP32;

View File

@ -35,11 +35,14 @@ struct GowinUtils
BelId get_io_bel_from_iologic(BelId bel);
// BSRAM
bool have_SP32(void);
bool has_SP32(void);
bool need_SP_fix(void);
bool need_BSRAM_OUTREG_fix(void);
bool need_BLKSEL_fix(void);
// Power saving
bool has_BANDGAP(void);
// DSP
inline int get_dsp_18_z(int z) const { return z & (~3); }
inline int get_dsp_9_idx(int z) const { return z & 3; }
@ -65,7 +68,7 @@ struct GowinUtils
CellInfo *dsp_bus_dst(const CellInfo *ci, const char *bus_prefix, int wire_num) const;
bool is_diff_io_supported(IdString type);
bool have_bottom_io_cnds(void);
bool has_bottom_io_cnds(void);
IdString get_bottom_io_wire_a_net(int8_t condition);
IdString get_bottom_io_wire_b_net(int8_t condition);

View File

@ -68,7 +68,7 @@ struct GowinPacker
void config_bottom_row(CellInfo &ci, Loc loc, uint8_t cnd = Bottom_io_POD::NORMAL)
{
if (!gwu.have_bottom_io_cnds()) {
if (!gwu.has_bottom_io_cnds()) {
return;
}
if (!ci.type.in(id_OBUF, id_TBUF, id_IOBUF)) {
@ -1802,7 +1802,7 @@ struct GowinPacker
// For GW1N-9/GW1NR-9/GW1NS-4 series, 32/36-bit SP/SPX9 is divided into two
// SP/SPX9s, which occupy two BSRAMs.
// So divide it here
if ((bit_width == 32 || bit_width == 36) && !gwu.have_SP32()) {
if ((bit_width == 32 || bit_width == 36) && !gwu.has_SP32()) {
divide_sp(ci, new_cells);
bit_width = ci->params.at(id_BIT_WIDTH).as_int64();
}
@ -2839,6 +2839,41 @@ struct GowinPacker
}
}
// ===================================
// Global power regulator
// ===================================
void pack_bandgap(void)
{
if (!gwu.has_BANDGAP()) {
return;
}
log_info("Pack BANDGAP...\n");
bool user_bandgap = false;
for (auto &cell : ctx->cells) {
auto &ci = *cell.second;
if (ci.type == id_BANDGAP) {
user_bandgap = true;
break;
}
}
if (!user_bandgap) {
// make default BANDGAP
auto bandgap_cell = std::make_unique<CellInfo>(ctx, id_BANDGAP, id_BANDGAP);
bandgap_cell->addInput(id_BGEN);
bandgap_cell->connectPort(id_BGEN, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
ctx->cells[bandgap_cell->name] = std::move(bandgap_cell);
}
if (ctx->verbose) {
if (user_bandgap) {
log_info("Have user BANDGAP\n");
} else {
log_info("No user BANDGAP. Make one.\n");
}
}
}
// ===================================
// Replace INV with LUT
// ===================================
@ -2957,6 +2992,9 @@ struct GowinPacker
pack_gsr();
ctx->check();
pack_bandgap();
ctx->check();
pack_wideluts();
ctx->check();