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 is carry then LUT0 must be carry too
|
||||||
if (lut1->lutInfo.is_carry && (lut0 == nullptr || !lut0->lutInfo.is_carry))
|
if (lut1->lutInfo.is_carry && (lut0 == nullptr || !lut0->lutInfo.is_carry))
|
||||||
return false;
|
return false;
|
||||||
|
if (!lut1->lutInfo.is_carry && lut0 != nullptr && lut0->lutInfo.is_carry)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
// Check for correct use of FF1 DI
|
// Check for correct use of FF1 DI
|
||||||
if (ff1 != nullptr && ff1->ffInfo.di != nullptr && (lut1 == nullptr || ff1->ffInfo.di != lut1->lutInfo.f))
|
if (ff1 != nullptr && ff1->ffInfo.di != nullptr && (lut1 == nullptr || ff1->ffInfo.di != lut1->lutInfo.f))
|
||||||
|
@ -205,3 +205,5 @@ X(CER)
|
|||||||
X(RST)
|
X(RST)
|
||||||
|
|
||||||
X(WEAMUX)
|
X(WEAMUX)
|
||||||
|
|
||||||
|
X(VCC_DRV)
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
namespace {
|
namespace {
|
||||||
struct NexusFasmWriter
|
struct NexusFasmWriter
|
||||||
@ -291,12 +293,10 @@ struct NexusFasmWriter
|
|||||||
push(stringf("SLICE%c", slice));
|
push(stringf("SLICE%c", slice));
|
||||||
if (cell->params.count(id_INIT))
|
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);
|
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) {
|
if (cell->lutInfo.is_carry) {
|
||||||
write_bit("MODE.CCU2");
|
write_bit("MODE.CCU2");
|
||||||
write_enum(cell, "INJECT", "NO");
|
write_enum(cell, "CCU2.INJECT", "NO");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
pop(2);
|
pop(2);
|
||||||
}
|
}
|
||||||
// Write config for an OXIDE_FF cell
|
// Write config for an OXIDE_FF cell
|
||||||
|
@ -448,6 +448,14 @@ struct NexusPacker
|
|||||||
// Pin is tied to a constant
|
// Pin is tied to a constant
|
||||||
// If there is a hard constant option; use it
|
// If there is a hard constant option; use it
|
||||||
if ((pin_style & int(req_mux)) == req_mux) {
|
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);
|
disconnect_port(ctx, cell, port_name);
|
||||||
ctx->set_cell_pinmux(cell, port_name, req_mux);
|
ctx->set_cell_pinmux(cell, port_name, req_mux);
|
||||||
} else if (port.second.net == nullptr) {
|
} 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) {}
|
explicit NexusPacker(Context *ctx) : ctx(ctx) {}
|
||||||
|
|
||||||
void operator()()
|
void operator()()
|
||||||
@ -1128,6 +1223,7 @@ struct NexusPacker
|
|||||||
convert_prims();
|
convert_prims();
|
||||||
pack_bram();
|
pack_bram();
|
||||||
pack_lutram();
|
pack_lutram();
|
||||||
|
pack_carries();
|
||||||
pack_widefn();
|
pack_widefn();
|
||||||
pack_ffs();
|
pack_ffs();
|
||||||
pack_constants();
|
pack_constants();
|
||||||
|
Loading…
Reference in New Issue
Block a user