yosys/kernel/unstable/patch.cc

194 lines
5.0 KiB
C++
Raw Normal View History

2025-12-19 19:14:33 +01:00
#include "kernel/unstable/patch.h"
2025-12-31 17:46:27 +01:00
#include "kernel/celltypes.h"
2026-05-19 12:36:41 +02:00
#include "kernel/log.h"
2025-12-31 17:46:27 +01:00
#include "kernel/rtlil.h"
2025-12-19 19:14:33 +01:00
YOSYS_NAMESPACE_BEGIN
using namespace RTLIL;
template class CellAdderMixin<Patch>;
2025-12-19 19:14:33 +01:00
Cell* Patch::addCell(IdString name, IdString type) {
2026-05-19 12:36:41 +02:00
cells_.push_back(std::make_unique<Cell>(Cell::ConstructToken{}));
2026-05-14 17:43:46 +02:00
Cell* cell = cells_.back().get();
2026-05-19 12:36:41 +02:00
cell->name = name;
2026-05-14 17:43:46 +02:00
cell->type = type;
cell->module = nullptr;
2026-05-14 17:43:46 +02:00
return cell;
}
Wire* Patch::addWire(IdString name, int width) {
2026-05-19 15:33:41 +02:00
wires_.push_back(std::make_unique<Wire>(Wire::ConstructToken{}));
Wire* wire = wires_.back().get();
wire->name = name;
wire->width = width;
wire->module = nullptr;
2026-05-19 15:33:41 +02:00
return wire;
}
// TODO code golf
RTLIL::Wire *RTLIL::Patch::addWire(RTLIL::IdString name, const RTLIL::Wire *other)
{
RTLIL::Wire *wire = addWire(std::move(name));
wire->width = other->width;
wire->start_offset = other->start_offset;
wire->port_id = other->port_id;
wire->port_input = other->port_input;
wire->port_output = other->port_output;
wire->upto = other->upto;
wire->is_signed = other->is_signed;
wire->attributes = other->attributes;
return wire;
2025-12-19 19:14:33 +01:00
}
struct SrcCollector {
pool<Cell*> to_do;
pool<Cell*> done;
pool<string> src;
void collect_src(Cell* old_cell) {
if (done.count(old_cell))
return;
done.insert(old_cell);
2026-05-28 14:49:07 +02:00
log_debug("collect %s\n", old_cell->name);
src.insert(old_cell->get_src_attribute());
std::vector<Cell*> input_cells = {};
for (auto [port_name, sig] : old_cell->connections()) {
auto dir = old_cell->port_dir(port_name);
log_assert(dir != PD_UNKNOWN);
if (dir == PD_INPUT || dir == PD_INOUT) {
if (sig.size() && sig.is_wire()) {
Wire* in_wire = sig.as_wire();
if (!in_wire->module)
input_cells.push_back(in_wire->driverCell());
// if (!leaves.count(in_wire))
}
2026-05-26 11:59:19 +02:00
}
2026-05-19 19:31:16 +02:00
}
for (auto input : input_cells)
collect_src(input);
2026-05-19 19:31:16 +02:00
}
void collect_src(SigSpec old_sig) {
2026-05-28 14:49:07 +02:00
log_debug("collect %s\n", log_signal(old_sig));
for (auto bit : old_sig) {
if (bit.is_wire() && bit.wire->module) {
log_assert(bit.wire->driverCell_);
to_do.insert(bit.wire->driverCell_);
}
}
for (auto cell : to_do)
collect_src(cell);
}
};
2026-05-19 19:31:16 +02:00
void Patch::gc(Cell* old_cell) {
2026-05-28 14:49:07 +02:00
log_debug("gc %s\n", old_cell->name);
2026-05-19 19:31:16 +02:00
std::vector<Cell*> inputs = {};
for (auto [port_name, sig] : old_cell->connections()) {
auto dir = old_cell->port_dir(port_name);
log_assert(dir != PD_UNKNOWN);
2026-05-28 22:51:30 +02:00
// TODO only running GC through whole connections?
log_debug("\tport %s\n", port_name);
2026-05-26 11:59:19 +02:00
if (sig.size() && sig.is_wire()) {
if (dir == PD_OUTPUT || dir == PD_INOUT) {
2026-05-19 19:31:16 +02:00
for (auto bit : sig) {
// Reject GC if used
2026-05-28 22:51:30 +02:00
if (!mod->fanout(bit).empty()) {
log_debug("\treject fanout\n");
2026-05-19 19:31:16 +02:00
return;
2026-05-28 22:51:30 +02:00
} else
log_debug("\tok\n");
2026-05-19 19:31:16 +02:00
}
}
2026-05-26 11:59:19 +02:00
if (dir == PD_INPUT || dir == PD_INOUT) {
Wire* in_wire = sig.as_wire();
log_assert(in_wire);
2026-05-28 22:51:30 +02:00
log_debug("\twire %s\n", in_wire->name);
if (in_wire->known_driver() && !leaves.count(in_wire))
2026-05-26 11:59:19 +02:00
inputs.push_back(in_wire->driverCell());
}
2026-05-19 19:31:16 +02:00
}
}
2026-05-28 22:51:30 +02:00
log_debug("\tremove %s\n", old_cell->name);
2026-05-26 12:22:38 +02:00
old_cell->module->remove(old_cell);
2026-05-19 19:31:16 +02:00
for (auto input : inputs)
gc(input);
}
Wire* Patch::commit_wire(std::unique_ptr<Wire> wire) {
Wire* raw = wire.release();
mod->wires_[raw->name] = raw;
raw->module = mod;
return raw;
}
Cell* Patch::commit_cell(std::unique_ptr<Cell> cell) {
Cell* raw = cell.release();
mod->cells_[raw->name] = raw;
raw->module = mod;
raw->initIndex();
return raw;
}
void Patch::patch(Cell* old_cell, IdString old_port, SigSpec new_sig) {
SigSpec old_sig = old_cell->getPort(old_port);
log_assert(old_sig.size() == new_sig.size());
2026-05-28 22:51:30 +02:00
log("patching %s %s which is %s with %s:\n", old_cell->name, old_port, log_signal(old_sig), log_signal(new_sig));
SrcCollector collector;
collector.collect_src(old_sig);
std::string src_str = AttrObject::strpool_attribute_to_str(collector.src);
old_cell->setPort(old_port, SigSpec());
mod->connect(old_sig, new_sig);
if (map)
map->add(old_sig, new_sig);
2026-05-28 12:56:13 +02:00
// Inefficient
for (auto& cell : cells_) {
2026-05-28 22:51:30 +02:00
log_debug("cell %s\n", cell->name);
2026-05-28 12:56:13 +02:00
for (auto& [port_name, sig] : cell->connections()) {
2026-05-28 22:51:30 +02:00
log_debug("port %s\n", port_name);
2026-05-28 12:56:13 +02:00
auto dir = cell->port_dir(port_name);
if (dir == PD_INPUT || dir == PD_INOUT) {
2026-05-28 22:51:30 +02:00
for (auto bit : sig) {
log("bit %s\n", log_signal(bit));
if (bit.is_wire() && bit.wire->module) {
2026-05-28 12:56:13 +02:00
leaves.insert(bit.wire);
2026-05-28 22:51:30 +02:00
log_debug("leaf %s\n", bit.wire->name);
}
}
2026-05-28 12:56:13 +02:00
}
}
}
2026-05-19 12:36:41 +02:00
for (auto& cell: cells_) {
2026-05-19 19:31:16 +02:00
cell->set_src_attribute(src_str);
cell->fixup_parameters();
commit_cell(std::move(cell));
}
for (auto& wire: wires_)
commit_wire(std::move(wire));
2026-05-29 11:59:27 +02:00
// Flush pending sigmap updates (from the mod->connect above) into the
// fanout index so gc() sees the updated fanout for cells whose outputs
// were the patched wires. Without this, downstream consumers like the
// $output_port / $public sentinels still appear in the OLD wire's fanout
// instead of the new representative.
mod->sigNormalize();
2026-05-19 19:31:16 +02:00
gc(old_cell);
2026-05-28 22:51:30 +02:00
cells_.clear();
wires_.clear();
leaves.clear();
2025-12-31 17:46:27 +01:00
}
2025-12-19 19:14:33 +01:00
YOSYS_NAMESPACE_END