mirror of https://github.com/YosysHQ/nextpnr.git
current progress
This commit is contained in:
parent
1ac1b67f7f
commit
fcecdb9397
|
|
@ -36,14 +36,10 @@ struct APassThroughCell
|
||||||
{
|
{
|
||||||
APassThroughCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper}
|
APassThroughCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper}
|
||||||
{
|
{
|
||||||
lower->cluster = name;
|
|
||||||
lower->constr_abs_z = false;
|
|
||||||
lower->params[id_INIT_L00] = Property(LUT_D0, 4); // IN1
|
lower->params[id_INIT_L00] = Property(LUT_D0, 4); // IN1
|
||||||
lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
|
lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
|
||||||
lower->params[id_INIT_L10] = Property(LUT_D0, 4); // L00 -> COMB2OUT
|
lower->params[id_INIT_L10] = Property(LUT_D0, 4); // L00 -> COMB2OUT
|
||||||
|
|
||||||
upper->cluster = name;
|
|
||||||
upper->constr_abs_z = false;
|
|
||||||
upper->params[id_INIT_L02] = Property(LUT_D0, 4); // IN5
|
upper->params[id_INIT_L02] = Property(LUT_D0, 4); // IN5
|
||||||
upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused)
|
upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused)
|
||||||
upper->params[id_INIT_L11] = Property(LUT_D0, 4); // L02
|
upper->params[id_INIT_L11] = Property(LUT_D0, 4); // L02
|
||||||
|
|
@ -62,8 +58,8 @@ struct APassThroughCell
|
||||||
PortRef a0() const { return PortRef{upper, id_IN1}; }
|
PortRef a0() const { return PortRef{upper, id_IN1}; }
|
||||||
PortRef a1() const { return PortRef{lower, id_IN1}; }
|
PortRef a1() const { return PortRef{lower, id_IN1}; }
|
||||||
|
|
||||||
CellInfo *upper;
|
|
||||||
CellInfo *lower;
|
CellInfo *lower;
|
||||||
|
CellInfo *upper;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Propagate B0 through POUTY1 and B1 through COUTY1
|
// Propagate B0 through POUTY1 and B1 through COUTY1
|
||||||
|
|
@ -72,6 +68,8 @@ struct APassThroughCell
|
||||||
// TODO: is it worth trying to unify this with APassThroughCell?
|
// TODO: is it worth trying to unify this with APassThroughCell?
|
||||||
struct BPassThroughCell
|
struct BPassThroughCell
|
||||||
{
|
{
|
||||||
|
BPassThroughCell() : lower{nullptr}, upper{nullptr} {}
|
||||||
|
|
||||||
BPassThroughCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper}
|
BPassThroughCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper}
|
||||||
{
|
{
|
||||||
lower->cluster = name;
|
lower->cluster = name;
|
||||||
|
|
@ -80,8 +78,6 @@ struct BPassThroughCell
|
||||||
lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
|
lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
|
||||||
lower->params[id_INIT_L10] = Property(LUT_D0, 4); // L00 -> COMB2OUT
|
lower->params[id_INIT_L10] = Property(LUT_D0, 4); // L00 -> COMB2OUT
|
||||||
|
|
||||||
upper->cluster = name;
|
|
||||||
upper->constr_abs_z = false;
|
|
||||||
upper->params[id_INIT_L02] = Property(LUT_D0, 4); // IN5
|
upper->params[id_INIT_L02] = Property(LUT_D0, 4); // IN5
|
||||||
upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused)
|
upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused)
|
||||||
upper->params[id_INIT_L11] = Property(LUT_D0, 4); // L02
|
upper->params[id_INIT_L11] = Property(LUT_D0, 4); // L02
|
||||||
|
|
@ -97,25 +93,23 @@ struct BPassThroughCell
|
||||||
PortRef b0() const { return PortRef{upper, id_IN1}; }
|
PortRef b0() const { return PortRef{upper, id_IN1}; }
|
||||||
PortRef b1() const { return PortRef{lower, id_IN1}; }
|
PortRef b1() const { return PortRef{lower, id_IN1}; }
|
||||||
|
|
||||||
CellInfo *upper;
|
|
||||||
CellInfo *lower;
|
CellInfo *lower;
|
||||||
|
CellInfo *upper;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Micko points out this is an L2T4 CPE_HALF
|
// TODO: Micko points out this is an L2T4 CPE_HALF
|
||||||
struct CarryGenCell
|
struct CarryGenCell
|
||||||
{
|
{
|
||||||
|
CarryGenCell() : lower{nullptr}, upper{nullptr} {}
|
||||||
|
|
||||||
CarryGenCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x) : lower{lower}, upper{upper}
|
CarryGenCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x) : lower{lower}, upper{upper}
|
||||||
{
|
{
|
||||||
// TODO: simplify AND with zero/OR with zero into something more sensical.
|
// TODO: simplify AND with zero/OR with zero into something more sensical.
|
||||||
|
|
||||||
lower->cluster = name;
|
|
||||||
lower->constr_abs_z = false;
|
|
||||||
lower->params[id_INIT_L00] = Property(LUT_ZERO, 4); // (unused)
|
lower->params[id_INIT_L00] = Property(LUT_ZERO, 4); // (unused)
|
||||||
lower->params[id_INIT_L01] = Property(LUT_D1, 4); // CINX
|
lower->params[id_INIT_L01] = Property(LUT_D1, 4); // CINX
|
||||||
lower->params[id_INIT_L10] = Property(is_even_x ? LUT_AND : LUT_OR, 4);
|
lower->params[id_INIT_L10] = Property(is_even_x ? LUT_AND : LUT_OR, 4);
|
||||||
|
|
||||||
upper->cluster = name;
|
|
||||||
upper->constr_abs_z = false;
|
|
||||||
upper->params[id_INIT_L02] = Property(LUT_D1, 4); // PINY1
|
upper->params[id_INIT_L02] = Property(LUT_D1, 4); // PINY1
|
||||||
upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused)
|
upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused)
|
||||||
upper->params[id_INIT_L11] = Property(is_even_x ? LUT_AND : LUT_OR, 4);
|
upper->params[id_INIT_L11] = Property(is_even_x ? LUT_AND : LUT_OR, 4);
|
||||||
|
|
@ -134,25 +128,23 @@ struct CarryGenCell
|
||||||
upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1
|
upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1
|
||||||
}
|
}
|
||||||
|
|
||||||
CellInfo *upper;
|
|
||||||
CellInfo *lower;
|
CellInfo *lower;
|
||||||
|
CellInfo *upper;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This prepares B bits for multiplication.
|
// This prepares B bits for multiplication.
|
||||||
struct MultfabCell
|
struct MultfabCell
|
||||||
{
|
{
|
||||||
|
MultfabCell() : lower{nullptr}, upper{nullptr} {}
|
||||||
|
|
||||||
MultfabCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x) : lower{lower}, upper{upper}
|
MultfabCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x) : lower{lower}, upper{upper}
|
||||||
{
|
{
|
||||||
// TODO: perhaps C_I[1234] could be pips?
|
// TODO: perhaps C_I[1234] could be pips?
|
||||||
|
|
||||||
lower->cluster = name;
|
|
||||||
lower->constr_abs_z = false;
|
|
||||||
lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
||||||
lower->params[id_INIT_L01] = Property(is_even_x ? LUT_ZERO : LUT_D1, 4); // CINX
|
lower->params[id_INIT_L01] = Property(is_even_x ? LUT_ZERO : LUT_D1, 4); // CINX
|
||||||
lower->params[id_INIT_L10] = Property(LUT_XOR, 4); // XOR
|
lower->params[id_INIT_L10] = Property(LUT_XOR, 4); // XOR
|
||||||
|
|
||||||
upper->cluster = name;
|
|
||||||
upper->constr_abs_z = false;
|
|
||||||
upper->params[id_INIT_L02] = Property(LUT_D1, 4); // PINY1
|
upper->params[id_INIT_L02] = Property(LUT_D1, 4); // PINY1
|
||||||
upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused)
|
upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused)
|
||||||
upper->params[id_INIT_L11] = Property(LUT_D0, 4); // L02
|
upper->params[id_INIT_L11] = Property(LUT_D0, 4); // L02
|
||||||
|
|
@ -175,26 +167,24 @@ struct MultfabCell
|
||||||
upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1
|
upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1
|
||||||
}
|
}
|
||||||
|
|
||||||
CellInfo *upper;
|
|
||||||
CellInfo *lower;
|
CellInfo *lower;
|
||||||
|
CellInfo *upper;
|
||||||
};
|
};
|
||||||
|
|
||||||
// CITE: CPE_ges_f-routing-1.pdf
|
// CITE: CPE_ges_f-routing-1.pdf
|
||||||
// TODO:
|
// TODO:
|
||||||
struct FRoutingCell
|
struct FRoutingCell
|
||||||
{
|
{
|
||||||
|
FRoutingCell() : lower{nullptr}, upper{nullptr} {}
|
||||||
|
|
||||||
FRoutingCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x) : lower{lower}, upper{upper}
|
FRoutingCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x) : lower{lower}, upper{upper}
|
||||||
{
|
{
|
||||||
// TODO: simplify AND with zero/OR with zero into something more sensical.
|
// TODO: simplify AND with zero/OR with zero into something more sensical.
|
||||||
|
|
||||||
lower->cluster = name;
|
|
||||||
lower->constr_abs_z = false;
|
|
||||||
lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
||||||
lower->params[id_INIT_L01] = Property(LUT_ONE, 4); // (unused)
|
lower->params[id_INIT_L01] = Property(LUT_ONE, 4); // (unused)
|
||||||
lower->params[id_INIT_L10] = Property(LUT_AND, 4);
|
lower->params[id_INIT_L10] = Property(LUT_AND, 4);
|
||||||
|
|
||||||
upper->cluster = name;
|
|
||||||
upper->constr_abs_z = false;
|
|
||||||
upper->params[id_INIT_L02] = Property(LUT_ZERO, 4); // (unused)
|
upper->params[id_INIT_L02] = Property(LUT_ZERO, 4); // (unused)
|
||||||
upper->params[id_INIT_L03] = Property(LUT_ONE, 4); // (unused)
|
upper->params[id_INIT_L03] = Property(LUT_ONE, 4); // (unused)
|
||||||
upper->params[id_INIT_L11] = Property(LUT_AND, 4);
|
upper->params[id_INIT_L11] = Property(LUT_AND, 4);
|
||||||
|
|
@ -216,8 +206,8 @@ struct FRoutingCell
|
||||||
upper->params[id_C_O2] = Property(0b11, 2); // COMB2OUT -> OUT2
|
upper->params[id_C_O2] = Property(0b11, 2); // COMB2OUT -> OUT2
|
||||||
}
|
}
|
||||||
|
|
||||||
CellInfo *upper;
|
|
||||||
CellInfo *lower;
|
CellInfo *lower;
|
||||||
|
CellInfo *upper;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Multiply two bits of A with two bits of B.
|
// Multiply two bits of A with two bits of B.
|
||||||
|
|
@ -225,16 +215,14 @@ struct FRoutingCell
|
||||||
// CITE: CPE_MULT.pdf
|
// CITE: CPE_MULT.pdf
|
||||||
struct MultCell
|
struct MultCell
|
||||||
{
|
{
|
||||||
|
MultCell() : lower{nullptr}, upper{nullptr} {}
|
||||||
|
|
||||||
MultCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper}
|
MultCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper}
|
||||||
{
|
{
|
||||||
lower->cluster = name;
|
|
||||||
lower->constr_abs_z = false;
|
|
||||||
lower->params[id_INIT_L00] = Property(LUT_AND, 4);
|
lower->params[id_INIT_L00] = Property(LUT_AND, 4);
|
||||||
lower->params[id_INIT_L01] = Property(LUT_D1, 4); // CINX
|
lower->params[id_INIT_L01] = Property(LUT_D1, 4); // CINX
|
||||||
lower->params[id_INIT_L10] = Property(LUT_XOR, 4);
|
lower->params[id_INIT_L10] = Property(LUT_XOR, 4);
|
||||||
|
|
||||||
upper->cluster = name;
|
|
||||||
upper->constr_abs_z = false;
|
|
||||||
upper->params[id_INIT_L02] = Property(LUT_AND, 4);
|
upper->params[id_INIT_L02] = Property(LUT_AND, 4);
|
||||||
upper->params[id_INIT_L03] = Property(LUT_D1, 4); // PINX
|
upper->params[id_INIT_L03] = Property(LUT_D1, 4); // PINX
|
||||||
upper->params[id_INIT_L11] = Property(LUT_XOR, 4);
|
upper->params[id_INIT_L11] = Property(LUT_XOR, 4);
|
||||||
|
|
@ -254,16 +242,16 @@ struct MultCell
|
||||||
PortRef a1() const { return PortRef{upper, id_IN1}; }
|
PortRef a1() const { return PortRef{upper, id_IN1}; }
|
||||||
PortRef a2() const { return PortRef{lower, id_IN1}; }
|
PortRef a2() const { return PortRef{lower, id_IN1}; }
|
||||||
|
|
||||||
CellInfo *upper;
|
|
||||||
CellInfo *lower;
|
CellInfo *lower;
|
||||||
|
CellInfo *upper;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MultMsbCell
|
struct MultMsbCell
|
||||||
{
|
{
|
||||||
|
MultMsbCell() : lower{nullptr}, upper{nullptr} {}
|
||||||
|
|
||||||
MultMsbCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper}
|
MultMsbCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper}
|
||||||
{
|
{
|
||||||
lower->cluster = name;
|
|
||||||
lower->constr_abs_z = false;
|
|
||||||
lower->params[id_INIT_L00] = Property(LUT_AND, 4);
|
lower->params[id_INIT_L00] = Property(LUT_AND, 4);
|
||||||
lower->params[id_INIT_L01] = Property(LUT_D1, 4); // CINX
|
lower->params[id_INIT_L01] = Property(LUT_D1, 4); // CINX
|
||||||
lower->params[id_INIT_L10] = Property(LUT_XOR, 4);
|
lower->params[id_INIT_L10] = Property(LUT_XOR, 4);
|
||||||
|
|
@ -286,17 +274,17 @@ struct MultMsbCell
|
||||||
upper->params[id_C_O1] = Property(0b10, 2); // CP_OUT1 -> OUT1
|
upper->params[id_C_O1] = Property(0b10, 2); // CP_OUT1 -> OUT1
|
||||||
}
|
}
|
||||||
|
|
||||||
CellInfo *upper;
|
|
||||||
CellInfo *lower;
|
CellInfo *lower;
|
||||||
|
CellInfo *upper;
|
||||||
};
|
};
|
||||||
|
|
||||||
// CITE: CPE_ges_MSB-routing.pdf
|
// CITE: CPE_ges_MSB-routing.pdf
|
||||||
struct MsbRoutingCell
|
struct MsbRoutingCell
|
||||||
{
|
{
|
||||||
|
MsbRoutingCell() : lower{nullptr}, upper{nullptr} {}
|
||||||
|
|
||||||
MsbRoutingCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper}
|
MsbRoutingCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper}
|
||||||
{
|
{
|
||||||
lower->cluster = name;
|
|
||||||
lower->constr_abs_z = false;
|
|
||||||
lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1
|
||||||
lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
|
lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
|
||||||
lower->params[id_INIT_L10] = Property(LUT_OR, 4);
|
lower->params[id_INIT_L10] = Property(LUT_OR, 4);
|
||||||
|
|
@ -321,20 +309,18 @@ struct MsbRoutingCell
|
||||||
upper->params[id_C_O2] = Property(0b10, 2); // CP_OUT2 -> OUT2
|
upper->params[id_C_O2] = Property(0b10, 2); // CP_OUT2 -> OUT2
|
||||||
}
|
}
|
||||||
|
|
||||||
CellInfo *upper;
|
|
||||||
CellInfo *lower;
|
CellInfo *lower;
|
||||||
|
CellInfo *upper;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MultiplierColumn
|
struct MultiplierColumn
|
||||||
{
|
{
|
||||||
// the variables are in bottom-up physical order as a mnemonic.
|
|
||||||
|
|
||||||
BPassThroughCell b_passthru;
|
BPassThroughCell b_passthru;
|
||||||
CarryGenCell carry;
|
CarryGenCell carry;
|
||||||
MultfabCell multfab;
|
MultfabCell multfab;
|
||||||
FRoutingCell f_route;
|
FRoutingCell f_route;
|
||||||
std::vector<MultCell> mults;
|
std::vector<MultCell> mults;
|
||||||
MultMsbCell multmsb;
|
MultMsbCell mult_msb;
|
||||||
MsbRoutingCell msb_route;
|
MsbRoutingCell msb_route;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -343,6 +329,15 @@ struct Multiplier
|
||||||
{
|
{
|
||||||
std::vector<APassThroughCell> a_passthrus;
|
std::vector<APassThroughCell> a_passthrus;
|
||||||
std::vector<MultiplierColumn> cols;
|
std::vector<MultiplierColumn> cols;
|
||||||
|
|
||||||
|
size_t cpe_count() const
|
||||||
|
{
|
||||||
|
auto count = a_passthrus.size();
|
||||||
|
for (const auto &col : cols) {
|
||||||
|
count += 6 + col.mults.size();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void GateMatePacker::pack_mult()
|
void GateMatePacker::pack_mult()
|
||||||
|
|
@ -350,18 +345,59 @@ void GateMatePacker::pack_mult()
|
||||||
// note to self: use constr_children for recursive constraints
|
// note to self: use constr_children for recursive constraints
|
||||||
// fpga_generic.pas in p_r might have useful info
|
// fpga_generic.pas in p_r might have useful info
|
||||||
|
|
||||||
auto create_mult_cell = [&](IdString name) {
|
auto create_a_passthru = [&](IdString name) {
|
||||||
// instantiate a full CPE by creating two halves.
|
auto *a_passthru_lower = create_cell_ptr(id_CPE_HALF_L, ctx->idf("%s$a_passthru_lower", name.c_str(ctx)));
|
||||||
auto *lower = create_cell_ptr(id_CPE_HALF_L, ctx->idf("%s$lower", name.c_str(ctx)));
|
auto *a_passthru_upper = create_cell_ptr(id_CPE_HALF_U, ctx->idf("%s$a_passthru_upper", name.c_str(ctx)));
|
||||||
auto *upper = create_cell_ptr(id_CPE_HALF_U, ctx->idf("%s$upper", name.c_str(ctx)));
|
return APassThroughCell{a_passthru_lower, a_passthru_upper, name};
|
||||||
return MultCell{lower, upper, name};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto create_multfab_cell = [&](IdString name, bool is_multfa) {
|
auto create_mult_col = [&](IdString name, int a_width, bool is_even_x) {
|
||||||
// instantiate a full CPE by creating two halves.
|
// Ideally this would be the MultiplierColumn constructor, but we need create_cell_ptr here.
|
||||||
auto *lower = create_cell_ptr(id_CPE_HALF_L, ctx->idf("%s$lower", name.c_str(ctx)));
|
auto col = MultiplierColumn{};
|
||||||
auto *upper = create_cell_ptr(id_CPE_HALF_U, ctx->idf("%s$upper", name.c_str(ctx)));
|
|
||||||
return MultfabCell{lower, upper, name, is_multfa};
|
{
|
||||||
|
auto *b_passthru_lower = create_cell_ptr(id_CPE_HALF_L, ctx->idf("%s$b_passthru_lower", name.c_str(ctx)));
|
||||||
|
auto *b_passthru_upper = create_cell_ptr(id_CPE_HALF_U, ctx->idf("%s$b_passthru_upper", name.c_str(ctx)));
|
||||||
|
col.b_passthru = BPassThroughCell{b_passthru_lower, b_passthru_upper, name};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto *carry_lower = create_cell_ptr(id_CPE_HALF_L, ctx->idf("%s$carry_lower", name.c_str(ctx)));
|
||||||
|
auto *carry_upper = create_cell_ptr(id_CPE_HALF_U, ctx->idf("%s$carry_upper", name.c_str(ctx)));
|
||||||
|
col.carry = CarryGenCell{carry_lower, carry_upper, name, is_even_x};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto *multfab_lower = create_cell_ptr(id_CPE_HALF_L, ctx->idf("%s$multfab_lower", name.c_str(ctx)));
|
||||||
|
auto *multfab_upper = create_cell_ptr(id_CPE_HALF_U, ctx->idf("%s$multfab_upper", name.c_str(ctx)));
|
||||||
|
col.multfab = MultfabCell{multfab_lower, multfab_upper, name, is_even_x};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto *f_route_lower = create_cell_ptr(id_CPE_HALF_L, ctx->idf("%s$f_route_lower", name.c_str(ctx)));
|
||||||
|
auto *f_route_upper = create_cell_ptr(id_CPE_HALF_U, ctx->idf("%s$f_route_upper", name.c_str(ctx)));
|
||||||
|
col.f_route = FRoutingCell{f_route_lower, f_route_upper, name, is_even_x};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < a_width / 2; i++) {
|
||||||
|
auto *mult_lower = create_cell_ptr(id_CPE_HALF_L, ctx->idf("%s$row%d$mult_lower", name.c_str(ctx), i));
|
||||||
|
auto *mult_upper = create_cell_ptr(id_CPE_HALF_U, ctx->idf("%s$row%d$mult_upper", name.c_str(ctx), i));
|
||||||
|
col.mults.push_back(MultCell{mult_lower, mult_upper, name});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto *mult_msb_lower = create_cell_ptr(id_CPE_HALF_L, ctx->idf("%s$mult_msb_lower", name.c_str(ctx)));
|
||||||
|
auto *mult_msb_upper = create_cell_ptr(id_CPE_HALF_U, ctx->idf("%s$mult_msb_upper", name.c_str(ctx)));
|
||||||
|
col.mult_msb = MultMsbCell{mult_msb_lower, mult_msb_upper, name};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto *msb_route_lower = create_cell_ptr(id_CPE_HALF_L, ctx->idf("%s$msb_route_lower", name.c_str(ctx)));
|
||||||
|
auto *msb_route_upper = create_cell_ptr(id_CPE_HALF_U, ctx->idf("%s$msb_route_upper", name.c_str(ctx)));
|
||||||
|
col.msb_route = MsbRoutingCell{msb_route_lower, msb_route_upper, name};
|
||||||
|
}
|
||||||
|
|
||||||
|
return col;
|
||||||
};
|
};
|
||||||
|
|
||||||
log_info("Packing multipliers...\n");
|
log_info("Packing multipliers...\n");
|
||||||
|
|
@ -378,13 +414,70 @@ void GateMatePacker::pack_mult()
|
||||||
auto a_width = int_or_default(mult->params, id_A_WIDTH);
|
auto a_width = int_or_default(mult->params, id_A_WIDTH);
|
||||||
auto b_width = int_or_default(mult->params, id_B_WIDTH);
|
auto b_width = int_or_default(mult->params, id_B_WIDTH);
|
||||||
auto p_width = int_or_default(mult->params, id_P_WIDTH);
|
auto p_width = int_or_default(mult->params, id_P_WIDTH);
|
||||||
log_info(" Configuring '%s' as a %d * %d = %d multiplier\n", mult->name.c_str(ctx), a_width, b_width,
|
log_info(" Configuring '%s' as a %d-bit * %d-bit = %d-bit multiplier.\n", mult->name.c_str(ctx), a_width,
|
||||||
p_width);
|
b_width, p_width);
|
||||||
|
|
||||||
NPNR_ASSERT(a_width <= 2);
|
auto m = Multiplier{};
|
||||||
NPNR_ASSERT(b_width <= 2);
|
|
||||||
|
|
||||||
auto [mult_l, mult_u] = create_mult_cell(mult->name);
|
// Step 1: instantiate all the CPEs.
|
||||||
|
for (int a = 0; a <= a_width / 2; a++)
|
||||||
|
m.a_passthrus.push_back(create_a_passthru(ctx->idf("%s$col0$row%d", mult->name.c_str(ctx), a)));
|
||||||
|
for (int b = 0; b <= b_width / 2; b++)
|
||||||
|
m.cols.push_back(create_mult_col(ctx->idf("%s$col%d", mult->name.c_str(ctx), b + 1), a_width, b % 2 == 0));
|
||||||
|
|
||||||
|
// Step 2: constrain them together.
|
||||||
|
// We define (0,0) to be the B passthrough cell of column 1.
|
||||||
|
auto *root = m.cols[0].b_passthru.upper;
|
||||||
|
|
||||||
|
auto constrain_cell = [&](CellInfo *cell, int x_offset, int y_offset) {
|
||||||
|
if (cell == root)
|
||||||
|
return;
|
||||||
|
root->constr_children.push_back(cell);
|
||||||
|
cell->cluster = root->name;
|
||||||
|
cell->constr_abs_z = false;
|
||||||
|
cell->constr_x = x_offset;
|
||||||
|
cell->constr_y = y_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constrain A passthrough cells.
|
||||||
|
for (int a = 0; a <= a_width / 2; a++) {
|
||||||
|
auto &a_passthru = m.a_passthrus[a];
|
||||||
|
constrain_cell(a_passthru.lower, -1, 4 + a);
|
||||||
|
constrain_cell(a_passthru.upper, -1, 4 + a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constrain multiplier columns.
|
||||||
|
for (int b = 0; b <= b_width / 2; b++) {
|
||||||
|
auto &col = m.cols[b];
|
||||||
|
constrain_cell(col.b_passthru.lower, b, b);
|
||||||
|
constrain_cell(col.b_passthru.upper, b, b);
|
||||||
|
|
||||||
|
constrain_cell(col.carry.lower, b + 1, b);
|
||||||
|
constrain_cell(col.carry.upper, b + 1, b);
|
||||||
|
|
||||||
|
constrain_cell(col.multfab.lower, b + 2, b);
|
||||||
|
constrain_cell(col.multfab.upper, b + 2, b);
|
||||||
|
|
||||||
|
constrain_cell(col.f_route.lower, b + 3, b);
|
||||||
|
constrain_cell(col.f_route.upper, b + 3, b);
|
||||||
|
|
||||||
|
for (size_t mult_idx = 0; mult_idx < col.mults.size(); mult_idx++) {
|
||||||
|
constrain_cell(col.mults[mult_idx].lower, b + 4 + mult_idx, b);
|
||||||
|
constrain_cell(col.mults[mult_idx].upper, b + 4 + mult_idx, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
constrain_cell(col.mult_msb.lower, b + 4 + col.mults.size() + 1, b);
|
||||||
|
constrain_cell(col.mult_msb.upper, b + 4 + col.mults.size() + 1, b);
|
||||||
|
|
||||||
|
constrain_cell(col.msb_route.lower, b + 4 + col.mults.size() + 2, b);
|
||||||
|
constrain_cell(col.msb_route.upper, b + 4 + col.mults.size() + 2, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: connect them.
|
||||||
|
|
||||||
|
// Connect A passthrough cells.
|
||||||
|
|
||||||
|
log_info(" Created %zu CPEs.\n", m.cpe_count());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue