From 7dd4a8c1d546c048b3b755d361820c865add7956 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sat, 6 Jul 2024 19:14:43 +1000 Subject: [PATCH] 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 --- himbaechel/uarch/gowin/constids.inc | 4 +++ himbaechel/uarch/gowin/gowin.cc | 2 +- himbaechel/uarch/gowin/gowin.h | 2 ++ himbaechel/uarch/gowin/gowin_arch_gen.py | 9 +++++ himbaechel/uarch/gowin/gowin_utils.cc | 10 ++++-- himbaechel/uarch/gowin/gowin_utils.h | 7 ++-- himbaechel/uarch/gowin/pack.cc | 42 ++++++++++++++++++++++-- 7 files changed, 69 insertions(+), 7 deletions(-) diff --git a/himbaechel/uarch/gowin/constids.inc b/himbaechel/uarch/gowin/constids.inc index 032de7ac65..c597a8cfdd 100644 --- a/himbaechel/uarch/gowin/constids.inc +++ b/himbaechel/uarch/gowin/constids.inc @@ -987,6 +987,10 @@ X(GSR) X(GSR0) X(GSRI) +// power saving +X(BANDGAP) +X(BGEN) + // inverter X(INV) diff --git a/himbaechel/uarch/gowin/gowin.cc b/himbaechel/uarch/gowin/gowin.cc index 5bb7bd2f96..8942154b33 100644 --- a/himbaechel/uarch/gowin/gowin.cc +++ b/himbaechel/uarch/gowin/gowin.cc @@ -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) { diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index c815fe0a2c..b2fc5f80ef 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -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 diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index cc19e3c09c..a6cffd358b 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -19,6 +19,7 @@ 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 @@ 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; diff --git a/himbaechel/uarch/gowin/gowin_utils.cc b/himbaechel/uarch/gowin/gowin_utils.cc index 603b6fc5b5..37cff7077c 100644 --- a/himbaechel/uarch/gowin/gowin_utils.cc +++ b/himbaechel/uarch/gowin/gowin_utils.cc @@ -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(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(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(ctx->chip_info->extra_data.get()); return extra->chip_flags & Extra_chip_data_POD::HAS_SP32; diff --git a/himbaechel/uarch/gowin/gowin_utils.h b/himbaechel/uarch/gowin/gowin_utils.h index 65ae632e99..7b76ea9aae 100644 --- a/himbaechel/uarch/gowin/gowin_utils.h +++ b/himbaechel/uarch/gowin/gowin_utils.h @@ -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); diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index b0975b3a3f..7fedad6e15 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -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(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();