Add RTLIL "buffered-normalized mode" and improve "bufnorm" pass

Signed-off-by: Claire Xenia Wolf <claire@clairexen.net>
This commit is contained in:
Claire Xenia Wolf 2023-09-29 15:49:15 +02:00 committed by Martin Povišer
parent 8bb70bac8d
commit 80119386c0
5 changed files with 238 additions and 13 deletions

View File

@ -118,13 +118,17 @@ void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
}
}
void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire)
void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire, bool flag_d)
{
for (auto &it : wire->attributes) {
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
if (flag_d && wire->driverCell) {
f << stringf("%s" "driver %s %s\n", indent.c_str(),
wire->driverCell->name.c_str(), wire->driverPort.c_str());
}
f << stringf("%s" "wire ", indent.c_str());
if (wire->width != 1)
f << stringf("width %d ", wire->width);
@ -298,7 +302,7 @@ void RTLIL_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL::
f << stringf("\n");
}
void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n, bool flag_d)
{
bool print_header = flag_m || design->selected_whole_module(module->name);
bool print_body = !flag_n || !design->selected_whole_module(module->name);
@ -335,7 +339,7 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
if (!only_selected || design->selected(module, it)) {
if (only_selected)
f << stringf("\n");
dump_wire(f, indent + " ", it);
dump_wire(f, indent + " ", it, flag_d);
}
for (auto it : module->memories)
@ -384,7 +388,7 @@ void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
f << stringf("%s" "end\n", indent.c_str());
}
void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n, bool flag_d)
{
int init_autoidx = autoidx;
@ -410,7 +414,7 @@ void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
if (!only_selected || design->selected(module)) {
if (only_selected)
f << stringf("\n");
dump_module(f, "", module, design, only_selected, flag_m, flag_n);
dump_module(f, "", module, design, only_selected, flag_m, flag_n, flag_d);
}
}
@ -456,7 +460,7 @@ struct RTLILBackend : public Backend {
log("Output filename: %s\n", filename.c_str());
*f << stringf("# Generated by %s\n", yosys_version_str);
RTLIL_BACKEND::dump_design(*f, design, selected, true, false);
RTLIL_BACKEND::dump_design(*f, design, selected, true, false, false);
}
} RTLILBackend;
@ -493,6 +497,9 @@ struct DumpPass : public Pass {
log(" -n\n");
log(" only dump the module headers if the entire module is selected\n");
log("\n");
log(" -d\n");
log(" include driver cell and port info on wires in dump format\n");
log("\n");
log(" -o <filename>\n");
log(" write to the specified file.\n");
log("\n");
@ -503,7 +510,7 @@ struct DumpPass : public Pass {
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string filename;
bool flag_m = false, flag_n = false, append = false;
bool flag_m = false, flag_n = false, flag_d = false, append = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@ -527,6 +534,10 @@ struct DumpPass : public Pass {
flag_n = true;
continue;
}
if (arg == "-d") {
flag_d = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -548,7 +559,7 @@ struct DumpPass : public Pass {
f = &buf;
}
RTLIL_BACKEND::dump_design(*f, design, true, flag_m, flag_n);
RTLIL_BACKEND::dump_design(*f, design, true, flag_m, flag_n, flag_d);
if (!empty) {
delete f;

View File

@ -34,7 +34,7 @@ namespace RTLIL_BACKEND {
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true);
void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint = true);
void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint = true);
void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire, bool flag_d = false);
void dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory);
void dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell);
void dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs);
@ -42,8 +42,8 @@ namespace RTLIL_BACKEND {
void dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy);
void dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc);
void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right);
void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
void dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false, bool flag_d = false);
void dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false, bool flag_d = false);
}
YOSYS_NAMESPACE_END

View File

