From c6f408dfa7e27cd8dac790ae84b347201005b65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Milanovi=C4=87?= Date: Tue, 21 Oct 2025 13:47:07 +0200 Subject: [PATCH] gatemate: additional region handling (#1583) * gatemate: Use GATEMATE_DIE attribute to select placement die * add DIE parameter in CCF * add penalty delay when crossing between dies * Add predictDelay --- himbaechel/uarch/gatemate/ccf.cc | 8 +++++- himbaechel/uarch/gatemate/constids.inc | 2 ++ himbaechel/uarch/gatemate/delay.cc | 15 +++++++++- himbaechel/uarch/gatemate/gatemate.h | 3 +- himbaechel/uarch/gatemate/pack.cc | 38 ++++++++++++++++++++++---- himbaechel/uarch/gatemate/pack.h | 3 ++ himbaechel/uarch/gatemate/pack_cpe.cc | 18 ++++++++++-- himbaechel/uarch/gatemate/pack_io.cc | 22 +++++++++++---- 8 files changed, 92 insertions(+), 17 deletions(-) diff --git a/himbaechel/uarch/gatemate/ccf.cc b/himbaechel/uarch/gatemate/ccf.cc index 85baca90..4738299d 100644 --- a/himbaechel/uarch/gatemate/ccf.cc +++ b/himbaechel/uarch/gatemate/ccf.cc @@ -69,7 +69,7 @@ struct GateMateCCFReader boost::algorithm::to_upper(name); if (expr.size() != 2) { - if (name == "LOC" || name == "DRIVE" || name == "DELAY_IBF" || name == "DELAY_OBF") + if (name == "LOC" || name == "DRIVE" || name == "DELAY_IBF" || name == "DELAY_OBF" || name == "DIE") log_error("Parameter must be in form NAME=VALUE (on line %d)\n", lineno); log_warning("Parameter '%s' missing value, defaulting to '1' (on line %d)\n", name.c_str(), lineno); expr.push_back("1"); @@ -99,6 +99,12 @@ struct GateMateCCFReader uarch->available_pads.erase(ctx->id("SER_CLK_N")); if (value == "SER_CLK_N") uarch->available_pads.erase(ctx->id("SER_CLK")); + } else if (name == "DIE") { + if (uarch->die_to_index.count(ctx->id(value))) { + props->emplace(ctx->id(name), Property(value)); + } else + log_error("Uknown value '%s' for parameter '%s' in line %d.\n", value.c_str(), name.c_str(), + lineno); } else if (name == "SCHMITT_TRIGGER" || name == "PULLUP" || name == "PULLDOWN" || name == "KEEPER" || name == "FF_IBF" || name == "FF_OBF" || name == "LVDS_BOOST" || name == "LVDS_RTERM") { if (value == "1") diff --git a/himbaechel/uarch/gatemate/constids.inc b/himbaechel/uarch/gatemate/constids.inc index e82a1620..c8a484a6 100644 --- a/himbaechel/uarch/gatemate/constids.inc +++ b/himbaechel/uarch/gatemate/constids.inc @@ -2473,6 +2473,8 @@ X(1A) X(1B) X(2A) X(2B) +X(DIE) +X(GATEMATE_DIE) // Timing X(timing_ADDF2x_IN5_8_comb2) diff --git a/himbaechel/uarch/gatemate/delay.cc b/himbaechel/uarch/gatemate/delay.cc index d6ce7275..cbfcfcfc 100644 --- a/himbaechel/uarch/gatemate/delay.cc +++ b/himbaechel/uarch/gatemate/delay.cc @@ -30,10 +30,23 @@ NEXTPNR_NAMESPACE_BEGIN delay_t GateMateImpl::estimateDelay(WireId src, WireId dst) const { int sx, sy, dx, dy; + int d2d = 0; + if (tile_extra_data(src.tile)->die != tile_extra_data(dst.tile)->die) + d2d += 2000; tile_xy(ctx->chip_info, src.tile, sx, sy); tile_xy(ctx->chip_info, dst.tile, dx, dy); - return 100 + 100 * (std::abs(dx - sx) + std::abs(dy - sy)); + return 100 + 100 * (std::abs(dx - sx) + std::abs(dy - sy)) + d2d; +} + +delay_t GateMateImpl::predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const +{ + int d2d = 0; + if (tile_extra_data(src_bel.tile)->die != tile_extra_data(dst_bel.tile)->die) + d2d += 2000; + + Loc src_loc = ctx->getBelLocation(src_bel), dst_loc = ctx->getBelLocation(dst_bel); + return 100 + 100 * (std::abs(dst_loc.x - src_loc.x) + std::abs(dst_loc.y - src_loc.y)) + d2d; } bool GateMateImpl::get_delay_from_tmg_db(IdString id, DelayQuad &delay) const diff --git a/himbaechel/uarch/gatemate/gatemate.h b/himbaechel/uarch/gatemate/gatemate.h index cb8f87a9..25b2face 100644 --- a/himbaechel/uarch/gatemate/gatemate.h +++ b/himbaechel/uarch/gatemate/gatemate.h @@ -58,6 +58,7 @@ struct GateMateImpl : HimbaechelAPI bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override; delay_t estimateDelay(WireId src, WireId dst) const override; + delay_t predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const override; bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override; TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override; TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const override; @@ -106,6 +107,7 @@ struct GateMateImpl : HimbaechelAPI pool ignore; MultiDieStrategy strategy; dict index_to_die; + dict die_to_index; private: bool getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc, @@ -139,7 +141,6 @@ struct GateMateImpl : HimbaechelAPI std::map timing; dict ram_signal_clk; IdString forced_die; - dict die_to_index; }; NEXTPNR_NAMESPACE_END diff --git a/himbaechel/uarch/gatemate/pack.cc b/himbaechel/uarch/gatemate/pack.cc index 51620cbe..98d797a2 100644 --- a/himbaechel/uarch/gatemate/pack.cc +++ b/himbaechel/uarch/gatemate/pack.cc @@ -420,10 +420,35 @@ void GateMatePacker::assign_clocks() if (user.cell->region && user.cell->region->name != die) log_error("Trying to assign cell '%s' to multiple regions.\n", user.cell->name.c_str(ctx)); ctx->constrainCellToRegion(user.cell->name, die); - if (user.cell->cluster != ClusterId()) { - CellInfo *root = ctx->getClusterRootCell(user.cell->cluster); - recursiveAddToRegion(root, die); - } + } + } +} + +void GateMatePacker::assign_regions() +{ + log_info("Assign cell region based on attributes..\n"); + for (auto &cell : ctx->cells) { + CellInfo &ci = *cell.second; + if (ci.attrs.count(id_GATEMATE_DIE) != 0) { + std::string die_name = str_or_default(ci.attrs, id_GATEMATE_DIE, ""); + IdString die = ctx->id(die_name); + if (!uarch->die_to_index.count(die)) + log_error("Trying to assign cell '%s' to non existing die '%s'.\n", ci.name.c_str(ctx), die.c_str(ctx)); + if (ci.region && ci.region->name != die) + log_error("Trying to assign cell '%s' to multiple regions.\n", ci.name.c_str(ctx)); + ctx->constrainCellToRegion(ci.name, die); + } + } +} + +void GateMatePacker::fix_regions() +{ + log_info("Fix cell assigned regions..\n"); + for (auto &cell : ctx->cells) { + CellInfo &ci = *cell.second; + if (ci.region && ci.cluster != ClusterId()) { + CellInfo *root = ctx->getClusterRootCell(ci.cluster); + recursiveAddToRegion(root, ci.region->name); } } } @@ -487,6 +512,8 @@ void GateMateImpl::pack() preferred_die = 0; GateMatePacker packer(ctx, this); + if (forced_die == IdString()) + packer.assign_regions(); packer.pack_constants(); packer.cleanup(); packer.pack_io(); @@ -503,16 +530,15 @@ void GateMateImpl::pack() packer.copy_clocks(); packer.remove_constants(); packer.remove_double_constrained(); - if (forced_die != IdString()) { for (auto &cell : ctx->cells) { if (cell.second->belStrength != PlaceStrength::STRENGTH_FIXED) ctx->constrainCellToRegion(cell.second->name, forced_die); } } - if (strategy == MultiDieStrategy::FULL_USE) packer.assign_clocks(); + packer.fix_regions(); } void GateMateImpl::repack() diff --git a/himbaechel/uarch/gatemate/pack.h b/himbaechel/uarch/gatemate/pack.h index 82da5ff1..d7bae92d 100644 --- a/himbaechel/uarch/gatemate/pack.h +++ b/himbaechel/uarch/gatemate/pack.h @@ -72,6 +72,8 @@ struct GateMatePacker void reassign_clocks(); void copy_clocks(); void assign_clocks(); + void assign_regions(); + void fix_regions(); private: void rename_param(CellInfo *cell, IdString name, IdString new_name, int width); @@ -93,6 +95,7 @@ struct GateMatePacker void strategy_clk1(); void strategy_full(); + void override_region(CellInfo *first, CellInfo *second); void recursiveAddToRegion(CellInfo *root, IdString die); PllCfgRecord get_pll_settings(double f_ref, double f_core, int mode, int low_jitter, bool pdiv0_mux, bool feedback); diff --git a/himbaechel/uarch/gatemate/pack_cpe.cc b/himbaechel/uarch/gatemate/pack_cpe.cc index 93f42fab..dbc62492 100644 --- a/himbaechel/uarch/gatemate/pack_cpe.cc +++ b/himbaechel/uarch/gatemate/pack_cpe.cc @@ -166,6 +166,18 @@ void GateMatePacker::dff_update_params() } } +void GateMatePacker::override_region(CellInfo *first, CellInfo *second) +{ + if (first->region) { + if (second->region && second->region->name != first->region->name) { + log_warning("Unable to place cell '%s' in '%s' region\n", first->name.c_str(ctx), + first->region->name.c_str(ctx)); + } + } else { + second->region = first->region; + } +} + void GateMatePacker::pack_cpe() { log_info("Packing CPEs..\n"); @@ -173,7 +185,7 @@ void GateMatePacker::pack_cpe() auto merge_dff = [&](CellInfo &ci, CellInfo *dff) { dff->cluster = ci.name; - dff->region = ci.region; + override_region(dff, &ci); dff->constr_abs_z = false; dff->constr_z = +2; ci.cluster = ci.name; @@ -520,7 +532,7 @@ void GateMatePacker::pack_addf() CellInfo *dff = net_only_drives(ctx, o, is_dff, id_D, true); if (dff && are_ffs_compatible(dff, other)) { dff->cluster = cell->cluster; - dff->region = cell->region; + override_region(dff, cell); dff->constr_abs_z = false; dff->constr_z = +2; cell->constr_children.push_back(dff); @@ -589,7 +601,7 @@ void GateMatePacker::pack_addf() CellInfo *cy = grp.at(i); if (i != 0) { cy->cluster = root->name; - cy->region = root->region; + override_region(cy, root); root->constr_children.push_back(cy); cy->constr_abs_z = false; cy->constr_y = +i; diff --git a/himbaechel/uarch/gatemate/pack_io.cc b/himbaechel/uarch/gatemate/pack_io.cc index d6f8e5d1..575acce5 100644 --- a/himbaechel/uarch/gatemate/pack_io.cc +++ b/himbaechel/uarch/gatemate/pack_io.cc @@ -28,7 +28,7 @@ std::string get_die_name(int total_dies, int die) { if (total_dies == 1) return ""; - return stringf("on die '%d%c'", int(die / total_dies) + 1, 'A' + int(die % total_dies)); + return stringf(" on die '%d%c'", int(die / total_dies) + 1, 'A' + int(die % total_dies)); } void GateMatePacker::pack_io() @@ -187,6 +187,8 @@ void GateMatePacker::pack_io() keys.push_back(p.first); continue; } + if (p.first.in(id_DIE)) + continue; if (ci.type.in(id_CC_IBUF, id_CC_IOBUF) && p.first.in(id_PULLUP, id_PULLDOWN, id_KEEPER, id_SCHMITT_TRIGGER, id_DELAY_IBF, id_FF_IBF)) continue; @@ -305,10 +307,20 @@ void GateMatePacker::pack_io() } BelId bel; - if (uarch->locations.count(std::make_pair(ctx->id(loc), uarch->preferred_die))) - bel = ctx->getBelByLocation(uarch->locations[std::make_pair(ctx->id(loc), uarch->preferred_die)]); - else - bel = ctx->get_package_pin_bel(ctx->id(loc)); + if (ci.params.count(id_DIE)) { + std::string die_name = str_or_default(ci.params, id_DIE, ""); + int die = uarch->die_to_index[ctx->id(die_name)]; + ci.unsetParam(id_DIE); + if (uarch->locations.count(std::make_pair(ctx->id(loc), die))) + bel = ctx->getBelByLocation(uarch->locations[std::make_pair(ctx->id(loc), die)]); + else + log_error("Unable to place '%s' to specified '%s' die.\n", ci.name.c_str(ctx), die_name.c_str()); + } else { + if (uarch->locations.count(std::make_pair(ctx->id(loc), uarch->preferred_die))) + bel = ctx->getBelByLocation(uarch->locations[std::make_pair(ctx->id(loc), uarch->preferred_die)]); + else + bel = ctx->get_package_pin_bel(ctx->id(loc)); + } if (bel == BelId()) log_error("Unable to constrain IO '%s', device does not have a pin named '%s'\n", ci.name.c_str(ctx), loc.c_str());