From d39e67da7ed08b790fcc0b3c7ff9551164070fb2 Mon Sep 17 00:00:00 2001 From: gatecat Date: Wed, 12 May 2021 20:35:02 +0100 Subject: mistral: First pass at carry packing Signed-off-by: gatecat --- mistral/archdefs.h | 1 + mistral/constids.inc | 6 ++---- mistral/lab.cc | 42 ++++++++++++++++++++++++++++++++++++++---- mistral/pack.cc | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 8 deletions(-) (limited to 'mistral') diff --git a/mistral/archdefs.h b/mistral/archdefs.h index ab00cb26..35b5bf63 100644 --- a/mistral/archdefs.h +++ b/mistral/archdefs.h @@ -183,6 +183,7 @@ struct ArchCellInfo : BaseClusterInfo int lut_bits_count; bool is_carry, is_shared, is_extended; + bool carry_start, carry_end; } combInfo; struct { diff --git a/mistral/constids.inc b/mistral/constids.inc index f1b51ee5..76d82a0b 100644 --- a/mistral/constids.inc +++ b/mistral/constids.inc @@ -39,9 +39,9 @@ X(Q) X(COMBOUT) X(SUM_OUT) -X(CIN) +X(CI) X(SHAREIN) -X(COUT) +X(CO) X(SHAREOUT) X(CARRY_START) @@ -64,8 +64,6 @@ X(LUT1) X(D0) X(D1) -X(CI) -X(CO) X(SO) X(WIRE) diff --git a/mistral/lab.cc b/mistral/lab.cc index 0719b37b..202753b4 100644 --- a/mistral/lab.cc +++ b/mistral/lab.cc @@ -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); } else { // 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); } } 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))); } 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); } else { 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_F1, PORT_IN, arch->get_port(CycloneV::LAB, x, y, z, CycloneV::F1)); // 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_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); // Combinational output 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_shared = false; cell->combInfo.is_extended = false; + cell->combInfo.carry_start = false; + cell->combInfo.carry_end = false; if (cell->type == id_MISTRAL_ALUT_ARITH) { 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}) { 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.carry_start = (ci == nullptr) || (ci->driver.cell == nullptr); + cell->combInfo.carry_end = (co == nullptr) || (co->users.empty()); } else { cell->combInfo.lut_input_count = 0; 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); } +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 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; } + // 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 (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 diff --git a/mistral/pack.cc b/mistral/pack.cc index 78657321..aed9572e 100644 --- a/mistral/pack.cc +++ b/mistral/pack.cc @@ -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 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() { init_constant_nets(); pack_constants(); pack_io(); + constrain_carries(); } }; }; // namespace -- cgit v1.2.3