mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-23 14:23:41 +00:00
WIP
This commit is contained in:
parent
9d3b7f7474
commit
6a26b2db55
1 changed files with 213 additions and 87 deletions
|
@ -6,17 +6,15 @@ USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
// Signal cell driver(s), precompute a cell output signal to a cell map
|
// Signal cell driver(s), precompute a cell output signal to a cell map
|
||||||
void sigCellDrivers(RTLIL::Design *design, dict<RTLIL::SigSpec, std::set<Cell *>> &sig2CellsInFanout,
|
void sigCellDrivers(RTLIL::Module *module, SigMap &sigmap, dict<RTLIL::SigSpec, std::set<Cell *>> &sig2CellsInFanout,
|
||||||
dict<RTLIL::SigSpec, std::set<Cell *>> &sig2CellsInFanin)
|
dict<RTLIL::SigSpec, std::set<Cell *>> &sig2CellsInFanin)
|
||||||
{
|
{
|
||||||
for (auto module : design->selected_modules()) {
|
|
||||||
SigMap sigmap(module);
|
|
||||||
for (auto cell : module->selected_cells()) {
|
for (auto cell : module->selected_cells()) {
|
||||||
for (auto &conn : cell->connections()) {
|
for (auto &conn : cell->connections()) {
|
||||||
IdString portName = conn.first;
|
IdString portName = conn.first;
|
||||||
RTLIL::SigSpec actual = conn.second;
|
RTLIL::SigSpec actual = conn.second;
|
||||||
if (cell->output(portName)) {
|
if (cell->output(portName)) {
|
||||||
sig2CellsInFanin[actual].insert(cell);
|
sig2CellsInFanin[sigmap(actual)].insert(cell);
|
||||||
for (int i = 0; i < actual.size(); i++) {
|
for (int i = 0; i < actual.size(); i++) {
|
||||||
SigSpec bit_sig = actual.extract(i, 1);
|
SigSpec bit_sig = actual.extract(i, 1);
|
||||||
sig2CellsInFanin[sigmap(bit_sig)].insert(cell);
|
sig2CellsInFanin[sigmap(bit_sig)].insert(cell);
|
||||||
|
@ -32,18 +30,16 @@ void sigCellDrivers(RTLIL::Design *design, dict<RTLIL::SigSpec, std::set<Cell *>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign statements fanin, fanout, traces the lhs2rhs and rhs2lhs sigspecs and precompute maps
|
// Assign statements fanin, fanout, traces the lhs2rhs and rhs2lhs sigspecs and precompute maps
|
||||||
void lhs2rhs_rhs2lhs(RTLIL::Design *design, dict<RTLIL::SigSpec, std::set<RTLIL::SigSpec>> &rhsSig2LhsSig,
|
void lhs2rhs_rhs2lhs(RTLIL::Module *module, SigMap &sigmap, dict<RTLIL::SigSpec, std::set<RTLIL::SigSpec>> &rhsSig2LhsSig,
|
||||||
dict<RTLIL::SigSpec, RTLIL::SigSpec> &lhsSig2rhsSig)
|
dict<RTLIL::SigSpec, RTLIL::SigSpec> &lhsSig2rhsSig)
|
||||||
{
|
{
|
||||||
for (auto module : design->selected_modules()) {
|
|
||||||
SigMap sigmap(module);
|
|
||||||
for (auto it = module->connections().begin(); it != module->connections().end(); ++it) {
|
for (auto it = module->connections().begin(); it != module->connections().end(); ++it) {
|
||||||
RTLIL::SigSpec lhs = it->first;
|
RTLIL::SigSpec lhs = it->first;
|
||||||
RTLIL::SigSpec rhs = it->second;
|
RTLIL::SigSpec rhs = it->second;
|
||||||
|
if (!lhs.is_chunk()) {
|
||||||
std::vector<SigSpec> lhsBits;
|
std::vector<SigSpec> lhsBits;
|
||||||
for (int i = 0; i < lhs.size(); i++) {
|
for (int i = 0; i < lhs.size(); i++) {
|
||||||
SigSpec bit_sig = lhs.extract(i, 1);
|
SigSpec bit_sig = lhs.extract(i, 1);
|
||||||
|
@ -52,42 +48,121 @@ void lhs2rhs_rhs2lhs(RTLIL::Design *design, dict<RTLIL::SigSpec, std::set<RTLIL:
|
||||||
std::vector<SigSpec> rhsBits;
|
std::vector<SigSpec> rhsBits;
|
||||||
for (int i = 0; i < rhs.size(); i++) {
|
for (int i = 0; i < rhs.size(); i++) {
|
||||||
SigSpec bit_sig = rhs.extract(i, 1);
|
SigSpec bit_sig = rhs.extract(i, 1);
|
||||||
if (bit_sig.is_fully_const()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
rhsBits.push_back(bit_sig);
|
rhsBits.push_back(bit_sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < lhsBits.size(); i++) {
|
for (uint32_t i = 0; i < lhsBits.size(); i++) {
|
||||||
if (i < rhsBits.size()) {
|
if (i < rhsBits.size()) {
|
||||||
rhsSig2LhsSig[sigmap(rhsBits[i])].insert(sigmap(lhsBits[i]));
|
rhsSig2LhsSig[sigmap(rhsBits[i])].insert(sigmap(lhsBits[i]));
|
||||||
lhsSig2rhsSig[sigmap(lhsBits[i])] = sigmap(rhsBits[i]);
|
lhsSig2rhsSig[lhsBits[i]] = sigmap(rhsBits[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
rhsSig2LhsSig[sigmap(rhs)].insert(sigmap(lhs));
|
||||||
|
lhsSig2rhsSig[lhs] = sigmap(rhs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AnnotateCellFanout : public ScriptPass {
|
void fixfanout(RTLIL::Module *module, SigMap &sigmap, dict<RTLIL::SigSpec, std::set<Cell *>> &sig2CellsInFanout, RTLIL::Cell *cell, int fanout,
|
||||||
AnnotateCellFanout() : ScriptPass("annotate_cell_fanout", "Annotate the cell fanout on the cell") {}
|
int limit)
|
||||||
void script() override {}
|
{
|
||||||
|
if (fanout <= limit) {
|
||||||
void execute(std::vector<std::string>, RTLIL::Design *design) override
|
std::cout << "Nothing to do for: " << cell->name.c_str() << std::endl;
|
||||||
{
|
std::cout << "Fanout: " << fanout << std::endl;
|
||||||
if (design == nullptr) {
|
return; // No need to insert buffers
|
||||||
log_error("No design object");
|
} else {
|
||||||
return;
|
std::cout << "Something to do for: " << cell->name.c_str() << std::endl;
|
||||||
|
std::cout << "Fanout: " << fanout << std::endl;
|
||||||
}
|
}
|
||||||
log("Running annotate_cell_fanout pass\n");
|
|
||||||
log_flush();
|
int num_buffers = std::min((int)std::ceil(static_cast<double>(fanout) / limit), limit);
|
||||||
|
int max_output_per_buffer = std::ceil((float)fanout / (float)num_buffers);
|
||||||
|
std::cout << "fanout: " << fanout << "\n";
|
||||||
|
std::cout << "limit: " << limit << "\n";
|
||||||
|
std::cout << "num_buffers: " << num_buffers << "\n";
|
||||||
|
std::cout << "max_output_per_buffer: " << max_output_per_buffer << "\n";
|
||||||
|
std::vector<RTLIL::SigSpec> buffer_outputs;
|
||||||
|
std::vector<RTLIL::Cell*> buffers;
|
||||||
|
std::cout << "HERE1\n" << std::flush;
|
||||||
|
std::cout << "CELL: " << cell->name.c_str() << "\n" << std::flush;
|
||||||
|
RTLIL::SigSpec cellOutSig;
|
||||||
|
for (auto &conn : cell->connections()) {
|
||||||
|
IdString portName = conn.first;
|
||||||
|
RTLIL::SigSpec actual = conn.second;
|
||||||
|
if (cell->output(portName)) {
|
||||||
|
cellOutSig = sigmap(actual);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "HERE2\n" << std::flush;
|
||||||
|
for (int i = 0; i < num_buffers; ++i) {
|
||||||
|
RTLIL::Cell *buffer = module->addCell(NEW_ID2_SUFFIX("fbuf"), ID($buf)); // Assuming BUF is defined
|
||||||
|
RTLIL::SigSpec buffer_output = module->addWire(NEW_ID2_SUFFIX("fbuf"));
|
||||||
|
buffer->setPort(ID(A), cellOutSig);
|
||||||
|
buffer->setPort(ID(Y), sigmap(buffer_output));
|
||||||
|
buffer_outputs.push_back(buffer_output);
|
||||||
|
buffers.push_back(buffer);
|
||||||
|
}
|
||||||
|
std::cout << "Lookup\n" << std::flush;
|
||||||
|
std::set<Cell *> cells = sig2CellsInFanout[cellOutSig];
|
||||||
|
std::cout << "Lookup OK\n" << std::flush;
|
||||||
|
int indexCurrentBuffer = 0;
|
||||||
|
int indexFanout = 0;
|
||||||
|
std::map<Cell*, int> bufferActualFanout;
|
||||||
|
for (Cell *c : cells) {
|
||||||
|
for (auto &conn : c->connections()) {
|
||||||
|
IdString portName = conn.first;
|
||||||
|
RTLIL::SigSpec actual = conn.second;
|
||||||
|
if (c->input(portName)) {
|
||||||
|
if (sigmap(actual) == cellOutSig) {
|
||||||
|
c->setPort(portName, buffer_outputs[indexCurrentBuffer]);
|
||||||
|
sig2CellsInFanout[sigmap(buffer_outputs[indexCurrentBuffer])].insert(c);
|
||||||
|
indexFanout++;
|
||||||
|
bufferActualFanout[buffers[indexCurrentBuffer]] = indexFanout;
|
||||||
|
if (indexFanout >= max_output_per_buffer) {
|
||||||
|
indexFanout = 0;
|
||||||
|
indexCurrentBuffer++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively fix the fanout of the newly created buffers
|
||||||
|
for (std::map<Cell*, int>::iterator itr = bufferActualFanout.begin(); itr != bufferActualFanout.end(); itr++) {
|
||||||
|
if (itr->second == 1) {
|
||||||
|
std::cout << "Buffer of 1" << std::endl;
|
||||||
|
for (Cell *c : cells) {
|
||||||
|
for (auto &conn : c->connections()) {
|
||||||
|
IdString portName = conn.first;
|
||||||
|
RTLIL::SigSpec actual = conn.second;
|
||||||
|
if (c->input(portName)) {
|
||||||
|
if (sigmap(buffer_outputs[indexCurrentBuffer]) == sigmap(actual)) {
|
||||||
|
c->setPort(portName, cellOutSig);
|
||||||
|
std::cout << "Remove buffer of 1" << std::endl;
|
||||||
|
module->remove(buffers[indexCurrentBuffer]);
|
||||||
|
//module->remove({buffer_outputs[indexCurrentBuffer].as_wire()});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fixfanout(module, sigmap, sig2CellsInFanout, itr->first, itr->second, limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void calculateFanout(RTLIL::Module *module, SigMap &sigmap, dict<RTLIL::SigSpec, std::set<Cell *>>& sig2CellsInFanout, dict<Cell *, int> &cellFanout)
|
||||||
|
{
|
||||||
// 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;
|
||||||
dict<RTLIL::SigSpec, std::set<Cell *>> sig2CellsInFanout;
|
sigCellDrivers(module, sigmap, sig2CellsInFanout, sig2CellsInFanin);
|
||||||
sigCellDrivers(design, sig2CellsInFanout, sig2CellsInFanin);
|
|
||||||
// Precompute lhs2rhs and rhs2lhs sigspec map
|
// Precompute lhs2rhs and rhs2lhs sigspec map
|
||||||
dict<RTLIL::SigSpec, RTLIL::SigSpec> lhsSig2RhsSig;
|
dict<RTLIL::SigSpec, RTLIL::SigSpec> lhsSig2RhsSig;
|
||||||
dict<RTLIL::SigSpec, std::set<RTLIL::SigSpec>> rhsSig2LhsSig;
|
dict<RTLIL::SigSpec, std::set<RTLIL::SigSpec>> rhsSig2LhsSig;
|
||||||
lhs2rhs_rhs2lhs(design, rhsSig2LhsSig, lhsSig2RhsSig);
|
lhs2rhs_rhs2lhs(module, sigmap, rhsSig2LhsSig, lhsSig2RhsSig);
|
||||||
|
|
||||||
// Accumulate fanout from cell connections
|
// Accumulate fanout from cell connections
|
||||||
dict<RTLIL::SigSpec, int> sigFanout;
|
dict<RTLIL::SigSpec, int> sigFanout;
|
||||||
|
@ -109,7 +184,6 @@ struct AnnotateCellFanout : public ScriptPass {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect max fanout from all the output bits of a cell
|
// Collect max fanout from all the output bits of a cell
|
||||||
dict<Cell *, int> cellFanout;
|
|
||||||
for (auto itrSig : sigFanout) {
|
for (auto itrSig : sigFanout) {
|
||||||
SigSpec sigspec = itrSig.first;
|
SigSpec sigspec = itrSig.first;
|
||||||
int fanout = itrSig.second;
|
int fanout = itrSig.second;
|
||||||
|
@ -125,24 +199,76 @@ struct AnnotateCellFanout : public ScriptPass {
|
||||||
|
|
||||||
// Find cells with no fanout info (connected to output ports, or not connected)
|
// Find cells with no fanout info (connected to output ports, or not connected)
|
||||||
std::set<Cell *> noFanoutInfo;
|
std::set<Cell *> noFanoutInfo;
|
||||||
for (auto module : design->selected_modules()) {
|
|
||||||
for (auto cell : module->selected_cells()) {
|
for (auto cell : module->selected_cells()) {
|
||||||
if (!cellFanout.count(cell)) {
|
if (!cellFanout.count(cell)) {
|
||||||
noFanoutInfo.insert(cell);
|
noFanoutInfo.insert(cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Set those cells to fanout 1
|
// Set those cells to fanout 1
|
||||||
for (auto cell : noFanoutInfo) {
|
for (auto cell : noFanoutInfo) {
|
||||||
cellFanout[cell] = 1;
|
cellFanout[cell] = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AnnotateCellFanout : public ScriptPass {
|
||||||
|
AnnotateCellFanout() : ScriptPass("annotate_cell_fanout", "Annotate the cell fanout on the cell") {}
|
||||||
|
void script() override {}
|
||||||
|
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||||
|
{
|
||||||
|
int limit = -1;
|
||||||
|
if (design == nullptr) {
|
||||||
|
log_error("No design object\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log("Running annotate_cell_fanout pass\n");
|
||||||
|
log_flush();
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||||
|
if (args[argidx] == "-limit") {
|
||||||
|
limit = std::atoi(args[++argidx].c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
if (limit < 2) {
|
||||||
|
log_error("Fanout cannot be limited to less than 2\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto module : design->selected_modules()) {
|
||||||
|
bool fixedFanout = false;
|
||||||
|
{
|
||||||
|
SigMap sigmap(module);
|
||||||
|
dict<Cell *, int> cellFanout;
|
||||||
|
dict<RTLIL::SigSpec, std::set<Cell *>> sig2CellsInFanout;
|
||||||
|
calculateFanout(module, sigmap, sig2CellsInFanout, cellFanout);
|
||||||
// Add attribute with fanout info to every cell
|
// Add attribute with fanout info to every cell
|
||||||
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)) {
|
||||||
|
fixfanout(module, sigmap, sig2CellsInFanout, cell, fanout, limit);
|
||||||
|
fixedFanout = true;
|
||||||
|
} else {
|
||||||
cell->set_string_attribute("$FANOUT", std::to_string(fanout));
|
cell->set_string_attribute("$FANOUT", std::to_string(fanout));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fixedFanout) {
|
||||||
|
SigMap sigmap(module);
|
||||||
|
dict<Cell *, int> cellFanout;
|
||||||
|
dict<RTLIL::SigSpec, std::set<Cell *>> sig2CellsInFanout;
|
||||||
|
calculateFanout(module, sigmap, sig2CellsInFanout, cellFanout);
|
||||||
|
for (auto itrCell : cellFanout) {
|
||||||
|
Cell *cell = itrCell.first;
|
||||||
|
int fanout = itrCell.second;
|
||||||
|
cell->set_string_attribute("$FANOUT", std::to_string(fanout));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log("End annotate_cell_fanout pass\n");
|
log("End annotate_cell_fanout pass\n");
|
||||||
log_flush();
|
log_flush();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue