Update a passthru to use new primitives

This commit is contained in:
Miodrag Milanovic 2025-07-01 12:35:01 +02:00
parent 998e3e1e6f
commit b6c7f56a83
5 changed files with 135 additions and 51 deletions

View File

@ -266,6 +266,8 @@ struct BitstreamBackend
break;
case id_CPE_LT_L.index:
case id_CPE_LT_U.index:
case id_CPE_CPLINES.index:
case id_CPE_COMP.index:
case id_CPE_L2T4.index:
case id_CPE_L2T5.index:
case id_CPE_ADDF.index:

View File

@ -41,7 +41,19 @@ CellInfo *GateMatePacker::create_cell_ptr(IdString type, IdString name)
add_port(id_IN4, PORT_IN);
add_port(id_OUT, PORT_OUT);
if (type.in(id_CPE_LT_L, id_CPE_L2T5_L, id_CPE_CI)) {
add_port(id_CINX, PORT_IN);
add_port(id_PINX, PORT_IN);
add_port(id_CINY1, PORT_IN);
add_port(id_PINY1, PORT_IN);
add_port(id_CINY2, PORT_IN);
add_port(id_PINY2, PORT_IN);
add_port(id_COUTX, PORT_OUT);
add_port(id_POUTX, PORT_OUT);
add_port(id_COUTY1, PORT_OUT);
add_port(id_POUTY1, PORT_OUT);
add_port(id_COUTY2, PORT_OUT);
add_port(id_POUTY2, PORT_OUT);
}
} else if (type.in(id_CLKIN)) {
for (int i = 0; i < 4; i++) {
@ -69,6 +81,28 @@ CellInfo *GateMatePacker::create_cell_ptr(IdString type, IdString name)
add_port(id_RAM_I, PORT_IN);
add_port(id_RAM_O, PORT_OUT);
add_port(id_OUT, PORT_OUT);
} else if (type.in(id_CPE_COMP)) {
add_port(id_COMB1, PORT_IN);
add_port(id_COMB2, PORT_IN);
add_port(id_COMPOUT, PORT_OUT);
} else if (type.in(id_CPE_CPLINES)) {
add_port(id_OUT1, PORT_IN);
add_port(id_OUT2, PORT_IN);
add_port(id_COMPOUT, PORT_IN);
add_port(id_CINX, PORT_IN);
add_port(id_PINX, PORT_IN);
add_port(id_CINY1, PORT_IN);
add_port(id_PINY1, PORT_IN);
add_port(id_CINY2, PORT_IN);
add_port(id_PINY2, PORT_IN);
add_port(id_COUTX, PORT_OUT);
add_port(id_POUTX, PORT_OUT);
add_port(id_COUTY1, PORT_OUT);
add_port(id_POUTY1, PORT_OUT);
add_port(id_COUTY2, PORT_OUT);
add_port(id_POUTY2, PORT_OUT);
} else {
log_error("Trying to create unknown cell type %s\n", type.c_str(ctx));
}

View File

@ -940,8 +940,18 @@ X(CPE_LT_L)
//X(OUT)
//X(CPOUT)
X(MUXOUT)
X(CINX)
X(PINX)
X(CINY1)
X(PINY1)
X(CINY2)
X(PINY2)
X(COUTX)
X(POUTX)
X(COUTY1)
X(POUTY1)
X(COUTY2)
X(POUTY2)
// hardware primitive CPE_FF_L
X(CPE_FF_L)
@ -976,24 +986,44 @@ X(OUT2)
X(CPOUT1)
X(CPOUT2)
//X(MUXOUT)
//X(CINX)
//X(PINX)
//X(CINY1)
//X(PINY1)
//X(CINY2)
//X(PINY2)
//X(COUTX)
//X(POUTX)
//X(COUTY1)
//X(POUTY1)
//X(COUTY2)
//X(POUTY2)
// hardware primitive CPE_LINES
X(CPE_LINES)
// CPE_LINES pins
X(CINX)
X(PINX)
// hardware primitive CPE_COMP
X(CPE_COMP)
// CPE_COMP pins
X(COMB1)
X(COMB2)
X(COMPOUT)
// hardware primitive CPE_CPLINES
X(CPE_CPLINES)
// CPE_CPLINES pins
//X(OUT1)
//X(OUT2)
//X(COMPOUT)
//X(CINX)
//X(PINX)
//X(CINY1)
X(PINY1)
X(CINY2)
X(PINY2)
X(COUTX)
X(POUTX)
//X(PINY1)
//X(CINY2)
//X(PINY2)
//X(COUTX)
//X(POUTX)
//X(COUTY1)
X(POUTY1)
X(COUTY2)
X(POUTY2)
//X(POUTY1)
//X(COUTY2)
//X(POUTY2)
// hardware primitive GPIO
X(GPIO)

View File

@ -93,8 +93,9 @@ enum CPE_Z
CPE_FF_L_Z = 3,
CPE_RAMIO_U_Z = 4,
CPE_RAMIO_L_Z = 5,
CPE_LINES_Z = 6,
CPE_LT_FULL_Z = 7,
CPE_COMP_Z = 6,
CPE_CPLINES_Z = 7,
CPE_LT_FULL_Z = 8,
};
enum ClusterPlacement

