nexus: Basic support for carries
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
c89d830e16
commit
e6c2887773
@ -59,6 +59,8 @@ bool Arch::nexus_logic_tile_valid(LogicTileStatus <s) const
|
||||
// If LUT1 is carry then LUT0 must be carry too
|
||||
if (lut1->lutInfo.is_carry && (lut0 == nullptr || !lut0->lutInfo.is_carry))
|
||||
return false;
|
||||
if (!lut1->lutInfo.is_carry && lut0 != nullptr && lut0->lutInfo.is_carry)
|
||||
return false;
|
||||
}
|
||||
// Check for correct use of FF1 DI
|
||||
if (ff1 != nullptr && ff1->ffInfo.di != nullptr && (lut1 == nullptr || ff1->ffInfo.di != lut1->lutInfo.f))
|
||||
|
@ -205,3 +205,5 @@ X(CER)
|
||||
X(RST)
|
||||
|
||||
X(WEAMUX)
|
||||
|
||||
X(VCC_DRV)
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "nextpnr.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
namespace {
|
||||
struct NexusFasmWriter
|
||||
@ -291,12 +293,10 @@ struct NexusFasmWriter
|
||||
push(stringf("SLICE%c", slice));
|
||||
if (cell->params.count(id_INIT))
|
||||
write_int_vector(stringf("K%d.INIT[15:0]", k), int_or_default(cell->params, id_INIT, 0), 16);
|
||||
#if 0
|
||||
if (cell->lutInfo.is_carry) {
|
||||
write_bit("MODE.CCU2");
|
||||
write_enum(cell, "INJECT", "NO");
|
||||
write_enum(cell, "CCU2.INJECT", "NO");
|
||||
}
|
||||
#endif
|
||||
pop(2);
|
||||
}
|
||||
// Write config for an OXIDE_FF cell
|
||||
|
@ -448,6 +448,14 @@ struct NexusPacker
|
||||
// Pin is tied to a constant
|
||||
// If there is a hard constant option; use it
|
||||
if ((pin_style & int(req_mux)) == req_mux) {
|
||||
|
||||
if (cell->type == id_OXIDE_COMB) {
|
||||
// Due to potentially overlapping routing, explicitly keep the one-driver
|
||||
// until can correctly use the dedicated Vcc route
|
||||
if (str_or_default(cell->params, id_MODE, "LOGIC") != "LOGIC")
|
||||
continue;
|
||||
}
|
||||
|
||||
disconnect_port(ctx, cell, port_name);
|
||||
ctx->set_cell_pinmux(cell, port_name, req_mux);
|
||||
} else if (port.second.net == nullptr) {
|
||||
@ -1120,6 +1128,93 @@ struct NexusPacker
|
||||
}
|
||||
}
|
||||
|
||||
void pack_carries()
|
||||
{
|
||||
// Find root carry cells
|
||||
log_info("Packing carries...\n");
|
||||
std::vector<CellInfo *> roots;
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (ci->type != id_CCU2)
|
||||
continue;
|
||||
if (get_net_or_empty(ci, id_CIN) != nullptr)
|
||||
continue;
|
||||
roots.push_back(ci);
|
||||
}
|
||||
for (CellInfo *root : roots) {
|
||||
CellInfo *ci = root;
|
||||
CellInfo *constr_base = nullptr;
|
||||
int idx = 0;
|
||||
do {
|
||||
if (ci->type != id_CCU2)
|
||||
log_error("Found non-carry cell '%s' in carry chain!\n", ctx->nameOf(ci));
|
||||
// Split the carry into two COMB cells
|
||||
std::vector<CellInfo *> combs;
|
||||
for (int i = 0; i < 2; i++)
|
||||
combs.push_back(
|
||||
ctx->createCell(ctx->id(stringf("%s$ccu2_comb[%d]$", ctx->nameOf(ci), i)), id_OXIDE_COMB));
|
||||
// Rewire LUT ports
|
||||
for (int i = 0; i < 2; i++) {
|
||||
combs[i]->params[id_MODE] = std::string("CCU2");
|
||||
replace_port(ci, bus_flat("A", i), combs[i], id_A);
|
||||
replace_port(ci, bus_flat("B", i), combs[i], id_B);
|
||||
replace_port(ci, bus_flat("C", i), combs[i], id_C);
|
||||
replace_port(ci, bus_flat("D", i), combs[i], id_D);
|
||||
replace_port(ci, bus_flat("S", i), combs[i], id_F);
|
||||
}
|
||||
|
||||
// External carry chain
|
||||
replace_port(ci, id_CIN, combs[0], id_FCI);
|
||||
replace_port(ci, id_COUT, combs[1], id_FCO);
|
||||
|
||||
// Copy parameters
|
||||
if (ci->params.count(id_INJECT))
|
||||
combs[0]->params[id_INJECT] = ci->params[id_INJECT];
|
||||
combs[0]->params[id_INIT] = ctx->parse_lattice_param(ci, id_INIT0, 16, 0);
|
||||
combs[1]->params[id_INIT] = ctx->parse_lattice_param(ci, id_INIT1, 16, 0);
|
||||
|
||||
// Internal carry net between the two split COMB cells
|
||||
NetInfo *int_cy = ctx->createNet(ctx->id(stringf("%s$widefn_int_cy$", ctx->nameOf(ci))));
|
||||
combs[0]->addOutput(id_FCO);
|
||||
combs[1]->addInput(id_FCI);
|
||||
connect_port(ctx, int_cy, combs[0], id_FCO);
|
||||
connect_port(ctx, int_cy, combs[1], id_FCI);
|
||||
|
||||
// Relative constraints
|
||||
for (int i = 0; i < 2; i++) {
|
||||
int z = (idx % 8);
|
||||
combs[i]->constr_z = ((z / 2) << 3) | (z % 2);
|
||||
combs[i]->constr_abs_z = true;
|
||||
if (constr_base == nullptr) {
|
||||
// This is the very first cell in the chain
|
||||
constr_base = combs[i];
|
||||
} else {
|
||||
combs[i]->constr_x = (idx / 8);
|
||||
combs[i]->constr_y = 0;
|
||||
combs[i]->constr_parent = constr_base;
|
||||
constr_base->constr_children.push_back(combs[i]);
|
||||
}
|
||||
|
||||
++idx;
|
||||
}
|
||||
|
||||
ctx->cells.erase(ci->name);
|
||||
|
||||
// Find next cell in chain, if it exists
|
||||
NetInfo *fco = get_net_or_empty(combs[1], id_FCO);
|
||||
ci = nullptr;
|
||||
if (fco != nullptr) {
|
||||
if (fco->users.size() > 1)
|
||||
log_error("Carry cell '%s' has multiple fanout on FCO\n", ctx->nameOf(combs[1]));
|
||||
else if (fco->users.size() == 1) {
|
||||
NPNR_ASSERT(fco->users.at(0).port == id_CIN);
|
||||
ci = fco->users.at(0).cell;
|
||||
}
|
||||
}
|
||||
} while (ci != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
explicit NexusPacker(Context *ctx) : ctx(ctx) {}
|
||||
|
||||
void operator()()
|
||||
@ -1128,6 +1223,7 @@ struct NexusPacker
|
||||
convert_prims();
|
||||
pack_bram();
|
||||
pack_lutram();
|
||||
pack_carries();
|
||||
pack_widefn();
|
||||
pack_ffs();
|
||||
pack_constants();
|
||||
|
Loading…
Reference in New Issue
Block a user