3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-06-21 13:23:40 +00:00
This commit is contained in:
Alain Dargelas 2025-03-03 10:39:47 -08:00
parent b95fc57136
commit c7623e4850

View file

@ -75,6 +75,28 @@ RTLIL::Wire *getParentWire(const RTLIL::SigSpec &sigspec)
return first_bit.wire; return first_bit.wire;
} }
// Find if a signal is used in another (One level)
bool isSigSpecUsedIn(SigSpec &haystack, SigMap &sigmap, SigSpec &needle)
{
bool match = false;
// Input chunk is one of the cell's outputs, its a match
for (SigChunk chunk_a : haystack.chunks()) {
if (sigmap(SigSpec(chunk_a)) == sigmap(needle)) {
match = true;
} else {
for (SigChunk chunk_c : needle.chunks()) {
if (sigmap(SigSpec(chunk_a)) == sigmap(SigSpec(chunk_c))) {
match = true;
break;
}
}
}
if (match)
break;
}
return match;
}
// For a given cell with fanout exceeding the limit, // For a given cell with fanout exceeding the limit,
// - create an array of buffers per cell output chunk (2 dimentions array of buffers) // - create an array of buffers per cell output chunk (2 dimentions array of buffers)
// - connect cell chunk to corresponding buffers // - connect cell chunk to corresponding buffers
@ -202,29 +224,13 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic
// Input of that cell is a list of chunks // Input of that cell is a list of chunks
if (debug) if (debug)
std::cout << " NOT A CHUNK" << std::endl; std::cout << " NOT A CHUNK" << std::endl;
bool match = false; if (isSigSpecUsedIn(actual, sigmap, cellOutSig)) {
// Input chunk is one of the cell's outputs, its a match
for (SigChunk chunk_a : actual.chunks()) {
if (sigmap(SigSpec(chunk_a)) == sigmap(SigSpec(cellOutSig))) {
match = true;
} else {
for (SigChunk chunk_c : cellOutSig.chunks()) {
if (sigmap(SigSpec(chunk_a)) == sigmap(SigSpec(chunk_c))) {
match = true;
break;
}
}
}
if (match)
break;
}
if (match) {
if (debug) if (debug)
std::cout << " MATCH" << std::endl; std::cout << " MATCH" << std::endl;
// Create a new chunk vector // Create a new chunk vector
std::vector<RTLIL::SigChunk> newChunks; std::vector<RTLIL::SigChunk> newChunks;
for (SigChunk chunk : actual.chunks()) { for (SigChunk chunk : actual.chunks()) {
bool replacedChunck = false; bool replacedChunk = false;
if (buffer_outputs.find(chunk) != buffer_outputs.end()) { if (buffer_outputs.find(chunk) != buffer_outputs.end()) {
if (debug) if (debug)
std::cout << " CHUNK, indexCurrentBuffer: " << bufferIndexes[chunk] std::cout << " CHUNK, indexCurrentBuffer: " << bufferIndexes[chunk]
@ -236,11 +242,11 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic
std::tuple<RTLIL::SigSpec, Cell *> &buf_info = buf_info_vec[bufferIndex]; std::tuple<RTLIL::SigSpec, Cell *> &buf_info = buf_info_vec[bufferIndex];
SigSpec newSig = std::get<0>(buf_info); SigSpec newSig = std::get<0>(buf_info);
Cell *newBuf = std::get<1>(buf_info); Cell *newBuf = std::get<1>(buf_info);
// Append the buffer's output in the chunck vector // Append the buffer's output in the chunk vector
newChunks.push_back(newSig.as_chunk()); newChunks.push_back(newSig.as_chunk());
// Keep track of fanout map information for recursive calls // Keep track of fanout map information for recursive calls
sig2CellsInFanout[newSig].insert(c); sig2CellsInFanout[newSig].insert(c);
replacedChunck = true; replacedChunk = true;
// Increment buffer capacity // Increment buffer capacity
bufferActualFanout[newBuf]++; bufferActualFanout[newBuf]++;
if (debug) if (debug)
@ -257,12 +263,12 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic
} }
} }
} }
if (!replacedChunck) { if (!replacedChunk) {
// Append original chunck if no buffer used // Append original chunk if no buffer used
newChunks.push_back(chunk); newChunks.push_back(chunk);
} }
} }
// Override the fanout cell's input with the newly created chunck vector // Override the fanout cell's input with the newly created chunk vector
c->setPort(portName, newChunks); c->setPort(portName, newChunks);
break; break;
} }
@ -271,6 +277,7 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic
} }
} }
// Post-processing for all newly added buffers
for (std::map<Cell *, int>::iterator itr = bufferActualFanout.begin(); itr != bufferActualFanout.end(); itr++) { for (std::map<Cell *, int>::iterator itr = bufferActualFanout.begin(); itr != bufferActualFanout.end(); itr++) {
if (itr->second == 1) { if (itr->second == 1) {
// Remove previously inserted buffers with fanout of 1 (Hard to predict the last buffer usage in above step) // Remove previously inserted buffers with fanout of 1 (Hard to predict the last buffer usage in above step)
@ -278,38 +285,54 @@ void fixfanout(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, dic
std::cout << "Buffer with fanout 1: " << itr->first->name.c_str() << std::endl; std::cout << "Buffer with fanout 1: " << itr->first->name.c_str() << std::endl;
RTLIL::SigSpec bufferInSig = itr->first->getPort(ID::A); RTLIL::SigSpec bufferInSig = itr->first->getPort(ID::A);
RTLIL::SigSpec bufferOutSig = itr->first->getPort(ID::Y); RTLIL::SigSpec bufferOutSig = itr->first->getPort(ID::Y);
// Find which cell use that buffer's output and reconnect its input to the former cell (buffer's input)
for (Cell *c : cells) { for (Cell *c : cells) {
bool reconnected = false;
if (debug) if (debug)
std::cout << "Cell in its fanout: " << c->name.c_str() << std::endl; std::cout << " Cell in its fanout: " << c->name.c_str() << std::endl;
for (auto &conn : c->connections()) { for (auto &conn : c->connections()) {
IdString portName = conn.first; IdString portName = conn.first;
RTLIL::SigSpec actual = conn.second; RTLIL::SigSpec actual = conn.second;
if (c->input(portName)) { if (c->input(portName)) {
if (actual.is_chunk()) { if (actual.is_chunk()) {
// Input is a chunk
if (bufferOutSig == sigmap(actual)) { if (bufferOutSig == sigmap(actual)) {
// Input is one of the cell's outputs, its a match
if (debug) if (debug)
std::cout << "Replace: " << getParentWire(bufferOutSig)->name.c_str() std::cout << " Replace: " << getParentWire(bufferOutSig)->name.c_str()
<< " by " << getParentWire(bufferInSig)->name.c_str() << std::endl; << " by " << getParentWire(bufferInSig)->name.c_str() << std::endl;
// Override cell's input with original buffer's input
c->setPort(portName, bufferInSig); c->setPort(portName, bufferInSig);
reconnected = true;
break;
} }
} else { } else {
std::vector<RTLIL::SigChunk> newChunks; // Input is a vector of chunks
for (SigChunk chunk : actual.chunks()) { if (isSigSpecUsedIn(actual, sigmap, bufferOutSig)) {
if (sigmap(SigSpec(chunk)) == sigmap(bufferOutSig)) { std::vector<RTLIL::SigChunk> newChunks;
if (debug) for (SigChunk chunk : actual.chunks()) {
std::cout << "Replace: " << getParentWire(bufferOutSig)->name.c_str() if (sigmap(SigSpec(chunk)) == sigmap(bufferOutSig)) {
<< " by " << getParentWire(bufferInSig)->name.c_str() if (debug)
<< std::endl; std::cout
newChunks.push_back(bufferInSig.as_chunk()); << " Replace: "
} else { << getParentWire(bufferOutSig)->name.c_str() << " by "
newChunks.push_back(chunk); << getParentWire(bufferInSig)->name.c_str() << std::endl;
newChunks.push_back(bufferInSig.as_chunk());
} else {
newChunks.push_back(chunk);
}
} }
c->setPort(portName, newChunks);
reconnected = true;
break;
} }
c->setPort(portName, newChunks);
} }
} }
} }
if (reconnected)
break;
} }
// Delete the now unsused buffer and it's output signal
module->remove(itr->first); module->remove(itr->first);
module->remove({bufferOutSig.as_wire()}); module->remove({bufferOutSig.as_wire()});
} else { } else {