From d0b5dfa6efaf8325be4dc50296647463db23d51f Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Wed, 27 Sep 2023 18:59:53 +0200 Subject: [PATCH 01/11] Add bufnorm pass Signed-off-by: Claire Xenia Wolf --- passes/techmap/Makefile.inc | 1 + passes/techmap/bufnorm.cc | 180 ++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 passes/techmap/bufnorm.cc diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 0282af79045..6bf40434d2d 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -41,6 +41,7 @@ OBJS += passes/techmap/nlutmap.o OBJS += passes/techmap/shregmap.o OBJS += passes/techmap/deminout.o OBJS += passes/techmap/insbuf.o +OBJS += passes/techmap/bufnorm.o OBJS += passes/techmap/attrmvcp.o OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o diff --git a/passes/techmap/bufnorm.cc b/passes/techmap/bufnorm.cc new file mode 100644 index 00000000000..77588bb6b3d --- /dev/null +++ b/passes/techmap/bufnorm.cc @@ -0,0 +1,180 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct BufnormPass : public Pass { + BufnormPass() : Pass("bufnorm", "convert design into buffered-normalized form") { } + void help() override + { + log("\n"); + log(" bufnorm [options] [selection]\n"); + log("\n"); + log("Insert buffer cells into the design as needed, to make sure that each wire\n"); + log("has exactly one driving cell port, and aliasing wires are buffered using a\n"); + log("chain of buffers in canonical order.\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 connections_mode = false, bits_mode = false; + IdString buf_celltype, buf_inport = ID::A, buf_outport = ID::Y; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + if (arg == "-conn") { + connections_mode = true; + continue; + } + if (arg == "-bits") { + bits_mode = true; + continue; + } + if (arg == "-buf" && argidx+3 < args.size()) { + buf_celltype = RTLIL::escape_id(args[++argidx]); + buf_inport = RTLIL::escape_id(args[++argidx]); + buf_outport = RTLIL::escape_id(args[++argidx]); + continue; + } + break; + } + extra_args(args, argidx, design); + + if (buf_celltype == IdString()) + buf_celltype = bits_mode ? ID($_BUF_) : ID($pos); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + module->new_connections({}); + + { + vector old_buffers; + for (auto cell : module->cells()) + { + if (cell->type == buf_celltype) + { + SigSpec insig = sigmap(cell->getPort(buf_inport)); + SigSpec outsig = sigmap(cell->getPort(buf_outport)); + for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) + sigmap.add(insig[i], outsig[i]); + old_buffers.push_back(cell); + } + else + { + for (auto &conn : cell->connections()) + { + if (!cell->output(conn.first) || conn.second.is_wire()) + continue; + SigSpec insig = module->addWire(NEW_ID, GetSize(conn.second)); + SigSpec outsig = sigmap(conn.second); + for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) + sigmap.add(insig[i], outsig[i]); + cell->setPort(conn.first, insig); + } + } + } + for (auto cell : old_buffers) + module->remove(cell); + } + + dict> bit2wires; + dict mapped_bits; + pool unmapped_wires; + + for (auto wire : module->wires()) + { + for (auto key : sigmap(wire)) + bit2wires[key].insert(wire); + + if (wire->port_input) { + for (auto bit : SigSpec(wire)) + mapped_bits[sigmap(bit)] = bit; + } else { + unmapped_wires.insert(wire); + } + } + + for (auto cell : module->cells()) + { + for (auto &conn : cell->connections()) + { + if (!cell->output(conn.first)) + continue; + + for (auto bit : conn.second) + mapped_bits[sigmap(bit)] = bit; + unmapped_wires.erase(conn.second.as_wire()); + } + } + + struct { + bool operator()(Wire *a, Wire *b) const { + if (a->port_id != b->port_id) + return a->port_id < b->port_id; + return a->name.str() < b->name.str(); + } + } compareWires; + + unmapped_wires.sort(compareWires); + + for (auto wire : unmapped_wires) + { + SigSpec keysig = sigmap(wire), insig = wire, outsig = wire; + for (int i = 0; i < GetSize(insig); i++) + insig[i] = mapped_bits.at(keysig[i], State::Sx); + for (int i = 0; i < GetSize(outsig); i++) + mapped_bits[keysig[i]] = outsig[i]; + + if (connections_mode) { + if (bits_mode) { + for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) + module->connect(outsig[i], insig[i]); + } else { + module->connect(outsig, insig); + } + } else { + if (bits_mode) { + for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) { + Cell *c = module->addCell(NEW_ID, buf_celltype); + c->setPort(buf_inport, insig[i]); + c->setPort(buf_outport, outsig[i]); + c->fixup_parameters(); + } + } else { + Cell *c = module->addCell(NEW_ID, buf_celltype); + c->setPort(buf_inport, insig); + c->setPort(buf_outport, outsig); + c->fixup_parameters(); + } + } + } + } + } +} BufnormPass; + +PRIVATE_NAMESPACE_END From 32808a03935a3874de0a4ac09dae121d4d25f45d Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Wed, 27 Sep 2023 19:27:08 +0200 Subject: [PATCH 02/11] Improvements and fixes to "bufnorm" cmd Signed-off-by: Claire Xenia Wolf --- passes/techmap/bufnorm.cc | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/passes/techmap/bufnorm.cc b/passes/techmap/bufnorm.cc index 77588bb6b3d..ff27c6c8cd6 100644 --- a/passes/techmap/bufnorm.cc +++ b/passes/techmap/bufnorm.cc @@ -69,6 +69,8 @@ struct BufnormPass : public Pass { for (auto module : design->selected_modules()) { + log("Buffer-normalizing module %s.\n", log_id(module)); + SigMap sigmap(module); module->new_connections({}); @@ -112,6 +114,7 @@ struct BufnormPass : public Pass { bit2wires[key].insert(wire); if (wire->port_input) { + log(" primary input: %s\n", log_id(module)); for (auto bit : SigSpec(wire)) mapped_bits[sigmap(bit)] = bit; } else { @@ -126,9 +129,14 @@ struct BufnormPass : public Pass { if (!cell->output(conn.first)) continue; + Wire *w = conn.second.as_wire(); + if (w->name.isPublic()) + log(" directly driven by cell %s port %s: %s\n", + log_id(cell), log_id(conn.first), log_id(w)); + for (auto bit : conn.second) mapped_bits[sigmap(bit)] = bit; - unmapped_wires.erase(conn.second.as_wire()); + unmapped_wires.erase(w); } } @@ -142,6 +150,8 @@ struct BufnormPass : public Pass { unmapped_wires.sort(compareWires); + pool added_buffers; + for (auto wire : unmapped_wires) { SigSpec keysig = sigmap(wire), insig = wire, outsig = wire; @@ -150,6 +160,8 @@ struct BufnormPass : public Pass { for (int i = 0; i < GetSize(outsig); i++) mapped_bits[keysig[i]] = outsig[i]; + log(" adding buffer for %s -> %s\n", log_signal(insig), log_signal(outsig)); + if (connections_mode) { if (bits_mode) { for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) @@ -164,12 +176,36 @@ struct BufnormPass : public Pass { c->setPort(buf_inport, insig[i]); c->setPort(buf_outport, outsig[i]); c->fixup_parameters(); + added_buffers.insert(c); } } else { Cell *c = module->addCell(NEW_ID, buf_celltype); c->setPort(buf_inport, insig); c->setPort(buf_outport, outsig); c->fixup_parameters(); + added_buffers.insert(c); + } + } + } + + for (auto cell : module->cells()) + { + if (added_buffers.count(cell)) + continue; + + for (auto &conn : cell->connections()) + { + if (cell->output(conn.first)) + continue; + + SigSpec newsig = conn.second; + for (auto &bit : newsig) + bit = mapped_bits[sigmap(bit)]; + + if (conn.second != newsig) { + log(" fixing input signal on cell %s port %s: %s\n", + log_id(cell), log_id(conn.first), log_signal(newsig)); + cell->setPort(conn.first, newsig); } } } From f4b7ea5fb3434f8e487cc329172accda1154d543 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Thu, 28 Sep 2023 20:42:07 +0200 Subject: [PATCH 03/11] Improvements in "bufnorm" pass Signed-off-by: Claire Xenia Wolf --- passes/techmap/bufnorm.cc | 186 +++++++++++++++++++++++++++++--------- 1 file changed, 141 insertions(+), 45 deletions(-) diff --git a/passes/techmap/bufnorm.cc b/passes/techmap/bufnorm.cc index ff27c6c8cd6..8e5bfa77537 100644 --- a/passes/techmap/bufnorm.cc +++ b/passes/techmap/bufnorm.cc @@ -31,8 +31,36 @@ struct BufnormPass : public Pass { log(" bufnorm [options] [selection]\n"); log("\n"); log("Insert buffer cells into the design as needed, to make sure that each wire\n"); - log("has exactly one driving cell port, and aliasing wires are buffered using a\n"); - log("chain of buffers in canonical order.\n"); + log("has exactly one driving cell port, and aliasing wires are buffered using\n"); + log("buffer cells, than can be chained in a canonical order.\n"); + log("\n"); + log("Running 'bufnorm' on the whole design enters 'buffered-normalized mode'.\n"); + log("The commands 'bufnorm -conn' exits 'buffered-normalized mode' again.\n"); + log("\n"); + log(" -bits\n"); + log(" Create single-bit $_BUF_ cells instead of multi-bit $pos cells.\n"); + log("\n"); + log(" -chain\n"); + log(" Chain all alias wires. By default only wires with the 'keep'\n"); + log(" attribute on them are chained.\n"); + log("\n"); + log(" -chain-outputs\n"); + log(" Chain ouput ports. (Uneffected by -flat.)\n"); + log("\n"); + log(" -flat\n"); + log(" Do not chain any wires, not even the ones marked with 'keep'.\n"); + log("\n"); + log(" -nosticky\n"); + log(" Disable 'sticky' behavior of output ports already driving whole\n"); + log(" wires, and always enforce canonical sort order instead.\n"); + log("\n"); + log(" -alphasort\n"); + log(" Strictly use alphanumeric sort for chain-order. (Default is\n"); + log(" to chain 'keep' wires first, then ports in declaration order,\n"); + log(" and then the other wires in alphanumeric sort order.)\n"); + log("\n"); + log(" -conn\n"); + log(" Remove buffers and exit 'buffered-normalized mode'.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override @@ -40,6 +68,8 @@ struct BufnormPass : public Pass { log_header(design, "Executing BUFNORM pass (convert to buffer-normalized form).\n"); bool connections_mode = false, bits_mode = false; + bool chain_mode = false, flat_mode = false, nosticky_mode = false; + bool chain_outputs_mode = false, alphasort_mode = false; IdString buf_celltype, buf_inport = ID::A, buf_outport = ID::Y; size_t argidx; @@ -54,16 +84,39 @@ struct BufnormPass : public Pass { bits_mode = true; continue; } - if (arg == "-buf" && argidx+3 < args.size()) { - buf_celltype = RTLIL::escape_id(args[++argidx]); - buf_inport = RTLIL::escape_id(args[++argidx]); - buf_outport = RTLIL::escape_id(args[++argidx]); + if (arg == "-chain") { + chain_mode = true; + continue; + } + if (arg == "-chain-outputs") { + chain_outputs_mode = true; + continue; + } + if (arg == "-flat") { + flat_mode = true; + continue; + } + if (arg == "-nosticky") { + nosticky_mode = true; continue; } + if (arg == "-alphasort") { + alphasort_mode = true; + continue; + } + //if (arg == "-buf" && argidx+3 < args.size()) { + // buf_celltype = RTLIL::escape_id(args[++argidx]); + // buf_inport = RTLIL::escape_id(args[++argidx]); + // buf_outport = RTLIL::escape_id(args[++argidx]); + // continue; + //} break; } extra_args(args, argidx, design); + if (chain_mode && flat_mode) + log_cmd_error("Options -chain and -flat are exclusive.\n"); + if (buf_celltype == IdString()) buf_celltype = bits_mode ? ID($_BUF_) : ID($pos); @@ -78,43 +131,34 @@ struct BufnormPass : public Pass { vector old_buffers; for (auto cell : module->cells()) { - if (cell->type == buf_celltype) - { - SigSpec insig = sigmap(cell->getPort(buf_inport)); - SigSpec outsig = sigmap(cell->getPort(buf_outport)); - for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) - sigmap.add(insig[i], outsig[i]); - old_buffers.push_back(cell); - } - else - { - for (auto &conn : cell->connections()) - { - if (!cell->output(conn.first) || conn.second.is_wire()) - continue; - SigSpec insig = module->addWire(NEW_ID, GetSize(conn.second)); - SigSpec outsig = sigmap(conn.second); - for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) - sigmap.add(insig[i], outsig[i]); - cell->setPort(conn.first, insig); - } - } + if (cell->type != buf_celltype) + continue; + + SigSpec insig = sigmap(cell->getPort(buf_inport)); + SigSpec outsig = sigmap(cell->getPort(buf_outport)); + for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) + sigmap.add(insig[i], outsig[i]); + old_buffers.push_back(cell); } for (auto cell : old_buffers) module->remove(cell); } dict> bit2wires; + dict> whole_wires; dict mapped_bits; pool unmapped_wires; for (auto wire : module->wires()) { - for (auto key : sigmap(wire)) - bit2wires[key].insert(wire); + SigSpec keysig = sigmap(wire); + whole_wires[keysig].insert(wire); + + for (auto keybit : sigmap(wire)) + bit2wires[keybit].insert(wire); if (wire->port_input) { - log(" primary input: %s\n", log_id(module)); + log(" primary input: %s\n", log_id(wire)); for (auto bit : SigSpec(wire)) mapped_bits[sigmap(bit)] = bit; } else { @@ -122,6 +166,36 @@ struct BufnormPass : public Pass { } } + struct { + bool alphasort_mode; + bool operator()(Wire *a, Wire *b) const + { + if (!alphasort_mode) + { + // Wires with keep attribute first + bool keep_a = a->get_bool_attribute(ID::keep); + bool keep_b = a->get_bool_attribute(ID::keep); + if (keep_a != keep_b) return keep_a; + + // Ports before non-ports + if ((a->port_id != 0) != (b->port_id != 0)) + return a->port_id != 0; + + // Ports in declaration order + if (a->port_id != b->port_id) + return a->port_id < b->port_id; + } + + // Nets with public names first + if (a->name.isPublic() != b->name.isPublic()) + return a->name.isPublic(); + + // Otherwise just sort by name alphanumerically + return a->name.str() < b->name.str(); + } + } compareWires; + compareWires.alphasort_mode = alphasort_mode; + for (auto cell : module->cells()) { for (auto &conn : cell->connections()) @@ -129,38 +203,60 @@ struct BufnormPass : public Pass { if (!cell->output(conn.first)) continue; - Wire *w = conn.second.as_wire(); + Wire *w = nullptr; + + if (!nosticky_mode && conn.second.is_wire()) + w = conn.second.as_wire(); + + if (w == nullptr) + { + SigSpec keysig = sigmap(conn.second); + auto it = whole_wires.find(keysig); + if (it != whole_wires.end()) { + it->second.sort(compareWires); + w = *(it->second.begin()); + } else { + w = module->addWire(NEW_ID, GetSize(conn.second)); + for (int i = 0; i < GetSize(w); i++) + sigmap.add(SigBit(w, i), keysig[i]); + } + } + if (w->name.isPublic()) log(" directly driven by cell %s port %s: %s\n", log_id(cell), log_id(conn.first), log_id(w)); - for (auto bit : conn.second) + for (auto bit : SigSpec(w)) mapped_bits[sigmap(bit)] = bit; unmapped_wires.erase(w); - } - } - struct { - bool operator()(Wire *a, Wire *b) const { - if (a->port_id != b->port_id) - return a->port_id < b->port_id; - return a->name.str() < b->name.str(); + cell->setPort(conn.first, w); } - } compareWires; - - unmapped_wires.sort(compareWires); + } pool added_buffers; + unmapped_wires.sort(compareWires); for (auto wire : unmapped_wires) { + bool chain_this_wire = chain_mode; + if (!flat_mode && wire->get_bool_attribute(ID::keep)) + chain_this_wire = true; + if (chain_outputs_mode && wire->port_output) + chain_this_wire = true; + SigSpec keysig = sigmap(wire), insig = wire, outsig = wire; for (int i = 0; i < GetSize(insig); i++) insig[i] = mapped_bits.at(keysig[i], State::Sx); - for (int i = 0; i < GetSize(outsig); i++) - mapped_bits[keysig[i]] = outsig[i]; + if (chain_this_wire) { + for (int i = 0; i < GetSize(outsig); i++) + mapped_bits[keysig[i]] = outsig[i]; + } - log(" adding buffer for %s -> %s\n", log_signal(insig), log_signal(outsig)); + log(" %s %s for %s -> %s\n", + chain_this_wire ? "chaining" : "adding", + connections_mode ? "connection" : "buffer", + log_signal(insig), log_signal(outsig)); if (connections_mode) { if (bits_mode) { From 4d469f461ba375b1562c2f3f252bb1854024c953 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Fri, 29 Sep 2023 07:03:23 +0200 Subject: [PATCH 04/11] Add coarse-grain $buf buffer cell type Signed-off-by: Claire Xenia Wolf --- kernel/calc.cc | 8 ++++++++ kernel/cellaigs.cc | 2 +- kernel/celledges.cc | 2 +- kernel/celltypes.h | 5 +++-- kernel/qcsat.cc | 2 +- kernel/rtlil.cc | 28 ++++++++++++++++++++++++++-- kernel/rtlil.h | 3 +++ kernel/satgen.cc | 6 +++--- techlibs/common/simlib.v | 20 +++++++++++++++++++- 9 files changed, 65 insertions(+), 11 deletions(-) diff --git a/kernel/calc.cc b/kernel/calc.cc index 9b02a6e30c8..a7de08f8977 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -601,6 +601,14 @@ RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, boo return arg1_ext; } +RTLIL::Const RTLIL::const_buf(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len) +{ + RTLIL::Const arg1_ext = arg1; + extend_u0(arg1_ext, result_len, signed1); + + return arg1_ext; +} + RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len) { RTLIL::Const arg1_ext = arg1; diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index 5dda4503fdd..de0a4939430 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -290,7 +290,7 @@ Aig::Aig(Cell *cell) } } - if (cell->type.in(ID($not), ID($_NOT_), ID($pos), ID($_BUF_))) + if (cell->type.in(ID($not), ID($_NOT_), ID($pos), ID($buf), ID($_BUF_))) { for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) { int A = mk.inport(ID::A, i); diff --git a/kernel/celledges.cc b/kernel/celledges.cc index 09cdfd55b96..0fbe17c56d3 100644 --- a/kernel/celledges.cc +++ b/kernel/celledges.cc @@ -392,7 +392,7 @@ PRIVATE_NAMESPACE_END bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell) { - if (cell->type.in(ID($not), ID($pos))) { + if (cell->type.in(ID($not), ID($pos), ID($buf))) { bitwise_unary_op(this, cell); return true; } diff --git a/kernel/celltypes.h b/kernel/celltypes.h index fde6624e179..9868827e699 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -114,7 +114,7 @@ struct CellTypes void setup_internals_eval() { std::vector unary_ops = { - ID($not), ID($pos), ID($neg), + ID($not), ID($pos), ID($buf), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not), ID($slice), ID($lut), ID($sop) }; @@ -339,7 +339,7 @@ struct CellTypes type = ID($shl); if (type != ID($sshr) && type != ID($sshl) && type != ID($shr) && type != ID($shl) && type != ID($shift) && type != ID($shiftx) && - type != ID($pos) && type != ID($neg) && type != ID($not)) { + type != ID($pos) && type != ID($buf) && type != ID($neg) && type != ID($not)) { if (!signed1 || !signed2) signed1 = false, signed2 = false; } @@ -381,6 +381,7 @@ struct CellTypes HANDLE_CELL_TYPE(modfloor) HANDLE_CELL_TYPE(pow) HANDLE_CELL_TYPE(pos) + HANDLE_CELL_TYPE(buf) HANDLE_CELL_TYPE(neg) #undef HANDLE_CELL_TYPE diff --git a/kernel/qcsat.cc b/kernel/qcsat.cc index aaee984fbaa..c9d00efa1cd 100644 --- a/kernel/qcsat.cc +++ b/kernel/qcsat.cc @@ -77,7 +77,7 @@ void QuickConeSat::prepare() int QuickConeSat::cell_complexity(RTLIL::Cell *cell) { - if (cell->type.in(ID($concat), ID($slice), ID($pos), ID($_BUF_))) + if (cell->type.in(ID($concat), ID($slice), ID($pos), ID($buf), ID($_BUF_))) return 0; if (cell->type.in(ID($not), ID($and), ID($or), ID($xor), ID($xnor), ID($reduce_and), ID($reduce_or), ID($reduce_xor), diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d62736e1587..96ded993d99 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1108,6 +1108,13 @@ namespace { cell->type.begins_with("$verific$") || cell->type.begins_with("$array:") || cell->type.begins_with("$extern:")) return; + if (cell->type == ID($buf)) { + port(ID::A, param(ID::WIDTH)); + port(ID::Y, param(ID::WIDTH)); + check_expected(); + return; + } + if (cell->type.in(ID($not), ID($pos), ID($neg))) { param_bool(ID::A_SIGNED); port(ID::A, param(ID::A_WIDTH)); @@ -2493,6 +2500,23 @@ DEF_METHOD(ReduceBool, 1, ID($reduce_bool)) DEF_METHOD(LogicNot, 1, ID($logic_not)) #undef DEF_METHOD +#define DEF_METHOD(_func, _y_size, _type) \ + RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool /* is_signed */, const std::string &src) { \ + RTLIL::Cell *cell = addCell(name, _type); \ + cell->parameters[ID::WIDTH] = sig_a.size(); \ + cell->setPort(ID::A, sig_a); \ + cell->setPort(ID::Y, sig_y); \ + cell->set_src_attribute(src); \ + return cell; \ + } \ + RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed, const std::string &src) { \ + RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \ + add ## _func(name, sig_a, sig_y, is_signed, src); \ + return sig_y; \ + } +DEF_METHOD(Buf, sig_a.size(), ID($buf)) +#undef DEF_METHOD + #define DEF_METHOD(_func, _y_size, _type) \ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed, const std::string &src) { \ RTLIL::Cell *cell = addCell(name, _type); \ @@ -3654,9 +3678,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:")) return; - if (type == ID($mux) || type == ID($pmux) || type == ID($bmux)) { + if (type == ID($buf) || type == ID($mux) || type == ID($pmux) || type == ID($bmux)) { parameters[ID::WIDTH] = GetSize(connections_[ID::Y]); - if (type != ID($mux)) + if (type != ID($buf) && type != ID($mux)) parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]); check(); return; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 3191987113a..ba01c6a1bb4 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -503,6 +503,7 @@ namespace RTLIL RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); + RTLIL::Const const_buf (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_mux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3); @@ -1280,6 +1281,7 @@ struct RTLIL::Module : public RTLIL::AttrObject RTLIL::Cell* addNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addPos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addBuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addNeg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); @@ -1414,6 +1416,7 @@ struct RTLIL::Module : public RTLIL::AttrObject RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec Buf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); diff --git a/kernel/satgen.cc b/kernel/satgen.cc index a6db78868a3..946343c6324 100644 --- a/kernel/satgen.cc +++ b/kernel/satgen.cc @@ -430,7 +430,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) return true; } - if (cell->type.in(ID($pos), ID($neg))) + if (cell->type.in(ID($pos), ID($buf), ID($neg))) { std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); @@ -438,7 +438,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - if (cell->type == ID($pos)) { + if (cell->type.in(ID($pos), ID($buf))) { ez->assume(ez->vec_eq(a, yy)); } else { std::vector zero(a.size(), ez->CONST_FALSE); @@ -451,7 +451,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidthUnary(undef_a, undef_y, cell); - if (cell->type == ID($pos)) { + if (cell->type.in(ID($pos), ID($buf))) { ez->assume(ez->vec_eq(undef_a, undef_y)); } else { int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 5bbad34f677..5593cfe0e9a 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -58,7 +58,6 @@ endgenerate endmodule - // -------------------------------------------------------- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -88,6 +87,25 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $buf (A, Y) +//- +//- A simple coarse-grain buffer cell type. +//- +module \$buf (A, Y); + +parameter WIDTH = 0; + +input [WIDTH-1:0] A; +output [WIDTH-1:0] Y; + +assign Y = A; + +endmodule + +// -------------------------------------------------------- + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| //- //- $neg (A, Y) From d027ead4b582e285731d386ea3c60d72778f3f0d Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Fri, 29 Sep 2023 07:04:22 +0200 Subject: [PATCH 05/11] Improvements in "bufnorm" pass Signed-off-by: Claire Xenia Wolf --- kernel/constids.inc | 1 + passes/techmap/bufnorm.cc | 225 ++++++++++++++++++++++++++------------ 2 files changed, 154 insertions(+), 72 deletions(-) diff --git a/kernel/constids.inc b/kernel/constids.inc index 00db94af441..3052afb49e1 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -43,6 +43,7 @@ X(CE_OVER_SRST) X(CFG_ABITS) X(CFG_DBITS) X(CFG_INIT) +X(chain) X(CI) X(CLK) X(clkbuf_driver) diff --git a/passes/techmap/bufnorm.cc b/passes/techmap/bufnorm.cc index 8e5bfa77537..0aba2a75073 100644 --- a/passes/techmap/bufnorm.cc +++ b/passes/techmap/bufnorm.cc @@ -35,20 +35,29 @@ struct BufnormPass : public Pass { log("buffer cells, than can be chained in a canonical order.\n"); log("\n"); log("Running 'bufnorm' on the whole design enters 'buffered-normalized mode'.\n"); - log("The commands 'bufnorm -conn' exits 'buffered-normalized mode' again.\n"); log("\n"); - log(" -bits\n"); - log(" Create single-bit $_BUF_ cells instead of multi-bit $pos cells.\n"); + log(" -buf\n"); + log(" Create $buf cells for all buffers. The default is to use $_BUF_ cells\n"); + log(" for sigle-bit buffers and $buf cells only for multi-bit buffers.\n"); log("\n"); log(" -chain\n"); - log(" Chain all alias wires. By default only wires with the 'keep'\n"); - log(" attribute on them are chained.\n"); + log(" Chain all alias wires. By default only wires with positive-valued\n"); + log(" 'chain' or 'keep' attribute on them are chained.\n"); + log("\n"); + log(" -output\n"); + log(" Enable chaining of ouput ports wires.\n"); + log("\n"); + log(" -public\n"); + log(" Enable chaining of wires wth public names.\n"); + log("\n"); + log(" -nochain\n"); + log(" Disable chaining of wires with 'chain' attribute.\n"); log("\n"); - log(" -chain-outputs\n"); - log(" Chain ouput ports. (Uneffected by -flat.)\n"); + log(" -nokeep\n"); + log(" Disable chaining of wires with 'keep' attribute.\n"); log("\n"); log(" -flat\n"); - log(" Do not chain any wires, not even the ones marked with 'keep'.\n"); + log(" Alias for -nokeep and -nochain.\n"); log("\n"); log(" -nosticky\n"); log(" Disable 'sticky' behavior of output ports already driving whole\n"); @@ -59,41 +68,71 @@ struct BufnormPass : public Pass { log(" to chain 'keep' wires first, then ports in declaration order,\n"); log(" and then the other wires in alphanumeric sort order.)\n"); log("\n"); + log(" -noinit\n"); + log(" Do not move 'init' attributes to the wires on FF output ports.\n"); + log("\n"); + log("Run 'bufnorm' with -pos, -bits, or -conn on the whole design to remove all\n"); + log("$buf buffer cells and exit 'buffered-normalized mode' again.\n"); + log("\n"); + log(" -pos\n"); + log(" Create (multi- and single-bit) $pos cells instead $buf and $_BUF_.\n"); + log("\n"); + log(" -bits\n"); + log(" Create arrays of $_BUF_ cells instead of multi-bit $buf cells.\n"); + log("\n"); log(" -conn\n"); - log(" Remove buffers and exit 'buffered-normalized mode'.\n"); + log(" Create 'direct connections' instead of buffer cells.\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 connections_mode = false, bits_mode = false; - bool chain_mode = false, flat_mode = false, nosticky_mode = false; - bool chain_outputs_mode = false, alphasort_mode = false; - IdString buf_celltype, buf_inport = ID::A, buf_outport = ID::Y; + bool buf_mode = false; + bool chain_mode = false; + bool output_mode = false; + bool public_mode = false; + bool nochain_mode = false; + bool nokeep_mode = false; + bool nosticky_mode = false; + bool alphasort_mode = false; + bool noinit_mode = false; // FIXME: Actually move init attributes + + bool pos_mode = false; + bool bits_mode = false; + bool conn_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; - if (arg == "-conn") { - connections_mode = true; - continue; - } - if (arg == "-bits") { - bits_mode = true; + if (arg == "-buf") { + buf_mode = true; continue; } if (arg == "-chain") { chain_mode = true; continue; } - if (arg == "-chain-outputs") { - chain_outputs_mode = true; + if (arg == "-output") { + output_mode = true; + continue; + } + if (arg == "-public") { + public_mode = true; + continue; + } + if (arg == "-nochain") { + nochain_mode = true; + continue; + } + if (arg == "-nokeep") { + nokeep_mode = true; continue; } if (arg == "-flat") { - flat_mode = true; + nochain_mode = true; + nokeep_mode = true; continue; } if (arg == "-nosticky") { @@ -104,21 +143,34 @@ struct BufnormPass : public Pass { alphasort_mode = true; continue; } - //if (arg == "-buf" && argidx+3 < args.size()) { - // buf_celltype = RTLIL::escape_id(args[++argidx]); - // buf_inport = RTLIL::escape_id(args[++argidx]); - // buf_outport = RTLIL::escape_id(args[++argidx]); - // continue; - //} + if (arg == "-noinit") { + noinit_mode = true; + continue; + } + if (arg == "-pos") { + pos_mode = true; + continue; + } + if (arg == "-bits") { + bits_mode = true; + continue; + } + if (arg == "-conn") { + conn_mode = true; + continue; + } break; } extra_args(args, argidx, design); - if (chain_mode && flat_mode) - log_cmd_error("Options -chain and -flat are exclusive.\n"); + if (buf_mode && pos_mode) + log_cmd_error("Options -buf and -pos are exclusive.\n"); + + if (buf_mode && conn_mode) + log_cmd_error("Options -buf and -conn are exclusive.\n"); - if (buf_celltype == IdString()) - buf_celltype = bits_mode ? ID($_BUF_) : ID($pos); + if (pos_mode && conn_mode) + log_cmd_error("Options -pos and -conn are exclusive.\n"); for (auto module : design->selected_modules()) { @@ -131,11 +183,11 @@ struct BufnormPass : public Pass { vector old_buffers; for (auto cell : module->cells()) { - if (cell->type != buf_celltype) + if (!cell->type.in(ID($buf), ID($_BUF_))) continue; - SigSpec insig = sigmap(cell->getPort(buf_inport)); - SigSpec outsig = sigmap(cell->getPort(buf_outport)); + SigSpec insig = sigmap(cell->getPort(ID::A)); + SigSpec outsig = sigmap(cell->getPort(ID::Y)); for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) sigmap.add(insig[i], outsig[i]); old_buffers.push_back(cell); @@ -166,35 +218,65 @@ struct BufnormPass : public Pass { } } - struct { - bool alphasort_mode; - bool operator()(Wire *a, Wire *b) const + auto chain_this_wire_f = [&](Wire *wire) + { + if (chain_mode) + return true; + + if (output_mode && wire->port_output) + return true; + + if (public_mode && wire->name.isPublic()) + return true; + + if (!nokeep_mode && wire->get_bool_attribute(ID::keep)) + return true; + + if (!nochain_mode && wire->get_bool_attribute(ID::chain)) + return true; + + return false; + }; + + auto compare_wires_f = [&](Wire *a, Wire *b) + { + // Chaining wires first, then flat wires + bool chain_a = chain_this_wire_f(a); + bool chain_b = chain_this_wire_f(b); + if (chain_a != chain_b) return chain_a; + + if (!alphasort_mode) { - if (!alphasort_mode) - { - // Wires with keep attribute first + // Wires with 'chain' attribute first, high values before low values + if (!nochain_mode) { + int chain_a_val = a->attributes.at(ID::chain, Const(0)).as_int(); + int chain_b_val = b->attributes.at(ID::chain, Const(0)).as_int(); + if (chain_a_val != chain_b_val) return chain_a_val > chain_b_val; + } + + // Then wires with 'keep' attribute + if (!nokeep_mode) { bool keep_a = a->get_bool_attribute(ID::keep); - bool keep_b = a->get_bool_attribute(ID::keep); + bool keep_b = b->get_bool_attribute(ID::keep); if (keep_a != keep_b) return keep_a; - - // Ports before non-ports - if ((a->port_id != 0) != (b->port_id != 0)) - return a->port_id != 0; - - // Ports in declaration order - if (a->port_id != b->port_id) - return a->port_id < b->port_id; } - // Nets with public names first - if (a->name.isPublic() != b->name.isPublic()) - return a->name.isPublic(); + // Ports before non-ports + if ((a->port_id != 0) != (b->port_id != 0)) + return a->port_id != 0; - // Otherwise just sort by name alphanumerically - return a->name.str() < b->name.str(); + // Ports in declaration order + if (a->port_id != b->port_id) + return a->port_id < b->port_id; } - } compareWires; - compareWires.alphasort_mode = alphasort_mode; + + // Nets with public names first + if (a->name.isPublic() != b->name.isPublic()) + return a->name.isPublic(); + + // Otherwise just sort by name alphanumerically + return a->name.str() < b->name.str(); + }; for (auto cell : module->cells()) { @@ -213,7 +295,7 @@ struct BufnormPass : public Pass { SigSpec keysig = sigmap(conn.second); auto it = whole_wires.find(keysig); if (it != whole_wires.end()) { - it->second.sort(compareWires); + it->second.sort(compare_wires_f); w = *(it->second.begin()); } else { w = module->addWire(NEW_ID, GetSize(conn.second)); @@ -236,14 +318,10 @@ struct BufnormPass : public Pass { pool added_buffers; - unmapped_wires.sort(compareWires); + unmapped_wires.sort(compare_wires_f); for (auto wire : unmapped_wires) { - bool chain_this_wire = chain_mode; - if (!flat_mode && wire->get_bool_attribute(ID::keep)) - chain_this_wire = true; - if (chain_outputs_mode && wire->port_output) - chain_this_wire = true; + bool chain_this_wire = chain_this_wire_f(wire); SigSpec keysig = sigmap(wire), insig = wire, outsig = wire; for (int i = 0; i < GetSize(insig); i++) @@ -255,10 +333,10 @@ struct BufnormPass : public Pass { log(" %s %s for %s -> %s\n", chain_this_wire ? "chaining" : "adding", - connections_mode ? "connection" : "buffer", + conn_mode ? "connection" : "buffer", log_signal(insig), log_signal(outsig)); - if (connections_mode) { + if (conn_mode) { if (bits_mode) { for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) module->connect(outsig[i], insig[i]); @@ -267,17 +345,20 @@ struct BufnormPass : public Pass { } } else { if (bits_mode) { + IdString celltype = pos_mode ? ID($pos) : buf_mode ? ID($buf) : ID($_BUF_); for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) { - Cell *c = module->addCell(NEW_ID, buf_celltype); - c->setPort(buf_inport, insig[i]); - c->setPort(buf_outport, outsig[i]); + Cell *c = module->addCell(NEW_ID, celltype); + c->setPort(ID::A, insig[i]); + c->setPort(ID::Y, outsig[i]); c->fixup_parameters(); added_buffers.insert(c); } } else { - Cell *c = module->addCell(NEW_ID, buf_celltype); - c->setPort(buf_inport, insig); - c->setPort(buf_outport, outsig); + IdString celltype = pos_mode ? ID($pos) : buf_mode ? ID($buf) : + GetSize(outsig) == 1 ? ID($_BUF_) : ID($buf); + Cell *c = module->addCell(NEW_ID, celltype); + c->setPort(ID::A, insig); + c->setPort(ID::Y, outsig); c->fixup_parameters(); added_buffers.insert(c); } From 8bb70bac8db5a4e555a1a1457935b1b4164d4c35 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Fri, 29 Sep 2023 10:03:36 +0200 Subject: [PATCH 06/11] Improvements in "bufnorm" pass Signed-off-by: Claire Xenia Wolf --- passes/techmap/bufnorm.cc | 79 ++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 17 deletions(-) diff --git a/passes/techmap/bufnorm.cc b/passes/techmap/bufnorm.cc index 0aba2a75073..4ca96d53014 100644 --- a/passes/techmap/bufnorm.cc +++ b/passes/techmap/bufnorm.cc @@ -172,6 +172,12 @@ struct BufnormPass : public Pass { if (pos_mode && conn_mode) log_cmd_error("Options -pos and -conn are exclusive.\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; + for (auto module : design->selected_modules()) { log("Buffer-normalizing module %s.\n", log_id(module)); @@ -179,21 +185,29 @@ struct BufnormPass : public Pass { SigMap sigmap(module); module->new_connections({}); + dict, Cell*> old_buffers; + { - vector old_buffers; + vector old_dup_buffers; for (auto cell : module->cells()) { if (!cell->type.in(ID($buf), ID($_BUF_))) continue; - SigSpec insig = sigmap(cell->getPort(ID::A)); - SigSpec outsig = sigmap(cell->getPort(ID::Y)); + SigSpec insig = cell->getPort(ID::A); + SigSpec outsig = cell->getPort(ID::Y); for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) sigmap.add(insig[i], outsig[i]); - old_buffers.push_back(cell); + + pair key(cell->type, outsig.as_wire()); + if (old_buffers.count(key)) + old_dup_buffers.push_back(cell); + else + old_buffers[key] = cell; } - for (auto cell : old_buffers) + for (auto cell : old_dup_buffers) module->remove(cell); + count_removed_buffers += GetSize(old_dup_buffers); } dict> bit2wires; @@ -280,6 +294,9 @@ struct BufnormPass : public Pass { for (auto cell : module->cells()) { + if (cell->type.in(ID($buf), ID($_BUF_))) + continue; + for (auto &conn : cell->connections()) { if (!cell->output(conn.first)) @@ -318,6 +335,34 @@ struct BufnormPass : public Pass { pool added_buffers; + auto make_buffer_f = [&](const IdString &type, const SigSpec &src, const SigSpec &dst) + { + auto it = old_buffers.find(pair(type, dst)); + + if (it != old_buffers.end()) + { + Cell *cell = it->second; + old_buffers.erase(it); + added_buffers.insert(cell); + + if (cell->getPort(ID::A) == src) { + count_kept_buffers++; + } else { + cell->setPort(ID::A, src); + count_updated_buffers++; + } + return; + } + + Cell *cell = module->addCell(NEW_ID, type); + added_buffers.insert(cell); + + cell->setPort(ID::A, src); + cell->setPort(ID::Y, dst); + cell->fixup_parameters(); + count_created_buffers++; + }; + unmapped_wires.sort(compare_wires_f); for (auto wire : unmapped_wires) { @@ -346,25 +391,20 @@ struct BufnormPass : public Pass { } else { if (bits_mode) { IdString celltype = pos_mode ? ID($pos) : buf_mode ? ID($buf) : ID($_BUF_); - for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) { - Cell *c = module->addCell(NEW_ID, celltype); - c->setPort(ID::A, insig[i]); - c->setPort(ID::Y, outsig[i]); - c->fixup_parameters(); - added_buffers.insert(c); - } + for (int i = 0; i < GetSize(insig) && i < GetSize(outsig); i++) + make_buffer_f(celltype, insig[i], outsig[i]); } else { IdString celltype = pos_mode ? ID($pos) : buf_mode ? ID($buf) : GetSize(outsig) == 1 ? ID($_BUF_) : ID($buf); - Cell *c = module->addCell(NEW_ID, celltype); - c->setPort(ID::A, insig); - c->setPort(ID::Y, outsig); - c->fixup_parameters(); - added_buffers.insert(c); + make_buffer_f(celltype, insig, outsig); } } } + for (auto &it : old_buffers) + module->remove(it.second); + count_removed_buffers += GetSize(old_buffers); + for (auto cell : module->cells()) { if (added_buffers.count(cell)) @@ -383,10 +423,15 @@ struct BufnormPass : public Pass { log(" fixing input signal on cell %s port %s: %s\n", log_id(cell), log_id(conn.first), log_signal(newsig)); cell->setPort(conn.first, newsig); + count_updated_cellports++; } } } } + + 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); } } BufnormPass; From 80119386c07dbc18dd2174309f17b6e8e5b2bcc2 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Fri, 29 Sep 2023 15:49:15 +0200 Subject: [PATCH 07/11] Add RTLIL "buffered-normalized mode" and improve "bufnorm" pass Signed-off-by: Claire Xenia Wolf --- backends/rtlil/rtlil_backend.cc | 27 +++++-- backends/rtlil/rtlil_backend.h | 6 +- kernel/rtlil.cc | 133 ++++++++++++++++++++++++++++++++ kernel/rtlil.h | 9 +++ passes/techmap/bufnorm.cc | 76 +++++++++++++++++- 5 files changed, 238 insertions(+), 13 deletions(-) diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc index 032954d8cd6..e6f8daf9619 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 35829729c56..21d79d8ecf9 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 96ded993d99..eaba0fe3178 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 ba01c6a1bb4..3e4c92af3ba 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 @@ struct RTLIL::Module : public RTLIL::AttrObject 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 @@ struct RTLIL::Wire : public RTLIL::AttrObject 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 4ca96d53014..b3aed1b8e03 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; From 865df26facfe26edc2238d1294d67277dbff7210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 21 May 2024 13:08:40 +0200 Subject: [PATCH 08/11] Adjust buf-normalized mode --- backends/rtlil/rtlil_backend.cc | 26 ++++++++++------------ backends/rtlil/rtlil_backend.h | 6 +++--- kernel/celledges.cc | 2 +- kernel/rtlil.cc | 38 +++++++++++++++++++-------------- kernel/rtlil.h | 14 ++++++++++-- 5 files changed, 49 insertions(+), 37 deletions(-) diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc index e6f8daf9619..ddc4769f6d7 100644 --- a/backends/rtlil/rtlil_backend.cc +++ b/backends/rtlil/rtlil_backend.cc @@ -118,16 +118,16 @@ 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, bool flag_d) +void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire) { 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()); + if (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) @@ -302,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, bool flag_d) +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 print_header = flag_m || design->selected_whole_module(module->name); bool print_body = !flag_n || !design->selected_whole_module(module->name); @@ -339,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, flag_d); + dump_wire(f, indent + " ", it); } for (auto it : module->memories) @@ -388,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, bool flag_d) +void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n) { int init_autoidx = autoidx; @@ -414,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, flag_d); + dump_module(f, "", module, design, only_selected, flag_m, flag_n); } } @@ -460,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, false); + RTLIL_BACKEND::dump_design(*f, design, selected, true, false); } } RTLILBackend; @@ -510,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, flag_d = false, append = false; + bool flag_m = false, flag_n = false, append = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -534,10 +534,6 @@ struct DumpPass : public Pass { flag_n = true; continue; } - if (arg == "-d") { - flag_d = true; - continue; - } break; } extra_args(args, argidx, design); @@ -559,7 +555,7 @@ struct DumpPass : public Pass { f = &buf; } - RTLIL_BACKEND::dump_design(*f, design, true, flag_m, flag_n, flag_d); + RTLIL_BACKEND::dump_design(*f, design, true, flag_m, flag_n); if (!empty) { delete f; diff --git a/backends/rtlil/rtlil_backend.h b/backends/rtlil/rtlil_backend.h index 21d79d8ecf9..35829729c56 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, bool flag_d = false); + void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire); 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, 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); + 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); } YOSYS_NAMESPACE_END diff --git a/kernel/celledges.cc b/kernel/celledges.cc index 0fbe17c56d3..bad7124d9b1 100644 --- a/kernel/celledges.cc +++ b/kernel/celledges.cc @@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) { - bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); + bool is_signed = (cell->type != ID($buf)) && cell->getParam(ID::A_SIGNED).as_bool(); int a_width = GetSize(cell->getPort(ID::A)); int y_width = GetSize(cell->getPort(ID::Y)); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index eaba0fe3178..2d313537895 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3575,10 +3575,12 @@ void RTLIL::Design::bufNormalize(bool enable) for (auto module : modules()) { module->bufNormQueue.clear(); for (auto wire : module->wires()) { - wire->driverCell = nullptr; - wire->driverPort = IdString(); + wire->driverCell_ = nullptr; + wire->driverPort_ = IdString(); } } + + flagBufferedNormalized = false; return; } @@ -3592,9 +3594,9 @@ void RTLIL::Design::bufNormalize(bool enable) continue; if (conn.second.is_wire()) { Wire *wire = conn.second.as_wire(); - log_assert(wire->driverCell == nullptr); - wire->driverCell = cell; - wire->driverPort = conn.first; + log_assert(wire->driverCell_ == nullptr); + wire->driverCell_ = cell; + wire->driverPort_ = conn.first; } else { pair key(cell, conn.first); module->bufNormQueue.insert(key); @@ -3614,7 +3616,7 @@ void RTLIL::Module::bufNormalize() if (!design->flagBufferedNormalized) return; - while (GetSize(bufNormQueue)) + while (GetSize(bufNormQueue) || !connections_.empty()) { pool> queue; bufNormQueue.swap(queue); @@ -3636,9 +3638,13 @@ void RTLIL::Module::bufNormalize() if (sig.is_wire()) { Wire *wire = sig.as_wire(); - log_assert(wire->driverCell == nullptr); - wire->driverCell = cell; - wire->driverPort = portname; + if (wire->driverCell_) { + log_error("Conflict between %s %s in module %s\n", + log_id(cell), log_id(wire->driverCell_), log_id(this)); + } + log_assert(wire->driverCell_ == nullptr); + wire->driverCell_ = cell; + wire->driverPort_ = portname; continue; } @@ -3688,9 +3694,9 @@ void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal 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 (w->driverCell_ == this && w->driverPort_ == portname) { + w->driverCell_ = nullptr; + w->driverPort_ = IdString(); } } @@ -3705,12 +3711,12 @@ void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal } Wire *w = signal.as_wire(); - if (w->driverCell != nullptr) { - pair other_key(w->driverCell, w->driverPort); + if (w->driverCell_ != nullptr) { + pair other_key(w->driverCell_, w->driverPort_); module->bufNormQueue.insert(other_key); } - w->driverCell = this; - w->driverPort = portname; + w->driverCell_ = this; + w->driverPort_ = portname; module->bufNormQueue.erase(key); break; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 3e4c92af3ba..c49734cd08b 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1510,6 +1510,10 @@ struct RTLIL::Module : public RTLIL::AttrObject #endif }; +namespace RTLIL_BACKEND { +void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire); +} + struct RTLIL::Wire : public RTLIL::AttrObject { unsigned int hashidx_; @@ -1521,6 +1525,12 @@ struct RTLIL::Wire : public RTLIL::AttrObject Wire(); ~Wire(); + friend struct RTLIL::Design; + friend struct RTLIL::Cell; + friend void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire); + RTLIL::Cell *driverCell_ = nullptr; + RTLIL::IdString driverPort_; + public: // do not simply copy wires Wire(RTLIL::Wire &other) = delete; @@ -1531,8 +1541,8 @@ struct RTLIL::Wire : public RTLIL::AttrObject int width, start_offset, port_id; bool port_input, port_output, upto, is_signed; - RTLIL::Cell *driverCell = nullptr; - RTLIL::IdString driverPort; + RTLIL::Cell *driverCell() const { log_assert(driverCell_); return driverCell_; }; + RTLIL::IdString driverPort() const { log_assert(driverCell_); return driverPort_; }; #ifdef WITH_PYTHON static std::map *get_all_wires(void); From 38de01807e6cfc711903181f677bb3c07f1f13a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 11 Sep 2024 11:12:36 +0200 Subject: [PATCH 09/11] Mark `bufnorm` experimental --- passes/techmap/bufnorm.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/passes/techmap/bufnorm.cc b/passes/techmap/bufnorm.cc index b3aed1b8e03..75060673ea0 100644 --- a/passes/techmap/bufnorm.cc +++ b/passes/techmap/bufnorm.cc @@ -24,7 +24,9 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct BufnormPass : public Pass { - BufnormPass() : Pass("bufnorm", "convert design into buffered-normalized form") { } + BufnormPass() : Pass("bufnorm", "(experimental) convert design into buffered-normalized form") { + experimental(); + } void help() override { log("\n"); From e13ace675e3536d41199d70cb10445fcfedbc63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 16 Sep 2024 14:42:53 +0200 Subject: [PATCH 10/11] dump: Update help after option removal --- backends/rtlil/rtlil_backend.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc index ddc4769f6d7..434992cc7b3 100644 --- a/backends/rtlil/rtlil_backend.cc +++ b/backends/rtlil/rtlil_backend.cc @@ -497,9 +497,6 @@ 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"); From eeffca947037ddba7efb834d6784dba1e8dfa5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 17 Sep 2024 10:46:07 +0200 Subject: [PATCH 11/11] simlib: Add `$buf` disclaimer --- techlibs/common/simlib.v | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 5593cfe0e9a..60f98af2838 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -91,7 +91,9 @@ endmodule //- //- $buf (A, Y) //- -//- A simple coarse-grain buffer cell type. +//- A simple coarse-grain buffer cell type for the experimental buffered-normalized +//- mode. Note this cell does't get removed by 'opt_clean' and is not recommended +//- for general use. //- module \$buf (A, Y);