From 0829b46e9ba9ee5031dc432d6559c0f31f42fcbb Mon Sep 17 00:00:00 2001 From: Lofty Date: Thu, 17 Jul 2025 07:54:22 +0100 Subject: [PATCH] move multiplier router to its own file --- himbaechel/uarch/gatemate/CMakeLists.txt | 1 + himbaechel/uarch/gatemate/gatemate.cc | 113 +------------------ himbaechel/uarch/gatemate/gatemate.h | 1 + himbaechel/uarch/gatemate/route_mult.cc | 138 +++++++++++++++++++++++ 4 files changed, 141 insertions(+), 112 deletions(-) create mode 100644 himbaechel/uarch/gatemate/route_mult.cc diff --git a/himbaechel/uarch/gatemate/CMakeLists.txt b/himbaechel/uarch/gatemate/CMakeLists.txt index 85f706a1..b5f61388 100644 --- a/himbaechel/uarch/gatemate/CMakeLists.txt +++ b/himbaechel/uarch/gatemate/CMakeLists.txt @@ -20,6 +20,7 @@ set(SOURCES pack.h pll.cc route_clock.cc + route_mult.cc ) set(TEST_SOURCES diff --git a/himbaechel/uarch/gatemate/gatemate.cc b/himbaechel/uarch/gatemate/gatemate.cc index 33800fd8..eb4b3d7d 100644 --- a/himbaechel/uarch/gatemate/gatemate.cc +++ b/himbaechel/uarch/gatemate/gatemate.cc @@ -188,118 +188,7 @@ void GateMateImpl::preRoute() { ctx->assignArchInfo(); route_clock(); - - log_info("Routing multipliers...\n"); - - // I am fully aware the nextpnr API is absolutely not designed around naming specific pips. - // Unfortunately, this is the easiest way to describe the specific routing required. - // Myrtle, please forgive me. - for (auto &a_passthru : this->multiplier_a_passthrus) { - auto *lower = a_passthru.first; - auto *upper = a_passthru.second; - - auto *lower_out = lower->ports.at(id_OUT).net; - auto *upper_out = upper->ports.at(id_OUT).net; - - auto loc = ctx->getBelLocation(lower->bel); - log_info(" A passthrough at (%d, %d) has 4-group (%d, %d)\n", loc.x, loc.y, (loc.x - 3) % 4, (loc.y - 3) % 4); - log_info(" lower.OUT [OUT1] = %s\n", ctx->nameOfWire(ctx->getBelPinWire(lower->bel, id_OUT))); - log_info(" upper.OUT [OUT2] = %s\n", ctx->nameOfWire(ctx->getBelPinWire(upper->bel, id_OUT))); - - auto x_fourgroup = (loc.x - 3) % 4; - auto y_fourgroup = (loc.y - 3) % 4; - - auto find_downhill_pip = [&](WireId from, WireId to) { - NPNR_ASSERT(from != WireId()); - NPNR_ASSERT(to != WireId()); - for (auto pip : ctx->getPipsDownhill(from)) { - if (ctx->getPipDstWire(pip) == to) { - log_info(" pip %s\n", ctx->nameOfPip(pip)); - - return pip; - } - } - log_error("Couldn't find pip from %s to %s\n", ctx->nameOfWire(from), ctx->nameOfWire(to)); - }; - - bool is_fourgroup_a = (x_fourgroup == 0 && y_fourgroup == 0) || (x_fourgroup == 2 && y_fourgroup == 2); - bool is_fourgroup_b = (x_fourgroup == 2 && y_fourgroup == 0) || (x_fourgroup == 0 && y_fourgroup == 2); - - if (is_fourgroup_a) { - auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y); - auto x2y1 = ctx->idf("X%dY%d", loc.x + 1, loc.y); - auto x2y2 = ctx->idf("X%dY%d", loc.x + 1, loc.y + 1); - auto x4y2 = ctx->idf("X%dY%d", loc.x + 3, loc.y + 1); - - { - log_info(" routing net '%s' -> IN5\n", lower_out->name.c_str(ctx)); - auto cpe_combout1 = ctx->getBelPinWire(lower->bel, id_OUT); - auto cpe_out1 = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT1_int"))); - auto sb_big = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P05.D0"))); - auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P05.D0"))); - auto cpe_in5 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("CPE.IN5"))); - auto cpe_in5_int = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("CPE.IN5_int"))); - - ctx->bindPip(find_downhill_pip(cpe_combout1, cpe_out1), lower_out, STRENGTH_USER); - ctx->bindPip(find_downhill_pip(cpe_out1, sb_big), lower_out, STRENGTH_USER); - ctx->bindPip(find_downhill_pip(sb_big, in_mux), lower_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(in_mux, cpe_in5), lower_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(cpe_in5, cpe_in5_int), lower_out, STRENGTH_USER); - } - - { - log_info(" routing net '%s' -> IN1\n", upper_out->name.c_str(ctx)); - auto cpe_combout2 = ctx->getBelPinWire(upper->bel, id_OUT); - auto cpe_out2_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT2_int"))); - auto sb_big = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P01.D0"))); - auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P01.D0"))); - auto cpe_in1 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("CPE.IN1"))); - auto cpe_in1_int = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("CPE.IN1_int"))); - - ctx->bindPip(find_downhill_pip(cpe_combout2, cpe_out2_int), upper_out, STRENGTH_USER); - ctx->bindPip(find_downhill_pip(cpe_out2_int, sb_big), upper_out, STRENGTH_USER); - ctx->bindPip(find_downhill_pip(sb_big, in_mux), upper_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(in_mux, cpe_in1), upper_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(cpe_in1, cpe_in1_int), upper_out, STRENGTH_USER); - - log_info(" routing net '%s' -> IN8\n", upper_out->name.c_str(ctx)); - - auto out_mux_d0 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("OM.P12.D0"))); - auto out_mux_y = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("OM.P12.Y"))); - auto sb_sml = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("SB_SML.P12.Y1_int"))); - auto sb_big_d2_1 = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_BIG.P12.D2_1"))); - auto sb_big_y1 = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_BIG.P12.Y1"))); - auto sb_big_ydiag = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_BIG.P12.YDIAG"))); - auto in_mux_p12 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P12.D2"))); - auto in_mux_p04 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P04.D7"))); // aka IM.P12.Y - auto in_mux_p08 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P08.D6"))); // aka IM.P04.Y - auto in_mux_p08_y = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P08.Y"))); // - auto cpe_in8_int = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("CPE.IN8_int"))); - - ctx->bindPip(find_downhill_pip(out_mux_d0, out_mux_y), upper_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(out_mux_y, sb_sml), upper_out, STRENGTH_USER); - ctx->bindPip(find_downhill_pip(sb_sml, sb_big_d2_1), upper_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(sb_big_d2_1, sb_big_y1), upper_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(sb_big_y1, sb_big_ydiag), upper_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(sb_big_ydiag, in_mux_p12), upper_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(in_mux_p12, in_mux_p04), upper_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(in_mux_p04, in_mux_p08), upper_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(in_mux_p08, in_mux_p08_y), upper_out, STRENGTH_USER); // inverting - ctx->bindPip(find_downhill_pip(in_mux_p08_y, cpe_in8_int), upper_out, STRENGTH_USER); - } - } else if (is_fourgroup_b) { - log_info(" don't know how to route net '%s' (it's four-group B)\n", lower_out->name.c_str(ctx)); - log_info(" don't know how to route net '%s' (it's four-group B)\n", upper_out->name.c_str(ctx)); - } else { - auto lower_l10 = lower->params[id_INIT_L10].as_int64(); - lower->params[id_INIT_L10] = Property(~lower_l10 & 0b1111, 4); - auto upper_l10 = upper->params[id_INIT_L10].as_int64(); - upper->params[id_INIT_L10] = Property(~upper_l10 & 0b1111, 4); - - log_info(" don't know how to route net '%s' (it's a light square)\n", lower_out->name.c_str(ctx)); - log_info(" don't know how to route net '%s' (it's a light square)\n", upper_out->name.c_str(ctx)); - } - } + route_mult(); } void GateMateImpl::postRoute() diff --git a/himbaechel/uarch/gatemate/gatemate.h b/himbaechel/uarch/gatemate/gatemate.h index 148dce55..44cca731 100644 --- a/himbaechel/uarch/gatemate/gatemate.h +++ b/himbaechel/uarch/gatemate/gatemate.h @@ -85,6 +85,7 @@ struct GateMateImpl : HimbaechelAPI void assign_cell_info(); void route_clock(); + void route_mult(); void repack(); const GateMateBelExtraDataPOD *bel_extra_data(BelId bel) const; diff --git a/himbaechel/uarch/gatemate/route_mult.cc b/himbaechel/uarch/gatemate/route_mult.cc new file mode 100644 index 00000000..90ef0190 --- /dev/null +++ b/himbaechel/uarch/gatemate/route_mult.cc @@ -0,0 +1,138 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2024 The Project Peppercorn Authors. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "gatemate.h" +#include "nextpnr_namespaces.h" + +#define HIMBAECHEL_CONSTIDS "uarch/gatemate/constids.inc" +#include "himbaechel_constids.h" + +NEXTPNR_NAMESPACE_BEGIN + +void GateMateImpl::route_mult() { + log_info("Routing multipliers...\n"); + + // I am fully aware the nextpnr API is absolutely not designed around naming specific pips. + // Unfortunately, this is the easiest way to describe the specific routing required. + // Myrtle, please forgive me. + for (auto &a_passthru : this->multiplier_a_passthrus) { + auto *lower = a_passthru.first; + auto *upper = a_passthru.second; + + auto *lower_out = lower->ports.at(id_OUT).net; + auto *upper_out = upper->ports.at(id_OUT).net; + + auto loc = ctx->getBelLocation(lower->bel); + log_info(" A passthrough at (%d, %d) has 4-group (%d, %d)\n", loc.x, loc.y, (loc.x - 3) % 4, (loc.y - 3) % 4); + log_info(" lower.OUT [OUT1] = %s\n", ctx->nameOfWire(ctx->getBelPinWire(lower->bel, id_OUT))); + log_info(" upper.OUT [OUT2] = %s\n", ctx->nameOfWire(ctx->getBelPinWire(upper->bel, id_OUT))); + + auto x_fourgroup = (loc.x - 3) % 4; + auto y_fourgroup = (loc.y - 3) % 4; + bool is_fourgroup_a = (x_fourgroup == 0 && y_fourgroup == 0) || (x_fourgroup == 2 && y_fourgroup == 2); + bool is_fourgroup_b = (x_fourgroup == 2 && y_fourgroup == 0) || (x_fourgroup == 0 && y_fourgroup == 2); + auto x_within_fourgroup = (loc.x - 3) % 2; + auto y_within_fourgroup = (loc.y - 3) % 2; + + auto find_downhill_pip = [&](WireId from, WireId to) { + NPNR_ASSERT(from != WireId()); + NPNR_ASSERT(to != WireId()); + for (auto pip : ctx->getPipsDownhill(from)) { + if (ctx->getPipDstWire(pip) == to) { + log_info(" pip %s\n", ctx->nameOfPip(pip)); + + return pip; + } + } + log_error("Couldn't find pip from %s to %s\n", ctx->nameOfWire(from), ctx->nameOfWire(to)); + }; + + if (is_fourgroup_a) { + auto x1y1 = ctx->idf("X%dY%d", loc.x, loc.y); + auto x2y1 = ctx->idf("X%dY%d", loc.x + 1, loc.y); + auto x2y2 = ctx->idf("X%dY%d", loc.x + 1, loc.y + 1); + auto x4y2 = ctx->idf("X%dY%d", loc.x + 3, loc.y + 1); + + { + log_info(" routing net '%s' -> IN5\n", lower_out->name.c_str(ctx)); + auto cpe_combout1 = ctx->getBelPinWire(lower->bel, id_OUT); + auto cpe_out1 = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT1_int"))); + auto sb_big = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P05.D0"))); + auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P05.D0"))); + auto cpe_in5 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("CPE.IN5"))); + auto cpe_in5_int = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("CPE.IN5_int"))); + + ctx->bindPip(find_downhill_pip(cpe_combout1, cpe_out1), lower_out, STRENGTH_USER); + ctx->bindPip(find_downhill_pip(cpe_out1, sb_big), lower_out, STRENGTH_USER); + ctx->bindPip(find_downhill_pip(sb_big, in_mux), lower_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(in_mux, cpe_in5), lower_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(cpe_in5, cpe_in5_int), lower_out, STRENGTH_USER); + } + + { + log_info(" routing net '%s' -> IN1\n", upper_out->name.c_str(ctx)); + auto cpe_combout2 = ctx->getBelPinWire(upper->bel, id_OUT); + auto cpe_out2_int = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("CPE.OUT2_int"))); + auto sb_big = ctx->getWireByName(IdStringList::concat(x1y1, ctx->idf("SB_BIG.P01.D0"))); + auto in_mux = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("IM.P01.D0"))); + auto cpe_in1 = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("CPE.IN1"))); + auto cpe_in1_int = ctx->getWireByName(IdStringList::concat(x2y1, ctx->idf("CPE.IN1_int"))); + + ctx->bindPip(find_downhill_pip(cpe_combout2, cpe_out2_int), upper_out, STRENGTH_USER); + ctx->bindPip(find_downhill_pip(cpe_out2_int, sb_big), upper_out, STRENGTH_USER); + ctx->bindPip(find_downhill_pip(sb_big, in_mux), upper_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(in_mux, cpe_in1), upper_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(cpe_in1, cpe_in1_int), upper_out, STRENGTH_USER); + + log_info(" routing net '%s' -> IN8\n", upper_out->name.c_str(ctx)); + + auto out_mux_d0 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("OM.P12.D0"))); + auto out_mux_y = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("OM.P12.Y"))); + auto sb_sml = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("SB_SML.P12.Y1_int"))); + auto sb_big_d2_1 = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_BIG.P12.D2_1"))); + auto sb_big_y1 = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_BIG.P12.Y1"))); + auto sb_big_ydiag = ctx->getWireByName(IdStringList::concat(x4y2, ctx->idf("SB_BIG.P12.YDIAG"))); + auto in_mux_p12 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P12.D2"))); + auto in_mux_p04 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P04.D7"))); // aka IM.P12.Y + auto in_mux_p08 = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P08.D6"))); // aka IM.P04.Y + auto in_mux_p08_y = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("IM.P08.Y"))); // + auto cpe_in8_int = ctx->getWireByName(IdStringList::concat(x2y2, ctx->idf("CPE.IN8_int"))); + + ctx->bindPip(find_downhill_pip(out_mux_d0, out_mux_y), upper_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(out_mux_y, sb_sml), upper_out, STRENGTH_USER); + ctx->bindPip(find_downhill_pip(sb_sml, sb_big_d2_1), upper_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(sb_big_d2_1, sb_big_y1), upper_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(sb_big_y1, sb_big_ydiag), upper_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(sb_big_ydiag, in_mux_p12), upper_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(in_mux_p12, in_mux_p04), upper_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(in_mux_p04, in_mux_p08), upper_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(in_mux_p08, in_mux_p08_y), upper_out, STRENGTH_USER); // inverting + ctx->bindPip(find_downhill_pip(in_mux_p08_y, cpe_in8_int), upper_out, STRENGTH_USER); + } + } else if (is_fourgroup_b) { + log_info(" don't know how to route net '%s' (it's four-group B)\n", lower_out->name.c_str(ctx)); + log_info(" don't know how to route net '%s' (it's four-group B)\n", upper_out->name.c_str(ctx)); + } else { + log_info(" don't know how to route net '%s' (it's a light square)\n", lower_out->name.c_str(ctx)); + log_info(" don't know how to route net '%s' (it's a light square)\n", upper_out->name.c_str(ctx)); + } + } +} + +NEXTPNR_NAMESPACE_END