From 124c0fc8121f0ac1e7d9823f3f1576e5fa2c087b Mon Sep 17 00:00:00 2001 From: gatecat Date: Fri, 30 Sep 2022 12:03:16 +0200 Subject: fabulous: Add split MUX bels Signed-off-by: gatecat --- generic/viaduct/fabulous/constids.inc | 10 +++++++++ generic/viaduct/fabulous/fabulous.cc | 41 ++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/generic/viaduct/fabulous/constids.inc b/generic/viaduct/fabulous/constids.inc index c46d5e6d..13396358 100644 --- a/generic/viaduct/fabulous/constids.inc +++ b/generic/viaduct/fabulous/constids.inc @@ -14,6 +14,7 @@ X(OutPass4_frame_config) X(RegFile_32x4) X(MULADD) X(MUX8LUT_frame_config) +X(MUX8LUT_frame_config_mux) X(CLK) X(I) @@ -86,3 +87,12 @@ X(BelBegin) X(BelEnd) X(GlobalClk) X(CFG) + +X(FABULOUS_MUX2) +X(FABULOUS_MUX4) +X(FABULOUS_MUX8) + +X(M_AB) +X(M_AD) +X(M_EF) +X(M_AH) diff --git a/generic/viaduct/fabulous/fabulous.cc b/generic/viaduct/fabulous/fabulous.cc index e2adb894..287d7e51 100644 --- a/generic/viaduct/fabulous/fabulous.cc +++ b/generic/viaduct/fabulous/fabulous.cc @@ -293,12 +293,48 @@ struct FabulousImpl : ViaductAPI 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 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() { // 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 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.pins.count(id_Q)) { // Add a Q pseudo-pin and pseudo-pip from Q to O @@ -309,6 +345,9 @@ struct FabulousImpl : ViaductAPI // Pseudo-pip for FF mode 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) { if (!data.pins.count(id_PAD)) { // Add a PAD pseudo-pin for the top level -- cgit v1.2.3 From 3826a31ad3667d691d95ae027bd0ce66c5596f73 Mon Sep 17 00:00:00 2001 From: gatecat Date: Fri, 30 Sep 2022 13:27:51 +0200 Subject: fabulous: Pack, validity check and FASM support for muxes Signed-off-by: gatecat --- generic/viaduct/fabulous/fabulous.cc | 9 +++--- generic/viaduct/fabulous/fasm.cc | 11 ++++++- generic/viaduct/fabulous/pack.cc | 48 ++++++++++++++++++++++++++++++ generic/viaduct/fabulous/validity_check.cc | 21 +++++++++++++ 4 files changed, 84 insertions(+), 5 deletions(-) diff --git a/generic/viaduct/fabulous/fabulous.cc b/generic/viaduct/fabulous/fabulous.cc index 287d7e51..9cb7e74f 100644 --- a/generic/viaduct/fabulous/fabulous.cc +++ b/generic/viaduct/fabulous/fabulous.cc @@ -317,12 +317,13 @@ struct FabulousImpl : ViaductAPI } // 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); + 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); + 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); } } diff --git a/generic/viaduct/fabulous/fasm.cc b/generic/viaduct/fabulous/fasm.cc index e4725555..e4b95f62 100644 --- a/generic/viaduct/fabulous/fasm.cc +++ b/generic/viaduct/fabulous/fasm.cc @@ -123,6 +123,14 @@ struct FabFasmWriter write_bool(lc, "NEG_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) @@ -161,7 +169,8 @@ struct FabFasmWriter void write_cell(const CellInfo *ci) { 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); else if (ci->type == id_IO_1_bidirectional_frame_config_pass) write_io(ci); diff --git a/generic/viaduct/fabulous/pack.cc b/generic/viaduct/fabulous/pack.cc index 0273a28a..56a6f855 100644 --- a/generic/viaduct/fabulous/pack.cc +++ b/generic/viaduct/fabulous/pack.cc @@ -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 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() { pool to_delete; @@ -238,6 +285,7 @@ struct FabulousPacker handle_constants(); handle_io(); pack_luts(); + pack_muxes(); prepare_ffs(); pack_ffs(); } diff --git a/generic/viaduct/fabulous/validity_check.cc b/generic/viaduct/fabulous/validity_check.cc index 91dba689..30b21f29 100644 --- a/generic/viaduct/fabulous/validity_check.cc +++ b/generic/viaduct/fabulous/validity_check.cc @@ -33,6 +33,7 @@ CLBState::CLBState(const LogicConfig &cfg) if (cfg.split_lc) { ff = std::make_unique(cfg.lc_per_clb * cfg.ff_per_lc); } + mux = std::make_unique(cfg.lc_per_clb); // 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... return true; } -- cgit v1.2.3