Merge pull request #1031 from YosysHQ/gatecat/fab-next

fabulous: Add support for the CLB muxes
This commit is contained in:
myrtle 2022-09-30 16:13:32 +02:00 committed by GitHub
commit 41709dac8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 130 additions and 2 deletions

View File

@ -14,6 +14,7 @@ X(OutPass4_frame_config)
X(RegFile_32x4) X(RegFile_32x4)
X(MULADD) X(MULADD)
X(MUX8LUT_frame_config) X(MUX8LUT_frame_config)
X(MUX8LUT_frame_config_mux)
X(CLK) X(CLK)
X(I) X(I)
@ -86,3 +87,12 @@ X(BelBegin)
X(BelEnd) X(BelEnd)
X(GlobalClk) X(GlobalClk)
X(CFG) X(CFG)
X(FABULOUS_MUX2)
X(FABULOUS_MUX4)
X(FABULOUS_MUX8)
X(M_AB)
X(M_AD)
X(M_EF)
X(M_AH)

View File

@ -293,12 +293,49 @@ struct FabulousImpl : ViaductAPI
postprocess_bels(); postprocess_bels();
} }
void generate_split_mux8(BelId bel)
{
// _don't_ take a reference here because it might be invalidated by adding bels
auto data = ctx->bel_info(bel);
const std::array<IdString, 4> mux_outs{id_M_AB, id_M_AD, id_M_EF, id_M_AH};
for (unsigned k = 1; k <= 3; k++) {
// create MUX2 through 8
unsigned m = (1U << k);
for (unsigned i = 0; i < 8; i += m) {
// mux indexing scheme
// - MUX2s are at (z % 2) == 0
// - MUX4s are at (z % 4) == 1
// - MUX8s are at (z % 8) == 7
int idx = (m == 2) ? i : (m == 4) ? (i + 1) : (i + 7);
BelId mux =
ctx->addBel(IdStringList::concat(data.name[0], ctx->idf("MUX%d_%d", m, i)),
ctx->idf("FABULOUS_MUX%d", m), Loc(data.x, data.y, data.z + 1 + idx), false, false);
blk_trk->set_bel_type(mux, BelFlags::BLOCK_CLB, BelFlags::FUNC_MUX, idx);
// M data inputs
for (unsigned j = 0; j < m; j++) {
ctx->addBelInput(mux, ctx->idf("I%d", j), data.pins.at(ctx->idf("%c", char('A' + i + j))).wire);
}
// K select inputs
for (unsigned j = 0; j < k; j++) {
ctx->addBelInput(mux, ctx->idf("S%d", j),
data.pins.at(ctx->idf("S%d", (m == 8 && j == 2) ? 3 : ((i / m) * k + j))).wire);
}
// Output
IdString output = (m == 2) ? mux_outs.at(i / m)
: (m == 4) ? mux_outs.at((i / m) * k + 1)
: mux_outs.at(3);
ctx->addBelOutput(mux, id_O, data.pins.at(output).wire);
}
}
}
void postprocess_bels() void postprocess_bels()
{ {
// This does some post-processing on bels to make them useful for nextpnr place-and-route regardless of the code // This does some post-processing on bels to make them useful for nextpnr place-and-route regardless of the code
// path that creates them. In the future, splitting muxes and creating split LCs would be done here, too // path that creates them. In the future, splitting muxes and creating split LCs would be done here, too
for (auto bel : ctx->getBels()) { for (auto bel : ctx->getBels()) {
auto &data = ctx->bel_info(bel); // _don't_ take a reference here because it might be invalidated by adding bels
auto data = ctx->bel_info(bel);
if (data.type == id_FABULOUS_LC) { if (data.type == id_FABULOUS_LC) {
if (!data.pins.count(id_Q)) { if (!data.pins.count(id_Q)) {
// Add a Q pseudo-pin and pseudo-pip from Q to O // Add a Q pseudo-pin and pseudo-pip from Q to O
@ -309,6 +346,9 @@ struct FabulousImpl : ViaductAPI
// Pseudo-pip for FF mode // Pseudo-pip for FF mode
add_pseudo_pip(q_wire, o_wire, id_O2Q); add_pseudo_pip(q_wire, o_wire, id_O2Q);
} }
} else if (data.type.in(id_MUX8LUT_frame_config, id_MUX8LUT_frame_config_mux)) {
generate_split_mux8(bel);
ctx->bel_info(bel).hidden = true;
} else if (data.type == id_IO_1_bidirectional_frame_config_pass) { } else if (data.type == id_IO_1_bidirectional_frame_config_pass) {
if (!data.pins.count(id_PAD)) { if (!data.pins.count(id_PAD)) {
// Add a PAD pseudo-pin for the top level // Add a PAD pseudo-pin for the top level

View File

@ -123,6 +123,14 @@ struct FabFasmWriter
write_bool(lc, "NEG_SR"); write_bool(lc, "NEG_SR");
write_bool(lc, "ASYNC_SR"); write_bool(lc, "ASYNC_SR");
} }
if (lc->type.in(id_FABULOUS_MUX4, id_FABULOUS_MUX8)) {
// TODO: don't hardcode prefix
out << prefix << "I.c0" << std::endl;
}
if (lc->type == id_FABULOUS_MUX8) {
// TODO: don't hardcode prefix
out << prefix << "I.c1" << std::endl;
}
} }
void write_io(const CellInfo *io) void write_io(const CellInfo *io)
@ -161,7 +169,8 @@ struct FabFasmWriter
void write_cell(const CellInfo *ci) void write_cell(const CellInfo *ci)
{ {
out << stringf("# config for cell '%s'\n", ctx->nameOf(ci)) << std::endl; out << stringf("# config for cell '%s'\n", ctx->nameOf(ci)) << std::endl;
if (ci->type.in(id_FABULOUS_COMB, id_FABULOUS_FF, id_FABULOUS_LC)) if (ci->type.in(id_FABULOUS_COMB, id_FABULOUS_FF, id_FABULOUS_LC, id_FABULOUS_MUX2, id_FABULOUS_MUX4,
id_FABULOUS_MUX8))
write_logic(ci); write_logic(ci);
else if (ci->type == id_IO_1_bidirectional_frame_config_pass) else if (ci->type == id_IO_1_bidirectional_frame_config_pass)
write_io(ci); write_io(ci);

View File

@ -132,6 +132,53 @@ struct FabulousPacker
} }
} }
void pack_muxes()
{
// TODO: don't hardcode z-offset -- we should come up with our own constraint structure
int lut_muxes_dz = 9;
int lut_lut_dz = 1;
for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second.get();
unsigned k = 0;
if (ci->type == id_FABULOUS_MUX2)
k = 1;
else if (ci->type == id_FABULOUS_MUX4)
k = 2;
else if (ci->type == id_FABULOUS_MUX8)
k = 3;
else
continue;
unsigned m = (1U << k);
std::vector<CellInfo *> luts;
for (unsigned i = 0; i < m; i++) {
NetInfo *ii = ci->getPort(ctx->idf("I%d", i));
if (!ii || !ii->driver.cell || !ii->driver.cell->type.in(id_FABULOUS_LC, id_FABULOUS_COMB) ||
ii->driver.port != id_O)
log_error("mux %s input I%d net %s is not driven by a LUT!\n", ctx->nameOf(ci), i, ctx->nameOf(ii));
CellInfo *lut = ii->driver.cell;
NPNR_ASSERT(lut->cluster == ClusterId());
luts.push_back(lut);
}
luts.at(0)->cluster = luts.at(0)->name;
for (unsigned i = 0; i < m; i++) {
luts.at(i)->cluster = luts.at(0)->name;
luts.at(i)->constr_x = 0;
luts.at(i)->constr_y = 0;
luts.at(i)->constr_z = i * lut_lut_dz;
luts.at(i)->constr_abs_z = false;
if (i > 0)
luts.at(0)->constr_children.push_back(luts.at(i));
}
int extra_mux_dz = (m == 8) ? 7 : (m == 4) ? 1 : 0;
ci->cluster = luts.at(0)->name;
ci->constr_x = 0;
ci->constr_y = 0;
ci->constr_z = lut_muxes_dz + extra_mux_dz;
ci->constr_abs_z = false;
luts.at(0)->constr_children.push_back(ci);
}
}
void pack_ffs() void pack_ffs()
{ {
pool<IdString> to_delete; pool<IdString> to_delete;
@ -238,6 +285,7 @@ struct FabulousPacker
handle_constants(); handle_constants();
handle_io(); handle_io();
pack_luts(); pack_luts();
pack_muxes();
prepare_ffs(); prepare_ffs();
pack_ffs(); pack_ffs();
} }

View File

@ -33,6 +33,7 @@ CLBState::CLBState(const LogicConfig &cfg)
if (cfg.split_lc) { if (cfg.split_lc) {
ff = std::make_unique<CellInfo *[]>(cfg.lc_per_clb * cfg.ff_per_lc); ff = std::make_unique<CellInfo *[]>(cfg.lc_per_clb * cfg.ff_per_lc);
} }
mux = std::make_unique<CellInfo *[]>(cfg.lc_per_clb);
// TODO: mux // TODO: mux
} }
@ -173,6 +174,26 @@ bool CLBState::check_validity(const LogicConfig &cfg, const CellTagger &cell_dat
} }
} }
} }
// don't allow mixed MUX types in the classic fabulous arch where ctrl sigs are shared
int tile_mux_type = 0;
for (unsigned z = 0; z < cfg.lc_per_clb; z++) {
const CellInfo *m = mux[z];
if (!m)
continue;
int this_mux = 0;
if (m->type == id_FABULOUS_MUX2)
this_mux = 2;
else if (m->type == id_FABULOUS_MUX4)
this_mux = 4;
else if (m->type == id_FABULOUS_MUX8)
this_mux = 8;
else
NPNR_ASSERT_FALSE("unknown mux type");
if (tile_mux_type == 0)
tile_mux_type = this_mux;
else if (tile_mux_type != this_mux)
return false;
}
// TODO: other checks... // TODO: other checks...
return true; return true;
} }