aboutsummaryrefslogtreecommitdiffstats
path: root/mistral
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-05-12 20:35:02 +0100
committergatecat <gatecat@ds0.me>2021-05-15 14:54:33 +0100
commitd39e67da7ed08b790fcc0b3c7ff9551164070fb2 (patch)
treee2ae7c00050b7580fd83b5b9bcc1ac1763a604fe /mistral
parent7574eab2b603bd850d6f3819d2183d8600b59cd3 (diff)
downloadnextpnr-d39e67da7ed08b790fcc0b3c7ff9551164070fb2.tar.gz
nextpnr-d39e67da7ed08b790fcc0b3c7ff9551164070fb2.tar.bz2
nextpnr-d39e67da7ed08b790fcc0b3c7ff9551164070fb2.zip
mistral: First pass at carry packing
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'mistral')
-rw-r--r--mistral/archdefs.h1
-rw-r--r--mistral/constids.inc6
-rw-r--r--mistral/lab.cc42
-rw-r--r--mistral/pack.cc41
4 files changed, 82 insertions, 8 deletions
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<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()
{
init_constant_nets();
pack_constants();
pack_io();
+ constrain_carries();
}
};
}; // namespace