mistral: First pass at carry packing

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2021-05-12 20:35:02 +01:00
parent 7574eab2b6
commit d39e67da7e
4 changed files with 82 additions and 8 deletions

View File

@ -183,6 +183,7 @@ struct ArchCellInfo : BaseClusterInfo
int lut_bits_count; int lut_bits_count;
bool is_carry, is_shared, is_extended; bool is_carry, is_shared, is_extended;
bool carry_start, carry_end;
} combInfo; } combInfo;
struct struct
{ {

View File

@ -39,9 +39,9 @@ X(Q)
X(COMBOUT) X(COMBOUT)
X(SUM_OUT) X(SUM_OUT)
X(CIN) X(CI)
X(SHAREIN) X(SHAREIN)
X(COUT) X(CO)
X(SHAREOUT) X(SHAREOUT)
X(CARRY_START) X(CARRY_START)
@ -64,8 +64,6 @@ X(LUT1)
X(D0) X(D0)
X(D1) X(D1)
X(CI)
X(CO)
X(SO) X(SO)
X(WIRE) X(WIRE)

View File

@ -48,7 +48,7 @@ static void create_alm(Arch *arch, int x, int y, int z, uint32_t lab_idx)
share_in = arch->add_wire(x, y, id_CARRY_START); share_in = arch->add_wire(x, y, id_CARRY_START);
} else { } else {
// Output of last tile // Output of last tile
carry_in = arch->add_wire(x, y - 1, id_COUT); carry_in = arch->add_wire(x, y - 1, id_CO);
share_in = arch->add_wire(x, y - 1, id_SHAREOUT); share_in = arch->add_wire(x, y - 1, id_SHAREOUT);
} }
} else { } else {
@ -57,7 +57,7 @@ static void create_alm(Arch *arch, int x, int y, int z, uint32_t lab_idx)
share_in = arch->add_wire(x, y, arch->id(stringf("SHARE[%d]", (z * 2 + i) - 1))); share_in = arch->add_wire(x, y, arch->id(stringf("SHARE[%d]", (z * 2 + i) - 1)));
} }
if (z == 9 && i == 1) { if (z == 9 && i == 1) {
carry_out = arch->add_wire(x, y, id_COUT); carry_out = arch->add_wire(x, y, id_CO);
share_out = arch->add_wire(x, y, id_SHAREOUT); share_out = arch->add_wire(x, y, id_SHAREOUT);
} else { } else {
carry_out = arch->add_wire(x, y, arch->id(stringf("CARRY[%d]", z * 2 + i))); carry_out = arch->add_wire(x, y, arch->id(stringf("CARRY[%d]", z * 2 + i)));
@ -75,9 +75,9 @@ static void create_alm(Arch *arch, int x, int y, int z, uint32_t lab_idx)
arch->add_bel_pin(bel, id_F0, PORT_IN, arch->get_port(CycloneV::LAB, x, y, z, CycloneV::F0)); arch->add_bel_pin(bel, id_F0, PORT_IN, arch->get_port(CycloneV::LAB, x, y, z, CycloneV::F0));
arch->add_bel_pin(bel, id_F1, PORT_IN, arch->get_port(CycloneV::LAB, x, y, z, CycloneV::F1)); arch->add_bel_pin(bel, id_F1, PORT_IN, arch->get_port(CycloneV::LAB, x, y, z, CycloneV::F1));
// Carry/share chain // Carry/share chain
arch->add_bel_pin(bel, id_CIN, PORT_IN, carry_in); arch->add_bel_pin(bel, id_CI, PORT_IN, carry_in);
arch->add_bel_pin(bel, id_SHAREIN, PORT_IN, share_in); arch->add_bel_pin(bel, id_SHAREIN, PORT_IN, share_in);
arch->add_bel_pin(bel, id_COUT, PORT_OUT, carry_out); arch->add_bel_pin(bel, id_CO, PORT_OUT, carry_out);
arch->add_bel_pin(bel, id_SHAREOUT, PORT_OUT, share_out); arch->add_bel_pin(bel, id_SHAREOUT, PORT_OUT, share_out);
// Combinational output // Combinational output
alm.comb_out[i] = arch->add_wire(x, y, arch->id(stringf("COMBOUT[%d]", z * 2 + i))); alm.comb_out[i] = arch->add_wire(x, y, arch->id(stringf("COMBOUT[%d]", z * 2 + i)));
@ -231,6 +231,8 @@ void Arch::assign_comb_info(CellInfo *cell) const
cell->combInfo.is_carry = false; cell->combInfo.is_carry = false;
cell->combInfo.is_shared = false; cell->combInfo.is_shared = false;
cell->combInfo.is_extended = false; cell->combInfo.is_extended = false;
cell->combInfo.carry_start = false;
cell->combInfo.carry_end = false;
if (cell->type == id_MISTRAL_ALUT_ARITH) { if (cell->type == id_MISTRAL_ALUT_ARITH) {
cell->combInfo.is_carry = true; cell->combInfo.is_carry = true;
@ -241,7 +243,13 @@ void Arch::assign_comb_info(CellInfo *cell) const
for (auto pin : {id_A, id_B, id_C, id_D0, id_D1}) { for (auto pin : {id_A, id_B, id_C, id_D0, id_D1}) {
cell->combInfo.lut_in[i++] = get_net_or_empty(cell, pin); cell->combInfo.lut_in[i++] = get_net_or_empty(cell, pin);
} }
const NetInfo *ci = get_net_or_empty(cell, id_CI);
const NetInfo *co = get_net_or_empty(cell, id_CO);
cell->combInfo.comb_out = get_net_or_empty(cell, id_SO); cell->combInfo.comb_out = get_net_or_empty(cell, id_SO);
cell->combInfo.carry_start = (ci == nullptr) || (ci->driver.cell == nullptr);
cell->combInfo.carry_end = (co == nullptr) || (co->users.empty());
} else { } else {
cell->combInfo.lut_input_count = 0; cell->combInfo.lut_input_count = 0;
switch (cell->type.index) { switch (cell->type.index) {
@ -296,6 +304,22 @@ void Arch::assign_ff_info(CellInfo *cell) const
cell->ffInfo.datain = get_net_or_empty(cell, id_DATAIN); cell->ffInfo.datain = get_net_or_empty(cell, id_DATAIN);
} }
namespace {
// Check if the other side of a carry chain wire is being used
bool carry_used(const Arch *arch, BelId bel, IdString pin)
{
WireId wire = arch->getBelPinWire(bel, pin);
for (auto bp : arch->getWireBelPins(wire)) {
if (bp.bel == bel)
continue;
CellInfo *ci = arch->getBoundBelCell(bp.bel);
if (ci != nullptr && ci->combInfo.is_carry)
return true;
}
return false;
}
} // namespace
// Validity checking functions // Validity checking functions
bool Arch::is_alm_legal(uint32_t lab, uint8_t alm) const bool Arch::is_alm_legal(uint32_t lab, uint8_t alm) const
{ {
@ -342,6 +366,16 @@ bool Arch::is_alm_legal(uint32_t lab, uint8_t alm) const
return false; return false;
} }
// Never allow two disjoint carry chains to accidentally stack
for (int i = 0; i < 2; i++) {
if (!luts[i])
continue;
if (luts[i]->combInfo.carry_start && carry_used(this, alm_data.lut_bels[i], id_CI))
return false;
if (luts[i]->combInfo.carry_end && carry_used(this, alm_data.lut_bels[i], id_CO))
return false;
}
// For each ALM half; check FF control set sharing and input routeability // For each ALM half; check FF control set sharing and input routeability
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
// There are two ways to route from the fabric into FF data - either routing through a LUT or using the E/F // There are two ways to route from the fabric into FF data - either routing through a LUT or using the E/F

View File

@ -275,11 +275,52 @@ struct MistralPacker
} }
} }
void constrain_carries()
{
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (ci->type != id_MISTRAL_ALUT_ARITH)
continue;
const NetInfo *cin = get_net_or_empty(ci, id_CI);
if (cin != nullptr && cin->driver.cell != nullptr)
continue; // not the start of a chain
std::vector<CellInfo *> chain;
CellInfo *cursor = ci;
while (true) {
chain.push_back(cursor);
const NetInfo *co = get_net_or_empty(cursor, id_CO);
if (co == nullptr || co->users.empty())
break;
if (co->users.size() > 1)
log_error("Carry net %s has more than one sink!\n", ctx->nameOf(co));
auto &usr = co->users.at(0);
if (usr.port != id_CI)
log_error("Carry net %s drives port %s, expected CI\n", ctx->nameOf(co), ctx->nameOf(usr.port));
cursor = usr.cell;
}
chain.at(0)->constr_abs_z = true;
chain.at(0)->constr_z = 0;
chain.at(0)->cluster = chain.at(0)->name;
for (int i = 1; i < int(chain.size()); i++) {
chain.at(i)->constr_x = 0;
chain.at(i)->constr_y = (i / 20);
// 2 COMB, 4 FF per ALM
chain.at(i)->constr_z = ((i / 2) % 10) * 6 + (i % 2);
chain.at(i)->constr_abs_z = true;
chain.at(i)->cluster = chain.at(0)->name;
chain.at(0)->constr_children.push_back(chain.at(i));
}
}
}
void run() void run()
{ {
init_constant_nets(); init_constant_nets();
pack_constants(); pack_constants();
pack_io(); pack_io();
constrain_carries();
} }
}; };
}; // namespace }; // namespace