@ -21,6 +21,7 @@
#include "kernel/macc.h"
#include "kernel/celltypes.h"
#include "kernel/binding.h"
#include "kernel/sigtools.h"
#include "frontends/verilog/verilog_frontend.h"
#include "frontends/verilog/preproc.h"
#include "backends/rtlil/rtlil_backend.h"
@ -3564,6 +3565,104 @@ void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname)
}
}
void RTLIL::Design::bufNormalize(bool enable)
{
if (!enable)
{
if (!flagBufferedNormalized)
return;
for (auto module : modules()) {
module->bufNormQueue.clear();
for (auto wire : module->wires()) {
wire->driverCell = nullptr;
wire->driverPort = IdString();
}
}
return;
}
if (!flagBufferedNormalized)
{
for (auto module : modules())
{
for (auto cell : module->cells())
for (auto &conn : cell->connections()) {
if (!cell->output(conn.first) || GetSize(conn.second) == 0)
continue;
if (conn.second.is_wire()) {
Wire *wire = conn.second.as_wire();
log_assert(wire->driverCell == nullptr);
wire->driverCell = cell;
wire->driverPort = conn.first;
} else {
pair<RTLIL::Cell*, RTLIL::IdString> key(cell, conn.first);
module->bufNormQueue.insert(key);
}
}
}
flagBufferedNormalized = true;
}
for (auto module : modules())
module->bufNormalize();
}
void RTLIL::Module::bufNormalize()
{
if (!design->flagBufferedNormalized)
return;
while (GetSize(bufNormQueue))
{
pool<pair<RTLIL::Cell*, RTLIL::IdString>> 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);
new_connections({});
for (auto &key : queue)
{
Cell *cell = key.first;
const IdString &portname = key.second;
const SigSpec &sig = cell->getPort(portname);
if (GetSize(sig) == 0) continue;
if (sig.is_wire()) {
Wire *wire = sig.as_wire();
log_assert(wire->driverCell == nullptr);
wire->driverCell = cell;
wire->driverPort = portname;
continue;
}
for (auto &chunk : sig.chunks())
if (chunk.wire) outWires.insert(chunk.wire);
Wire *wire = addWire(NEW_ID, GetSize(sig));
sigmap.add(sig, wire);
cell->setPort(portname, wire);
// FIXME: Move init attributes from old 'sig' to new 'wire'
}
for (auto wire : outWires)
{
SigSpec outsig = wire, insig = sigmap(wire);
for (int i = 0; i < GetSize(wire); i++)
if (insig[i] == outsig[i])
insig[i] = State::Sx;
addBuf(NEW_ID, insig, outsig);
}
}
}
void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal)
{
auto r = connections_.insert(portname);
@ -3583,6 +3682,40 @@ void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal
log_backtrace("-X- ", yosys_xtrace-1);
}
while (module->design && module->design->flagBufferedNormalized && output(portname))
{
pair<RTLIL::Cell*, RTLIL::IdString> key(this, portname);
if (conn_it->second.is_wire()) {
Wire *w = conn_it->second.as_wire();
if (w->driverCell == this && w->driverPort == portname) {
w->driverCell = nullptr;
w->driverPort = IdString();
}
}
if (GetSize(signal) == 0) {
module->bufNormQueue.erase(key);
break;
}
if (!signal.is_wire()) {
module->bufNormQueue.insert(key);
break;
}
Wire *w = signal.as_wire();
if (w->driverCell != nullptr) {
pair<RTLIL::Cell*, RTLIL::IdString> other_key(w->driverCell, w->driverPort);
module->bufNormQueue.insert(other_key);
}
w->driverCell = this;
w->driverPort = portname;
module->bufNormQueue.erase(key);
break;
}
conn_it->second = std::move(signal);
}

View File

@ -1066,6 +1066,9 @@ struct RTLIL::Design
pool<RTLIL::Monitor*> monitors;
dict<std::string, std::string> scratchpad;
bool flagBufferedNormalized = false;
void bufNormalize(bool enable=true);
int refcount_modules_;
dict<RTLIL::IdString, RTLIL::Module*> modules_;
std::vector<RTLIL::Binding*> bindings_;
@ -1210,6 +1213,9 @@ public:
std::vector<RTLIL::IdString> ports;
void fixup_ports();
pool<pair<RTLIL::Cell*, RTLIL::IdString>> bufNormQueue;
void bufNormalize();
template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
void cloneInto(RTLIL::Module *new_mod) const;
@ -1525,6 +1531,9 @@ public:
int width, start_offset, port_id;
bool port_input, port_output, upto, is_signed;
RTLIL::Cell *driverCell = nullptr;
RTLIL::IdString driverPort;
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Wire*> *get_all_wires(void);
#endif

