mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-23 06:13:41 +00:00
split input nets with high fanout
This commit is contained in:
parent
a1ad385702
commit
d5d58349fd
1 changed files with 74 additions and 51 deletions
|
@ -98,7 +98,7 @@ bool isSigSpecUsedIn(SigSpec &haystack, SigMap &sigmap, SigSpec &needle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a buffer and fix the fanout connections to use the buffer's input
|
// Remove a buffer and fix the fanout connections to use the buffer's input
|
||||||
void removeBuffer(Module *module, SigMap &sigmap, std::set<Cell *>& fanoutcells, Cell *buffer, bool debug)
|
void removeBuffer(Module *module, SigMap &sigmap, std::set<Cell *> &fanoutcells, Cell *buffer, bool debug)
|
||||||
{
|
{
|
||||||
if (debug)
|
if (debug)
|
||||||
std::cout << "Buffer with fanout 1: " << buffer->name.c_str() << std::endl;
|
std::cout << "Buffer with fanout 1: " << buffer->name.c_str() << std::endl;
|
||||||
|
@ -154,7 +154,8 @@ void removeBuffer(Module *module, SigMap &sigmap, std::set<Cell *>& fanoutcells,
|
||||||
module->remove({bufferOutSig.as_wire()});
|
module->remove({bufferOutSig.as_wire()});
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::SigSpec getCellOutputSigSpec(Cell* cell, SigMap& sigmap) {
|
RTLIL::SigSpec getCellOutputSigSpec(Cell *cell, SigMap &sigmap)
|
||||||
|
{
|
||||||
RTLIL::SigSpec cellOutSig;
|
RTLIL::SigSpec cellOutSig;
|
||||||
for (auto &conn : cell->connections()) {
|
for (auto &conn : cell->connections()) {
|
||||||
IdString portName = conn.first;
|
IdString portName = conn.first;
|
||||||
|
@ -168,14 +169,14 @@ RTLIL::SigSpec getCellOutputSigSpec(Cell* cell, SigMap& sigmap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get new output signal for a given signal, used all datastructures with change to buffer
|
// Get new output signal for a given signal, used all datastructures with change to buffer
|
||||||
SigSpec updateToBuffer(std::map<SigSpec, int>& bufferIndexes, std::map<RTLIL::SigSpec,
|
SigSpec updateToBuffer(std::map<SigSpec, int> &bufferIndexes,
|
||||||
std::vector<std::tuple<RTLIL::SigSpec, Cell *>>>& buffer_outputs,
|
std::map<RTLIL::SigSpec, std::vector<std::tuple<RTLIL::SigSpec, Cell *>>> &buffer_outputs,
|
||||||
dict<RTLIL::SigSpec, std::set<Cell *>> &sig2CellsInFanout,
|
dict<RTLIL::SigSpec, std::set<Cell *>> &sig2CellsInFanout, std::map<Cell *, int> &bufferActualFanout,
|
||||||
std::map<Cell *, int>& bufferActualFanout, int max_output_per_buffer, Cell* cell, SigSpec sigToReplace, bool debug)
|
int max_output_per_buffer, Cell *cell, SigSpec sigToReplace, bool debug)
|
||||||
{
|
{
|
||||||
if (debug)
|
if (debug)
|
||||||
std::cout << " CHUNK, indexCurrentBuffer: " << bufferIndexes[sigToReplace] << " buffer_outputs " << buffer_outputs[sigToReplace].size()
|
std::cout << " CHUNK, indexCurrentBuffer: " << bufferIndexes[sigToReplace] << " buffer_outputs "
|
||||||
<< std::endl;
|
<< buffer_outputs[sigToReplace].size() << std::endl;
|
||||||
// Retrieve the buffer information for that cell's chunk
|
// Retrieve the buffer information for that cell's chunk
|
||||||
std::vector<std::tuple<RTLIL::SigSpec, Cell *>> &buf_info_vec = buffer_outputs[sigToReplace];
|
std::vector<std::tuple<RTLIL::SigSpec, Cell *>> &buf_info_vec = buffer_outputs[sigToReplace];
|
||||||
// Retrieve which buffer is getting filled
|
// Retrieve which buffer is getting filled
|
||||||
|
@ -288,8 +289,8 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic
|
||||||
std::cout << " IS A CHUNK" << std::endl;
|
std::cout << " IS A CHUNK" << std::endl;
|
||||||
if (buffer_outputs.find(actual) != buffer_outputs.end()) {
|
if (buffer_outputs.find(actual) != buffer_outputs.end()) {
|
||||||
// Input is one of the cell's outputs, its a match
|
// Input is one of the cell's outputs, its a match
|
||||||
SigSpec newSig = updateToBuffer(bufferIndexes, buffer_outputs, sig2CellsInFanout,
|
SigSpec newSig = updateToBuffer(bufferIndexes, buffer_outputs, sig2CellsInFanout, bufferActualFanout,
|
||||||
bufferActualFanout, max_output_per_buffer, fanoutcell, actual, debug);
|
max_output_per_buffer, fanoutcell, actual, debug);
|
||||||
// Override the fanout cell's input with the buffer output
|
// Override the fanout cell's input with the buffer output
|
||||||
fanoutcell->setPort(portName, newSig);
|
fanoutcell->setPort(portName, newSig);
|
||||||
}
|
}
|
||||||
|
@ -302,8 +303,9 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic
|
||||||
std::vector<RTLIL::SigChunk> newChunks;
|
std::vector<RTLIL::SigChunk> newChunks;
|
||||||
for (SigChunk chunk : actual.chunks()) {
|
for (SigChunk chunk : actual.chunks()) {
|
||||||
if (buffer_outputs.find(chunk) != buffer_outputs.end()) {
|
if (buffer_outputs.find(chunk) != buffer_outputs.end()) {
|
||||||
SigSpec newSig = updateToBuffer(bufferIndexes, buffer_outputs, sig2CellsInFanout,
|
SigSpec newSig =
|
||||||
bufferActualFanout, max_output_per_buffer, fanoutcell, chunk, debug);
|
updateToBuffer(bufferIndexes, buffer_outputs, sig2CellsInFanout, bufferActualFanout,
|
||||||
|
max_output_per_buffer, fanoutcell, chunk, debug);
|
||||||
// Append the buffer's output in the chunk vector
|
// Append the buffer's output in the chunk vector
|
||||||
newChunks.push_back(newSig.as_chunk());
|
newChunks.push_back(newSig.as_chunk());
|
||||||
} else {
|
} else {
|
||||||
|
@ -332,7 +334,8 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void calculateFanout(RTLIL::Module *module, SigMap &sigmap, dict<RTLIL::SigSpec, std::set<Cell *>> &sig2CellsInFanout, dict<Cell *, int> &cellFanout)
|
void calculateFanout(RTLIL::Module *module, SigMap &sigmap, dict<RTLIL::SigSpec, std::set<Cell *>> &sig2CellsInFanout, dict<Cell *, int> &cellFanout,
|
||||||
|
dict<SigSpec, int> &sigFanout)
|
||||||
{
|
{
|
||||||
// Precompute cell output sigspec to cell map
|
// Precompute cell output sigspec to cell map
|
||||||
dict<RTLIL::SigSpec, std::set<Cell *>> sig2CellsInFanin;
|
dict<RTLIL::SigSpec, std::set<Cell *>> sig2CellsInFanin;
|
||||||
|
@ -343,7 +346,6 @@ void calculateFanout(RTLIL::Module *module, SigMap &sigmap, dict<RTLIL::SigSpec,
|
||||||
lhs2rhs_rhs2lhs(module, sigmap, rhsSig2LhsSig, lhsSig2RhsSig);
|
lhs2rhs_rhs2lhs(module, sigmap, rhsSig2LhsSig, lhsSig2RhsSig);
|
||||||
|
|
||||||
// Accumulate fanout from cell connections
|
// Accumulate fanout from cell connections
|
||||||
dict<RTLIL::SigSpec, int> sigFanout;
|
|
||||||
for (auto itrSig : sig2CellsInFanout) {
|
for (auto itrSig : sig2CellsInFanout) {
|
||||||
SigSpec sigspec = itrSig.first;
|
SigSpec sigspec = itrSig.first;
|
||||||
std::set<Cell *> &cells = itrSig.second;
|
std::set<Cell *> &cells = itrSig.second;
|
||||||
|
@ -400,10 +402,41 @@ std::string substringuntil(const std::string &str, char delimiter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void splitNet(Design *design, std::set<std::string> &netsToSplitS, RTLIL::SigSpec &sigToSplit, bool formalFriendly, bool inputsToo = false)
|
||||||
|
{
|
||||||
|
Wire *parentWire = getParentWire(sigToSplit);
|
||||||
|
if (!parentWire)
|
||||||
|
return;
|
||||||
|
std::string parent = parentWire->name.c_str();
|
||||||
|
if (parent == "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parent = substringuntil(parent, '[');
|
||||||
|
if (netsToSplitS.find(parent) == netsToSplitS.end()) {
|
||||||
|
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
|
||||||
|
} else {
|
||||||
|
std::cout << "splitnets -ports_only o:" << parent << std::endl;
|
||||||
|
Pass::call(design, "splitnets -ports_only o:" + parent); // Output port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct AnnotateCellFanout : public ScriptPass {
|
struct AnnotateCellFanout : public ScriptPass {
|
||||||
AnnotateCellFanout() : ScriptPass("annotate_cell_fanout", "Annotate the cell fanout on the cell") {}
|
AnnotateCellFanout() : ScriptPass("annotate_cell_fanout", "Annotate the cell fanout on the cell") {}
|
||||||
void script() override {}
|
void script() override {}
|
||||||
void help() override
|
void help() override
|
||||||
{
|
{
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" annotate_cell_fanout [options] [selection]\n");
|
log(" annotate_cell_fanout [options] [selection]\n");
|
||||||
|
@ -453,53 +486,41 @@ struct AnnotateCellFanout : public ScriptPass {
|
||||||
}
|
}
|
||||||
for (auto module : design->selected_modules()) {
|
for (auto module : design->selected_modules()) {
|
||||||
bool fixedFanout = false;
|
bool fixedFanout = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
// Split output nets of cells with high fanout
|
// Calculate fanout
|
||||||
SigMap sigmap(module);
|
SigMap sigmap(module);
|
||||||
dict<Cell *, int> cellFanout;
|
dict<Cell *, int> cellFanout;
|
||||||
|
dict<SigSpec, int> sigFanout;
|
||||||
dict<RTLIL::SigSpec, std::set<Cell *>> sig2CellsInFanout;
|
dict<RTLIL::SigSpec, std::set<Cell *>> sig2CellsInFanout;
|
||||||
calculateFanout(module, sigmap, sig2CellsInFanout, cellFanout);
|
calculateFanout(module, sigmap, sig2CellsInFanout, cellFanout, sigFanout);
|
||||||
|
|
||||||
std::vector<Cell *> cellsToFixFanout;
|
std::set<std::string> netsToSplitS;
|
||||||
|
// Split output nets of cells with high fanout
|
||||||
for (auto itrCell : cellFanout) {
|
for (auto itrCell : cellFanout) {
|
||||||
Cell *cell = itrCell.first;
|
Cell *cell = itrCell.first;
|
||||||
int fanout = itrCell.second;
|
int fanout = itrCell.second;
|
||||||
if (limit > 0 && (fanout > limit)) {
|
if (limit > 0 && (fanout > limit)) {
|
||||||
cellsToFixFanout.push_back(cell);
|
RTLIL::SigSpec cellOutSig = getCellOutputSigSpec(cell, sigmap);
|
||||||
|
splitNet(design, netsToSplitS, cellOutSig, formalFriendly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::set<std::string> netsToSplitS;
|
|
||||||
std::string netsToSplit;
|
// Split module input nets with high fanout
|
||||||
std::string portsToSplit;
|
std::set<Wire *> wiresToSplit;
|
||||||
for (Cell *cell : cellsToFixFanout) {
|
for (Wire *wire : module->wires()) {
|
||||||
RTLIL::SigSpec cellOutSig;
|
if (wire->port_input) {
|
||||||
for (auto &conn : cell->connections()) {
|
SigSpec inp = sigmap(wire);
|
||||||
IdString portName = conn.first;
|
int fanout = sigFanout[inp];
|
||||||
RTLIL::SigSpec actual = conn.second;
|
std::cout << "Input" << wire->name.c_str() << " fanout: " << fanout << std::endl;
|
||||||
if (cell->output(portName)) {
|
if (limit > 0 && (fanout > limit)) {
|
||||||
cellOutSig = sigmap(actual);
|
wiresToSplit.insert(wire);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string parent = getParentWire(cellOutSig)->name.c_str();
|
}
|
||||||
parent = substringuntil(parent, '[');
|
for (Wire *wire : wiresToSplit) {
|
||||||
if (netsToSplitS.find(parent) == netsToSplitS.end()) {
|
SigSpec inp = sigmap(wire);
|
||||||
netsToSplit += std::string(" w:") + parent; // Wire
|
splitNet(design, netsToSplitS, inp, formalFriendly, true);
|
||||||
portsToSplit += std::string(" o:") + parent; // Output port
|
|
||||||
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::string splitnets = std::string("splitnets ") + netsToSplit;
|
|
||||||
Pass::call(design, splitnets);
|
|
||||||
splitnets = std::string("splitnets -ports_only ") + portsToSplit;
|
|
||||||
if (!formalFriendly)
|
|
||||||
// Formal verification does not like ports to be split.
|
|
||||||
// This will prevent some buffering to happen on output ports used also internally in high
|
|
||||||
// fanout, but it will make formal happy.
|
|
||||||
Pass::call(design, splitnets);
|
|
||||||
netsToSplit = "";
|
|
||||||
portsToSplit = "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,8 +528,9 @@ struct AnnotateCellFanout : public ScriptPass {
|
||||||
// Fix high fanout
|
// Fix high fanout
|
||||||
SigMap sigmap(module);
|
SigMap sigmap(module);
|
||||||
dict<Cell *, int> cellFanout;
|
dict<Cell *, int> cellFanout;
|
||||||
|
dict<SigSpec, int> sigFanout;
|
||||||
dict<RTLIL::SigSpec, std::set<Cell *>> sig2CellsInFanout;
|
dict<RTLIL::SigSpec, std::set<Cell *>> sig2CellsInFanout;
|
||||||
calculateFanout(module, sigmap, sig2CellsInFanout, cellFanout);
|
calculateFanout(module, sigmap, sig2CellsInFanout, cellFanout, sigFanout);
|
||||||
|
|
||||||
for (auto itrCell : cellFanout) {
|
for (auto itrCell : cellFanout) {
|
||||||
Cell *cell = itrCell.first;
|
Cell *cell = itrCell.first;
|
||||||
|
@ -527,8 +549,9 @@ struct AnnotateCellFanout : public ScriptPass {
|
||||||
// If Fanout got fixed, recalculate and annotate final fanout
|
// If Fanout got fixed, recalculate and annotate final fanout
|
||||||
SigMap sigmap(module);
|
SigMap sigmap(module);
|
||||||
dict<Cell *, int> cellFanout;
|
dict<Cell *, int> cellFanout;
|
||||||
|
dict<SigSpec, int> sigFanout;
|
||||||
dict<RTLIL::SigSpec, std::set<Cell *>> sig2CellsInFanout;
|
dict<RTLIL::SigSpec, std::set<Cell *>> sig2CellsInFanout;
|
||||||
calculateFanout(module, sigmap, sig2CellsInFanout, cellFanout);
|
calculateFanout(module, sigmap, sig2CellsInFanout, cellFanout, sigFanout);
|
||||||
for (auto itrCell : cellFanout) {
|
for (auto itrCell : cellFanout) {
|
||||||
Cell *cell = itrCell.first;
|
Cell *cell = itrCell.first;
|
||||||
int fanout = itrCell.second;
|
int fanout = itrCell.second;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue