From 6cff6d9c49ceea0338c35734fd5129ffdea1c238 Mon Sep 17 00:00:00 2001 From: Alain Dargelas Date: Mon, 3 Mar 2025 16:51:10 -0800 Subject: [PATCH] input fanout --- passes/silimate/annotate_cell_fanout.cc | 125 +++++++++++++++++++----- 1 file changed, 100 insertions(+), 25 deletions(-) diff --git a/passes/silimate/annotate_cell_fanout.cc b/passes/silimate/annotate_cell_fanout.cc index 5aaef030b..91d0fe000 100644 --- a/passes/silimate/annotate_cell_fanout.cc +++ b/passes/silimate/annotate_cell_fanout.cc @@ -75,6 +75,13 @@ RTLIL::Wire *getParentWire(const RTLIL::SigSpec &sigspec) return first_bit.wire; } +std::string getSigSpecName(const RTLIL::SigSpec &sigspec) { + Wire* wire = getParentWire(sigspec); + if (wire) + return wire->name.c_str(); + return ""; +} + // Find if a signal is used in another (One level) bool isSigSpecUsedIn(SigSpec &haystack, SigMap &sigmap, SigSpec &needle) { @@ -204,6 +211,53 @@ SigSpec updateToBuffer(std::map &bufferIndexes, return newSig; } +RTLIL::IdString generateSigSpecName(RTLIL::Module *module, const RTLIL::SigSpec &sigspec) +{ + if (sigspec.empty()) { + return RTLIL::IdString(); // Empty SigSpec, return empty IdString + } + + std::stringstream ss; + + if (sigspec.is_wire()) { + // Handle wires + ss << sigspec.as_wire()->name.str(); + } else if (sigspec.size() == 1 && sigspec[0].wire) { + // Handle single-bit SigSpecs + ss << sigspec[0].wire->name.str(); + if (sigspec[0].wire->width != 1) { + ss << "[" << sigspec[0].offset << "]"; + } + } else if (sigspec.is_chunk()) { + // Handle slices + RTLIL::Wire *parent_wire = sigspec[0].wire; + SigChunk chunk = sigspec.as_chunk(); + if (parent_wire) { + ss << parent_wire->name.str() << "[" << chunk.offset + chunk.width - 1 << ":" << chunk.offset << "]"; + } + } else if (!sigspec.is_chunk()) { + // Handle vector of chunks + int max = 0; + int min = INT_MAX; + RTLIL::Wire *parent_wire = sigspec[0].wire; + for (SigChunk chunk : sigspec.chunks()) { + max = std::max(max, chunk.offset); + min = std::min(min, chunk.offset); + } + if (parent_wire) { + ss << parent_wire->name.str() << "[" << max << ":" << min << "]"; + } else { + ss << "\\sigspec_[" << max << ":" << min << "]"; + } + } else { + // Handle other cases (e.g., constants) + ss << "\\sigspec_"; + } + + RTLIL::IdString base_name = RTLIL::IdString(ss.str()); + return RTLIL::IdString(ss.str()); +} + // For a given cell with fanout exceeding the limit, // - create an array of buffers per cell output chunk (2 dimentions array of buffers) // - connect cell chunk to corresponding buffers @@ -212,17 +266,21 @@ SigSpec updateToBuffer(std::map &bufferIndexes, // The capacity of the buffers might be larger than the limit in a given pass, // Recursion is used until all buffers capacity is under or at the limit. void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dict> &sig2CellsInFanout, - RTLIL::Cell *cell, int fanout, int limit, bool debug) + SigSpec sigToBuffer, int fanout, int limit, bool debug) { + if (sigToBuffer.is_fully_const()) { + return; + } + std::string signame = generateSigSpecName(module, sigToBuffer).c_str(); if (fanout <= limit) { if (debug) { - std::cout << "Nothing to do for: " << cell->name.c_str() << std::endl; + std::cout << "Nothing to do for: " << signame << std::endl; std::cout << "Fanout: " << fanout << std::endl; } return; // No need to insert buffers } else { if (debug) { - std::cout << "Something to do for: " << cell->name.c_str() << std::endl; + std::cout << "Something to do for: " << signame << std::endl; std::cout << "Fanout: " << fanout << std::endl; } } @@ -235,14 +293,11 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic if (debug) { std::cout << "Fanout: " << fanout << "\n"; std::cout << "Limit: " << limit << "\n"; - std::cout << "Mum_buffers: " << num_buffers << "\n"; + std::cout << "Num_buffers: " << num_buffers << "\n"; std::cout << "Max_output_per_buffer: " << max_output_per_buffer << "\n"; - std::cout << "CELL: " << cell->name.c_str() << "\n" << std::flush; + std::cout << "Signal: " << signame << "\n" << std::flush; } - // Get cell output - RTLIL::SigSpec cellOutSig = getCellOutputSigSpec(cell, sigmap); - // Keep track of the fanout count for each new buffer std::map bufferActualFanout; // Array of buffers (The buffer output signal and the buffer cell) per cell output chunks @@ -251,25 +306,28 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic std::map bufferIndexes; // Create new buffers and new wires - for (SigChunk chunk : cellOutSig.chunks()) { + int index_buffer = 0; + for (SigChunk chunk : sigToBuffer.chunks()) { std::vector> buffer_chunk_outputs; for (int i = 0; i < num_buffers; ++i) { - RTLIL::Cell *buffer = module->addCell(NEW_ID2_SUFFIX("fbuf"), ID($pos)); + std::cout << "Name: " << signame + "_fbuf" + std::to_string(index_buffer) << std::endl; + RTLIL::Cell *buffer = module->addCell(signame + "_fbuf" + std::to_string(index_buffer), ID($pos)); bufferActualFanout[buffer] = 0; - RTLIL::SigSpec buffer_output = module->addWire(NEW_ID2_SUFFIX("fbuf"), chunk.size()); + RTLIL::SigSpec buffer_output = module->addWire(signame + "_wbuf" + std::to_string(index_buffer) , chunk.size()); buffer->setPort(ID(A), chunk); buffer->setPort(ID(Y), sigmap(buffer_output)); buffer->fixup_parameters(); buffer_chunk_outputs.push_back(std::make_tuple(buffer_output, buffer)); // Old - New bufferIndexes[chunk] = 0; + index_buffer++; } buffer_outputs.emplace(sigmap(SigSpec(chunk)), buffer_chunk_outputs); } // Cumulate all cells in the fanout of this cell - std::set fanoutcells = sig2CellsInFanout[cellOutSig]; - for (int i = 0; i < cellOutSig.size(); i++) { - SigSpec bit_sig = cellOutSig.extract(i, 1); + std::set fanoutcells = sig2CellsInFanout[sigToBuffer]; + for (int i = 0; i < sigToBuffer.size(); i++) { + SigSpec bit_sig = sigToBuffer.extract(i, 1); for (Cell *c : sig2CellsInFanout[sigmap(bit_sig)]) { fanoutcells.insert(c); } @@ -288,6 +346,7 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic if (debug) std::cout << " IS A CHUNK" << std::endl; if (buffer_outputs.find(actual) != buffer_outputs.end()) { + if (debug) std::cout << " MATCH" << std::endl; // Input is one of the cell's outputs, its a match SigSpec newSig = updateToBuffer(bufferIndexes, buffer_outputs, sig2CellsInFanout, bufferActualFanout, max_output_per_buffer, fanoutcell, actual, debug); @@ -298,11 +357,12 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic // Input of that cell is a list of chunks if (debug) std::cout << " NOT A CHUNK" << std::endl; - if (isSigSpecUsedIn(actual, sigmap, cellOutSig)) { + if (isSigSpecUsedIn(actual, sigmap, sigToBuffer)) { // Create a new chunk vector std::vector newChunks; for (SigChunk chunk : actual.chunks()) { if (buffer_outputs.find(chunk) != buffer_outputs.end()) { + if (debug) std::cout << " MATCH" << std::endl; SigSpec newSig = updateToBuffer(bufferIndexes, buffer_outputs, sig2CellsInFanout, bufferActualFanout, max_output_per_buffer, fanoutcell, chunk, debug); @@ -329,7 +389,8 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic removeBuffer(module, sigmap, fanoutcells, itr->first, debug); } else { // Recursively fix the fanout of the newly created buffers - fixfanout(design, module, sigmap, sig2CellsInFanout, itr->first, itr->second, limit, debug); + RTLIL::SigSpec sig = getCellOutputSigSpec(itr->first, sigmap); + fixfanout(design, module, sigmap, sig2CellsInFanout, sig, itr->second, limit, debug); } } } @@ -402,7 +463,7 @@ std::string substringuntil(const std::string &str, char delimiter) } } -void splitNet(Design *design, std::set &netsToSplitS, RTLIL::SigSpec &sigToSplit, bool formalFriendly, bool inputsToo = false) +void splitNet(Design *design, std::set &netsToSplitS, RTLIL::SigSpec &sigToSplit, bool formalFriendly, bool inputPort = false) { Wire *parentWire = getParentWire(sigToSplit); if (!parentWire) @@ -416,17 +477,14 @@ void splitNet(Design *design, std::set &netsToSplitS, RTLIL::SigSpe netsToSplitS.insert(parent); // Splitnets has to be invoke with individual nets. Sending a bunch of nets as selection, // selects more than required (bug in selection/splitnets). - std::cout << "splitnets -ports_only w:" << parent << std::endl; Pass::call(design, "splitnets w:" + parent); // Wire if (!formalFriendly) { // Formal verification does not like ports to be split. // This option will prevent some buffering to happen on high fanout input/output ports, // but it will make formal happy. - if (inputsToo) { - std::cout << "splitnets -ports_only x:" << parent << std::endl; - Pass::call(design, "splitnets -ports_only x:" + parent); // Input/Output port + if (inputPort) { + Pass::call(design, "splitnets -ports_only i:" + parent); // Input port } else { - std::cout << "splitnets -ports_only o:" << parent << std::endl; Pass::call(design, "splitnets -ports_only o:" + parent); // Output port } } @@ -496,7 +554,7 @@ struct AnnotateCellFanout : public ScriptPass { calculateFanout(module, sigmap, sig2CellsInFanout, cellFanout, sigFanout); std::set netsToSplitS; - // Split output nets of cells with high fanout + // Split cells' output nets with high fanout for (auto itrCell : cellFanout) { Cell *cell = itrCell.first; int fanout = itrCell.second; @@ -512,7 +570,6 @@ struct AnnotateCellFanout : public ScriptPass { if (wire->port_input) { SigSpec inp = sigmap(wire); int fanout = sigFanout[inp]; - std::cout << "Input" << wire->name.c_str() << " fanout: " << fanout << std::endl; if (limit > 0 && (fanout > limit)) { wiresToSplit.insert(wire); } @@ -532,17 +589,35 @@ struct AnnotateCellFanout : public ScriptPass { dict> sig2CellsInFanout; calculateFanout(module, sigmap, sig2CellsInFanout, cellFanout, sigFanout); + // Fix cells outputs with high fanout for (auto itrCell : cellFanout) { Cell *cell = itrCell.first; int fanout = itrCell.second; if (limit > 0 && (fanout > limit)) { - fixfanout(design, module, sigmap, sig2CellsInFanout, cell, fanout, limit, debug); + RTLIL::SigSpec cellOutSig = getCellOutputSigSpec(cell, sigmap); + fixfanout(design, module, sigmap, sig2CellsInFanout, cellOutSig, fanout, limit, debug); fixedFanout = true; } else { // Add attribute with fanout info to every cell cell->set_string_attribute("$FANOUT", std::to_string(fanout)); } } + + // Fix module input nets with high fanout + std::map sigsToFix; + for (Wire *wire : module->wires()) { + if (wire->port_input) { + SigSpec inp = sigmap(wire); + int fanout = sigFanout[inp]; + if (limit > 0 && (fanout > limit)) { + sigsToFix.emplace(inp, fanout); + } + } + } + for (auto sig : sigsToFix) { + fixfanout(design, module, sigmap, sig2CellsInFanout, sig.first, sig.second, limit, debug); + fixedFanout = true; + } } if (fixedFanout) {