View File

@ -46,12 +46,14 @@ struct ZeroDriver
// Propagate A0 through OUT1 and A1 through OUT2; zero COUTX and POUTX.
struct APassThroughCell
{
APassThroughCell(CellInfo *lower, CellInfo *upper, IdString name);
APassThroughCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, CellInfo *cplines, IdString name);
void clean_up(Context *ctx);
CellInfo *lower;
CellInfo *upper;
CellInfo *comp;
CellInfo *cplines;
};
// Propagate B0 through POUTY1 and B1 through COUTY1
@ -152,25 +154,23 @@ ZeroDriver::ZeroDriver(CellInfo *lower, CellInfo *upper, IdString name) : lower{
upper->params[id_INIT_L10] = Property(LUT_ZERO, 4); // (unused)
}
APassThroughCell::APassThroughCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper}
APassThroughCell::APassThroughCell(CellInfo *lower, CellInfo *upper, CellInfo *comp, CellInfo *cplines, IdString name)
: lower{lower}, upper{upper}, comp{comp}, cplines{cplines}
{
lower->params[id_INIT_L02] = Property(LUT_D0, 4); // IN5
lower->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused)
lower->params[id_INIT_L11] = Property(LUT_D0, 4); // L02
lower->params[id_INIT_L20] = Property(LUT_D1, 4); // L11 -> COMB1OUT
lower->params[id_INIT_L30] = Property(LUT_ONE, 4); // zero -> COMP_OUT (L30 is inverted)
lower->params[id_INIT_L00] = Property(LUT_D0, 4); // IN5
lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
lower->params[id_INIT_L10] = Property(LUT_D0, 4); // L02
comp->params[id_INIT_L30] = Property(LUT_ONE, 4); // zero -> COMP_OUT (L30 is inverted)
upper->params[id_INIT_L00] = Property(LUT_D0, 4); // IN1
upper->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused)
upper->params[id_INIT_L10] = Property(LUT_D0, 4); // L00 -> COMB2OUT
upper->params[id_C_SEL_C] = Property(1, 1); // COMP_OUT -> CX_VAL
upper->params[id_C_SEL_P] = Property(1, 1); // COMP_OUT -> PX_VAL
upper->params[id_C_CX_I] = Property(1, 1); // CX_VAL -> COUTX
upper->params[id_C_PX_I] = Property(1, 1); // PX_VAL -> POUTX
upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1
upper->params[id_C_O2] = Property(0b11, 2); // COMB2OUT -> OUT2
cplines->params[id_C_SEL_C] = Property(1, 1); // COMP_OUT -> CX_VAL
cplines->params[id_C_SEL_P] = Property(1, 1); // COMP_OUT -> PX_VAL
cplines->params[id_C_CX_I] = Property(1, 1); // CX_VAL -> COUTX
cplines->params[id_C_PX_I] = Property(1, 1); // PX_VAL -> POUTX
}
void APassThroughCell::clean_up(Context *ctx)
@ -185,9 +185,8 @@ void APassThroughCell::clean_up(Context *ctx)
bool net_is_gnd = lower_net->name == ctx->idf("$PACKER_GND");
bool net_is_vcc = lower_net->name == ctx->idf("$PACKER_VCC");
if (net_is_gnd || net_is_vcc) {
lower->params[id_INIT_L02] = Property(LUT_ZERO, 4);
lower->params[id_INIT_L11] = Property(LUT_ZERO, 4);
lower->params[id_INIT_L20] = Property(net_is_vcc ? LUT_ONE : LUT_ZERO, 4);
lower->params[id_INIT_L00] = Property(LUT_ZERO, 4);
lower->params[id_INIT_L10] = Property(LUT_ZERO, 4);
lower->disconnectPort(id_IN1);
}
}
@ -402,9 +401,14 @@ void GateMatePacker::pack_mult()
};
auto create_a_passthru = [&](IdString name) {
auto *a_passthru_lower = create_cell_ptr(id_CPE_LT_L, ctx->idf("%s$a_passthru_lower", name.c_str(ctx)));
auto *a_passthru_lower = create_cell_ptr(id_CPE_L2T4, ctx->idf("%s$a_passthru_lower", name.c_str(ctx)));
auto *a_passthru_upper = create_cell_ptr(id_CPE_L2T4, ctx->idf("%s$a_passthru_upper", name.c_str(ctx)));
return APassThroughCell{a_passthru_lower, a_passthru_upper, name};
auto *a_passthru_comp = create_cell_ptr(id_CPE_COMP, ctx->idf("%s$a_passthru_comp", name.c_str(ctx)));
auto *a_passthru_lines = create_cell_ptr(id_CPE_CPLINES, ctx->idf("%s$a_passthru_cplines", name.c_str(ctx)));
NetInfo *comp_conn = ctx->createNet(ctx->idf("%s$compout", name.c_str(ctx)));
a_passthru_comp->connectPort(id_COMPOUT, comp_conn);
a_passthru_lines->connectPort(id_COMPOUT, comp_conn);
return APassThroughCell{a_passthru_lower, a_passthru_upper, a_passthru_comp, a_passthru_lines, name};
};
auto create_mult_col = [&](IdString name, int a_width, bool is_even_x, bool carry_enable_cinx,
@ -511,38 +515,40 @@ void GateMatePacker::pack_mult()
};
// Constrain zero driver.
constrain_cell(m.zero.lower, -1, 3, 1);
constrain_cell(m.zero.upper, -1, 3, 0);
constrain_cell(m.zero.lower, -1, 3, CPE_LT_L_Z);
constrain_cell(m.zero.upper, -1, 3, CPE_LT_U_Z);
// Constrain A passthrough cells.
for (int a = 0; a < a_width / 2; a++) {
auto &a_passthru = m.a_passthrus.at(a);
constrain_cell(a_passthru.lower, -1, 4 + a, 1);
constrain_cell(a_passthru.upper, -1, 4 + a, 0);
constrain_cell(a_passthru.lower, -1, 4 + a, CPE_LT_L_Z);
constrain_cell(a_passthru.upper, -1, 4 + a, CPE_LT_U_Z);
constrain_cell(a_passthru.comp, -1, 4 + a, CPE_COMP_Z);
constrain_cell(a_passthru.cplines,-1, 4 + a, CPE_CPLINES_Z);
}
// Constrain multiplier columns.
for (int b = 0; b < b_width / 2; b++) {
auto &col = m.cols.at(b);
constrain_cell(col.b_passthru.lower, b, b, 1);
constrain_cell(col.b_passthru.upper, b, b, 0);
constrain_cell(col.b_passthru.lower, b, b, CPE_LT_L_Z);
constrain_cell(col.b_passthru.upper, b, b, CPE_LT_U_Z);
constrain_cell(col.carry.lower, b, b + 1, 1);
constrain_cell(col.carry.upper, b, b + 1, 0);
constrain_cell(col.carry.lower, b, b + 1, CPE_LT_L_Z);
constrain_cell(col.carry.upper, b, b + 1, CPE_LT_U_Z);
constrain_cell(col.multfab.lower, b, b + 2, 1);
constrain_cell(col.multfab.upper, b, b + 2, 0);
constrain_cell(col.multfab.lower, b, b + 2, CPE_LT_L_Z);
constrain_cell(col.multfab.upper, b, b + 2, CPE_LT_U_Z);
constrain_cell(col.f_route.lower, b, b + 3, 1);
constrain_cell(col.f_route.upper, b, b + 3, 0);
constrain_cell(col.f_route.lower, b, b + 3, CPE_LT_L_Z);
constrain_cell(col.f_route.upper, b, b + 3, CPE_LT_U_Z);
for (size_t mult_idx = 0; mult_idx < col.mults.size(); mult_idx++) {
constrain_cell(col.mults[mult_idx].lower, b, b + 4 + mult_idx, 1);
constrain_cell(col.mults[mult_idx].upper, b, b + 4 + mult_idx, 0);
constrain_cell(col.mults[mult_idx].lower, b, b + 4 + mult_idx, CPE_LT_L_Z);
constrain_cell(col.mults[mult_idx].upper, b, b + 4 + mult_idx, CPE_LT_U_Z);
}
constrain_cell(col.msb_route.lower, b, b + 4 + col.mults.size(), 1);
constrain_cell(col.msb_route.upper, b, b + 4 + col.mults.size(), 0);
constrain_cell(col.msb_route.lower, b, b + 4 + col.mults.size(), CPE_LT_L_Z);
constrain_cell(col.msb_route.upper, b, b + 4 + col.mults.size(), CPE_LT_U_Z);
}
// Step 3: connect them.
@ -565,9 +571,20 @@ void GateMatePacker::pack_mult()
cpe_half->connectPort(id_OUT, a_net);
// This may be GND/VCC; if so, clean it up.
if (a % 2 == 1)
if (a % 2 == 1) {
a_passthru.clean_up(ctx);
auto &mult_row = m.cols.at(0).mults.at(a / 2);
auto *so1_net =ctx->createNet(ctx->idf("%s_so1", cpe_half->name.c_str(ctx)));
a_passthru.cplines->connectPort(id_COUTX, so1_net);
mult_row.lower->connectPort(id_CINX, so1_net);
auto *so2_net =ctx->createNet(ctx->idf("%s_so2", cpe_half->name.c_str(ctx)));
a_passthru.cplines->connectPort(id_POUTX, so2_net);
mult_row.lower->connectPort(id_PINX, so2_net);
}
for (int b = 0; b < b_width / 2; b++) {
{
auto &mult_row = m.cols.at(b).mults.at(a / 2);