From 26fcf349ad9ef65e4f0758c7bb4a24d5a8b45bf7 Mon Sep 17 00:00:00 2001 From: gatecat Date: Thu, 23 Feb 2023 15:19:00 +0100 Subject: fabulous: LUT permutation support Signed-off-by: gatecat --- generic/viaduct/fabulous/constids.inc | 3 ++ generic/viaduct/fabulous/fabulous.cc | 57 ++++++++++++++++++++++++++++++ generic/viaduct/fabulous/fasm.cc | 42 +++++++++++++++++++++- generic/viaduct/fabulous/validity_check.cc | 2 +- 4 files changed, 102 insertions(+), 2 deletions(-) diff --git a/generic/viaduct/fabulous/constids.inc b/generic/viaduct/fabulous/constids.inc index 4299f483..7c8c3400 100644 --- a/generic/viaduct/fabulous/constids.inc +++ b/generic/viaduct/fabulous/constids.inc @@ -109,3 +109,6 @@ X(VDD) X(_CONST0_DRV) X(_CONST1_DRV) + +X(_LUT_PERM) +X(_LUT_PERM_IN) diff --git a/generic/viaduct/fabulous/fabulous.cc b/generic/viaduct/fabulous/fabulous.cc index 529d9ad0..3400be9a 100644 --- a/generic/viaduct/fabulous/fabulous.cc +++ b/generic/viaduct/fabulous/fabulous.cc @@ -70,6 +70,7 @@ struct FabulousImpl : ViaductAPI is_new_fab ? init_bels_v2() : init_bels_v1(); init_pips(); init_pseudo_constant_wires(); + setup_lut_permutation(); ctx->setDelayScaling(3.0, 3.0); ctx->delay_epsilon = 0.25; ctx->ripup_penalty = 0.5; @@ -435,6 +436,46 @@ struct FabulousImpl : ViaductAPI } } + void remove_bel_pin(BelId bel, IdString pin) + { + auto &bel_data = ctx->bel_info(bel); + auto &wire_data = ctx->wire_info(ctx->getBelPinWire(bel, pin)); + std::vector new_wire_pins; + for (const auto &wire_pin : wire_data.bel_pins) { + if (wire_pin.bel == bel && wire_pin.pin == pin) + continue; + new_wire_pins.push_back(wire_pin); + } + wire_data.bel_pins = new_wire_pins; + bel_data.pins.erase(pin); + } + + void setup_lut_permutation() + { + for (auto bel : ctx->getBels()) { + auto &bel_data = ctx->bel_info(bel); + if (!bel_data.type.in(id_FABULOUS_LC, id_FABULOUS_COMB)) + continue; + std::vector orig_inputs, new_inputs; + for (unsigned i = 0; i < cfg.clb.lut_k; i++) { + // Rewire the LUT input to a permutation pseudo-wire + IdString pin = ctx->idf("I%d", i); + orig_inputs.push_back(ctx->getBelPinWire(bel, pin)); + remove_bel_pin(bel, pin); + WireId in_wire = get_wire(bel_data.name[0], ctx->idf("%s_PERM_I%d", bel_data.name[1].c_str(ctx), i), + id__LUT_PERM_IN); + ctx->addBelInput(bel, pin, in_wire); + new_inputs.push_back(in_wire); + } + for (unsigned i = 0; i < cfg.clb.lut_k; i++) { + for (unsigned j = 0; j < cfg.clb.lut_k; j++) { + add_pseudo_pip(orig_inputs.at(i), new_inputs.at(j), id__LUT_PERM, 0.1, + PseudoPipTags(PseudoPipTags::LUT_PERM, bel, ((i << 4) | j))); + } + } + } + } + // Fast lookup of tile names to XY pairs dict tile2loc; Loc tile_loc(IdString tile) @@ -548,6 +589,22 @@ struct FabulousImpl : ViaductAPI const auto &tags = pp_tags.at(pip.index); if (tags.type == PseudoPipTags::LUT_CONST) { return ctx->checkBelAvail(tags.bel); + } else if (tags.type == PseudoPipTags::LUT_PERM) { + uint8_t from = (tags.data >> 4) & 0xF, to = (tags.data & 0xF); + if (from == to) + return true; + const CellInfo *lut = ctx->getBoundBelCell(tags.bel); + if (!lut) + return true; + bool is_carry = cell_tags.get(lut).comb.carry_used; + if (is_carry) { + // Because you have to make sure you route _something_ to each HA input in this mode (undefined I1/I2 inputs aren't OK) + // and you also can't swap I0 because it's fixed internally + // LUT permutation in carry mode is just more trouble than it's worth. + return false; + } else { + return true; // TODO: other cases where perm illegal; e.g. LUTRAM + } } else { // TODO: LUT permuation pseudopips return true; diff --git a/generic/viaduct/fabulous/fasm.cc b/generic/viaduct/fabulous/fasm.cc index 4d09d537..159bb8ff 100644 --- a/generic/viaduct/fabulous/fasm.cc +++ b/generic/viaduct/fabulous/fasm.cc @@ -122,11 +122,51 @@ struct FabFasmWriter void add_feature(const std::string &name) { out << prefix << name << std::endl; } + uint64_t depermute_lut(const CellInfo *lut) + { + uint64_t orig_init = int_or_default(lut->params, id_INIT, 0); + std::vector> phys_to_log; + phys_to_log.resize(cfg.clb.lut_k); + for (unsigned i = 0; i < cfg.clb.lut_k; i++) { + WireId pin_wire = ctx->getBelPinWire(lut->bel, ctx->idf("I%d", i)); + for (PipId pip : ctx->getPipsUphill(pin_wire)) { + if (!ctx->getBoundPipNet(pip)) + continue; + unsigned pip_data = pip_tags.at(pip.index).data; + unsigned from_pin = (pip_data >> 4) & 0xF; + unsigned to_pin = (pip_data)&0xF; + NPNR_ASSERT(to_pin == i); + phys_to_log[from_pin].push_back(i); + } + } + if (bool_or_default(lut->params, id_I0MUX, false)) // internal, hardcoded + phys_to_log[0].push_back(0); + for (unsigned i = 0; i < cfg.clb.lut_k; i++) { + for (auto j : phys_to_log.at(i)) + out << stringf(" # permute phys %d log %d\n", i, j); + } + uint64_t permuted_init = 0; + for (unsigned i = 0; i < (1U << cfg.clb.lut_k); i++) { + unsigned log_idx = 0; + for (unsigned j = 0; j < cfg.clb.lut_k; j++) { + if ((i >> j) & 0x1) { + for (auto log_pin : phys_to_log[j]) + log_idx |= (1 << log_pin); + } + } + if ((orig_init >> log_idx) & 0x1) + permuted_init |= (uint64_t(1U) << i); + } + return permuted_init; + } + void write_logic(const CellInfo *lc) { prefix = format_name(ctx->getBelName(lc->bel)) + "."; if (lc->type.in(id_FABULOUS_LC, id_FABULOUS_COMB)) { - write_int_vector_param(lc, "INIT", 0U, 1U << cfg.clb.lut_k); // todo lut depermute and thru + uint64_t init = depermute_lut(lc); + unsigned width = 1U << cfg.clb.lut_k; + write_int_vector(stringf("INIT[%d:0]", width - 1), init, width); // todo lut depermute and thru if (bool_or_default(lc->params, id_I0MUX, false)) add_feature("IOmux"); // typo in FABulous? } diff --git a/generic/viaduct/fabulous/validity_check.cc b/generic/viaduct/fabulous/validity_check.cc index 30b21f29..81f057c8 100644 --- a/generic/viaduct/fabulous/validity_check.cc +++ b/generic/viaduct/fabulous/validity_check.cc @@ -53,7 +53,7 @@ void CellTagger::assign_for(const Context *ctx, const FabricConfig &cfg, const C const NetInfo *sig = ci->getPort(ctx->idf("I%d", i)); t.comb.lut_inputs[i] = sig ? sig->name : IdString(); } - t.comb.carry_used = false; // TODO + t.comb.carry_used = ci->getPort(id_Ci) || ci->getPort(id_Co); // TODO t.comb.lut_out = ci->getPort(id_O); } if (ci->type.in(id_FABULOUS_FF, id_FABULOUS_LC)) { -- cgit v1.2.3