From f4c62f33ac56bc5725c44ad822e75d2387f98061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Mon, 12 Aug 2019 15:57:43 +0000 Subject: Add clock buffer insertion pass, improve iopadmap. A few new attributes are defined for use in cell libraries: - iopad_external_pin: marks PAD cell's external-facing pin. Pad insertion will be skipped for ports that are already connected to such a pin. - clkbuf_sink: marks an input pin as a clock pin, requesting clock buffer insertion. - clkbuf_driver: marks an output pin as a clock buffer output pin. Clock buffer insertion will be skipped for nets that are already driven by such a pin. All three are module attributes that should be set to a comma-separeted list of pin names. Clock buffer insertion itself works as follows: 1. All cell ports, starting from bottom up, can be marked as clock sinks (requesting clock buffer insertion) or as clock buffer outputs. 2. If a wire in a given module is driven by a cell port that is a clock buffer output, it is in turn also considered a clock buffer output. 3. If an input port in a non-top module is connected to a clock sink in a contained cell, it is also in turn considered a clock sink. 4. If a wire in a module is driven by a non-clock-buffer cell, and is also connected to a clock sink port in a contained cell, a clock buffer is inserted in this module. 5. For the top module, a clock buffer is also inserted on input ports connected to clock sinks, optionally with a special kind of input PAD (such as IBUFG for Xilinx). 6. Clock buffer insertion on a given wire is skipped if the clkbuf_inhibit attribute is set on it. --- passes/techmap/Makefile.inc | 1 + passes/techmap/clkbufmap.cc | 299 ++++++++++++++++++++++++++++++++++++++++++++ passes/techmap/iopadmap.cc | 76 ++++++++--- 3 files changed, 356 insertions(+), 20 deletions(-) create mode 100644 passes/techmap/clkbufmap.cc (limited to 'passes') diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 56f05eca4..631a80aa5 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -16,6 +16,7 @@ endif ifneq ($(SMALL),1) OBJS += passes/techmap/iopadmap.o +OBJS += passes/techmap/clkbufmap.o OBJS += passes/techmap/hilomap.o OBJS += passes/techmap/extract.o OBJS += passes/techmap/extract_fa.o diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc new file mode 100644 index 000000000..9ecc83071 --- /dev/null +++ b/passes/techmap/clkbufmap.cc @@ -0,0 +1,299 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford 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 + +void split_portname_pair(std::string &port1, std::string &port2) +{ + size_t pos = port1.find_first_of(':'); + if (pos != std::string::npos) { + port2 = port1.substr(pos+1); + port1 = port1.substr(0, pos); + } +} + +std::vector split(std::string text, const char *delim) +{ + std::vector list; + char *p = strdup(text.c_str()); + char *t = strtok(p, delim); + while (t != NULL) { + list.push_back(t); + t = strtok(NULL, delim); + } + free(p); + return list; +} + +struct ClkbufmapPass : public Pass { + ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { } + void help() YS_OVERRIDE + { + log("\n"); + log(" clkbufmap [options] [selection]\n"); + log("\n"); + log("Inserts global buffers between nets connected to clock inputs and their\n"); + log("drivers.\n"); + log("\n"); + log(" -buf :\n"); + log(" Specifies the cell type to use for the global buffers\n"); + log(" and its port names. The first port will be connected to\n"); + log(" the clock network sinks, and the second will be connected\n"); + log(" to the actual clock source. This option is required.\n"); + log("\n"); + log(" -inpad :\n"); + log(" If specified, a PAD cell of the given type is inserted on\n"); + log(" clock nets that are also top module's inputs (in addition\n"); + log(" to the global buffer).\n"); + log("\n"); + } + + void module_queue(Design *design, Module *module, std::vector &modules_sorted, pool &modules_processed) { + if (modules_processed.count(module)) + return; + for (auto cell : module->cells()) { + Module *submodule = design->module(cell->type); + if (!submodule) + continue; + module_queue(design, submodule, modules_sorted, modules_processed); + } + modules_sorted.push_back(module); + modules_processed.insert(module); + } + + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing CLKBUFMAP pass (inserting global clock buffers).\n"); + + std::string buf_celltype, buf_portname, buf_portname2; + std::string inpad_celltype, inpad_portname, inpad_portname2; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + if (arg == "-buf" && argidx+2 < args.size()) { + buf_celltype = args[++argidx]; + buf_portname = args[++argidx]; + split_portname_pair(buf_portname, buf_portname2); + continue; + } + if (arg == "-inpad" && argidx+2 < args.size()) { + inpad_celltype = args[++argidx]; + inpad_portname = args[++argidx]; + split_portname_pair(inpad_portname, inpad_portname2); + continue; + } + break; + } + extra_args(args, argidx, design); + + if (buf_celltype.empty()) + log_error("The -buf option is required."); + + // Cell type, port name, bit index. + pool>> sink_ports; + pool>> buf_ports; + + // Process submodules before module using them. + std::vector modules_sorted; + pool modules_processed; + for (auto module : design->selected_modules()) + module_queue(design, module, modules_sorted, modules_processed); + + for (auto module : modules_sorted) + { + if (module->get_blackbox_attribute()) { + auto it = module->attributes.find("\\clkbuf_driver"); + if (it != module->attributes.end()) { + auto value = it->second.decode_string(); + for (auto name : split(value, ",")) { + auto wire = module->wire(RTLIL::escape_id(name)); + if (!wire) + log_error("Module %s does not have port %s.\n", log_id(module), log_id(name)); + for (int i = 0; i < GetSize(wire); i++) + buf_ports.insert(make_pair(module->name, make_pair(RTLIL::escape_id(name), i))); + } + } + it = module->attributes.find("\\clkbuf_sink"); + if (it != module->attributes.end()) { + auto value = it->second.decode_string(); + for (auto name : split(value, ",")) { + auto wire = module->wire(RTLIL::escape_id(name)); + if (!wire) + log_error("Module %s does not have port %s.\n", log_id(module), log_id(name)); + for (int i = 0; i < GetSize(wire); i++) + sink_ports.insert(make_pair(module->name, make_pair(RTLIL::escape_id(name), i))); + } + } + continue; + } + pool sink_wire_bits; + pool buf_wire_bits; + pool driven_wire_bits; + SigMap sigmap(module); + // bit -> (buffer, buffer's input) + dict> buffered_bits; + + // First, collect nets that could use a clock buffer. + for (auto cell : module->cells()) + for (auto port : cell->connections()) + for (int i = 0; i < port.second.size(); i++) + if (sink_ports.count(make_pair(cell->type, make_pair(port.first, i)))) + sink_wire_bits.insert(sigmap(port.second[i])); + + // Second, collect ones that already have a clock buffer. + for (auto cell : module->cells()) + for (auto port : cell->connections()) + for (int i = 0; i < port.second.size(); i++) + if (buf_ports.count(make_pair(cell->type, make_pair(port.first, i)))) + buf_wire_bits.insert(sigmap(port.second[i])); + + // Collect all driven bits. + for (auto cell : module->cells()) + for (auto port : cell->connections()) + if (cell->output(port.first)) + for (int i = 0; i < port.second.size(); i++) + driven_wire_bits.insert(port.second[i]); + + // Insert buffers. + std::vector> input_queue; + for (auto wire : module->selected_wires()) + { + // Should not happen. + if (wire->port_input && wire->port_output) + continue; + if (wire->get_bool_attribute("\\clkbuf_inhibit")) + continue; + + pool input_bits; + + for (int i = 0; i < GetSize(wire); i++) + { + SigBit wire_bit(wire, i); + SigBit mapped_wire_bit = sigmap(wire_bit); + if (buf_wire_bits.count(mapped_wire_bit)) { + // Already buffered downstream. If this is an output, mark it. + if (wire->port_output) + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + } else if (!sink_wire_bits.count(mapped_wire_bit)) { + // Nothing to do. + } else if (driven_wire_bits.count(wire_bit) || (wire->port_input && module->get_bool_attribute("\\top"))) { + // Clock network not yet buffered, driven by one of + // our cells or a top-level input -- buffer it. + + log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i); + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype)); + Wire *iwire = module->addWire(NEW_ID); + cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit); + cell->setPort(RTLIL::escape_id(buf_portname2), iwire); + if (wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute("\\top")) { + log("Inserting %s on %s.%s[%d].\n", inpad_celltype.c_str(), log_id(module), log_id(wire), i); + RTLIL::Cell *cell2 = module->addCell(NEW_ID, RTLIL::escape_id(inpad_celltype)); + cell2->setPort(RTLIL::escape_id(inpad_portname), iwire); + iwire = module->addWire(NEW_ID); + cell2->setPort(RTLIL::escape_id(inpad_portname2), iwire); + } + buffered_bits[mapped_wire_bit] = make_pair(cell, iwire); + + if (wire->port_input) { + input_bits.insert(i); + } + } else if (wire->port_input) { + // A clock input in a submodule -- mark it, let higher level + // worry about it. + if (wire->port_input) + sink_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + } + } + if (!input_bits.empty()) { + // This is an input port and some buffers were inserted -- we need + // to create a new input wire and transfer attributes. + Wire *new_wire = module->addWire(NEW_ID, wire); + + for (int i = 0; i < wire->width; i++) { + SigBit wire_bit(wire, i); + SigBit mapped_wire_bit = sigmap(wire_bit); + auto it = buffered_bits.find(mapped_wire_bit); + if (it != buffered_bits.end()) { + + module->connect(it->second.second, SigSpec(new_wire, i)); + } else { + module->connect(SigSpec(wire, i), SigSpec(new_wire, i)); + } + } + input_queue.push_back(make_pair(wire, new_wire)); + } + } + + // Mark any newly-buffered output ports as such. + for (auto wire : module->selected_wires()) { + if (wire->port_input || !wire->port_output) + continue; + for (int i = 0; i < GetSize(wire); i++) + { + SigBit wire_bit(wire, i); + SigBit mapped_wire_bit = sigmap(wire_bit); + if (buffered_bits.count(mapped_wire_bit)) + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + } + } + + // Reconnect the drivers to buffer inputs. + for (auto cell : module->cells()) + for (auto port : cell->connections()) { + if (!cell->output(port.first)) + continue; + SigSpec sig = port.second; + bool newsig = false; + for (auto &bit : sig) { + const auto it = buffered_bits.find(sigmap(bit)); + if (it == buffered_bits.end()) + continue; + // Avoid substituting buffer's own output pin. + if (cell == it->second.first) + continue; + bit = it->second.second; + newsig = true; + } + if (newsig) + cell->setPort(port.first, sig); + } + + // This has to be done last, to avoid upsetting sigmap before the port reconnections. + for (auto &it : input_queue) { + Wire *wire = it.first; + Wire *new_wire = it.second; + module->swap_names(new_wire, wire); + wire->attributes.clear(); + wire->port_id = 0; + wire->port_input = false; + wire->port_output = false; + } + + module->fixup_ports(); + } + } +} ClkbufmapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index efcc082d5..e3d68ab0c 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -32,6 +32,19 @@ void split_portname_pair(std::string &port1, std::string &port2) } } +std::vector split(std::string text, const char *delim) +{ + std::vector list; + char *p = strdup(text.c_str()); + char *t = strtok(p, delim); + while (t != NULL) { + list.push_back(t); + t = strtok(NULL, delim); + } + free(p); + return list; +} + struct IopadmapPass : public Pass { IopadmapPass() : Pass("iopadmap", "technology mapping of i/o pads (or buffers)") { } void help() YS_OVERRIDE @@ -64,6 +77,11 @@ struct IopadmapPass : public Pass { log(" of the tristate driver and the 2nd portname is the internal output\n"); log(" buffering the external signal.\n"); log("\n"); + log(" -ignore [:]*\n"); + log(" Skips mapping inputs/outputs that are already connected to given\n"); + log(" ports of the given cell. Can be used multiple times. This is in\n"); + log(" addition to the cells specified as mapping targets.\n"); + log("\n"); log(" -widthparam \n"); log(" Use the specified parameter name to set the port width.\n"); log("\n"); @@ -88,6 +106,7 @@ struct IopadmapPass : public Pass { std::string toutpad_celltype, toutpad_portname, toutpad_portname2, toutpad_portname3; std::string tinoutpad_celltype, tinoutpad_portname, tinoutpad_portname2, tinoutpad_portname3, tinoutpad_portname4; std::string widthparam, nameparam; + pool> ignore; bool flag_bits = false; size_t argidx; @@ -127,6 +146,18 @@ struct IopadmapPass : public Pass { split_portname_pair(tinoutpad_portname3, tinoutpad_portname4); continue; } + if (arg == "-ignore" && argidx+2 < args.size()) { + std::string ignore_celltype = args[++argidx]; + std::string ignore_portname = args[++argidx]; + std::string ignore_portname2; + while (!ignore_portname.empty()) { + split_portname_pair(ignore_portname, ignore_portname2); + ignore.insert(make_pair(RTLIL::escape_id(ignore_celltype), RTLIL::escape_id(ignore_portname))); + + ignore_portname = ignore_portname2; + } + continue; + } if (arg == "-widthparam" && argidx+1 < args.size()) { widthparam = args[++argidx]; continue; @@ -143,6 +174,28 @@ struct IopadmapPass : public Pass { } extra_args(args, argidx, design); + if (!inpad_portname2.empty()) + ignore.insert(make_pair(RTLIL::escape_id(inpad_celltype), RTLIL::escape_id(inpad_portname2))); + if (!outpad_portname2.empty()) + ignore.insert(make_pair(RTLIL::escape_id(outpad_celltype), RTLIL::escape_id(outpad_portname2))); + if (!inoutpad_portname2.empty()) + ignore.insert(make_pair(RTLIL::escape_id(inoutpad_celltype), RTLIL::escape_id(inoutpad_portname2))); + if (!toutpad_portname3.empty()) + ignore.insert(make_pair(RTLIL::escape_id(toutpad_celltype), RTLIL::escape_id(toutpad_portname3))); + if (!tinoutpad_portname4.empty()) + ignore.insert(make_pair(RTLIL::escape_id(tinoutpad_celltype), RTLIL::escape_id(tinoutpad_portname4))); + + for (auto module : design->modules()) + { + auto it = module->attributes.find("\\iopad_external_pin"); + if (it != module->attributes.end()) { + auto value = it->second.decode_string(); + for (auto name : split(value, ",")) { + ignore.insert(make_pair(module->name, RTLIL::escape_id(name))); + } + } + } + for (auto module : design->selected_modules()) { dict> skip_wires; @@ -150,28 +203,11 @@ struct IopadmapPass : public Pass { SigMap sigmap(module); for (auto cell : module->cells()) - { - if (cell->type == RTLIL::escape_id(inpad_celltype) && cell->hasPort(RTLIL::escape_id(inpad_portname2))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inpad_portname2)))) - skip_wire_bits.insert(bit); - - if (cell->type == RTLIL::escape_id(outpad_celltype) && cell->hasPort(RTLIL::escape_id(outpad_portname2))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(outpad_portname2)))) - skip_wire_bits.insert(bit); - - if (cell->type == RTLIL::escape_id(inoutpad_celltype) && cell->hasPort(RTLIL::escape_id(inoutpad_portname2))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inoutpad_portname2)))) + for (auto port : cell->connections()) + if (ignore.count(make_pair(cell->type, port.first))) + for (auto bit : sigmap(port.second)) skip_wire_bits.insert(bit); - if (cell->type == RTLIL::escape_id(toutpad_celltype) && cell->hasPort(RTLIL::escape_id(toutpad_portname3))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(toutpad_portname3)))) - skip_wire_bits.insert(bit); - - if (cell->type == RTLIL::escape_id(tinoutpad_celltype) && cell->hasPort(RTLIL::escape_id(tinoutpad_portname4))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(tinoutpad_portname4)))) - skip_wire_bits.insert(bit); - } - if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty()) { dict>> tbuf_bits; -- cgit v1.2.3 From c6d5b97b98e6edc395ee14ad60430f7ebc264f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Tue, 13 Aug 2019 00:35:54 +0000 Subject: review fixes --- passes/techmap/clkbufmap.cc | 18 +++--------------- passes/techmap/iopadmap.cc | 15 +-------------- 2 files changed, 4 insertions(+), 29 deletions(-) (limited to 'passes') diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc index 9ecc83071..a2d10c48b 100644 --- a/passes/techmap/clkbufmap.cc +++ b/passes/techmap/clkbufmap.cc @@ -2,6 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2019 Marcin Koƛcielnicki * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -32,19 +33,6 @@ void split_portname_pair(std::string &port1, std::string &port2) } } -std::vector split(std::string text, const char *delim) -{ - std::vector list; - char *p = strdup(text.c_str()); - char *t = strtok(p, delim); - while (t != NULL) { - list.push_back(t); - t = strtok(NULL, delim); - } - free(p); - return list; -} - struct ClkbufmapPass : public Pass { ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { } void help() YS_OVERRIDE @@ -127,7 +115,7 @@ struct ClkbufmapPass : public Pass { auto it = module->attributes.find("\\clkbuf_driver"); if (it != module->attributes.end()) { auto value = it->second.decode_string(); - for (auto name : split(value, ",")) { + for (auto name : split_tokens(value, ",")) { auto wire = module->wire(RTLIL::escape_id(name)); if (!wire) log_error("Module %s does not have port %s.\n", log_id(module), log_id(name)); @@ -138,7 +126,7 @@ struct ClkbufmapPass : public Pass { it = module->attributes.find("\\clkbuf_sink"); if (it != module->attributes.end()) { auto value = it->second.decode_string(); - for (auto name : split(value, ",")) { + for (auto name : split_tokens(value, ",")) { auto wire = module->wire(RTLIL::escape_id(name)); if (!wire) log_error("Module %s does not have port %s.\n", log_id(module), log_id(name)); diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index e3d68ab0c..0fcb6b2ec 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -32,19 +32,6 @@ void split_portname_pair(std::string &port1, std::string &port2) } } -std::vector split(std::string text, const char *delim) -{ - std::vector list; - char *p = strdup(text.c_str()); - char *t = strtok(p, delim); - while (t != NULL) { - list.push_back(t); - t = strtok(NULL, delim); - } - free(p); - return list; -} - struct IopadmapPass : public Pass { IopadmapPass() : Pass("iopadmap", "technology mapping of i/o pads (or buffers)") { } void help() YS_OVERRIDE @@ -190,7 +177,7 @@ struct IopadmapPass : public Pass { auto it = module->attributes.find("\\iopad_external_pin"); if (it != module->attributes.end()) { auto value = it->second.decode_string(); - for (auto name : split(value, ",")) { + for (auto name : split_tokens(value, ",")) { ignore.insert(make_pair(module->name, RTLIL::escape_id(name))); } } -- cgit v1.2.3 From 3c75a72feb1cf83fa8fc138aa69155446b6b74f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Tue, 13 Aug 2019 19:36:59 +0000 Subject: move attributes to wires --- passes/techmap/clkbufmap.cc | 24 +++++------------------- passes/techmap/iopadmap.cc | 13 ++++--------- 2 files changed, 9 insertions(+), 28 deletions(-) (limited to 'passes') diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc index a2d10c48b..6fac1b437 100644 --- a/passes/techmap/clkbufmap.cc +++ b/passes/techmap/clkbufmap.cc @@ -112,27 +112,13 @@ struct ClkbufmapPass : public Pass { for (auto module : modules_sorted) { if (module->get_blackbox_attribute()) { - auto it = module->attributes.find("\\clkbuf_driver"); - if (it != module->attributes.end()) { - auto value = it->second.decode_string(); - for (auto name : split_tokens(value, ",")) { - auto wire = module->wire(RTLIL::escape_id(name)); - if (!wire) - log_error("Module %s does not have port %s.\n", log_id(module), log_id(name)); + for (auto wire : module->wires()) { + if (wire->get_bool_attribute("\\clkbuf_driver")) for (int i = 0; i < GetSize(wire); i++) - buf_ports.insert(make_pair(module->name, make_pair(RTLIL::escape_id(name), i))); - } - } - it = module->attributes.find("\\clkbuf_sink"); - if (it != module->attributes.end()) { - auto value = it->second.decode_string(); - for (auto name : split_tokens(value, ",")) { - auto wire = module->wire(RTLIL::escape_id(name)); - if (!wire) - log_error("Module %s does not have port %s.\n", log_id(module), log_id(name)); + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + if (wire->get_bool_attribute("\\clkbuf_sink")) for (int i = 0; i < GetSize(wire); i++) - sink_ports.insert(make_pair(module->name, make_pair(RTLIL::escape_id(name), i))); - } + sink_ports.insert(make_pair(module->name, make_pair(wire->name, i))); } continue; } diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index 0fcb6b2ec..5fe965600 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -173,15 +173,10 @@ struct IopadmapPass : public Pass { ignore.insert(make_pair(RTLIL::escape_id(tinoutpad_celltype), RTLIL::escape_id(tinoutpad_portname4))); for (auto module : design->modules()) - { - auto it = module->attributes.find("\\iopad_external_pin"); - if (it != module->attributes.end()) { - auto value = it->second.decode_string(); - for (auto name : split_tokens(value, ",")) { - ignore.insert(make_pair(module->name, RTLIL::escape_id(name))); - } - } - } + if (module->get_blackbox_attribute()) + for (auto wire : module->wires()) + if (wire->get_bool_attribute("\\iopad_external_pin")) + ignore.insert(make_pair(module->name, wire->name)); for (auto module : design->selected_modules()) { -- cgit v1.2.3 From 193eae0c84860c65bd5dd135b7e59c0c11ea76b0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Aug 2019 19:48:16 -0700 Subject: techmap -max_iter to apply to each module individually --- passes/techmap/techmap.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index b271c8781..a6c1214a7 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -943,7 +943,8 @@ struct TechmapPass : public Pass { log(" instead of inlining them.\n"); log("\n"); log(" -max_iter \n"); - log(" only run the specified number of iterations.\n"); + log(" only run the specified number of iterations for each module.\n"); + log(" default: unlimited\n"); log("\n"); log(" -recursive\n"); log(" instead of the iterative breadth-first algorithm use a recursive\n"); @@ -1157,15 +1158,16 @@ struct TechmapPass : public Pass { RTLIL::Module *module = *worker.module_queue.begin(); worker.module_queue.erase(module); + int module_max_iter = max_iter; bool did_something = true; std::set handled_cells; while (did_something) { did_something = false; - if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) - did_something = true; + if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) + did_something = true; if (did_something) module->check(); - if (max_iter > 0 && --max_iter == 0) + if (module_max_iter > 0 && --module_max_iter == 0) break; } } -- cgit v1.2.3 From fe61dcce8b70236b29691fa56c562d17497d3567 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Aug 2019 20:05:51 -0700 Subject: Grammar --- passes/techmap/techmap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index a6c1214a7..c4496f76f 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -943,7 +943,7 @@ struct TechmapPass : public Pass { log(" instead of inlining them.\n"); log("\n"); log(" -max_iter \n"); - log(" only run the specified number of iterations for each module.\n"); + log(" only run the specified number of iterations on each module.\n"); log(" default: unlimited\n"); log("\n"); log(" -recursive\n"); -- cgit v1.2.3 From 9b9d75945194f98e08b46e8e506832542ebf73ad Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Aug 2019 20:18:51 -0700 Subject: Fix copy-paste typo --- passes/pmgen/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 790811d4c..382a1b4ad 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -17,7 +17,7 @@ $(eval $(call add_extra_objs,passes/pmgen/ice40_dsp_pm.h)) OBJS += passes/pmgen/ice40_wrapcarry.o passes/pmgen/ice40_wrapcarry.o: passes/pmgen/ice40_wrapcarry_pm.h -$(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h)) +$(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h)) # -------------------------------------- -- cgit v1.2.3 From 948b6f91a140dafa4bd47177769eb4974d08f203 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 21 Aug 2019 17:00:24 +0200 Subject: Fix test_pmgen deps --- passes/pmgen/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 382a1b4ad..8e0cbdca8 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -4,7 +4,7 @@ # -------------------------------------- OBJS += passes/pmgen/test_pmgen.o -passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h +passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h $(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h)) # -------------------------------------- -- cgit v1.2.3 From d3a212ff91de5e4f082f2c133becd4338661ac16 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 21 Aug 2019 19:18:05 -0700 Subject: opt_expr to trim A port of $shiftx if Y_WIDTH == 1 --- passes/opt/opt_expr.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'passes') diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 858b3560c..b56ce252f 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -745,6 +745,23 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } + if (cell->type == ID($shiftx) && cell->getPort(ID::Y).size() == 1) { + SigSpec sig_a = assign_map(cell->getPort(ID::A)); + int width; + for (width = GetSize(sig_a); width > 1; width--) { + if (sig_a[width-1] != State::Sx) + break; + } + + if (width < GetSize(sig_a)) { + sig_a.remove(width, GetSize(sig_a)-width); + cell->setPort(ID::A, sig_a); + cell->setParam(ID(A_WIDTH), width); + did_something = true; + goto next_cell; + } + } + if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && cell->getPort(ID::Y).size() == 1 && invert_map.count(assign_map(cell->getPort(ID::A))) != 0) { cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str()); -- cgit v1.2.3 From d0ffe7544cd3c808857f3a99bbf330de61c618f2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 22 Aug 2019 08:05:01 -0700 Subject: Canonical form --- passes/opt/opt_expr.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index b56ce252f..7fdfa82bd 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -369,7 +369,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (auto cell : module->cells()) if (design->selected(module, cell) && cell->type[0] == '$') { if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && - cell->getPort(ID::A).size() == 1 && cell->getPort(ID::Y).size() == 1) + GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1) invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID::A)); if (cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == SigSpec(State::S1) && cell->getPort(ID::B) == SigSpec(State::S0)) @@ -740,12 +740,12 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt))) replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx); else - replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort(ID::Y).size())); + replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, GetSize(cell->getPort(ID::Y)))); goto next_cell; } } - if (cell->type == ID($shiftx) && cell->getPort(ID::Y).size() == 1) { + if (cell->type == ID($shiftx) && GetSize(cell->getPort(ID::Y)) == 1) { SigSpec sig_a = assign_map(cell->getPort(ID::A)); int width; for (width = GetSize(sig_a); width > 1; width--) { @@ -762,7 +762,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } - if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && cell->getPort(ID::Y).size() == 1 && + if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && GetSize(cell->getPort(ID::Y)) == 1 && invert_map.count(assign_map(cell->getPort(ID::A))) != 0) { cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str()); replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A)))); @@ -1159,7 +1159,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (mux_undef && cell->type.in(ID($mux), ID($pmux))) { RTLIL::SigSpec new_a, new_b, new_s; - int width = cell->getPort(ID::A).size(); + int width = GetSize(cell->getPort(ID::A)); if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) || cell->getPort(ID(S)).is_fully_undef()) { cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str()); -- cgit v1.2.3 From 9e31f01b343a9b246430419e81da647e75bd1626 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 22 Aug 2019 08:06:24 -0700 Subject: Add cover() --- passes/opt/opt_expr.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'passes') diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 7fdfa82bd..aca15e5f2 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -754,6 +754,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (width < GetSize(sig_a)) { + cover("opt.opt_expr.trim_shiftx"); sig_a.remove(width, GetSize(sig_a)-width); cell->setPort(ID::A, sig_a); cell->setParam(ID(A_WIDTH), width); -- cgit v1.2.3 From 379f33af5489850ef8e2e58ef12ff5b22da87711 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 22 Aug 2019 08:22:23 -0700 Subject: Handle $shift and Y_WIDTH > 1 as per @cliffordwolf --- passes/opt/opt_expr.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index aca15e5f2..c4da613ab 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -745,16 +745,20 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } - if (cell->type == ID($shiftx) && GetSize(cell->getPort(ID::Y)) == 1) { + if (cell->type.in(ID($shiftx), ID($shift))) { SigSpec sig_a = assign_map(cell->getPort(ID::A)); int width; + bool trim_x = true; + bool trim_0 = cell->type == ID($shift); for (width = GetSize(sig_a); width > 1; width--) { - if (sig_a[width-1] != State::Sx) - break; + if ((trim_x && sig_a[width-1] == State::Sx) || + (trim_0 && sig_a[width-1] == State::S0)) + continue; + break; } if (width < GetSize(sig_a)) { - cover("opt.opt_expr.trim_shiftx"); + cover_list("opt.opt_expr.xbit", "$shiftx", "$shift", cell->type.str()); sig_a.remove(width, GetSize(sig_a)-width); cell->setPort(ID::A, sig_a); cell->setParam(ID(A_WIDTH), width); -- cgit v1.2.3 From 6f971470f83b8e4ed29232be4b6cb5da89d50dc0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 22 Aug 2019 08:37:27 -0700 Subject: Respect opt_expr -keepdc as per @cliffordwolf --- passes/opt/opt_expr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index c4da613ab..73f48317a 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -748,7 +748,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (cell->type.in(ID($shiftx), ID($shift))) { SigSpec sig_a = assign_map(cell->getPort(ID::A)); int width; - bool trim_x = true; + bool trim_x = cell->type == ID($shiftx) || !keepdc; bool trim_0 = cell->type == ID($shift); for (width = GetSize(sig_a); width > 1; width--) { if ((trim_x && sig_a[width-1] == State::Sx) || -- cgit v1.2.3 From 9245f0d3f564644290b6650b3f8f642789062e9e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 22 Aug 2019 08:43:44 -0700 Subject: Copy-paste typo --- passes/opt/opt_expr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 73f48317a..00d7d6063 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -758,7 +758,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (width < GetSize(sig_a)) { - cover_list("opt.opt_expr.xbit", "$shiftx", "$shift", cell->type.str()); + cover_list("opt.opt_expr.trim", "$shiftx", "$shift", cell->type.str()); sig_a.remove(width, GetSize(sig_a)-width); cell->setPort(ID::A, sig_a); cell->setParam(ID(A_WIDTH), width); -- cgit v1.2.3 From c50d68653d093a8daa47f589836e6178be82b54f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 22 Aug 2019 14:20:03 -0700 Subject: Spelling --- passes/equiv/equiv_make.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc index dbd8682e6..4855ce29e 100644 --- a/passes/equiv/equiv_make.cc +++ b/passes/equiv/equiv_make.cc @@ -532,10 +532,10 @@ struct EquivMakePass : public Pass { log_cmd_error("Equiv module %s already exists.\n", args[argidx+2].c_str()); if (worker.gold_mod->has_memories() || worker.gold_mod->has_processes()) - log_cmd_error("Gold module contains memories or procresses. Run 'memory' or 'proc' respectively.\n"); + log_cmd_error("Gold module contains memories or processes. Run 'memory' or 'proc' respectively.\n"); if (worker.gate_mod->has_memories() || worker.gate_mod->has_processes()) - log_cmd_error("Gate module contains memories or procresses. Run 'memory' or 'proc' respectively.\n"); + log_cmd_error("Gate module contains memories or processes. Run 'memory' or 'proc' respectively.\n"); worker.read_blacklists(); worker.read_encfiles(); -- cgit v1.2.3 From 51ffb093b5beeb5e2c687d2bf34b13d246f3fc7d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 22 Aug 2019 16:42:19 -0700 Subject: In sat: 'x' in init attr should not override constant --- passes/sat/sat.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes') diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index dd56d8c71..bcc690fa3 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -268,6 +268,8 @@ struct SatHelper RTLIL::SigSpec removed_bits; for (int i = 0; i < lhs.size(); i++) { RTLIL::SigSpec bit = lhs.extract(i, 1); + if (bit.is_fully_const() && rhs[i] == State::Sx) + rhs[i] = bit; if (!satgen.initial_state.check_all(bit)) { removed_bits.append(bit); lhs.remove(i, 1); -- cgit v1.2.3 From adb81ba3861d66a94f237fd29a67b8978980cd37 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 23 Aug 2019 16:15:50 +0200 Subject: Add pmgen slices and choices Signed-off-by: Clifford Wolf --- passes/pmgen/README.md | 48 ++++++++++++++++-- passes/pmgen/pmgen.py | 116 ++++++++++++++++++++++++++++++++++++-------- passes/pmgen/test_pmgen.cc | 53 +++++++++++++++++++- passes/pmgen/test_pmgen.pmg | 87 ++++++++++++++++++++++++++++++++- 4 files changed, 276 insertions(+), 28 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index 5f6a8ab1b..27ed77091 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -178,6 +178,45 @@ evaluates to `false`. The `semioptional` statement marks matches that must match if at least one matching cell exists, but if no matching cell exists it is set to `nullptr`. +Slices and choices +------------------ + +Cell matches can contain "slices" and "choices". Slices can be used to +create matches for different sections of a cell. For example: + + state pmux_slice + + match pmux + select pmux->type == $pmux + slice idx GetSize(port(pmux, \S)) + index port(pmux, \S)[idx] === port(eq, \Y) + set pmux_slice idx + endmatch + +The first argument to `slice` is the local variable name used to identify the +slice. The second argument is the number of slices that should be created for +this cell. The `set` statement can be used to copy that index indo a state +variable so that later matches and/or code blocks can refer to it. + +A similar mechanism is "choices", where a list of options is given as +second argument, and the matcher will iterate over those options: + + state foo bar + state eq_ab eq_ba + + match eq + select eq->type == $eq + choice AB {\A, \B} + define BA (AB == \A ? \B : \A) + index port(eq, AB) === foo + index port(eq, BA) === bar + set eq_ab AB + set eq_ba BA + generate + +Notice how `define` can be used to define additional local variables similar +to the loop variables defined by `slice` and `choice`. + Additional code --------------- @@ -326,7 +365,7 @@ test-case generation. For example: match mul ... - generate 10 + generate 10 0 SigSpec Y = port(ff, \D); SigSpec A = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2)); SigSpec B = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2)); @@ -335,8 +374,11 @@ test-case generation. For example: The expression `rng(n)` returns a non-negative integer less than `n`. -The argument to `generate` is the chance of this generate block being executed -when the match block did not match anything, in percent. +The first argument to `generate` is the chance of this generate block being +executed when the match block did not match anything, in percent. + +The second argument to `generate` is the chance of this generate block being +executed when the match block did match something, in percent. The special statement `finish` can be used within generate blocks to terminate the current pattern matcher run. diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 18c3bf5a5..c2621393d 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -207,9 +207,10 @@ def process_pmgfile(f, filename): state_types[current_pattern][line[1]] = "Cell*"; block["if"] = list() - block["select"] = list() + block["setup"] = list() block["index"] = list() block["filter"] = list() + block["sets"] = list() block["optional"] = False block["semioptional"] = False @@ -228,7 +229,22 @@ def process_pmgfile(f, filename): if a[0] == "select": b = l.lstrip()[6:] - block["select"].append(rewrite_cpp(b.strip())) + block["setup"].append(("select", rewrite_cpp(b.strip()))) + continue + + if a[0] == "slice": + m = re.match(r"^\s*slice\s+(\S+)\s+(.*?)\s*$", l) + block["setup"].append(("slice", m.group(1), rewrite_cpp(m.group(2)))) + continue + + if a[0] == "choice": + m = re.match(r"^\s*choice\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l) + block["setup"].append(("choice", m.group(1), m.group(2), rewrite_cpp(m.group(3)))) + continue + + if a[0] == "define": + m = re.match(r"^\s*define\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l) + block["setup"].append(("define", m.group(1), m.group(2), rewrite_cpp(m.group(3)))) continue if a[0] == "index": @@ -242,6 +258,11 @@ def process_pmgfile(f, filename): block["filter"].append(rewrite_cpp(b.strip())) continue + if a[0] == "set": + m = re.match(r"^\s*set\s+(\S+)\s+(.*?)\s*$", l) + block["sets"].append((m.group(1), rewrite_cpp(m.group(2)))) + continue + if a[0] == "optional": block["optional"] = True continue @@ -252,14 +273,16 @@ def process_pmgfile(f, filename): if a[0] == "generate": block["genargs"] = list([int(s) for s in a[1:]]) + if len(block["genargs"]) == 0: block["genargs"].append(100) + if len(block["genargs"]) == 1: block["genargs"].append(0) + assert len(block["genargs"]) == 2 block["gencode"] = list() - assert len(block["genargs"]) < 2 while True: linenr += 1 l = f.readline() assert l != "" a = l.split() - if a[0] == "endmatch": break + if len(a) == 1 and a[0] == "endmatch": break block["gencode"].append(rewrite_cpp(l.rstrip())) break @@ -357,8 +380,17 @@ with open(outfile, "w") as f: index_types = list() for entry in block["index"]: index_types.append(entry[0]) + value_types = ["Cell*"] + for entry in block["setup"]: + if entry[0] == "slice": + value_types.append("int") + if entry[0] == "choice": + value_types.append(entry[1]) + if entry[0] == "define": + value_types.append(entry[1]) print(" typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f) - print(" dict> index_{};".format(index, index), file=f) + print(" typedef std::tuple<{}> index_{}_value_type;".format(", ".join(value_types), index), file=f) + print(" dict> index_{};".format(index, index, index), file=f) print(" dict> sigusers;", file=f) print(" pool blacklist_cells;", file=f) print(" pool autoremove_cells;", file=f) @@ -457,12 +489,34 @@ with open(outfile, "w") as f: if block["type"] == "match": print(" do {", file=f) print(" Cell *{} = cell;".format(block["cell"]), file=f) - for expr in block["select"]: - print(" if (!({})) break;".format(expr), file=f) + print(" index_{}_value_type value;".format(index), file=f) + print(" std::get<0>(value) = cell;", file=f) + loopcnt = 0 + valueidx = 1 + for item in block["setup"]: + if item[0] == "select": + print(" if (!({})) continue;".format(item[1]), file=f) + if item[0] == "slice": + print(" int &{} = std::get<{}>(value);".format(item[1], valueidx), file=f) + print(" for ({} = 0; {} < {}; {}++) {{".format(item[1], item[1], item[2], item[1]), file=f) + valueidx += 1 + loopcnt += 1 + if item[0] == "choice": + print(" vector<{}> _pmg_choices_{} = {};".format(item[1], item[2], item[3]), file=f) + print(" for (const {} &{} : _pmg_choices_{}) {{".format(item[1], item[2], item[2]), file=f) + print(" std::get<{}>(value) = {};".format(valueidx, item[2]), file=f) + valueidx += 1 + loopcnt += 1 + if item[0] == "define": + print(" {} &{} = std::get<{}>(value);".format(item[1], item[2], valueidx), file=f) + print(" {} = {};".format(item[2], item[3]), file=f) + valueidx += 1 print(" index_{}_key_type key;".format(index), file=f) for field, entry in enumerate(block["index"]): print(" std::get<{}>(key) = {};".format(field, entry[1]), file=f) - print(" index_{}[key].push_back(cell);".format(index), file=f) + print(" index_{}[key].push_back(value);".format(index), file=f) + for i in range(loopcnt): + print(" }", file=f) print(" } while (0);", file=f) print(" }", file=f) @@ -535,6 +589,8 @@ with open(outfile, "w") as f: const_st.add(s) elif blocks[i]["type"] == "match": const_st.add(blocks[i]["cell"]) + for item in blocks[i]["sets"]: + const_st.add(item[0]) else: assert False @@ -548,6 +604,10 @@ with open(outfile, "w") as f: s = block["cell"] assert s not in const_st nonconst_st.add(s) + for item in block["sets"]: + if item[0] in const_st: + const_st.remove(item[0]) + nonconst_st.add(item[0]) else: assert False @@ -570,7 +630,7 @@ with open(outfile, "w") as f: print("", file=f) for s in sorted(restore_st): t = state_types[current_pattern][s] - print(" {} backup_{} = {};".format(t, s, s), file=f) + print(" {} _pmg_backup_{} = {};".format(t, s, s), file=f) if block["type"] == "code": print("", file=f) @@ -610,7 +670,7 @@ with open(outfile, "w") as f: print("", file=f) for s in sorted(restore_st): t = state_types[current_pattern][s] - print(" {} = backup_{};".format(s, s), file=f) + print(" {} = _pmg_backup_{};".format(s, s), file=f) for s in sorted(nonconst_st): if s not in restore_st: t = state_types[current_pattern][s] @@ -622,7 +682,7 @@ with open(outfile, "w") as f: elif block["type"] == "match": assert len(restore_st) == 0 - print(" Cell* backup_{} = {};".format(block["cell"], block["cell"]), file=f) + print(" Cell* _pmg_backup_{} = {};".format(block["cell"], block["cell"]), file=f) if len(block["if"]): for expr in block["if"]: @@ -630,7 +690,7 @@ with open(outfile, "w") as f: print(" if (!({})) {{".format(expr), file=f) print(" {} = nullptr;".format(block["cell"]), file=f) print(" block_{}(recursion+1);".format(index+1), file=f) - print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f) + print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f) print(" return;", file=f) print(" }", file=f) @@ -645,21 +705,37 @@ with open(outfile, "w") as f: print("", file=f) print(" if (cells_ptr != index_{}.end()) {{".format(index), file=f) - print(" const vector &cells = cells_ptr->second;".format(index), file=f) - print(" for (int idx = 0; idx < GetSize(cells); idx++) {", file=f) - print(" {} = cells[idx];".format(block["cell"]), file=f) + print(" const vector &cells = cells_ptr->second;".format(index), file=f) + print(" for (int _pmg_idx = 0; _pmg_idx < GetSize(cells); _pmg_idx++) {", file=f) + print(" {} = std::get<0>(cells[_pmg_idx]);".format(block["cell"]), file=f) + valueidx = 1 + for item in block["setup"]: + if item[0] == "slice": + print(" const int &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], valueidx), file=f) + valueidx += 1 + if item[0] == "choice": + print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f) + valueidx += 1 + if item[0] == "define": + print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f) + valueidx += 1 print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f) for expr in block["filter"]: print(" if (!({})) continue;".format(expr), file=f) if block["semioptional"] or block["genargs"] is not None: print(" found_any_match = true;", file=f) - print(" auto rollback_ptr = rollback_cache.insert(make_pair(cells[idx], recursion));", file=f) + for item in block["sets"]: + print(" auto _pmg_backup_{} = {};".format(item[0], item[0]), file=f) + print(" {} = {};".format(item[0], item[1]), file=f) + print(" auto rollback_ptr = rollback_cache.insert(make_pair(std::get<0>(cells[_pmg_idx]), recursion));", file=f) print(" block_{}(recursion+1);".format(index+1), file=f) + for item in block["sets"]: + print(" {} = _pmg_backup_{};".format(item[0], item[0]), file=f) print(" if (rollback_ptr.second)", file=f) print(" rollback_cache.erase(rollback_ptr.first);", file=f) print(" if (rollback) {", file=f) print(" if (rollback != recursion) {{".format(index+1), file=f) - print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f) + print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f) print(" return;", file=f) print(" }", file=f) print(" rollback = 0;", file=f) @@ -676,13 +752,11 @@ with open(outfile, "w") as f: if block["semioptional"]: print(" if (!found_any_match) block_{}(recursion+1);".format(index+1), file=f) - print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f) + print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f) if block["genargs"] is not None: print("#define finish do { rollback = -1; return; } while(0)", file=f) - print(" if (generate_mode && !found_any_match) {", file=f) - if len(block["genargs"]) == 1: - print(" if (rng(100) >= {}) return;".format(block["genargs"][0]), file=f) + print(" if (generate_mode && rng(100) < (found_any_match ? {} : {})) {{".format(block["genargs"][1], block["genargs"][0]), file=f) for line in block["gencode"]: print(" " + line, file=f) print(" }", file=f) diff --git a/passes/pmgen/test_pmgen.cc b/passes/pmgen/test_pmgen.cc index 9f42a95d0..0ad769dfd 100644 --- a/passes/pmgen/test_pmgen.cc +++ b/passes/pmgen/test_pmgen.cc @@ -99,6 +99,24 @@ void reduce_tree(test_pmgen_pm &pm) log(" -> %s (%s)\n", log_id(c), log_id(c->type)); } +void opt_eqpmux(test_pmgen_pm &pm) +{ + auto &st = pm.st_eqpmux; + + SigSpec Y = st.pmux->getPort(ID::Y); + int width = GetSize(Y); + + SigSpec EQ = st.pmux->getPort(ID::B).extract(st.pmux_slice_eq*width, width); + SigSpec NE = st.pmux->getPort(ID::B).extract(st.pmux_slice_ne*width, width); + + log("Found eqpmux circuit driving %s (eq=%s, ne=%s, pmux=%s).\n", + log_signal(Y), log_id(st.eq), log_id(st.ne), log_id(st.pmux)); + + pm.autoremove(st.pmux); + Cell *c = pm.module->addMux(NEW_ID, NE, EQ, st.eq->getPort(ID::Y), Y); + log(" -> %s (%s)\n", log_id(c), log_id(c->type)); +} + #define GENERATE_PATTERN(pmclass, pattern) \ generate_pattern([](pmclass &pm, std::function f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design) @@ -149,16 +167,17 @@ void generate_pattern(std::function)> run, const log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass); int modcnt = 0; + int maxmodcnt = 100; int maxsubcnt = 4; int timeout = 0; vector mods; - while (modcnt < 100) + while (modcnt < maxmodcnt) { int submodcnt = 0, itercnt = 0, cellcnt = 0; Module *mod = design->addModule(NEW_ID); - while (modcnt < 100 && submodcnt < maxsubcnt && itercnt++ < 1000) + while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000) { if (timeout++ > 10000) log_error("pmgen generator is stuck: 10000 iterations an no matching module generated.\n"); @@ -232,6 +251,12 @@ struct TestPmgenPass : public Pass { log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n"); log("\n"); + log("\n"); + log(" test_pmgen -eqpmux [options] [selection]\n"); + log("\n"); + log("Demo for recursive pmgen patterns. Optimize EQ/NE/PMUX circuits.\n"); + log("\n"); + log("\n"); log(" test_pmgen -generate [options] \n"); log("\n"); @@ -277,6 +302,25 @@ struct TestPmgenPass : public Pass { test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree); } + void execute_eqpmux(std::vector args, RTLIL::Design *design) + { + log_header(design, "Executing TEST_PMGEN pass (-eqpmux).\n"); + + size_t argidx; + for (argidx = 2; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + test_pmgen_pm(module, module->selected_cells()).run_eqpmux(opt_eqpmux); + } + void execute_generate(std::vector args, RTLIL::Design *design) { log_header(design, "Executing TEST_PMGEN pass (-generate).\n"); @@ -299,6 +343,9 @@ struct TestPmgenPass : public Pass { if (pattern == "reduce") return GENERATE_PATTERN(test_pmgen_pm, reduce); + if (pattern == "eqpmux") + return GENERATE_PATTERN(test_pmgen_pm, eqpmux); + if (pattern == "ice40_dsp") return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp); @@ -319,6 +366,8 @@ struct TestPmgenPass : public Pass { return execute_reduce_chain(args, design); if (args[1] == "-reduce_tree") return execute_reduce_tree(args, design); + if (args[1] == "-eqpmux") + return execute_eqpmux(args, design); if (args[1] == "-generate") return execute_generate(args, design); } diff --git a/passes/pmgen/test_pmgen.pmg b/passes/pmgen/test_pmgen.pmg index 211477a62..287ed97d8 100644 --- a/passes/pmgen/test_pmgen.pmg +++ b/passes/pmgen/test_pmgen.pmg @@ -60,8 +60,8 @@ code portname endcode match next - select nusers(port(next, \Y)) == 2 select next->type.in($_AND_, $_OR_, $_XOR_) + select nusers(port(next, \Y)) == 2 index next->type === first->type index port(next, \Y) === port(first, portname) endmatch @@ -77,8 +77,8 @@ arg first match next semioptional - select nusers(port(next, \Y)) == 2 select next->type.in($_AND_, $_OR_, $_XOR_) + select nusers(port(next, \Y)) == 2 index next->type === chain.back().first->type index port(next, \Y) === port(chain.back().first, chain.back().second) generate 10 @@ -104,3 +104,86 @@ finally if (next) chain.pop_back(); endcode + +// ================================================================== + +pattern eqpmux + +state eq_ne_signed +state eq_inA eq_inB +state pmux_slice_eq pmux_slice_ne + +match eq + select eq->type == $eq + choice AB {\A, \B} + define BA AB == \A ? \B : \A + set eq_inA port(eq, \A) + set eq_inB port(eq, \B) + set eq_ne_signed param(eq, \A_SIGNED).as_bool() +generate 100 10 + SigSpec A = module->addWire(NEW_ID, rng(7)+1); + SigSpec B = module->addWire(NEW_ID, rng(7)+1); + SigSpec Y = module->addWire(NEW_ID); + module->addEq(NEW_ID, A, B, Y, rng(2)); +endmatch + +match pmux + select pmux->type == $pmux + slice idx GetSize(port(pmux, \S)) + index port(pmux, \S)[idx] === port(eq, \Y) + set pmux_slice_eq idx +generate 100 10 + int width = rng(7) + 1; + int numsel = rng(4) + 1; + int idx = rng(numsel); + + SigSpec A = module->addWire(NEW_ID, width); + SigSpec Y = module->addWire(NEW_ID, width); + + SigSpec B, S; + for (int i = 0; i < numsel; i++) { + B.append(module->addWire(NEW_ID, width)); + S.append(i == idx ? port(eq, \Y) : module->addWire(NEW_ID)); + } + + module->addPmux(NEW_ID, A, B, S, Y); +endmatch + +match ne + select ne->type == $ne + choice AB {\A, \B} + define BA (AB == \A ? \B : \A) + index port(ne, AB) === eq_inA + index port(ne, BA) === eq_inB + index param(ne, \A_SIGNED).as_bool() === eq_ne_signed +generate 100 10 + SigSpec A = eq_inA, B = eq_inB, Y; + if (rng(2)) { + std::swap(A, B); + } + if (rng(2)) { + for (auto bit : port(pmux, \S)) { + if (nusers(bit) < 2) + Y.append(bit); + } + if (GetSize(Y)) + Y = Y[rng(GetSize(Y))]; + else + Y = module->addWire(NEW_ID); + } else { + Y = module->addWire(NEW_ID); + } + module->addNe(NEW_ID, A, B, Y, rng(2)); +endmatch + +match pmux2 + select pmux2->type == $pmux + slice idx GetSize(port(pmux2, \S)) + index pmux2 === pmux + index port(pmux2, \S)[idx] === port(ne, \Y) + set pmux_slice_ne idx +endmatch + +code + accept; +endcode -- cgit v1.2.3 From 55bf8f69e085caa0a3f0ccae8bf231f77aba6bbc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 23 Aug 2019 16:26:54 +0200 Subject: Fix port hanlding in pmgen Signed-off-by: Clifford Wolf --- passes/pmgen/pmgen.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index c2621393d..573722d68 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -422,8 +422,6 @@ with open(outfile, "w") as f: print(" void add_siguser(const SigSpec &sig, Cell *cell) {", file=f) print(" for (auto bit : sigmap(sig)) {", file=f) print(" if (bit.wire == nullptr) continue;", file=f) - print(" if (sigusers.count(bit) == 0 && bit.wire->port_id)", file=f) - print(" sigusers[bit].insert(nullptr);", file=f) print(" sigusers[bit].insert(cell);", file=f) print(" }", file=f) print(" }", file=f) @@ -478,10 +476,11 @@ with open(outfile, "w") as f: else: print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f) current_pattern = None - print(" for (auto cell : module->cells()) {", file=f) + print(" for (auto port : module->ports)", file=f) + print(" add_siguser(module->wire(port), nullptr);", file=f) + print(" for (auto cell : module->cells())", file=f) print(" for (auto &conn : cell->connections())", file=f) print(" add_siguser(conn.second, cell);", file=f) - print(" }", file=f) print(" for (auto cell : cells) {", file=f) for index in range(len(blocks)): -- cgit v1.2.3 From 4d89c3f468b6090dceabb304b9f56f3a6a597057 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 23 Aug 2019 10:03:41 -0700 Subject: Review comment from @cliffordwolf --- passes/techmap/clkbufmap.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc index 6fac1b437..55341ead0 100644 --- a/passes/techmap/clkbufmap.cc +++ b/passes/techmap/clkbufmap.cc @@ -112,7 +112,8 @@ struct ClkbufmapPass : public Pass { for (auto module : modules_sorted) { if (module->get_blackbox_attribute()) { - for (auto wire : module->wires()) { + for (auto port : module->ports) { + auto wire = module->wire(port); if (wire->get_bool_attribute("\\clkbuf_driver")) for (int i = 0; i < GetSize(wire); i++) buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); -- cgit v1.2.3 From 619f2414e587a216edb68d39ce56e25e29f0502b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 23 Aug 2019 11:14:42 -0700 Subject: clkbufmap to only check clkbuf_inhibit if no selection given --- passes/techmap/clkbufmap.cc | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'passes') diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc index 55341ead0..82b3dcdf7 100644 --- a/passes/techmap/clkbufmap.cc +++ b/passes/techmap/clkbufmap.cc @@ -37,11 +37,18 @@ struct ClkbufmapPass : public Pass { ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { } void help() YS_OVERRIDE { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" clkbufmap [options] [selection]\n"); log("\n"); - log("Inserts global buffers between nets connected to clock inputs and their\n"); - log("drivers.\n"); + log("Inserts global buffers between nets connected to clock inputs and their drivers.\n"); + log("\n"); + log("In the absence of any selection, all wires without the 'clkbuf_inhibit'\n"); + log("attribute will be considered for global buffer insertion.\n"); + log("Alternatively, to consider all wires without the 'buffer_type' attribute set to\n"); + log("'none' or 'bufr' one would specify:\n"); + log(" 'w:* a:buffer_type=none a:buffer_type=bufr %%u %%d'\n"); + log("as the selection.\n"); log("\n"); log(" -buf :\n"); log(" Specifies the cell type to use for the global buffers\n"); @@ -94,10 +101,16 @@ struct ClkbufmapPass : public Pass { } break; } - extra_args(args, argidx, design); + + bool select = false; + if (argidx < args.size()) { + if (args[argidx].compare(0, 1, "-") != 0) + select = true; + extra_args(args, argidx, design); + } if (buf_celltype.empty()) - log_error("The -buf option is required."); + log_error("The -buf option is required.\n"); // Cell type, port name, bit index. pool>> sink_ports; @@ -158,7 +171,7 @@ struct ClkbufmapPass : public Pass { // Should not happen. if (wire->port_input && wire->port_output) continue; - if (wire->get_bool_attribute("\\clkbuf_inhibit")) + if (!select && wire->get_bool_attribute("\\clkbuf_inhibit")) continue; pool input_bits; -- cgit v1.2.3 From 967a36c12572bb7e1bd69921ae75dda767b4243f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 23 Aug 2019 13:15:41 -0700 Subject: indo -> into --- passes/pmgen/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index 27ed77091..0856c9ba3 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -195,7 +195,7 @@ create matches for different sections of a cell. For example: The first argument to `slice` is the local variable name used to identify the slice. The second argument is the number of slices that should be created for -this cell. The `set` statement can be used to copy that index indo a state +this cell. The `set` statement can be used to copy that index into a state variable so that later matches and/or code blocks can refer to it. A similar mechanism is "choices", where a list of options is given as -- cgit v1.2.3 From 5fb4b12cb50b870b546d76f9c702678d8f0aa60a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Tue, 27 Aug 2019 17:26:47 +0200 Subject: improve clkbuf_inhibit propagation upwards through hierarchy --- passes/techmap/clkbufmap.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc index 82b3dcdf7..246932d81 100644 --- a/passes/techmap/clkbufmap.cc +++ b/passes/techmap/clkbufmap.cc @@ -166,13 +166,24 @@ struct ClkbufmapPass : public Pass { // Insert buffers. std::vector> input_queue; - for (auto wire : module->selected_wires()) + // Copy current wire list, as we will be adding new ones during iteration. + std::vector wires(module->wires()); + for (auto wire : wires) { // Should not happen. if (wire->port_input && wire->port_output) continue; + bool process_wire = module->selected(wire); if (!select && wire->get_bool_attribute("\\clkbuf_inhibit")) + process_wire = false; + if (!process_wire) { + // This wire is supposed to be bypassed, so make sure we don't buffer it in + // some buffer higher up in the hierarchy. + if (wire->port_output) + for (int i = 0; i < GetSize(wire); i++) + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); continue; + } pool input_bits; -- cgit v1.2.3 From 28133432bea4a3fa01cd2f5e82a52a853cfccb84 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 27 Aug 2019 09:24:59 -0700 Subject: Ignore all 1'bx in (* init *) --- passes/sat/sat.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index bcc690fa3..430bba1e8 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -268,9 +268,7 @@ struct SatHelper RTLIL::SigSpec removed_bits; for (int i = 0; i < lhs.size(); i++) { RTLIL::SigSpec bit = lhs.extract(i, 1); - if (bit.is_fully_const() && rhs[i] == State::Sx) - rhs[i] = bit; - if (!satgen.initial_state.check_all(bit)) { + if (rhs[i] == State::Sx || !satgen.initial_state.check_all(bit)) { removed_bits.append(bit); lhs.remove(i, 1); rhs.remove(i, 1); -- cgit v1.2.3 From c499dc3e73390c3bc9bf8045f2e4cad963c1fbad Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 28 Aug 2019 09:45:22 +0200 Subject: Add $dlatch support to async2sync Signed-off-by: Clifford Wolf --- passes/sat/async2sync.cc | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc index d045d0dcb..24ae6e448 100644 --- a/passes/sat/async2sync.cc +++ b/passes/sat/async2sync.cc @@ -39,7 +39,7 @@ struct Async2syncPass : public Pass { log("reset value in the next cycle regardless of the data-in value at the time of\n"); log("the clock edge.\n"); log("\n"); - log("Currently only $adff and $dffsr cells are supported by this pass.\n"); + log("Currently only $adff, $dffsr, and $dlatch cells are supported by this pass.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -169,6 +169,41 @@ struct Async2syncPass : public Pass { cell->type = "$dff"; continue; } + + if (cell->type.in("$dlatch")) + { + bool en_pol = cell->parameters["\\EN_POLARITY"].as_bool(); + + SigSpec sig_en = cell->getPort("\\EN"); + SigSpec sig_d = cell->getPort("\\D"); + SigSpec sig_q = cell->getPort("\\Q"); + + log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_signal(sig_en), log_signal(sig_d), log_signal(sig_q)); + + Const init_val; + for (int i = 0; i < GetSize(sig_q); i++) { + SigBit bit = sigmap(sig_q[i]); + init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx); + del_initbits.insert(bit); + } + + Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q)); + new_q->attributes["\\init"] = init_val; + + if (en_pol) { + module->addMux(NEW_ID, new_q, sig_d, sig_en, sig_q); + } else { + module->addMux(NEW_ID, sig_d, new_q, sig_en, sig_q); + } + + cell->setPort("\\Q", new_q); + cell->unsetPort("\\EN"); + cell->unsetParam("\\EN_POLARITY"); + cell->type = "$ff"; + continue; + } } for (auto wire : module->wires()) -- cgit v1.2.3 From 0fda0e821cee249dd722c8b52e941c35bd9d8df0 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 28 Aug 2019 10:03:27 +0200 Subject: Add "paramap" pass Signed-off-by: Clifford Wolf --- passes/techmap/attrmap.cc | 185 +++++++++++++++++++++++++++++----------------- 1 file changed, 118 insertions(+), 67 deletions(-) (limited to 'passes') diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc index a38638e0b..3a2835733 100644 --- a/passes/techmap/attrmap.cc +++ b/passes/techmap/attrmap.cc @@ -143,6 +143,82 @@ void attrmap_apply(string objname, vector> &actio attributes.swap(new_attributes); } +void log_attrmap_paramap_options() +{ + log(" -tocase \n"); + log(" Match attribute names case-insensitively and set it to the specified\n"); + log(" name.\n"); + log("\n"); + log(" -rename \n"); + log(" Rename attributes as specified\n"); + log("\n"); + log(" -map = =\n"); + log(" Map key/value pairs as indicated.\n"); + log("\n"); + log(" -imap = =\n"); + log(" Like -map, but use case-insensitive match for when\n"); + log(" it is a string value.\n"); + log("\n"); + log(" -remove =\n"); + log(" Remove attributes matching this pattern.\n"); +} + +bool parse_attrmap_paramap_options(size_t &argidx, std::vector &args, vector> &actions) +{ + std::string arg = args[argidx]; + if (arg == "-tocase" && argidx+1 < args.size()) { + auto action = new AttrmapTocase; + action->name = args[++argidx]; + actions.push_back(std::unique_ptr(action)); + return true; + } + if (arg == "-rename" && argidx+2 < args.size()) { + auto action = new AttrmapRename; + action->old_name = args[++argidx]; + action->new_name = args[++argidx]; + actions.push_back(std::unique_ptr(action)); + return true; + } + if ((arg == "-map" || arg == "-imap") && argidx+2 < args.size()) { + string arg1 = args[++argidx]; + string arg2 = args[++argidx]; + string val1, val2; + size_t p = arg1.find("="); + if (p != string::npos) { + val1 = arg1.substr(p+1); + arg1 = arg1.substr(0, p); + } + p = arg2.find("="); + if (p != string::npos) { + val2 = arg2.substr(p+1); + arg2 = arg2.substr(0, p); + } + auto action = new AttrmapMap; + action->imap = (arg == "-map"); + action->old_name = arg1; + action->new_name = arg2; + action->old_value = val1; + action->new_value = val2; + actions.push_back(std::unique_ptr(action)); + return true; + } + if (arg == "-remove" && argidx+1 < args.size()) { + string arg1 = args[++argidx], val1; + size_t p = arg1.find("="); + if (p != string::npos) { + val1 = arg1.substr(p+1); + arg1 = arg1.substr(0, p); + } + auto action = new AttrmapRemove; + action->name = arg1; + action->has_value = (p != string::npos); + action->value = val1; + actions.push_back(std::unique_ptr(action)); + return true; + } + return false; +} + struct AttrmapPass : public Pass { AttrmapPass() : Pass("attrmap", "renaming attributes") { } void help() YS_OVERRIDE @@ -154,22 +230,7 @@ struct AttrmapPass : public Pass { log("This command renames attributes and/or mapps key/value pairs to\n"); log("other key/value pairs.\n"); log("\n"); - log(" -tocase \n"); - log(" Match attribute names case-insensitively and set it to the specified\n"); - log(" name.\n"); - log("\n"); - log(" -rename \n"); - log(" Rename attributes as specified\n"); - log("\n"); - log(" -map = =\n"); - log(" Map key/value pairs as indicated.\n"); - log("\n"); - log(" -imap = =\n"); - log(" Like -map, but use case-insensitive match for when\n"); - log(" it is a string value.\n"); - log("\n"); - log(" -remove =\n"); - log(" Remove attributes matching this pattern.\n"); + log_attrmap_paramap_options(); log("\n"); log(" -modattr\n"); log(" Operate on module attributes instead of attributes on wires and cells.\n"); @@ -190,58 +251,9 @@ struct AttrmapPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-tocase" && argidx+1 < args.size()) { - auto action = new AttrmapTocase; - action->name = args[++argidx]; - actions.push_back(std::unique_ptr(action)); - continue; - } - if (arg == "-rename" && argidx+2 < args.size()) { - auto action = new AttrmapRename; - action->old_name = args[++argidx]; - action->new_name = args[++argidx]; - actions.push_back(std::unique_ptr(action)); + if (parse_attrmap_paramap_options(argidx, args, actions)) continue; - } - if ((arg == "-map" || arg == "-imap") && argidx+2 < args.size()) { - string arg1 = args[++argidx]; - string arg2 = args[++argidx]; - string val1, val2; - size_t p = arg1.find("="); - if (p != string::npos) { - val1 = arg1.substr(p+1); - arg1 = arg1.substr(0, p); - } - p = arg2.find("="); - if (p != string::npos) { - val2 = arg2.substr(p+1); - arg2 = arg2.substr(0, p); - } - auto action = new AttrmapMap; - action->imap = (arg == "-map"); - action->old_name = arg1; - action->new_name = arg2; - action->old_value = val1; - action->new_value = val2; - actions.push_back(std::unique_ptr(action)); - continue; - } - if (arg == "-remove" && argidx+1 < args.size()) { - string arg1 = args[++argidx], val1; - size_t p = arg1.find("="); - if (p != string::npos) { - val1 = arg1.substr(p+1); - arg1 = arg1.substr(0, p); - } - auto action = new AttrmapRemove; - action->name = arg1; - action->has_value = (p != string::npos); - action->value = val1; - actions.push_back(std::unique_ptr(action)); - continue; - } - if (arg == "-modattr") { + if (args[argidx] == "-modattr") { modattr_mode = true; continue; } @@ -287,4 +299,43 @@ struct AttrmapPass : public Pass { } } AttrmapPass; +struct ParamapPass : public Pass { + ParamapPass() : Pass("paramap", "renaming cell parameters") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" paramap [options] [selection]\n"); + log("\n"); + log("This command renames cell parameters and/or mapps key/value pairs to\n"); + log("other key/value pairs.\n"); + log("\n"); + log_attrmap_paramap_options(); + log("\n"); + log("For example, mapping Diamond-style ECP5 \"init\" attributes to Yosys-style:\n"); + log("\n"); + log(" paramap -tocase INIT t:LUT4\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing PARAMAP pass (move or copy cell parameters).\n"); + + vector> actions; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (parse_attrmap_paramap_options(argidx, args, actions)) + continue; + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + for (auto cell : module->selected_cells()) + attrmap_apply(stringf("%s.%s", log_id(module), log_id(cell)), actions, cell->parameters); + } +} ParamapPass; + PRIVATE_NAMESPACE_END -- cgit v1.2.3 From 47ffbf554ef98a19222b42e48a9c58f3b55364fa Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 28 Aug 2019 10:06:42 +0200 Subject: Fix typo Signed-off-by: Clifford Wolf --- passes/techmap/attrmap.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc index 3a2835733..5f30817d4 100644 --- a/passes/techmap/attrmap.cc +++ b/passes/techmap/attrmap.cc @@ -227,7 +227,7 @@ struct AttrmapPass : public Pass { log("\n"); log(" attrmap [options] [selection]\n"); log("\n"); - log("This command renames attributes and/or mapps key/value pairs to\n"); + log("This command renames attributes and/or maps key/value pairs to\n"); log("other key/value pairs.\n"); log("\n"); log_attrmap_paramap_options(); @@ -307,7 +307,7 @@ struct ParamapPass : public Pass { log("\n"); log(" paramap [options] [selection]\n"); log("\n"); - log("This command renames cell parameters and/or mapps key/value pairs to\n"); + log("This command renames cell parameters and/or maps key/value pairs to\n"); log("other key/value pairs.\n"); log("\n"); log_attrmap_paramap_options(); -- cgit v1.2.3 From 14677610602ee18bcf1a41a0c54a626965e6bb06 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 29 Aug 2019 10:33:28 -0700 Subject: Fix typo that's gone unnoticed for 5 months!?! --- passes/techmap/shregmap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 5e298d8dd..02cc27ae2 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -346,7 +346,7 @@ struct ShregmapWorker IdString q_port = opts.ffcells.at(c1->type).second; auto c1_conn = c1->connections(); - auto c2_conn = c1->connections(); + auto c2_conn = c2->connections(); c1_conn.erase(d_port); c1_conn.erase(q_port); -- cgit v1.2.3