diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc index 032954d8c..e6f8daf96 100644 --- a/backends/rtlil/rtlil_backend.cc +++ b/backends/rtlil/rtlil_backend.cc @@ -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 \n"); log(" write to the specified file.\n"); log("\n"); @@ -503,7 +510,7 @@ struct DumpPass : public Pass { void execute(std::vector 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; diff --git a/backends/rtlil/rtlil_backend.h b/backends/rtlil/rtlil_backend.h index 35829729c..21d79d8ec 100644 --- a/backends/rtlil/rtlil_backend.h +++ b/backends/rtlil/rtlil_backend.h @@ -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 diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 96ded993d..eaba0fe31 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -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 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> queue; + bufNormQueue.swap(queue); + + pool 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 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 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); } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index ba01c6a1b..3e4c92af3 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1066,6 +1066,9 @@ struct RTLIL::Design pool monitors; dict scratchpad; + bool flagBufferedNormalized = false; + void bufNormalize(bool enable=true); + int refcount_modules_; dict modules_; std::vector bindings_; @@ -1210,6 +1213,9 @@ public: std::vector ports; void fixup_ports(); + pool> bufNormQueue; + void bufNormalize(); + template void rewrite_sigspecs(T &functor); template 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 *get_all_wires(void); #endif diff --git a/passes/techmap/bufnorm.cc b/passes/techmap/bufnorm.cc index 4ca96d530..b3aed1b8e 100644 --- a/passes/techmap/bufnorm.cc +++ b/passes/techmap/bufnorm.cc @@ -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 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;