From 85603a9cf3ff245515353908a3ab9188de8a3ff3 Mon Sep 17 00:00:00 2001 From: gatecat Date: Tue, 30 Jul 2024 19:13:51 +0200 Subject: [PATCH] Always use first seen xbar input Signed-off-by: gatecat --- himbaechel/uarch/ng-ultra/ng_ultra.cc | 83 +++++++++++++++++++++++++++ himbaechel/uarch/ng-ultra/ng_ultra.h | 2 + 2 files changed, 85 insertions(+) diff --git a/himbaechel/uarch/ng-ultra/ng_ultra.cc b/himbaechel/uarch/ng-ultra/ng_ultra.cc index e243a9f7..84a8d442 100644 --- a/himbaechel/uarch/ng-ultra/ng_ultra.cc +++ b/himbaechel/uarch/ng-ultra/ng_ultra.cc @@ -20,6 +20,7 @@ #include #include +#include #include "himbaechel_api.h" #include "design_utils.h" @@ -425,6 +426,8 @@ void NgUltraImpl::postRoute() } } + fixup_crossbars(); + print_utilisation(ctx); const ArchArgs &args = ctx->args; if (args.options.count("bit")) { @@ -744,6 +747,86 @@ delay_t NgUltraImpl::predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel return 500 + 100 * (std::abs(dst_loc.y - src_loc.y)/4 + std::abs(dst_loc.x - src_loc.x)/4); } +void NgUltraImpl::fixup_crossbars() +{ + + auto is_crossbar_pip = [&] (PipId pip) { + auto &pd = chip_pip_info(ctx->chip_info, pip); + auto src_orig_type = IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[pd.src_wire].wire_type).str(ctx); + auto dst_orig_type = IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[pd.dst_wire].wire_type).str(ctx); + if (!boost::starts_with(dst_orig_type,"CROSSBAR_") || !boost::ends_with(dst_orig_type, "OUTPUT_WIRE")) { + return false; + } + // replace _OUTPUT_WIRE with _INPUT_WIRE and check same crossbar + if (src_orig_type != (dst_orig_type.substr(0, dst_orig_type.size() - 11) + "INPUT_WIRE")) { + return false; + } + return true; + }; + + auto crossbar_key = [&] (PipId pip, bool src) { + auto &pd = chip_pip_info(ctx->chip_info, pip); + auto wire_name = IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[src ? pd.src_wire : pd.dst_wire].name).str(ctx); + return std::make_pair(pip.tile, ctx->id(wire_name.substr(0, wire_name.rfind('.')))); + }; + + for (auto &net : ctx->nets) { + NetInfo *ni = net.second.get(); + dict> downstream; + // build a map of wires to sinks + for (auto &w : ni->wires) { + if (w.second.pip != PipId()) { + downstream[ctx->getPipSrcWire(w.second.pip)].push_back(w.second.pip); + } + } + // the original drivers of crossbars + dict, WireId> crossbar_entries; + // traverse from the start forwards so we always reach closer wires first in the route tree + WireId src = ctx->getNetinfoSourceWire(ni); + if (src == WireId() || !downstream.count(src)) { + continue; + } + std::queue visit; + visit.push(src); + while (!visit.empty()) { + WireId cursor = visit.front(); + visit.pop(); + if (!downstream.count(cursor)) + continue; + for (auto pip : downstream.at(cursor)) { + WireId dst = ctx->getPipDstWire(pip); + if (is_crossbar_pip(pip)) { + auto key = crossbar_key(pip, true); + if (!crossbar_entries.count(key)) { + crossbar_entries[key] = ctx->getPipSrcWire(pip); + } else { + WireId xbar_src = crossbar_entries.at(key); + if (ctx->getPipSrcWire(pip) != xbar_src) { + // rewrite to be driven by original entry + ctx->unbindPip(pip); + PipId found_pip = PipId(); + for (auto search_pip : ctx->getPipsUphill(dst)) { + if (ctx->getPipSrcWire(search_pip) == xbar_src) { + found_pip = search_pip; + break; + } + } + NPNR_ASSERT(found_pip != PipId()); + // rebind + log_info(" replacing crossbar pip %s with %s on %s\n", ctx->nameOfPip(pip), ctx->nameOfPip(found_pip), ctx->nameOf(ni)); + ctx->bindPip(found_pip, ni, STRENGTH_STRONG); + } + } + } + visit.push(dst); + } + downstream.erase(cursor); + } + // check everything was visited by our BFS tree traversal + NPNR_ASSERT(downstream.empty()); + } +} + struct NgUltraArch : HimbaechelArch { NgUltraArch() : HimbaechelArch("ng-ultra"){}; diff --git a/himbaechel/uarch/ng-ultra/ng_ultra.h b/himbaechel/uarch/ng-ultra/ng_ultra.h index 43a0656c..5ef2ba34 100644 --- a/himbaechel/uarch/ng-ultra/ng_ultra.h +++ b/himbaechel/uarch/ng-ultra/ng_ultra.h @@ -104,6 +104,8 @@ TESTABLE_PRIVATE: bool update_bff_to_scc(CellInfo *cell, BelId bel, PipId dst_pip); void disable_beyond_fe_s_output(BelId bel); + void fixup_crossbars(); + // Misc utility functions bool get_mux_data(BelId bel, IdString port, uint8_t *value); bool get_mux_data(WireId wire, uint8_t *value);