mirror of https://github.com/YosysHQ/nextpnr.git
refactor multiplier checking
This commit is contained in:
parent
be652a481d
commit
69b06ed907
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<MultCell> mults;
|
||||
MsbRoutingCell msb_route;
|
||||
};
|
||||
|
||||
// A GateMate multiplier is made up of columns of 2x2 multipliers.
|
||||
struct Multiplier
|
||||
{
|
||||
ZeroDriver zero;
|
||||
std::vector<APassThroughCell> a_passthrus;
|
||||
std::vector<MultiplierColumn> 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<std::pair<IdString, int>, Loc> locations;
|
||||
int dies;
|
||||
int preferred_die;
|
||||
std::vector<Multiplier> multipliers;
|
||||
std::vector<CellInfo *> multipliers;
|
||||
|
||||
private:
|
||||
bool getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc,
|
||||
|
|
|
|||
|
|
@ -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<MultCell> mults;
|
||||
MsbRoutingCell msb_route;
|
||||
};
|
||||
|
||||
// A GateMate multiplier is made up of columns of 2x2 multipliers.
|
||||
struct Multiplier
|
||||
{
|
||||
ZeroDriver zero;
|
||||
std::vector<APassThroughCell> a_passthrus;
|
||||
std::vector<MultiplierColumn> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue