From 69b06ed907260437aeaecf8e06ddeb387731750c Mon Sep 17 00:00:00 2001 From: Lofty Date: Mon, 30 Jun 2025 12:26:51 +0100 Subject: [PATCH] refactor multiplier checking --- himbaechel/uarch/gatemate/bitstream.cc | 33 ++++--- himbaechel/uarch/gatemate/gatemate.h | 115 +----------------------- himbaechel/uarch/gatemate/pack_mult.cc | 116 ++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 134 deletions(-) diff --git a/himbaechel/uarch/gatemate/bitstream.cc b/himbaechel/uarch/gatemate/bitstream.cc index 6ee9ecdb..3c3539b0 100644 --- a/himbaechel/uarch/gatemate/bitstream.cc +++ b/himbaechel/uarch/gatemate/bitstream.cc @@ -219,33 +219,30 @@ struct BitstreamBackend void check_multipliers() { - for (const auto &multiplier : uarch->multipliers) { - for (const auto &col : multiplier.cols) { - for (const auto &mult : col.mults) { - NPNR_ASSERT(mult.lower != nullptr); - NPNR_ASSERT(mult.upper != nullptr); + for (auto *mult : uarch->multipliers) { + NPNR_ASSERT(mult != nullptr); - auto should_be_inverted = mult.lower->constr_x % 2 == 1; + auto should_be_inverted = mult->constr_x % 2 == 1; - // IN8 - if (need_inversion(mult.lower, id_IN4) != should_be_inverted) - log_error("%s.IN4 has wrong inversion state\n", mult.lower->name.c_str(ctx)); + // TODO: these are errors, but downgraded to allow providing *some* output. - // IN5 - if (need_inversion(mult.lower, id_IN1) != should_be_inverted) - log_error("%s.IN1 has wrong inversion state\n", mult.lower->name.c_str(ctx)); + // IN8 + if (need_inversion(mult, id_IN8) != should_be_inverted) + log_warning("%s.IN8 has wrong inversion state\n", mult->name.c_str(ctx)); - // IN1 - if (need_inversion(mult.upper, id_IN1) != should_be_inverted) - log_error("%s.IN1 has wrong inversion state\n", mult.upper->name.c_str(ctx)); - } - } + // IN5 + if (need_inversion(mult, id_IN5) != should_be_inverted) + log_warning("%s.IN5 has wrong inversion state\n", mult->name.c_str(ctx)); + + // IN1 + if (need_inversion(mult, id_IN1) != should_be_inverted) + log_warning("%s.IN1 has wrong inversion state\n", mult->name.c_str(ctx)); } } void write_bitstream() { - //check_multipliers(); + check_multipliers(); ChipConfig cc; cc.chip_name = device; diff --git a/himbaechel/uarch/gatemate/gatemate.h b/himbaechel/uarch/gatemate/gatemate.h index d5a43ef9..5a648750 100644 --- a/himbaechel/uarch/gatemate/gatemate.h +++ b/himbaechel/uarch/gatemate/gatemate.h @@ -30,119 +30,6 @@ NEXTPNR_NAMESPACE_BEGIN -// Constant zero. -struct ZeroDriver -{ - ZeroDriver() : lower{nullptr}, upper{nullptr} {} - ZeroDriver(CellInfo *lower, CellInfo *upper, IdString name); - - CellInfo *lower; - CellInfo *upper; -}; - -// Propagate A0 through OUT1 and A1 through OUT2; zero COUTX and POUTX. -struct APassThroughCell -{ - APassThroughCell(CellInfo *lower, CellInfo *upper, IdString name, bool inverted); - - void clean_up(Context *ctx); - - CellInfo *lower; - CellInfo *upper; - bool inverted; -}; - -// Propagate B0 through POUTY1 and B1 through COUTY1 -struct BPassThroughCell -{ - BPassThroughCell() : lower{nullptr}, upper{nullptr} {} - BPassThroughCell(CellInfo *lower, CellInfo *upper, IdString name); - - void clean_up(Context *ctx); - - CellInfo *lower; - CellInfo *upper; -}; - -// TODO: Micko points out this is an L2T4 CPE_HALF -struct CarryGenCell -{ - CarryGenCell() : lower{nullptr}, upper{nullptr} {} - CarryGenCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x, bool enable_cinx); - - CellInfo *lower; - CellInfo *upper; -}; - -// This prepares B bits for multiplication. -struct MultfabCell -{ - MultfabCell() : lower{nullptr}, upper{nullptr} {} - MultfabCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x, bool enable_cinx); - - CellInfo *lower; - CellInfo *upper; -}; - -// CITE: CPE_ges_f-routing-1.pdf -struct FRoutingCell -{ - FRoutingCell() : lower{nullptr}, upper{nullptr} {} - FRoutingCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x); - - CellInfo *lower; - CellInfo *upper; -}; - -// Multiply two bits of A with two bits of B. -// -// CITE: CPE_MULT.pdf -struct MultCell -{ - MultCell() : lower{nullptr}, upper{nullptr} {} - MultCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_msb); - - CellInfo *lower; - CellInfo *upper; -}; - -// CITE: CPE_ges_MSB-routing.pdf -struct MsbRoutingCell -{ - MsbRoutingCell() : lower{nullptr}, upper{nullptr} {} - MsbRoutingCell(CellInfo *lower, CellInfo *upper, IdString name); - - CellInfo *lower; - CellInfo *upper; -}; - -struct MultiplierColumn -{ - BPassThroughCell b_passthru; - CarryGenCell carry; - MultfabCell multfab; - FRoutingCell f_route; - std::vector mults; - MsbRoutingCell msb_route; -}; - -// A GateMate multiplier is made up of columns of 2x2 multipliers. -struct Multiplier -{ - ZeroDriver zero; - std::vector a_passthrus; - std::vector cols; - - size_t cpe_count() const - { - auto count = 1 /* (zero driver) */ + a_passthrus.size(); - for (const auto &col : cols) { - count += 4 /* (b_passthru, carry, multfab, f_route) */ + col.mults.size() + 1 /* (msb_route) */; - } - return count; - } -}; - struct GateMateImpl : HimbaechelAPI { ~GateMateImpl(); @@ -183,7 +70,7 @@ struct GateMateImpl : HimbaechelAPI dict, Loc> locations; int dies; int preferred_die; - std::vector multipliers; + std::vector multipliers; private: bool getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc, diff --git a/himbaechel/uarch/gatemate/pack_mult.cc b/himbaechel/uarch/gatemate/pack_mult.cc index 1dd332f6..b3463524 100644 --- a/himbaechel/uarch/gatemate/pack_mult.cc +++ b/himbaechel/uarch/gatemate/pack_mult.cc @@ -33,6 +33,119 @@ NEXTPNR_NAMESPACE_BEGIN +// Constant zero. +struct ZeroDriver +{ + ZeroDriver() : lower{nullptr}, upper{nullptr} {} + ZeroDriver(CellInfo *lower, CellInfo *upper, IdString name); + + CellInfo *lower; + CellInfo *upper; +}; + +// Propagate A0 through OUT1 and A1 through OUT2; zero COUTX and POUTX. +struct APassThroughCell +{ + APassThroughCell(CellInfo *lower, CellInfo *upper, IdString name, bool inverted); + + void clean_up(Context *ctx); + + CellInfo *lower; + CellInfo *upper; + bool inverted; +}; + +// Propagate B0 through POUTY1 and B1 through COUTY1 +struct BPassThroughCell +{ + BPassThroughCell() : lower{nullptr}, upper{nullptr} {} + BPassThroughCell(CellInfo *lower, CellInfo *upper, IdString name); + + void clean_up(Context *ctx); + + CellInfo *lower; + CellInfo *upper; +}; + +// TODO: Micko points out this is an L2T4 CPE_HALF +struct CarryGenCell +{ + CarryGenCell() : lower{nullptr}, upper{nullptr} {} + CarryGenCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x, bool enable_cinx); + + CellInfo *lower; + CellInfo *upper; +}; + +// This prepares B bits for multiplication. +struct MultfabCell +{ + MultfabCell() : lower{nullptr}, upper{nullptr} {} + MultfabCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x, bool enable_cinx); + + CellInfo *lower; + CellInfo *upper; +}; + +// CITE: CPE_ges_f-routing-1.pdf +struct FRoutingCell +{ + FRoutingCell() : lower{nullptr}, upper{nullptr} {} + FRoutingCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x); + + CellInfo *lower; + CellInfo *upper; +}; + +// Multiply two bits of A with two bits of B. +// +// CITE: CPE_MULT.pdf +struct MultCell +{ + MultCell() : lower{nullptr}, upper{nullptr} {} + MultCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_msb); + + CellInfo *lower; + CellInfo *upper; +}; + +// CITE: CPE_ges_MSB-routing.pdf +struct MsbRoutingCell +{ + MsbRoutingCell() : lower{nullptr}, upper{nullptr} {} + MsbRoutingCell(CellInfo *lower, CellInfo *upper, IdString name); + + CellInfo *lower; + CellInfo *upper; +}; + +struct MultiplierColumn +{ + BPassThroughCell b_passthru; + CarryGenCell carry; + MultfabCell multfab; + FRoutingCell f_route; + std::vector mults; + MsbRoutingCell msb_route; +}; + +// A GateMate multiplier is made up of columns of 2x2 multipliers. +struct Multiplier +{ + ZeroDriver zero; + std::vector a_passthrus; + std::vector cols; + + size_t cpe_count() const + { + auto count = 1 /* (zero driver) */ + a_passthrus.size(); + for (const auto &col : cols) { + count += 4 /* (b_passthru, carry, multfab, f_route) */ + col.mults.size() + 1 /* (msb_route) */; + } + return count; + } +}; + ZeroDriver::ZeroDriver(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper} { lower->params[id_INIT_L02] = Property(LUT_ZERO, 4); // (unused) @@ -349,6 +462,7 @@ void GateMatePacker::pack_mult() auto *mult_lower = create_cell_ptr(id_CPE_LT_L, ctx->idf("%s$row%d$mult", name.c_str(ctx), i)); auto *mult_upper = create_cell_ptr(id_CPE_LT_U, ctx->idf("%s$row%d$mult_upper", name.c_str(ctx), i)); col.mults.push_back(MultCell{mult_lower, mult_upper, name, i == ((a_width / 2) - 1)}); + uarch->multipliers.push_back(mult_lower); } { @@ -539,8 +653,6 @@ void GateMatePacker::pack_mult() ctx->cells.erase(mult->name); log_info(" Created %zu CPEs.\n", m.cpe_count()); - - uarch->multipliers.push_back(m); } }