View File

@ -83,11 +83,21 @@ struct BufnormPass : public Pass {
log(" -conn\n");
log(" Create 'direct connections' instead of buffer cells.\n");
log("\n");
log(" -nomode\n");
log(" Do not automatically enter or leave 'buffered-normalized mode'.\n");
log("\n");
log("The 'bufnorm' command can also be used to just switch in and out of\n");
log("'buffered-normalized mode' and run the low-level re-normalizer.\n");
log("\n");
log(" -update\n");
log(" Enter 'buffered-normalized mode' and (re-)normalize.\n");
log("\n");
log(" -reset\n");
log(" Leave 'buffered-normalized mode' without changing the netlist.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing BUFNORM pass (convert to buffer-normalized form).\n");
bool buf_mode = false;
bool chain_mode = false;
bool output_mode = false;
@ -97,66 +107,97 @@ struct BufnormPass : public Pass {
bool nosticky_mode = false;
bool alphasort_mode = false;
bool noinit_mode = false; // FIXME: Actually move init attributes
bool nomode_mode = false;
bool pos_mode = false;
bool bits_mode = false;
bool conn_mode = false;
bool update_mode = false;
bool reset_mode = false;
bool got_non_update_reset_opt = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
if (arg == "-buf") {
buf_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-chain") {
chain_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-output") {
output_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-public") {
public_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-nochain") {
nochain_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-nokeep") {
nokeep_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-flat") {
nochain_mode = true;
nokeep_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-nosticky") {
nosticky_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-alphasort") {
alphasort_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-noinit") {
noinit_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-pos") {
pos_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-bits") {
bits_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-conn") {
conn_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-nomode") {
nomode_mode = true;
got_non_update_reset_opt = true;
continue;
}
if (arg == "-update") {
update_mode = true;
continue;
}
if (arg == "-reset") {
reset_mode = true;
continue;
}
break;
@ -172,12 +213,38 @@ struct BufnormPass : public Pass {
if (pos_mode && conn_mode)
log_cmd_error("Options -pos and -conn are exclusive.\n");
if (update_mode && reset_mode)
log_cmd_error("Options -update and -reset are exclusive.\n");
if (update_mode && got_non_update_reset_opt)
log_cmd_error("Option -update can't be mixed with other options.\n");
if (reset_mode && got_non_update_reset_opt)
log_cmd_error("Option -reset can't be mixed with other options.\n");
if (update_mode) {
design->bufNormalize();
return;
}
if (reset_mode) {
design->bufNormalize(false);
return;
}
log_header(design, "Executing BUFNORM pass (convert to buffer-normalized form).\n");
int count_removed_buffers = 0;
int count_updated_buffers = 0;
int count_kept_buffers = 0;
int count_created_buffers = 0;
int count_updated_cellports = 0;
if (!nomode_mode && (pos_mode || bits_mode || conn_mode)) {
if (design->selection().full_selection)
design->bufNormalize(false);
}
for (auto module : design->selected_modules())
{
log("Buffer-normalizing module %s.\n", log_id(module));
@ -432,6 +499,11 @@ struct BufnormPass : public Pass {
log("Summary: removed %d, updated %d, kept %d, and created %d buffers, and updated %d cell ports.\n",
count_removed_buffers, count_updated_buffers, count_kept_buffers,
count_created_buffers, count_updated_cellports);
if (!nomode_mode && !(pos_mode || bits_mode || conn_mode)) {
if (design->selection().full_selection)
design->bufNormalize(true);
}
}
} BufnormPass;