3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-09-08 02:31:26 +00:00

WIP prototype bidir aware kernel bufnorm code

This commit is contained in:
Jannis Harder 2025-08-14 16:16:19 +02:00
parent 727dabba95
commit 4de384d776

View file

@ -4063,11 +4063,24 @@ void RTLIL::Design::bufNormalize(bool enable)
{ {
for (auto cell : module->cells()) for (auto cell : module->cells())
for (auto &conn : cell->connections()) { for (auto &conn : cell->connections()) {
if (!cell->output(conn.first) || GetSize(conn.second) == 0)
PortDir port_dir = cell->port_dir(conn.first);
if (port_dir == PD_INPUT || GetSize(conn.second) == 0)
continue; continue;
if (conn.second.is_wire()) { if (conn.second.is_wire()) {
Wire *wire = conn.second.as_wire(); Wire *wire = conn.second.as_wire();
log_assert(wire->driverCell_ == nullptr); if (wire->driverCell_ != nullptr) {
if (port_dir != PD_OUTPUT) {
continue;
} else if (wire->driverCell_->port_dir(wire->driverPort_) != PD_OUTPUT) {
// port_dir == PD_OUTPUT
} else {
log_error("Conflict between %s.%s and %s.%s driving %s in module %s\n",
log_id(cell), log_id(conn.first),
log_id(wire->driverCell_), log_id(wire->driverPort_),
log_id(wire), log_id(module));
}
}
wire->driverCell_ = cell; wire->driverCell_ = cell;
wire->driverPort_ = conn.first; wire->driverPort_ = conn.first;
} else { } else {
@ -4094,11 +4107,6 @@ void RTLIL::Module::bufNormalize()
pool<pair<RTLIL::Cell*, RTLIL::IdString>> queue; pool<pair<RTLIL::Cell*, RTLIL::IdString>> queue;
bufNormQueue.swap(queue); bufNormQueue.swap(queue);
pool<Wire*> outWires;
for (auto &conn : connections())
for (auto &chunk : conn.first.chunks())
if (chunk.wire) outWires.insert(chunk.wire);
SigMap sigmap(this); SigMap sigmap(this);
new_connections({}); new_connections({});
@ -4112,18 +4120,23 @@ void RTLIL::Module::bufNormalize()
if (sig.is_wire()) { if (sig.is_wire()) {
Wire *wire = sig.as_wire(); Wire *wire = sig.as_wire();
if (wire->driverCell_) { if (wire->driverCell_) {
log_error("Conflict between %s %s in module %s\n", PortDir port_dir = cell->port_dir(portname);
log_id(cell), log_id(wire->driverCell_), log_id(this)); if (port_dir != PD_OUTPUT) {
continue;
} else if (wire->driverCell_->port_dir(wire->driverPort_) != PD_OUTPUT) {
// port_dir == PD_OUTPUT
} else {
log_error("Conflict between %s.%s and %s.%s driving %s in module %s\n",
log_id(cell), log_id(portname),
log_id(wire->driverCell_), log_id(wire->driverPort_),
log_id(wire), log_id(this));
}
} }
log_assert(wire->driverCell_ == nullptr);
wire->driverCell_ = cell; wire->driverCell_ = cell;
wire->driverPort_ = portname; wire->driverPort_ = portname;
continue; continue;
} }
for (auto &chunk : sig.chunks())
if (chunk.wire) outWires.insert(chunk.wire);
Wire *wire = addWire(NEW_ID, GetSize(sig)); Wire *wire = addWire(NEW_ID, GetSize(sig));
sigmap.add(sig, wire); sigmap.add(sig, wire);
cell->setPort(portname, wire); cell->setPort(portname, wire);
@ -4131,13 +4144,75 @@ void RTLIL::Module::bufNormalize()
// FIXME: Move init attributes from old 'sig' to new 'wire' // FIXME: Move init attributes from old 'sig' to new 'wire'
} }
for (auto wire : outWires) pool<Wire*> conn_wires;
pool<Wire*> inout_conn_wires;
pool<Wire*> driven_conn_wires;
for (auto const &bit : sigmap.database)
if (bit.wire != nullptr)
conn_wires.insert(bit.wire);
for (auto wire : conn_wires) {
if (wire->driverCell_ == nullptr) {
if (!wire->port_input)
continue;
if (wire->port_output) {
inout_conn_wires.insert(wire);
} else {
driven_conn_wires.insert(wire);
}
continue;
}
if (wire->driverCell_->port_dir(wire->driverPort_) == PD_OUTPUT) {
if (wire->port_input && !wire->port_output) {
log_error("Conflict between %s.%s and input port %s in module %s\n",
log_id(wire->driverCell_), log_id(wire->driverPort_),
log_id(wire), log_id(this));
}
driven_conn_wires.insert(wire);
} else {
inout_conn_wires.insert(wire);
}
}
for (auto wire : inout_conn_wires)
for (int i = 0; i < GetSize(wire); ++i)
sigmap.database.promote(SigBit(wire, i));
for (auto wire : driven_conn_wires)
for (int i = 0; i < GetSize(wire); ++i)
sigmap.database.promote(SigBit(wire, i));
for (auto wire : conn_wires)
{ {
SigSpec outsig = wire, insig = sigmap(wire); SigSpec outsig = wire, insig = sigmap(wire);
for (int i = 0; i < GetSize(wire); i++) if (insig == outsig)
if (insig[i] == outsig[i]) continue;
insig[i] = State::Sx;
bool ambiguous_directionality = false;
for (int i = 0; i < GetSize(wire) && !ambiguous_directionality; i++) {
SigBit inbit = insig[i];
SigBit outbit = outsig[i];
if (inbit == outbit)
ambiguous_directionality = true;
else
ambiguous_directionality = !driven_conn_wires.count(inbit.wire);
}
if (ambiguous_directionality) {
Cell *connect = addCell(NEW_ID, ID($connect));
connect->setParam(ID::WIDTH, GetSize(insig));
connect->setPort(ID::A, insig);
connect->setPort(ID::Y, outsig);
} else {
addBuf(NEW_ID, insig, outsig); addBuf(NEW_ID, insig, outsig);
}
} }
} }
} }
@ -4161,7 +4236,9 @@ void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal
log_backtrace("-X- ", yosys_xtrace-1); log_backtrace("-X- ", yosys_xtrace-1);
} }
while (module->design && module->design->flagBufferedNormalized && output(portname)) PortDir pd;
while (module->design && module->design->flagBufferedNormalized && (pd = port_dir(portname)) != PD_INPUT)
{ {
pair<RTLIL::Cell*, RTLIL::IdString> key(this, portname); pair<RTLIL::Cell*, RTLIL::IdString> key(this, portname);
@ -4185,9 +4262,12 @@ void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal
Wire *w = signal.as_wire(); Wire *w = signal.as_wire();
if (w->driverCell_ != nullptr) { if (w->driverCell_ != nullptr) {
if (pd == PD_OUTPUT) {
pair<RTLIL::Cell*, RTLIL::IdString> other_key(w->driverCell_, w->driverPort_); pair<RTLIL::Cell*, RTLIL::IdString> other_key(w->driverCell_, w->driverPort_);
module->bufNormQueue.insert(other_key); module->bufNormQueue.insert(other_key);
} }
break;
}
w->driverCell_ = this; w->driverCell_ = this;
w->driverPort_ = portname; w->driverPort_ = portname;