diff options
74 files changed, 2059 insertions, 891 deletions
@@ -8,3 +8,4 @@ brew "pkg-config" brew "python3" brew "tcl-tk" brew "xdot" +brew "bash" @@ -1,4 +1,6 @@ -Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at> +ISC License + +Copyright (C) 2012 - 2020 Claire Wolf <claire@symbioticeda.com> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -669,7 +669,8 @@ ifneq ($(ABCREV),default) $(Q) if ( cd abc 2> /dev/null && ! git diff-index --quiet HEAD; ); then \ echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \ fi - $(Q) if test "`cd abc 2> /dev/null && git rev-parse --short HEAD`" != "$(ABCREV)"; then \ +# set a variable so the test fails if git fails to run - when comparing outputs directly, empty string would match empty string + $(Q) if ! (cd abc && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \ test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \ echo "Pulling ABC from $(ABCURL):"; set -x; \ test -d abc || git clone $(ABCURL) abc; \ @@ -715,6 +716,7 @@ test: $(TARGETS) $(EXTRA_TARGETS) +cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT) +cd tests/bram && bash run-test.sh $(SEEDOPT) +cd tests/various && bash run-test.sh + +cd tests/select && bash run-test.sh +cd tests/sat && bash run-test.sh +cd tests/svinterfaces && bash run-test.sh $(SEEDOPT) +cd tests/svtypes && bash run-test.sh $(SEEDOPT) @@ -931,6 +933,9 @@ echo-yosys-ver: echo-git-rev: @echo "$(GIT_REV)" +echo-abc-rev: + @echo "$(ABCREV)" + -include libs/*/*.d -include frontends/*/*.d -include passes/*/*.d @@ -1,7 +1,7 @@ ``` yosys -- Yosys Open SYnthesis Suite -Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at> +Copyright (C) 2012 - 2020 Claire Wolf <claire@symbioticeda.com> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -541,8 +541,6 @@ from SystemVerilog: SystemVerilog files being read into the same design afterwards. - typedefs are supported (including inside packages) - - type identifiers must currently be enclosed in (parentheses) when declaring - signals of that type (this is syntactically incorrect SystemVerilog) - type casts are currently not supported - enums are supported (including inside packages) diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 87db0edf7..22aa686a7 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -25,7 +25,6 @@ #include "kernel/log.h" #include <algorithm> #include <string> -#include <regex> #include <vector> #include <cmath> diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 081dcda99..628765831 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -536,6 +536,14 @@ struct Smt2Worker if (cell->attributes.count("\\reg")) infostr += " " + cell->attributes.at("\\reg").decode_string(); decls.push_back(stringf("; yosys-smt2-%s %s#%d %d %s\n", cell->type.c_str() + 1, get_id(module), idcounter, GetSize(cell->getPort("\\Y")), infostr.c_str())); + if (cell->getPort("\\Y").is_wire() && cell->getPort("\\Y").as_wire()->get_bool_attribute("\\maximize")){ + decls.push_back(stringf("; yosys-smt2-maximize %s#%d\n", get_id(module), idcounter)); + log("Wire %s is maximized\n", cell->getPort("\\Y").as_wire()->name.str().c_str()); + } + else if (cell->getPort("\\Y").is_wire() && cell->getPort("\\Y").as_wire()->get_bool_attribute("\\minimize")){ + decls.push_back(stringf("; yosys-smt2-minimize %s#%d\n", get_id(module), idcounter)); + log("Wire %s is minimized\n", cell->getPort("\\Y").as_wire()->name.str().c_str()); + } makebits(stringf("%s#%d", get_id(module), idcounter), GetSize(cell->getPort("\\Y")), log_signal(cell->getPort("\\Y"))); if (cell->type == "$anyseq") ex_input_eq.push_back(stringf(" (= (|%s#%d| state) (|%s#%d| other_state))", get_id(module), idcounter, get_id(module), idcounter)); @@ -1386,7 +1394,7 @@ struct Smt2Backend : public Backend { log("\n"); log("For this proof we create the following template (test.tpl).\n"); log("\n"); - log(" ; we need QF_UFBV for this poof\n"); + log(" ; we need QF_UFBV for this proof\n"); log(" (set-logic QF_UFBV)\n"); log("\n"); log(" ; insert the auto-generated code here\n"); @@ -1500,11 +1508,11 @@ struct Smt2Backend : public Backend { // extract module dependencies std::map<RTLIL::Module*, std::set<RTLIL::Module*>> module_deps; - for (auto &mod_it : design->modules_) { - module_deps[mod_it.second] = std::set<RTLIL::Module*>(); - for (auto &cell_it : mod_it.second->cells_) - if (design->modules_.count(cell_it.second->type) > 0) - module_deps[mod_it.second].insert(design->modules_.at(cell_it.second->type)); + for (auto mod : design->modules()) { + module_deps[mod] = std::set<RTLIL::Module*>(); + for (auto cell : mod->cells()) + if (design->has(cell->type)) + module_deps[mod].insert(design->module(cell->type)); } // simple good-enough topological sort diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index 3d6d3e1b3..630464419 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -1158,6 +1158,8 @@ def smt_forall_assert(): global asserts_cache_dirty asserts_cache_dirty = False + assert (len(smt.modinfo[topmod].maximize) + len(smt.modinfo[topmod].minimize) <= 1) + def make_assert_expr(asserts_cache): expr = list() for lst in asserts_cache: @@ -1236,6 +1238,18 @@ def smt_forall_assert(): smt.write("".join(assert_expr)) + if len(smt.modinfo[topmod].maximize) > 0: + for s in states: + if s in used_states_db: + smt.write("(maximize (|%s| %s))\n" % (smt.modinfo[topmod].maximize.copy().pop(), s)) + break + + if len(smt.modinfo[topmod].minimize) > 0: + for s in states: + if s in used_states_db: + smt.write("(minimize (|%s| %s))\n" % (smt.modinfo[topmod].minimize.copy().pop(), s)) + break + def smt_push(): global asserts_cache_dirty asserts_cache_dirty = True diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 34bf7ef38..69f59df79 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -101,6 +101,8 @@ class SmtModInfo: self.cells = dict() self.asserts = dict() self.covers = dict() + self.maximize = set() + self.minimize = set() self.anyconsts = dict() self.anyseqs = dict() self.allconsts = dict() @@ -502,6 +504,12 @@ class SmtIo: if fields[1] == "yosys-smt2-cover": self.modinfo[self.curmod].covers["%s_c %s" % (self.curmod, fields[2])] = fields[3] + if fields[1] == "yosys-smt2-maximize": + self.modinfo[self.curmod].maximize.add(fields[2]) + + if fields[1] == "yosys-smt2-minimize": + self.modinfo[self.curmod].minimize.add(fields[2]) + if fields[1] == "yosys-smt2-anyconst": self.modinfo[self.curmod].anyconsts[fields[2]] = (fields[4], None if len(fields) <= 5 else fields[5]) self.modinfo[self.curmod].asize[fields[2]] = int(fields[3]) @@ -696,7 +704,13 @@ class SmtIo: if msg is not None: print("%s waiting for solver (%s)" % (self.timestamp(), msg), flush=True) - result = self.read() + if self.forall: + result = self.read() + while result not in ["sat", "unsat", "unknown"]: + print("%s %s: %s" % (self.timestamp(), self.solver, result)) + result = self.read() + else: + result = self.read() if self.debug_file: print("(set-info :status %s)" % result, file=self.debug_file) diff --git a/examples/smtbmc/Makefile b/examples/smtbmc/Makefile index 96fa058d6..61994f942 100644 --- a/examples/smtbmc/Makefile +++ b/examples/smtbmc/Makefile @@ -1,5 +1,5 @@ -all: demo1 demo2 demo3 demo4 demo5 demo6 demo7 demo8 +all: demo1 demo2 demo3 demo4 demo5 demo6 demo7 demo8 demo9 demo1: demo1.smt2 yosys-smtbmc --dump-vcd demo1.vcd demo1.smt2 @@ -28,6 +28,9 @@ demo7: demo7.smt2 demo8: demo8.smt2 yosys-smtbmc -s z3 -t 1 -g demo8.smt2 +demo9: demo9.smt2 + yosys-smtbmc -s z3 -t 1 -g demo9.smt2 + demo1.smt2: demo1.v yosys -ql demo1.yslog -p 'read_verilog -formal demo1.v; prep -top demo1 -nordff; write_smt2 -wires demo1.smt2' @@ -52,6 +55,9 @@ demo7.smt2: demo7.v demo8.smt2: demo8.v yosys -ql demo8.yslog -p 'read_verilog -formal demo8.v; prep -top demo8 -nordff; write_smt2 -stbv -wires demo8.smt2' +demo9.smt2: demo9.v + yosys -ql demo9.yslog -p 'read_verilog -formal demo9.v; prep -top demo9 -nordff; write_smt2 -stbv -wires demo9.smt2' + clean: rm -f demo1.yslog demo1.smt2 demo1.vcd rm -f demo2.yslog demo2.smt2 demo2.vcd demo2.smtc demo2_tb.v demo2_tb demo2_tb.vcd @@ -61,6 +67,7 @@ clean: rm -f demo6.yslog demo6.smt2 rm -f demo7.yslog demo7.smt2 rm -f demo8.yslog demo8.smt2 + rm -f demo9.yslog demo9.smt2 -.PHONY: demo1 demo2 demo3 demo4 demo5 demo6 demo7 demo8 clean +.PHONY: demo1 demo2 demo3 demo4 demo5 demo6 demo7 demo8 demo9 clean diff --git a/examples/smtbmc/demo9.v b/examples/smtbmc/demo9.v new file mode 100644 index 000000000..f0b91e2ca --- /dev/null +++ b/examples/smtbmc/demo9.v @@ -0,0 +1,13 @@ +module demo9; + (* maximize *) wire[7:0] h = $anyconst; + wire [7:0] i = $allconst; + + wire [7:0] t0 = ((i << 8'b00000010) + 8'b00000011); + wire trigger = (t0 > h) && (h < 8'b00000100); + + always @* begin + assume(trigger == 1'b1); + cover(1); + end +endmodule + diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index a42569301..50c2a3ce6 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -444,7 +444,7 @@ void AigerReader::parse_xaiger() } } else if (c == 'r') { - uint32_t dataSize = parse_xaiger_literal(f); + uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); flopNum = parse_xaiger_literal(f); log_debug("flopNum = %u\n", flopNum); log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 650c7a937..d1f136fd7 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1179,12 +1179,13 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump for (auto n : design->verilog_globals) (*it)->children.push_back(n->clone()); - for (auto n : design->verilog_packages){ - for (auto o : n->children) { + // append nodes from previous packages using package-qualified names + for (auto &n : design->verilog_packages) { + for (auto &o : n->children) { AstNode *cloned_node = o->clone(); - log("cloned node %s\n", type2str(cloned_node->type).c_str()); - if (cloned_node->type == AST_ENUM){ - for (auto e : cloned_node->children){ + // log("cloned node %s\n", type2str(cloned_node->type).c_str()); + if (cloned_node->type == AST_ENUM) { + for (auto &e : cloned_node->children) { log_assert(e->type == AST_ENUM_ITEM); e->str = n->str + std::string("::") + e->str.substr(1); } @@ -1220,6 +1221,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump design->add(process_module(*it, defer)); } else if ((*it)->type == AST_PACKAGE) { + // process enum/other declarations + (*it)->simplify(true, false, false, 1, -1, false, false); design->verilog_packages.push_back((*it)->clone()); } else { @@ -1281,9 +1284,9 @@ AstNode * AST::find_modport(AstNode *intf, std::string name) // Iterate over all wires in an interface and add them as wires in the AST module: void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport) { - for (auto &wire_it : intfmodule->wires_){ - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true))); - std::string origname = log_id(wire_it.first); + for (auto w : intfmodule->wires()){ + AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); + std::string origname = log_id(w->name); std::string newname = intfname + "." + origname; wire->str = newname; if (modport != NULL) { @@ -1326,9 +1329,9 @@ void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RT for (auto &intf : local_interfaces) { std::string intfname = intf.first.str(); RTLIL::Module *intfmodule = intf.second; - for (auto &wire_it : intfmodule->wires_){ - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true))); - std::string newname = log_id(wire_it.first); + for (auto w : intfmodule->wires()){ + AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); + std::string newname = log_id(w->name); newname = intfname + "." + newname; wire->str = newname; new_ast->children.push_back(wire); @@ -1352,7 +1355,7 @@ void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RT std::pair<std::string,std::string> res = split_modport_from_type(ch->str); std::string interface_type = res.first; std::string interface_modport = res.second; // Is "", if no modport - if (design->modules_.count(interface_type) > 0) { + if (design->module(interface_type) != nullptr) { // Add a cell to the module corresponding to the interface port such that // it can further propagated down if needed: AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE); @@ -1362,7 +1365,7 @@ void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RT new_ast->children.push_back(cell_for_intf); // Get all members of this non-overridden dummy interface instance: - RTLIL::Module *intfmodule = design->modules_[interface_type]; // All interfaces should at this point in time (assuming + RTLIL::Module *intfmodule = design->module(interface_type); // All interfaces should at this point in time (assuming // reprocess_module is called from the hierarchy pass) be // present in design->modules_ AstModule *ast_module_of_interface = (AstModule*)intfmodule; @@ -1457,12 +1460,19 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R // Now that the interfaces have been exploded, we can delete the dummy port related to every interface. for(auto &intf : interfaces) { - if(mod->wires_.count(intf.first)) { - mod->wires_.erase(intf.first); + if(mod->wire(intf.first) != nullptr) { + // Normally, removing wires would be batched together as it's an + // expensive operation, however, in this case doing so would mean + // that a cell with the same name cannot be created (below)... + // Since we won't expect many interfaces to exist in a module, + // we can let this slide... + pool<RTLIL::Wire*> to_remove; + to_remove.insert(mod->wire(intf.first)); + mod->remove(to_remove); mod->fixup_ports(); - // We copy the cell of the interface to the sub-module such that it can further be found if it is propagated - // down to sub-sub-modules etc. - RTLIL::Cell * new_subcell = mod->addCell(intf.first, intf.second->name); + // We copy the cell of the interface to the sub-module such that it + // can further be found if it is propagated down to sub-sub-modules etc. + RTLIL::Cell *new_subcell = mod->addCell(intf.first, intf.second->name); new_subcell->set_bool_attribute("\\is_interface"); } else { diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 04c02d893..10e9f2683 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -432,7 +432,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) did_something = true; if (node->type == AST_ENUM) { - for (auto enode : node->children){ + for (auto enode YS_ATTRIBUTE(unused) : node->children){ log_assert(enode->type==AST_ENUM_ITEM); while (node->simplify(true, false, false, 1, -1, false, in_param)) did_something = true; @@ -1811,6 +1811,7 @@ skip_dynamic_range_lvalue_expansion:; newNode->children.push_back(assign_en); AstNode *assertnode = new AstNode(type); + assertnode->location = location; assertnode->str = str; assertnode->children.push_back(new AstNode(AST_IDENTIFIER)); assertnode->children.push_back(new AstNode(AST_IDENTIFIER)); @@ -1897,6 +1898,9 @@ skip_dynamic_range_lvalue_expansion:; bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); + newNode = new AstNode(AST_BLOCK); + AstNode *defNode = new AstNode(AST_BLOCK); + int data_range_left = children[0]->id2ast->children[0]->range_left; int data_range_right = children[0]->id2ast->children[0]->range_right; int mem_data_range_offset = std::min(data_range_left, data_range_right); @@ -1906,31 +1910,6 @@ skip_dynamic_range_lvalue_expansion:; children[0]->children[0]->children[0]->detectSignWidthWorker(addr_width_hint, addr_sign_hint); addr_bits = std::max(addr_bits, addr_width_hint); - AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); - wire_addr->str = id_addr; - wire_addr->was_checked = true; - current_ast_mod->children.push_back(wire_addr); - current_scope[wire_addr->str] = wire_addr; - while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); - wire_data->str = id_data; - wire_data->was_checked = true; - wire_data->is_signed = mem_signed; - current_ast_mod->children.push_back(wire_data); - current_scope[wire_data->str] = wire_data; - while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *wire_en = nullptr; - if (current_always->type != AST_INITIAL) { - wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); - wire_en->str = id_en; - wire_en->was_checked = true; - current_ast_mod->children.push_back(wire_en); - current_scope[wire_en->str] = wire_en; - while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } - } - std::vector<RTLIL::State> x_bits_addr, x_bits_data, set_bits_en; for (int i = 0; i < addr_bits; i++) x_bits_addr.push_back(RTLIL::State::Sx); @@ -1939,32 +1918,79 @@ skip_dynamic_range_lvalue_expansion:; for (int i = 0; i < mem_width; i++) set_bits_en.push_back(RTLIL::State::S1); - AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); - assign_addr->children[0]->str = id_addr; - assign_addr->children[0]->was_checked = true; + AstNode *node_addr = nullptr; + if (children[0]->children[0]->children[0]->isConst()) { + node_addr = children[0]->children[0]->children[0]->clone(); + } else { + AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + wire_addr->str = id_addr; + wire_addr->was_checked = true; + current_ast_mod->children.push_back(wire_addr); + current_scope[wire_addr->str] = wire_addr; + while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } - AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); - assign_data->children[0]->str = id_data; - assign_data->children[0]->was_checked = true; + AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); + assign_addr->children[0]->str = id_addr; + assign_addr->children[0]->was_checked = true; + defNode->children.push_back(assign_addr); - AstNode *assign_en = nullptr; - if (current_always->type != AST_INITIAL) { - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); + assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); + assign_addr->children[0]->str = id_addr; + assign_addr->children[0]->was_checked = true; + newNode->children.push_back(assign_addr); + + node_addr = new AstNode(AST_IDENTIFIER); + node_addr->str = id_addr; + } + + AstNode *node_data = nullptr; + if (children[0]->children.size() == 1 && children[1]->isConst()) { + node_data = children[1]->clone(); + } else { + AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + wire_data->str = id_data; + wire_data->was_checked = true; + wire_data->is_signed = mem_signed; + current_ast_mod->children.push_back(wire_data); + current_scope[wire_data->str] = wire_data; + while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } + + AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); + assign_data->children[0]->str = id_data; + assign_data->children[0]->was_checked = true; + defNode->children.push_back(assign_data); + + node_data = new AstNode(AST_IDENTIFIER); + node_data->str = id_data; + } + + AstNode *node_en = nullptr; + if (current_always->type == AST_INITIAL) { + node_en = AstNode::mkconst_int(1, false); + } else { + AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + wire_en->str = id_en; + wire_en->was_checked = true; + current_ast_mod->children.push_back(wire_en); + current_scope[wire_en->str] = wire_en; + while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } + + AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; - } + defNode->children.push_back(assign_en); - AstNode *default_signals = new AstNode(AST_BLOCK); - default_signals->children.push_back(assign_addr); - default_signals->children.push_back(assign_data); - if (current_always->type != AST_INITIAL) - default_signals->children.push_back(assign_en); - current_top_block->children.insert(current_top_block->children.begin(), default_signals); + node_en = new AstNode(AST_IDENTIFIER); + node_en->str = id_en; + } - assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); - assign_addr->children[0]->str = id_addr; - assign_addr->children[0]->was_checked = true; + if (!defNode->children.empty()) + current_top_block->children.insert(current_top_block->children.begin(), defNode); + else + delete defNode; + AstNode *assign_data = nullptr; + AstNode *assign_en = nullptr; if (children[0]->children.size() == 2) { if (children[0]->children[1]->range_valid) @@ -2025,9 +2051,11 @@ skip_dynamic_range_lvalue_expansion:; } else { - assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone()); - assign_data->children[0]->str = id_data; - assign_data->children[0]->was_checked = true; + if (!(children[0]->children.size() == 1 && children[1]->isConst())) { + assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone()); + assign_data->children[0]->str = id_data; + assign_data->children[0]->was_checked = true; + } if (current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); @@ -2035,28 +2063,20 @@ skip_dynamic_range_lvalue_expansion:; assign_en->children[0]->was_checked = true; } } - - newNode = new AstNode(AST_BLOCK); - newNode->children.push_back(assign_addr); - newNode->children.push_back(assign_data); - if (current_always->type != AST_INITIAL) + if (assign_data) + newNode->children.push_back(assign_data); + if (assign_en) newNode->children.push_back(assign_en); - AstNode *wrnode = new AstNode(current_always->type == AST_INITIAL ? AST_MEMINIT : AST_MEMWR); - wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); - wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); - if (current_always->type != AST_INITIAL) - wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); - else - wrnode->children.push_back(AstNode::mkconst_int(1, false)); + AstNode *wrnode = new AstNode(current_always->type == AST_INITIAL ? AST_MEMINIT : AST_MEMWR, node_addr, node_data, node_en); wrnode->str = children[0]->str; wrnode->id2ast = children[0]->id2ast; - wrnode->children[0]->str = id_addr; - wrnode->children[1]->str = id_data; - if (current_always->type != AST_INITIAL) - wrnode->children[2]->str = id_en; current_ast_mod->children.push_back(wrnode); + if (newNode->children.empty()) { + delete newNode; + newNode = new AstNode(); + } goto apply_newNode; } diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 6a8462b41..cf9b9531e 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -10,7 +10,7 @@ frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc -frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l +frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc $(Q) mkdir -p $(dir $@) $(P) flex -o frontends/verilog/verilog_lexer.cc $< diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 161253a99..7905ea598 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -32,8 +32,10 @@ * */ +#include "preproc.h" #include "verilog_frontend.h" #include "kernel/log.h" +#include <assert.h> #include <stdarg.h> #include <stdio.h> #include <string.h> @@ -199,6 +201,175 @@ static std::string next_token(bool pass_newline = false) return token; } +struct macro_arg_t +{ + macro_arg_t(const std::string &name_, const char *default_value_) + : name(name_), + has_default(default_value_ != nullptr), + default_value(default_value_ ? default_value_ : "") + {} + + std::string name; + bool has_default; + std::string default_value; +}; + +static bool all_white(const std::string &str) +{ + for (char c : str) + if (!isspace(c)) + return false; + return true; +} + +struct arg_map_t +{ + arg_map_t() + {} + + void add_arg(const std::string &name, const char *default_value) + { + if (find(name)) { + log_error("Duplicate macro arguments with name `%s'.\n", name.c_str()); + } + + name_to_pos[name] = args.size(); + args.push_back(macro_arg_t(name, default_value)); + } + + // Find an argument by name; return nullptr if it doesn't exist. If pos is not null, write + // the argument's position to it on success. + const macro_arg_t *find(const std::string &name, int *pos = nullptr) const + { + auto it = name_to_pos.find(name); + if (it == name_to_pos.end()) + return nullptr; + + if (pos) *pos = it->second; + return &args[it->second]; + } + + // Construct the name for the local macro definition we use for the given argument + // (something like macro_foobar_arg2). This doesn't include the leading backtick. + static std::string str_token(const std::string ¯o_name, int pos) + { + return stringf("macro_%s_arg%d", macro_name.c_str(), pos); + } + + // Return definitions for the macro arguments (so that substituting in the macro body and + // then performing macro expansion will do argument substitution properly). + std::vector<std::pair<std::string, std::string>> + get_vals(const std::string ¯o_name, const std::vector<std::string> &arg_vals) const + { + std::vector<std::pair<std::string, std::string>> ret; + for (int i = 0; i < GetSize(args); ++ i) { + // The SystemVerilog rules are: + // + // - If the call site specifies an argument and it's not whitespace, use + // it. + // + // - Otherwise, if the argument has a default value, use it. + // + // - Otherwise, if the call site specified whitespace, use that. + // + // - Otherwise, error. + const std::string *dflt = nullptr; + if (args[i].has_default) + dflt = &args[i].default_value; + + const std::string *given = nullptr; + if (i < GetSize(arg_vals)) + given = &arg_vals[i]; + + const std::string *val = nullptr; + if (given && (! (dflt && all_white(*given)))) + val = given; + else if (dflt) + val = dflt; + else if (given) + val = given; + else + log_error("Cannot expand macro `%s by giving only %d argument%s " + "(argument %d has no default).\n", + macro_name.c_str(), GetSize(arg_vals), + (GetSize(arg_vals) == 1 ? "" : "s"), i + 1); + + assert(val); + ret.push_back(std::make_pair(str_token(macro_name, i), * val)); + } + return ret; + } + + + std::vector<macro_arg_t> args; + std::map<std::string, int> name_to_pos; +}; + +struct define_body_t +{ + define_body_t(const std::string &body, const arg_map_t *args = nullptr) + : body(body), + has_args(args != nullptr), + args(args ? *args : arg_map_t()) + {} + + std::string body; + bool has_args; + arg_map_t args; +}; + +define_map_t::define_map_t() +{ + add("YOSYS", "1"); + add(formal_mode ? "FORMAL" : "SYNTHESIS", "1"); +} + +// We must define this destructor here (rather than relying on the default), because we need to +// define it somewhere we've got a complete definition of define_body_t. +define_map_t::~define_map_t() +{} + +void +define_map_t::add(const std::string &name, const std::string &txt, const arg_map_t *args) +{ + defines[name] = std::unique_ptr<define_body_t>(new define_body_t(txt, args)); +} + +void define_map_t::merge(const define_map_t &map) +{ + for (const auto &pr : map.defines) { + // These contortions are so that we take a copy of each definition body in + // map.defines. + defines[pr.first] = std::unique_ptr<define_body_t>(new define_body_t(*pr.second)); + } +} + +const define_body_t *define_map_t::find(const std::string &name) const +{ + auto it = defines.find(name); + return (it == defines.end()) ? nullptr : it->second.get(); +} + +void define_map_t::erase(const std::string &name) +{ + defines.erase(name); +} + +void define_map_t::clear() +{ + defines.clear(); +} + +void define_map_t::log() const +{ + for (auto &it : defines) { + const std::string &name = it.first; + const define_body_t &body = *it.second; + Yosys::log("`define %s%s %s\n", + name.c_str(), body.has_args ? "()" : "", body.body.c_str()); + } +} + static void input_file(std::istream &f, std::string filename) { char buffer[513]; @@ -215,11 +386,59 @@ static void input_file(std::istream &f, std::string filename) input_buffer.insert(it, "\n`file_pop\n"); } +// Read tokens to get one argument (either a macro argument at a callsite or a default argument in a +// macro definition). Writes the argument to dest. Returns true if we finished with ')' (the end of +// the argument list); false if we finished with ','. +static bool read_argument(std::string &dest) +{ + std::vector<char> openers; + for (;;) { + skip_spaces(); + std::string tok = next_token(true); + if (tok == ")") { + if (openers.empty()) + return true; + if (openers.back() != '(') + log_error("Mismatched brackets in macro argument: %c and %c.\n", + openers.back(), tok[0]); + + openers.pop_back(); + dest += tok; + continue; + } + if (tok == "]") { + char opener = openers.empty() ? '(' : openers.back(); + if (opener != '[') + log_error("Mismatched brackets in macro argument: %c and %c.\n", + opener, tok[0]); + + openers.pop_back(); + dest += tok; + continue; + } + if (tok == "}") { + char opener = openers.empty() ? '(' : openers.back(); + if (opener != '{') + log_error("Mismatched brackets in macro argument: %c and %c.\n", + opener, tok[0]); + + openers.pop_back(); + dest += tok; + continue; + } + + if (tok == "," && openers.empty()) { + return false; + } + + if (tok == "(" || tok == "[" || tok == "{") + openers.push_back(tok[0]); -static bool try_expand_macro(std::set<std::string> &defines_with_args, - std::map<std::string, std::string> &defines_map, - std::string &tok - ) + dest += tok; + } +} + +static bool try_expand_macro(define_map_t &defines, std::string &tok) { if (tok == "`\"") { std::string literal("\""); @@ -229,54 +448,272 @@ static bool try_expand_macro(std::set<std::string> &defines_with_args, if (ntok == "`\"") { insert_input(literal+"\""); return true; - } else if (!try_expand_macro(defines_with_args, defines_map, ntok)) { + } else if (!try_expand_macro(defines, ntok)) { literal += ntok; } } return false; // error - unmatched `" - } else if (tok.size() > 1 && tok[0] == '`' && defines_map.count(tok.substr(1)) > 0) { - std::string name = tok.substr(1); - // printf("expand: >>%s<< -> >>%s<<\n", name.c_str(), defines_map[name].c_str()); - std::string skipped_spaces = skip_spaces(); - tok = next_token(false); - if (tok == "(" && defines_with_args.count(name) > 0) { - int level = 1; - std::vector<std::string> args; - args.push_back(std::string()); - while (1) - { - skip_spaces(); - tok = next_token(true); - if (tok == ")" || tok == "}" || tok == "]") - level--; - if (level == 0) - break; - if (level == 1 && tok == ",") - args.push_back(std::string()); - else - args.back() += tok; - if (tok == "(" || tok == "{" || tok == "[") - level++; - } - for (int i = 0; i < GetSize(args); i++) - defines_map[stringf("macro_%s_arg%d", name.c_str(), i+1)] = args[i]; - } else { - insert_input(tok); - insert_input(skipped_spaces); - } - insert_input(defines_map[name]); - return true; - } else if (tok == "``") { + } + + if (tok == "``") { // Swallow `` in macro expansion return true; - } else return false; + } + + if (tok.size() <= 1 || tok[0] != '`') + return false; + + // This token looks like a macro name (`foo). + std::string macro_name = tok.substr(1); + const define_body_t *body = defines.find(tok.substr(1)); + + if (! body) { + // Apparently not a name we know. + return false; + } + + std::string name = tok.substr(1); + std::string skipped_spaces = skip_spaces(); + tok = next_token(false); + if (tok == "(" && body->has_args) { + std::vector<std::string> args; + bool done = false; + while (!done) { + std::string arg; + done = read_argument(arg); + args.push_back(arg); + } + for (const auto &pr : body->args.get_vals(name, args)) { + defines.add(pr.first, pr.second); + } + } else { + insert_input(tok); + insert_input(skipped_spaces); + } + insert_input(body->body); + return true; } -std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> &pre_defines_map, - dict<std::string, std::pair<std::string, bool>> &global_defines_cache, const std::list<std::string> &include_dirs) +// Read the arguments for a `define preprocessor directive with formal arguments. This is called +// just after reading the token containing "(". Returns the number of newlines to emit afterwards to +// keep line numbers in sync, together with the map from argument name to data (pos and default +// value). +static std::pair<int, arg_map_t> +read_define_args() { - std::set<std::string> defines_with_args; - std::map<std::string, std::string> defines_map(pre_defines_map); + // Each argument looks like one of the following: + // + // identifier + // identifier = default_text + // identifier = + // + // The first example is an argument with no default value. The second is an argument whose + // default value is default_text. The third is an argument with default value the empty + // string. + + int newline_count = 0; + arg_map_t args; + + // FSM state. + // + // 0: At start of identifier + // 1: After identifier (stored in arg_name) + // 2: After closing paren + int state = 0; + + std::string arg_name, default_val; + + skip_spaces(); + for (;;) { + if (state == 2) + // We've read the closing paren. + break; + + std::string tok = next_token(); + + // Cope with escaped EOLs + if (tok == "\\") { + char ch = next_char(); + if (ch == '\n') { + // Eat the \, the \n and any trailing space and keep going. + skip_spaces(); + continue; + } else { + // There aren't any other situations where a backslash makes sense. + log_error("Backslash in macro arguments (not at end of line).\n"); + } + } + + switch (state) { + case 0: + // At start of argument. If the token is ')', we've presumably just seen + // something like "`define foo() ...". Set state to 2 to finish. Otherwise, + // the token should be a valid simple identifier, but we'll allow anything + // here. + if (tok == ")") { + state = 2; + } else { + arg_name = tok; + state = 1; + } + skip_spaces(); + break; + + case 1: + // After argument. The token should either be an equals sign or a comma or + // closing paren. + if (tok == "=") { + std::string default_val; + //Read an argument into default_val and set state to 2 if we're at + // the end; 0 if we hit a comma. + state = read_argument(default_val) ? 2 : 0; + args.add_arg(arg_name, default_val.c_str()); + skip_spaces(); + break; + } + if (tok == ",") { + // Take the identifier as an argument with no default value. + args.add_arg(arg_name, nullptr); + state = 0; + skip_spaces(); + break; + } + if (tok == ")") { + // As with comma, but set state to 2 (end of args) + args.add_arg(arg_name, nullptr); + state = 2; + skip_spaces(); + break; + } + log_error("Trailing contents after identifier in macro argument `%s': " + "expected '=', ',' or ')'.\n", + arg_name.c_str()); + + default: + // The only FSM states are 0-2 and we dealt with 2 at the start of the loop. + __builtin_unreachable(); + } + } + + return std::make_pair(newline_count, args); +} + +// Read a `define preprocessor directive. This is called just after reading the token containing +// "`define". +static void +read_define(const std::string &filename, + define_map_t &defines_map, + define_map_t &global_defines_cache) +{ + std::string name, value; + arg_map_t args; + + skip_spaces(); + name = next_token(true); + + bool here_doc_mode = false; + int newline_count = 0; + + // The FSM state starts at 0. If it sees space (or enters here_doc_mode), it assumes this is + // a macro without formal arguments and jumps to state 1. + // + // In state 0, if it sees an opening parenthesis, it assumes this is a macro with formal + // arguments. It reads the arguments with read_define_args() and then jumps to state 2. + // + // In states 1 or 2, the FSM reads tokens to the end of line (or end of here_doc): this is + // the body of the macro definition. + int state = 0; + + if (skip_spaces() != "") + state = 1; + + for (;;) { + std::string tok = next_token(); + if (tok.empty()) + break; + + // printf("define-tok: >>%s<<\n", tok != "\n" ? tok.c_str() : "NEWLINE"); + + if (tok == "\"\"\"") { + here_doc_mode = !here_doc_mode; + continue; + } + + if (state == 0 && tok == "(") { + auto pr = read_define_args(); + newline_count += pr.first; + args = pr.second; + + state = 2; + continue; + } + + // This token isn't an opening parenthesis immediately following the macro name, so + // it's presumably at or after the start of the macro body. If state isn't already 2 + // (which would mean we'd parsed an argument list), set it to 1. + if (state == 0) { + state = 1; + } + + if (tok == "\n") { + if (here_doc_mode) { + value += " "; + newline_count++; + } else { + return_char('\n'); + break; + } + continue; + } + + if (tok == "\\") { + char ch = next_char(); + if (ch == '\n') { + value += " "; + newline_count++; + } else { + value += std::string("\\"); + return_char(ch); + } + continue; + } + + // Is this token the name of a macro argument? If so, replace it with a magic symbol + // that we'll replace with the argument value. + int arg_pos; + if (args.find(tok, &arg_pos)) { + value += '`' + args.str_token(name, arg_pos); + continue; + } + + // This token is nothing special. Insert it verbatim into the macro body. + value += tok; + } + + // Append some newlines so that we don't mess up line counts in error messages. + while (newline_count-- > 0) + return_char('\n'); + + if (strchr("abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789", name[0])) { + // printf("define: >>%s<< -> >>%s<<\n", name.c_str(), value.c_str()); + defines_map.add(name, value, (state == 2) ? &args : nullptr); + global_defines_cache.add(name, value, (state == 2) ? &args : nullptr); + } else { + log_file_error(filename, 0, "Invalid name for macro definition: >>%s<<.\n", name.c_str()); + } +} + +std::string +frontend_verilog_preproc(std::istream &f, + std::string filename, + const define_map_t &pre_defines, + define_map_t &global_defines_cache, + const std::list<std::string> &include_dirs) +{ + define_map_t defines; + defines.merge(pre_defines); + defines.merge(global_defines_cache); + std::vector<std::string> filename_stack; int ifdef_fail_level = 0; bool in_elseif = false; @@ -287,18 +724,6 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons input_file(f, filename); - defines_map["YOSYS"] = "1"; - defines_map[formal_mode ? "FORMAL" : "SYNTHESIS"] = "1"; - - for (auto &it : pre_defines_map) - defines_map[it.first] = it.second; - - for (auto &it : global_defines_cache) { - if (it.second.second) - defines_with_args.insert(it.first); - defines_map[it.first] = it.second.first; - } - while (!input_buffer.empty()) { std::string tok = next_token(); @@ -325,7 +750,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons std::string name = next_token(true); if (ifdef_fail_level == 0) ifdef_fail_level = 1, in_elseif = true; - else if (ifdef_fail_level == 1 && defines_map.count(name) != 0) + else if (ifdef_fail_level == 1 && defines.find(name)) ifdef_fail_level = 0, in_elseif = true; continue; } @@ -333,7 +758,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons if (tok == "`ifdef") { skip_spaces(); std::string name = next_token(true); - if (ifdef_fail_level > 0 || defines_map.count(name) == 0) + if (ifdef_fail_level > 0 || !defines.find(name)) ifdef_fail_level++; continue; } @@ -341,7 +766,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons if (tok == "`ifndef") { skip_spaces(); std::string name = next_token(true); - if (ifdef_fail_level > 0 || defines_map.count(name) != 0) + if (ifdef_fail_level > 0 || defines.find(name)) ifdef_fail_level++; continue; } @@ -355,7 +780,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons if (tok == "`include") { skip_spaces(); std::string fn = next_token(true); - while (try_expand_macro(defines_with_args, defines_map, fn)) { + while (try_expand_macro(defines, fn)) { fn = next_token(); } while (1) { @@ -433,74 +858,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons } if (tok == "`define") { - std::string name, value; - std::map<std::string, int> args; - skip_spaces(); - name = next_token(true); - bool here_doc_mode = false; - int newline_count = 0; - int state = 0; - if (skip_spaces() != "") - state = 3; - while (!tok.empty()) { - tok = next_token(); - if (tok == "\"\"\"") { - here_doc_mode = !here_doc_mode; - continue; - } - if (state == 0 && tok == "(") { - state = 1; - skip_spaces(); - } else - if (state == 1) { - if (tok == ")") - state = 2; - else if (tok != ",") { - int arg_idx = args.size()+1; - args[tok] = arg_idx; - } - skip_spaces(); - } else { - if (state != 2) - state = 3; - if (tok == "\n") { - if (here_doc_mode) { - value += " "; - newline_count++; - } else { - return_char('\n'); - break; - } - } else - if (tok == "\\") { - char ch = next_char(); - if (ch == '\n') { - value += " "; - newline_count++; - } else { - value += std::string("\\"); - return_char(ch); - } - } else - if (args.count(tok) > 0) - value += stringf("`macro_%s_arg%d", name.c_str(), args.at(tok)); - else - value += tok; - } - } - while (newline_count-- > 0) - return_char('\n'); - if (strchr("abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789", name[0])) { - // printf("define: >>%s<< -> >>%s<<\n", name.c_str(), value.c_str()); - defines_map[name] = value; - if (state == 2) - defines_with_args.insert(name); - else - defines_with_args.erase(name); - global_defines_cache[name] = std::pair<std::string, bool>(value, state == 2); - } else { - log_file_error(filename, 0, "Invalid name for macro definition: >>%s<<.\n", name.c_str()); - } + read_define(filename, defines, global_defines_cache); continue; } @@ -509,8 +867,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons skip_spaces(); name = next_token(true); // printf("undef: >>%s<<\n", name.c_str()); - defines_map.erase(name); - defines_with_args.erase(name); + defines.erase(name); global_defines_cache.erase(name); continue; } @@ -525,13 +882,12 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons } if (tok == "`resetall") { - defines_map.clear(); - defines_with_args.clear(); + defines.clear(); global_defines_cache.clear(); continue; } - if (try_expand_macro(defines_with_args, defines_map, tok)) + if (try_expand_macro(defines, tok)) continue; output_code.push_back(tok); diff --git a/frontends/verilog/preproc.h b/frontends/verilog/preproc.h new file mode 100644 index 000000000..673d633c0 --- /dev/null +++ b/frontends/verilog/preproc.h @@ -0,0 +1,77 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + * --- + * + * The Verilog preprocessor. + * + */ +#ifndef VERILOG_PREPROC_H +#define VERILOG_PREPROC_H + +#include "kernel/yosys.h" + +#include <iosfwd> +#include <list> +#include <memory> +#include <string> + +YOSYS_NAMESPACE_BEGIN + +struct define_body_t; +struct arg_map_t; + +struct define_map_t +{ + define_map_t(); + ~ define_map_t(); + + // Add a definition, overwriting any existing definition for name. + void add(const std::string &name, const std::string &txt, const arg_map_t *args = nullptr); + + // Merge in another map of definitions (which take precedence + // over anything currently defined). + void merge(const define_map_t &map); + + // Find a definition by name. If no match, returns null. + const define_body_t *find(const std::string &name) const; + + // Erase a definition by name (no effect if not defined). + void erase(const std::string &name); + + // Clear any existing definitions + void clear(); + + // Print a list of definitions, using the log function + void log() const; + + std::map<std::string, std::unique_ptr<define_body_t>> defines; +}; + + +struct define_map_t; + +std::string +frontend_verilog_preproc(std::istream &f, + std::string filename, + const define_map_t &pre_defines, + define_map_t &global_defines_cache, + const std::list<std::string> &include_dirs); + +YOSYS_NAMESPACE_END + +#endif diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 42eabc02d..6879e0943 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -27,6 +27,7 @@ */ #include "verilog_frontend.h" +#include "preproc.h" #include "kernel/yosys.h" #include "libs/sha1/sha1.h" #include <stdarg.h> @@ -47,6 +48,23 @@ static void error_on_dpi_function(AST::AstNode *node) error_on_dpi_function(child); } +static void add_package_types(std::map<std::string, AST::AstNode *> &user_types, std::vector<AST::AstNode *> &package_list) +{ + // prime the parser's user type lookup table with the package qualified names + // of typedefed names in the packages seen so far. + for (const auto &pkg : package_list) { + log_assert(pkg->type==AST::AST_PACKAGE); + for (const auto &node: pkg->children) { + if (node->type == AST::AST_TYPEDEF) { + std::string s = pkg->str + "::" + node->str.substr(1); + user_types[s] = node; + } + } + } + user_type_stack.clear(); + user_type_stack.push_back(new UserTypeMap()); +} + struct VerilogFrontend : public Frontend { VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } void help() YS_OVERRIDE @@ -237,7 +255,8 @@ struct VerilogFrontend : public Frontend { bool flag_defer = false; bool flag_noblackbox = false; bool flag_nowb = false; - std::map<std::string, std::string> defines_map; + define_map_t defines_map; + std::list<std::string> include_dirs; std::list<std::string> attributes; @@ -353,7 +372,7 @@ struct VerilogFrontend : public Frontend { } if (arg == "-lib") { lib_mode = true; - defines_map["BLACKBOX"] = string(); + defines_map.add("BLACKBOX", ""); continue; } if (arg == "-nowb") { @@ -405,7 +424,7 @@ struct VerilogFrontend : public Frontend { value = name.substr(equal+1); name = name.substr(0, equal); } - defines_map[name] = value; + defines_map.add(name, value); continue; } if (arg.compare(0, 2, "-D") == 0) { @@ -414,7 +433,7 @@ struct VerilogFrontend : public Frontend { std::string value; if (equal != std::string::npos) value = arg.substr(equal+1); - defines_map[name] = value; + defines_map.add(name, value); continue; } if (arg == "-I" && argidx+1 < args.size()) { @@ -444,12 +463,15 @@ struct VerilogFrontend : public Frontend { std::string code_after_preproc; if (!flag_nopp) { - code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, design->verilog_defines, include_dirs); + code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs); if (flag_ppdump) log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str()); lexin = new std::istringstream(code_after_preproc); } + // make package typedefs available to parser + add_package_types(pkg_user_types, design->verilog_packages); + frontend_verilog_yyset_lineno(1); frontend_verilog_yyrestart(NULL); frontend_verilog_yyparse(); @@ -468,6 +490,7 @@ struct VerilogFrontend : public Frontend { AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); + if (!flag_nopp) delete lexin; @@ -572,7 +595,7 @@ struct VerilogDefines : public Pass { value = name.substr(equal+1); name = name.substr(0, equal); } - design->verilog_defines[name] = std::pair<std::string, bool>(value, false); + design->verilog_defines->add(name, value); continue; } if (arg.compare(0, 2, "-D") == 0) { @@ -581,27 +604,25 @@ struct VerilogDefines : public Pass { std::string value; if (equal != std::string::npos) value = arg.substr(equal+1); - design->verilog_defines[name] = std::pair<std::string, bool>(value, false); + design->verilog_defines->add(name, value); continue; } if (arg == "-U" && argidx+1 < args.size()) { std::string name = args[++argidx]; - design->verilog_defines.erase(name); + design->verilog_defines->erase(name); continue; } if (arg.compare(0, 2, "-U") == 0) { std::string name = arg.substr(2); - design->verilog_defines.erase(name); + design->verilog_defines->erase(name); continue; } if (arg == "-reset") { - design->verilog_defines.clear(); + design->verilog_defines->clear(); continue; } if (arg == "-list") { - for (auto &it : design->verilog_defines) { - log("`define %s%s %s\n", it.first.c_str(), it.second.second ? "()" : "", it.second.first.c_str()); - } + design->verilog_defines->log(); continue; } break; diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index a2e06f0e4..444cc7297 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -45,6 +45,13 @@ namespace VERILOG_FRONTEND // this function converts a Verilog constant to an AST_CONSTANT node AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false); + // names of locally typedef'ed types in a stack + typedef std::map<std::string, AST::AstNode*> UserTypeMap; + extern std::vector<UserTypeMap *> user_type_stack; + + // names of package typedef'ed types + extern std::map<std::string, AST::AstNode*> pkg_user_types; + // state of `default_nettype extern bool default_nettype_wire; @@ -79,10 +86,6 @@ namespace VERILOG_FRONTEND extern std::istream *lexin; } -// the pre-processor -std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> &pre_defines_map, - dict<std::string, std::pair<std::string, bool>> &global_defines_cache, const std::list<std::string> &include_dirs); - YOSYS_NAMESPACE_END // the usual bison/flex stuff diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 0a7c34ec0..f6a3ac4db 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -99,6 +99,18 @@ YYLTYPE old_location; #define YY_BUF_SIZE 65536 extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); + +static bool isUserType(std::string &s) +{ + // check current scope then outer scopes for a name + for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) { + if ((*it)->count(s) > 0) { + return true; + } + } + return false; +} + %} %option yylineno @@ -113,8 +125,10 @@ extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); %x SYNOPSYS_TRANSLATE_OFF %x SYNOPSYS_FLAGS %x IMPORT_DPI +%x BASED_CONST %% + int comment_caller; <INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* { fn_stack.push_back(current_filename); @@ -273,9 +287,21 @@ extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); return TOK_CONSTVAL; } -[0-9]*[ \t]*\'[sS]?[bodhBODH]?[ \t\r\n]*[0-9a-fA-FzxZX?_]+ { +\'[01zxZX] { yylval->string = new std::string(yytext); - return TOK_CONSTVAL; + return TOK_UNBASED_UNSIZED_CONSTVAL; +} + +\'[sS]?[bodhBODH] { + BEGIN(BASED_CONST); + yylval->string = new std::string(yytext); + return TOK_BASE; +} + +<BASED_CONST>[0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* { + BEGIN(0); + yylval->string = new std::string(yytext); + return TOK_BASED_CONSTVAL; } [0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)? { @@ -358,9 +384,34 @@ supply1 { return TOK_SUPPLY1; } "$signed" { return TOK_TO_SIGNED; } "$unsigned" { return TOK_TO_UNSIGNED; } +[a-zA-Z_][a-zA-Z0-9_]*::[a-zA-Z_$][a-zA-Z0-9_$]* { + // package qualifier + auto s = std::string("\\") + yytext; + if (pkg_user_types.count(s) > 0) { + // package qualified typedefed name + yylval->string = new std::string(s); + return TOK_PKG_USER_TYPE; + } + else { + // backup before :: just return first part + size_t len = strchr(yytext, ':') - yytext; + yyless(len); + yylval->string = new std::string(std::string("\\") + yytext); + return TOK_ID; + } +} + [a-zA-Z_$][a-zA-Z0-9_$]* { - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_ID; + auto s = std::string("\\") + yytext; + if (isUserType(s)) { + // previously typedefed name + yylval->string = new std::string(s); + return TOK_USER_TYPE; + } + else { + yylval->string = new std::string(std::string("\\") + yytext); + return TOK_ID; + } } [a-zA-Z_$][a-zA-Z0-9_$\.]* { @@ -478,16 +529,17 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { return TOK_SPECIFY_AND; } -"/*" { BEGIN(COMMENT); } +<INITIAL,BASED_CONST>"/*" { comment_caller=YY_START; BEGIN(COMMENT); } <COMMENT>. /* ignore comment body */ <COMMENT>\n /* ignore comment body */ -<COMMENT>"*/" { BEGIN(0); } +<COMMENT>"*/" { BEGIN(comment_caller); } -[ \t\r\n] /* ignore whitespaces */ -\\[\r\n] /* ignore continuation sequence */ -"//"[^\r\n]* /* ignore one-line comments */ +<INITIAL,BASED_CONST>[ \t\r\n] /* ignore whitespaces */ +<INITIAL,BASED_CONST>\\[\r\n] /* ignore continuation sequence */ +<INITIAL,BASED_CONST>"//"[^\r\n]* /* ignore one-line comments */ -. { return *yytext; } +<INITIAL>. { return *yytext; } +<*>. { BEGIN(0); return *yytext; } %% diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 91982e2a3..be2872e59 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -54,6 +54,8 @@ namespace VERILOG_FRONTEND { std::map<std::string, AstNode*> *attr_list, default_attr_list; std::stack<std::map<std::string, AstNode*> *> attr_list_stack; std::map<std::string, AstNode*> *albuf; + std::vector<UserTypeMap*> user_type_stack; + std::map<std::string, AstNode*> pkg_user_types; std::vector<AstNode*> ast_stack; struct AstNode *astbuf1, *astbuf2, *astbuf3; struct AstNode *current_function_or_task; @@ -125,6 +127,40 @@ struct specify_rise_fall { specify_triple fall; }; +static void addTypedefNode(std::string *name, AstNode *node) +{ + log_assert(node); + auto *tnode = new AstNode(AST_TYPEDEF, node); + tnode->str = *name; + auto user_types = user_type_stack.back(); + (*user_types)[*name] = tnode; + if (current_ast_mod && current_ast_mod->type == AST_PACKAGE) { + // typedef inside a package so we need the qualified name + auto qname = current_ast_mod->str + "::" + (*name).substr(1); + pkg_user_types[qname] = tnode; + } + delete name; + ast_stack.back()->children.push_back(tnode); +} + +static void enterTypeScope() +{ + auto user_types = new UserTypeMap(); + user_type_stack.push_back(user_types); +} + +static void exitTypeScope() +{ + user_type_stack.pop_back(); +} + +static bool isInLocalScope(const std::string *name) +{ + // tests if a name was declared in the current block scope + auto user_types = user_type_stack.back(); + return (user_types->count(*name) > 0); +} + static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true) { auto range = new AstNode(AST_RANGE); @@ -166,6 +202,8 @@ static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE %token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS +%token <string> TOK_BASE TOK_BASED_CONSTVAL TOK_UNBASED_UNSIZED_CONSTVAL +%token <string> TOK_USER_TYPE TOK_PKG_USER_TYPE %token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM @@ -188,7 +226,8 @@ static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = %type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list -%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id +%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number +%type <string> type_name %type <ast> opt_enum_init %type <boolean> opt_signed opt_property unique_case_attr always_comb_or_latch always_or_always_ff %type <al> attr case_attr @@ -329,10 +368,15 @@ hierarchical_id: }; hierarchical_type_id: - '(' hierarchical_id ')' { $$ = $2; }; + TOK_USER_TYPE + | TOK_PKG_USER_TYPE // package qualified type name + | '(' TOK_USER_TYPE ')' { $$ = $2; } // non-standard grammar + ; module: - attr TOK_MODULE TOK_ID { + attr TOK_MODULE { + enterTypeScope(); + } TOK_ID { do_not_require_port_stubs = false; AstNode *mod = new AstNode(AST_MODULE); ast_stack.back()->children.push_back(mod); @@ -340,9 +384,9 @@ module: current_ast_mod = mod; port_stubs.clear(); port_counter = 0; - mod->str = *$3; + mod->str = *$4; append_attr(mod, $1); - delete $3; + delete $4; } module_para_opt module_args_opt ';' module_body TOK_ENDMODULE { if (port_stubs.size() != 0) frontend_verilog_yyerror("Missing details for module port `%s'.", @@ -351,6 +395,7 @@ module: ast_stack.pop_back(); log_assert(ast_stack.size() == 1); current_ast_mod = NULL; + exitTypeScope(); }; module_para_opt: @@ -454,16 +499,19 @@ module_arg: }; package: - attr TOK_PACKAGE TOK_ID { + attr TOK_PACKAGE { + enterTypeScope(); + } TOK_ID { AstNode *mod = new AstNode(AST_PACKAGE); ast_stack.back()->children.push_back(mod); ast_stack.push_back(mod); current_ast_mod = mod; - mod->str = *$3; + mod->str = *$4; append_attr(mod, $1); } ';' package_body TOK_ENDPACKAGE { ast_stack.pop_back(); current_ast_mod = NULL; + exitTypeScope(); }; package_body: @@ -476,7 +524,9 @@ package_body_stmt: localparam_decl; interface: - TOK_INTERFACE TOK_ID { + TOK_INTERFACE { + enterTypeScope(); + } TOK_ID { do_not_require_port_stubs = false; AstNode *intf = new AstNode(AST_INTERFACE); ast_stack.back()->children.push_back(intf); @@ -484,8 +534,8 @@ interface: current_ast_mod = intf; port_stubs.clear(); port_counter = 0; - intf->str = *$2; - delete $2; + intf->str = *$3; + delete $3; } module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE { if (port_stubs.size() != 0) frontend_verilog_yyerror("Missing details for module port `%s'.", @@ -493,6 +543,7 @@ interface: ast_stack.pop_back(); log_assert(ast_stack.size() == 1); current_ast_mod = NULL; + exitTypeScope(); }; interface_body: @@ -1590,8 +1641,12 @@ assign_expr: ast_stack.back()->children.push_back(node); }; +type_name: TOK_ID // first time seen + | TOK_USER_TYPE { if (isInLocalScope($1)) frontend_verilog_yyerror("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); } + ; + typedef_decl: - TOK_TYPEDEF wire_type range TOK_ID range_or_multirange ';' { + TOK_TYPEDEF wire_type range type_name range_or_multirange ';' { astbuf1 = $2; astbuf2 = $3; if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) { @@ -1624,13 +1679,10 @@ typedef_decl: } astbuf1->children.push_back(rangeNode); } - - ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1)); - ast_stack.back()->children.back()->str = *$4; + addTypedefNode($4, astbuf1); } | - TOK_TYPEDEF enum_type TOK_ID ';' { - ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1)); - ast_stack.back()->children.back()->str = *$3; + TOK_TYPEDEF enum_type type_name ';' { + addTypedefNode($3, astbuf1); } ; @@ -1954,6 +2006,7 @@ assert: delete $5; } else { AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1966,6 +2019,7 @@ assert: delete $5; } else { AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5); + SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1978,6 +2032,7 @@ assert: delete $6; } else { AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); + SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1990,6 +2045,7 @@ assert: delete $6; } else { AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6); + SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1999,6 +2055,7 @@ assert: } | opt_sva_label TOK_COVER opt_property '(' expr ')' ';' { AstNode *node = new AstNode(AST_COVER, $5); + SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) { node->str = *$1; delete $1; @@ -2007,6 +2064,7 @@ assert: } | opt_sva_label TOK_COVER opt_property '(' ')' ';' { AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + SET_AST_NODE_LOC(node, @1, @5); if ($1 != nullptr) { node->str = *$1; delete $1; @@ -2015,6 +2073,7 @@ assert: } | opt_sva_label TOK_COVER ';' { AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + SET_AST_NODE_LOC(node, @1, @2); if ($1 != nullptr) { node->str = *$1; delete $1; @@ -2026,6 +2085,7 @@ assert: delete $5; } else { AstNode *node = new AstNode(AST_ASSUME, $5); + SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -2040,6 +2100,7 @@ assert: delete $6; } else { AstNode *node = new AstNode(AST_FAIR, $6); + SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -2052,35 +2113,45 @@ assert: assert_property: opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); + AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + SET_AST_NODE_LOC(node, @1, @6); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; } } | opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + AstNode *node = new AstNode(AST_ASSUME, $5); + SET_AST_NODE_LOC(node, @1, @6); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; } } | opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6)); + AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); + SET_AST_NODE_LOC(node, @1, @7); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; } } | opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + AstNode *node = new AstNode(AST_FAIR, $6); + SET_AST_NODE_LOC(node, @1, @7); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; } } | opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5)); + AstNode *node = new AstNode(AST_COVER, $5); + SET_AST_NODE_LOC(node, @1, @6); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; @@ -2090,7 +2161,9 @@ assert_property: if (norestrict_mode) { delete $5; } else { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + AstNode *node = new AstNode(AST_ASSUME, $5); + SET_AST_NODE_LOC(node, @1, @6); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; @@ -2101,7 +2174,9 @@ assert_property: if (norestrict_mode) { delete $6; } else { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + AstNode *node = new AstNode(AST_FAIR, $6); + SET_AST_NODE_LOC(node, @1, @7); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; @@ -2113,18 +2188,22 @@ simple_behavioral_stmt: lvalue '=' delay expr { AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4); ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @4); } | lvalue TOK_INCREMENT { AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_ADD, $1->clone(), AstNode::mkconst_int(1, true))); ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @2); } | lvalue TOK_DECREMENT { AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_SUB, $1->clone(), AstNode::mkconst_int(1, true))); ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @2); } | lvalue OP_LE delay expr { AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4); ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @4); }; // this production creates the obligatory if-else shift/reduce conflict @@ -2152,20 +2231,21 @@ behavioral_stmt: } opt_arg_list ';'{ ast_stack.pop_back(); } | - attr TOK_BEGIN opt_label { + attr TOK_BEGIN { + enterTypeScope(); + } opt_label { AstNode *node = new AstNode(AST_BLOCK); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); append_attr(node, $1); - if ($3 != NULL) - node->str = *$3; + if ($4 != NULL) + node->str = *$4; } behavioral_stmt_list TOK_END opt_label { - if ($3 != NULL && $7 != NULL && *$3 != *$7) - frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1); - if ($3 != NULL) - delete $3; - if ($7 != NULL) - delete $7; + exitTypeScope(); + if ($4 != NULL && $8 != NULL && *$4 != *$8) + frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $4->c_str()+1, $8->c_str()+1); + delete $4; + delete $8; ast_stack.pop_back(); } | attr TOK_FOR '(' { @@ -2182,6 +2262,7 @@ behavioral_stmt: } behavioral_stmt { SET_AST_NODE_LOC(ast_stack.back(), @13, @13); ast_stack.pop_back(); + SET_AST_NODE_LOC(ast_stack.back(), @2, @13); ast_stack.pop_back(); } | attr TOK_WHILE '(' expr ')' { @@ -2242,6 +2323,8 @@ behavioral_stmt: ast_stack.pop_back(); }; + ; + unique_case_attr: /* empty */ { $$ = false; @@ -2335,6 +2418,7 @@ gen_case_item: ast_stack.push_back(node); } case_select { case_type_stack.push_back(0); + SET_AST_NODE_LOC(ast_stack.back(), @2, @2); } gen_stmt_or_null { case_type_stack.pop_back(); ast_stack.pop_back(); @@ -2346,10 +2430,14 @@ case_select: case_expr_list: TOK_DEFAULT { - ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT)); + AstNode *node = new AstNode(AST_DEFAULT); + SET_AST_NODE_LOC(node, @1, @1); + ast_stack.back()->children.push_back(node); } | TOK_SVA_LABEL { - ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER)); + AstNode *node = new AstNode(AST_IDENTIFIER); + SET_AST_NODE_LOC(node, @1, @1); + ast_stack.back()->children.push_back(node); ast_stack.back()->children.back()->str = *$1; delete $1; } | @@ -2369,6 +2457,7 @@ rvalue: hierarchical_id range { $$ = new AstNode(AST_IDENTIFIER, $2); $$->str = *$1; + SET_AST_NODE_LOC($$, @1, @1); delete $1; if ($2 == nullptr && ($$->str == "\\$initstate" || $$->str == "\\$anyconst" || $$->str == "\\$anyseq" || @@ -2378,6 +2467,7 @@ rvalue: hierarchical_id non_opt_multirange { $$ = new AstNode(AST_IDENTIFIER, $2); $$->str = *$1; + SET_AST_NODE_LOC($$, @1, @1); delete $1; }; @@ -2450,16 +2540,17 @@ gen_stmt: case_type_stack.pop_back(); ast_stack.pop_back(); } | - TOK_BEGIN opt_label { + TOK_BEGIN { + enterTypeScope(); + } opt_label { AstNode *node = new AstNode(AST_GENBLOCK); - node->str = $2 ? *$2 : std::string(); + node->str = $3 ? *$3 : std::string(); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); } module_gen_body TOK_END opt_label { - if ($2 != NULL) - delete $2; - if ($6 != NULL) - delete $6; + exitTypeScope(); + delete $3; + delete $7; ast_stack.pop_back(); } | TOK_MSG_TASKS { @@ -2496,6 +2587,7 @@ expr: $$->children.push_back($1); $$->children.push_back($4); $$->children.push_back($6); + SET_AST_NODE_LOC($$, @1, @$); append_attr($$, $3); }; @@ -2503,7 +2595,7 @@ basic_expr: rvalue { $$ = $1; } | - '(' expr ')' TOK_CONSTVAL { + '(' expr ')' integral_number { if ($4->compare(0, 1, "'") != 0) frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str()); AstNode *bits = $2; @@ -2513,11 +2605,12 @@ basic_expr: $$ = new AstNode(AST_TO_BITS, bits, val); delete $4; } | - hierarchical_id TOK_CONSTVAL { + hierarchical_id integral_number { if ($2->compare(0, 1, "'") != 0) frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str()); AstNode *bits = new AstNode(AST_IDENTIFIER); bits->str = *$1; + SET_AST_NODE_LOC(bits, @1, @1); AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if (val == NULL) log_error("Value conversion failed: `%s'\n", $2->c_str()); @@ -2525,14 +2618,7 @@ basic_expr: delete $1; delete $2; } | - TOK_CONSTVAL TOK_CONSTVAL { - $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - if ($$ == NULL || (*$2)[0] != '\'') - log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str()); - delete $1; - delete $2; - } | - TOK_CONSTVAL { + integral_number { $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if ($$ == NULL) log_error("Value conversion failed: `%s'\n", $1->c_str()); @@ -2545,6 +2631,7 @@ basic_expr: if ((*$1)[j] != '_') p[i++] = (*$1)[j], p[i] = 0; $$->realvalue = strtod(p, &q); + SET_AST_NODE_LOC($$, @1, @1); log_assert(*q == 0); delete $1; free(p); @@ -2558,6 +2645,7 @@ basic_expr: node->str = *$1; delete $1; ast_stack.push_back(node); + SET_AST_NODE_LOC(node, @1, @1); append_attr(node, $2); } '(' arg_list optional_comma ')' { $$ = ast_stack.back(); @@ -2587,148 +2675,185 @@ basic_expr: } | '~' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_BIT_NOT, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | basic_expr '&' attr basic_expr { $$ = new AstNode(AST_BIT_AND, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_NAND attr basic_expr { $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_AND, $1, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '|' attr basic_expr { $$ = new AstNode(AST_BIT_OR, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_NOR attr basic_expr { $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_OR, $1, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '^' attr basic_expr { $$ = new AstNode(AST_BIT_XOR, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_XNOR attr basic_expr { $$ = new AstNode(AST_BIT_XNOR, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | '&' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_AND, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | OP_NAND attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_AND, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); $$ = new AstNode(AST_LOGIC_NOT, $$); } | '|' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_OR, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | OP_NOR attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_OR, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); $$ = new AstNode(AST_LOGIC_NOT, $$); + SET_AST_NODE_LOC($$, @1, @3); } | '^' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_XOR, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | OP_XNOR attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_XNOR, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | basic_expr OP_SHL attr basic_expr { $$ = new AstNode(AST_SHIFT_LEFT, $1, new AstNode(AST_TO_UNSIGNED, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_SHR attr basic_expr { $$ = new AstNode(AST_SHIFT_RIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_SSHL attr basic_expr { $$ = new AstNode(AST_SHIFT_SLEFT, $1, new AstNode(AST_TO_UNSIGNED, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_SSHR attr basic_expr { $$ = new AstNode(AST_SHIFT_SRIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '<' attr basic_expr { $$ = new AstNode(AST_LT, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_LE attr basic_expr { $$ = new AstNode(AST_LE, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_EQ attr basic_expr { $$ = new AstNode(AST_EQ, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_NE attr basic_expr { $$ = new AstNode(AST_NE, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_EQX attr basic_expr { $$ = new AstNode(AST_EQX, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_NEX attr basic_expr { $$ = new AstNode(AST_NEX, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_GE attr basic_expr { $$ = new AstNode(AST_GE, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '>' attr basic_expr { $$ = new AstNode(AST_GT, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '+' attr basic_expr { $$ = new AstNode(AST_ADD, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '-' attr basic_expr { $$ = new AstNode(AST_SUB, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '*' attr basic_expr { $$ = new AstNode(AST_MUL, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '/' attr basic_expr { $$ = new AstNode(AST_DIV, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '%' attr basic_expr { $$ = new AstNode(AST_MOD, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_POW attr basic_expr { $$ = new AstNode(AST_POW, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | '+' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_POS, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | '-' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_NEG, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | basic_expr OP_LAND attr basic_expr { $$ = new AstNode(AST_LOGIC_AND, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_LOR attr basic_expr { $$ = new AstNode(AST_LOGIC_OR, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | '!' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_LOGIC_NOT, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); }; @@ -2740,3 +2865,18 @@ concat_list: $$ = $3; $$->children.push_back($1); }; + +integral_number: + TOK_CONSTVAL { $$ = $1; } | + TOK_UNBASED_UNSIZED_CONSTVAL { $$ = $1; } | + TOK_BASE TOK_BASED_CONSTVAL { + $1->append(*$2); + $$ = $1; + delete $2; + } | + TOK_CONSTVAL TOK_BASE TOK_BASED_CONSTVAL { + $1->append(*$2).append(*$3); + $$ = $1; + delete $2; + delete $3; + }; diff --git a/kernel/driver.cc b/kernel/driver.cc index 398c89e03..5f0959776 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -413,22 +413,13 @@ int main(int argc, char **argv) scriptfile_tcl = true; break; case 'W': - log_warn_regexes.push_back(std::regex(optarg, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep)); + log_warn_regexes.push_back(YS_REGEX_COMPILE(optarg)); break; case 'w': - log_nowarn_regexes.push_back(std::regex(optarg, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep)); + log_nowarn_regexes.push_back(YS_REGEX_COMPILE(optarg)); break; case 'e': - log_werror_regexes.push_back(std::regex(optarg, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep)); + log_werror_regexes.push_back(YS_REGEX_COMPILE(optarg)); break; case 'D': vlog_defines.push_back(optarg); diff --git a/kernel/log.cc b/kernel/log.cc index 2f8ce9e8c..d84a4381e 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -41,8 +41,8 @@ YOSYS_NAMESPACE_BEGIN std::vector<FILE*> log_files; std::vector<std::ostream*> log_streams; std::map<std::string, std::set<std::string>> log_hdump; -std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes; -std::vector<std::pair<std::regex,LogExpectedItem>> log_expect_log, log_expect_warning, log_expect_error; +std::vector<YS_REGEX_TYPE> log_warn_regexes, log_nowarn_regexes, log_werror_regexes; +std::vector<std::pair<YS_REGEX_TYPE,LogExpectedItem>> log_expect_log, log_expect_warning, log_expect_error; std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored; int log_warnings_count = 0; int log_warnings_count_noexpect = 0; @@ -177,11 +177,11 @@ void logv(const char *format, va_list ap) if (!linebuffer.empty() && linebuffer.back() == '\n') { for (auto &re : log_warn_regexes) - if (std::regex_search(linebuffer, re)) + if (YS_REGEX_NS::regex_search(linebuffer, re)) log_warning("Found log message matching -W regex:\n%s", str.c_str()); for (auto &item : log_expect_log) - if (std::regex_search(linebuffer, item.first)) + if (YS_REGEX_NS::regex_search(linebuffer, item.first)) item.second.current_count++; linebuffer.clear(); @@ -238,7 +238,7 @@ static void logv_warning_with_prefix(const char *prefix, bool suppressed = false; for (auto &re : log_nowarn_regexes) - if (std::regex_search(message, re)) + if (YS_REGEX_NS::regex_search(message, re)) suppressed = true; if (suppressed) @@ -251,12 +251,12 @@ static void logv_warning_with_prefix(const char *prefix, log_make_debug = 0; for (auto &re : log_werror_regexes) - if (std::regex_search(message, re)) + if (YS_REGEX_NS::regex_search(message, re)) log_error("%s", message.c_str()); bool warning_match = false; for (auto &item : log_expect_warning) - if (std::regex_search(message, item.first)) { + if (YS_REGEX_NS::regex_search(message, item.first)) { item.second.current_count++; warning_match = true; } @@ -349,7 +349,7 @@ static void logv_error_with_prefix(const char *prefix, log_error_atexit(); for (auto &item : log_expect_error) - if (std::regex_search(log_last_error, item.first)) + if (YS_REGEX_NS::regex_search(log_last_error, item.first)) item.second.current_count++; if (check_expected_logs) diff --git a/kernel/log.h b/kernel/log.h index 603938f4c..cd0e8185c 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -23,7 +23,25 @@ #define LOG_H #include <time.h> -#include <regex> + +// In GCC 4.8 std::regex is not working correctlty, in order to make features +// using regular expressions to work replacement regex library is used +#if defined(__GNUC__) && !defined( __clang__) && ( __GNUC__ == 4 && __GNUC_MINOR__ <= 8) + #include <boost/xpressive/xpressive.hpp> + #define YS_REGEX_TYPE boost::xpressive::sregex + #define YS_REGEX_NS boost::xpressive + #define YS_REGEX_COMPILE(param) boost::xpressive::sregex::compile(param, \ + boost::xpressive::regex_constants::nosubs | \ + boost::xpressive::regex_constants::optimize) +# else + #include <regex> + #define YS_REGEX_TYPE std::regex + #define YS_REGEX_NS std + #define YS_REGEX_COMPILE(param) std::regex(param, \ + std::regex_constants::nosubs | \ + std::regex_constants::optimize | \ + std::regex_constants::egrep) +#endif #ifndef _WIN32 # include <sys/time.h> @@ -49,7 +67,7 @@ struct log_cmd_error_exception { }; extern std::vector<FILE*> log_files; extern std::vector<std::ostream*> log_streams; extern std::map<std::string, std::set<std::string>> log_hdump; -extern std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes; +extern std::vector<YS_REGEX_TYPE> log_warn_regexes, log_nowarn_regexes, log_werror_regexes; extern std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored; extern int log_warnings_count; extern int log_warnings_count_noexpect; @@ -151,7 +169,7 @@ struct LogExpectedItem std::string pattern; }; -extern std::vector<std::pair<std::regex,LogExpectedItem>> log_expect_log, log_expect_warning, log_expect_error; +extern std::vector<std::pair<YS_REGEX_TYPE,LogExpectedItem>> log_expect_log, log_expect_warning, log_expect_error; void log_check_expected(); const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 06181b763..79e50cccd 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -21,6 +21,7 @@ #include "kernel/macc.h" #include "kernel/celltypes.h" #include "frontends/verilog/verilog_frontend.h" +#include "frontends/verilog/preproc.h" #include "backends/ilang/ilang_backend.h" #include <string.h> @@ -379,6 +380,7 @@ void RTLIL::Selection::optimize(RTLIL::Design *design) } RTLIL::Design::Design() + : verilog_defines (new define_map_t) { static unsigned int hashidx_count = 123456789; hashidx_count = mkhash_xorshift(hashidx_count); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 58c5d9674..4afe4304f 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -952,6 +952,9 @@ struct RTLIL::Monitor virtual void notify_blackout(RTLIL::Module*) { } }; +// Forward declaration; defined in preproc.h. +struct define_map_t; + struct RTLIL::Design { unsigned int hashidx_; @@ -963,7 +966,7 @@ struct RTLIL::Design int refcount_modules_; dict<RTLIL::IdString, RTLIL::Module*> modules_; std::vector<AST::AstNode*> verilog_packages, verilog_globals; - dict<std::string, std::pair<std::string, bool>> verilog_defines; + std::unique_ptr<define_map_t> verilog_defines; std::vector<RTLIL::Selection> selection_stack; dict<RTLIL::IdString, RTLIL::Selection> selection_vars; diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 7694fc9b6..4cb53f05d 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -129,7 +129,7 @@ void yosys_banner() log(" | |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | |\n"); - log(" | Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at> |\n"); + log(" | Copyright (C) 2012 - 2020 Claire Wolf <claire@symbioticeda.com> |\n"); log(" | |\n"); log(" | Permission to use, copy, modify, and/or distribute this software for any |\n"); log(" | purpose with or without fee is hereby granted, provided that the above |\n"); diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex index bed6326e2..4925defe3 100644 --- a/manual/command-reference-manual.tex +++ b/manual/command-reference-manual.tex @@ -5350,7 +5350,7 @@ never transition from a non-zero value to a zero value. For this proof we create the following template (test.tpl). - ; we need QF_UFBV for this poof + ; we need QF_UFBV for this proof (set-logic QF_UFBV) ; insert the auto-generated code here diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index 20b38bf8e..60f20fa6d 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -1,4 +1,5 @@ +OBJS += passes/cmds/exec.o OBJS += passes/cmds/add.o OBJS += passes/cmds/delete.o OBJS += passes/cmds/design.o diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc index 7b76f3d4a..c49b8bf5d 100644 --- a/passes/cmds/add.cc +++ b/passes/cmds/add.cc @@ -206,6 +206,7 @@ struct AddPass : public Pass { extra_args(args, argidx, design); + bool selected_anything = false; for (auto module : design->modules()) { log_assert(module != nullptr); @@ -214,11 +215,14 @@ struct AddPass : public Pass { if (module->get_bool_attribute("\\blackbox")) continue; + selected_anything = true; if (is_formal_celltype(command)) add_formal(module, command, arg_name, enable_name); else if (command == "wire") add_wire(design, module, arg_name, arg_width, arg_flag_input, arg_flag_output, arg_flag_global); } + if (!selected_anything) + log_warning("No modules selected, or only blackboxes. Nothing was added.\n"); } } AddPass; diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc index 172addcc1..7ea0be9ee 100644 --- a/passes/cmds/design.cc +++ b/passes/cmds/design.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "frontends/verilog/preproc.h" #include "frontends/ast/ast.h" YOSYS_NAMESPACE_BEGIN @@ -194,13 +195,13 @@ struct DesignPass : public Pass { argidx = args.size(); } - for (auto &it : copy_from_design->modules_) { - if (sel.selected_whole_module(it.first)) { - copy_src_modules.push_back(it.second); + for (auto mod : copy_from_design->modules()) { + if (sel.selected_whole_module(mod->name)) { + copy_src_modules.push_back(mod); continue; } - if (sel.selected_module(it.first)) - log_cmd_error("Module %s is only partly selected.\n", RTLIL::id2cstr(it.first)); + if (sel.selected_module(mod->name)) + log_cmd_error("Module %s is only partly selected.\n", log_id(mod->name)); } if (import_mode) { @@ -230,8 +231,8 @@ struct DesignPass : public Pass { pool<Module*> queue; dict<IdString, IdString> done; - if (copy_to_design->modules_.count(prefix)) - delete copy_to_design->modules_.at(prefix); + if (copy_to_design->module(prefix) != nullptr) + copy_to_design->remove(copy_to_design->module(prefix)); if (GetSize(copy_src_modules) != 1) log_cmd_error("No top module found in source design.\n"); @@ -240,12 +241,13 @@ struct DesignPass : public Pass { { log("Importing %s as %s.\n", log_id(mod), log_id(prefix)); - copy_to_design->modules_[prefix] = mod->clone(); - copy_to_design->modules_[prefix]->name = prefix; - copy_to_design->modules_[prefix]->design = copy_to_design; - copy_to_design->modules_[prefix]->attributes.erase("\\top"); + RTLIL::Module *t = mod->clone(); + t->name = prefix; + t->design = copy_to_design; + t->attributes.erase("\\top"); + copy_to_design->add(t); - queue.insert(copy_to_design->modules_[prefix]); + queue.insert(t); done[mod->name] = prefix; } @@ -268,15 +270,16 @@ struct DesignPass : public Pass { log("Importing %s as %s.\n", log_id(fmod), log_id(trg_name)); - if (copy_to_design->modules_.count(trg_name)) - delete copy_to_design->modules_.at(trg_name); + if (copy_to_design->module(trg_name) != nullptr) + copy_to_design->remove(copy_to_design->module(trg_name)); - copy_to_design->modules_[trg_name] = fmod->clone(); - copy_to_design->modules_[trg_name]->name = trg_name; - copy_to_design->modules_[trg_name]->design = copy_to_design; - copy_to_design->modules_[trg_name]->attributes.erase("\\top"); + RTLIL::Module *t = fmod->clone(); + t->name = trg_name; + t->design = copy_to_design; + t->attributes.erase("\\top"); + copy_to_design->add(t); - queue.insert(copy_to_design->modules_[trg_name]); + queue.insert(t); done[cell->type] = trg_name; } @@ -294,12 +297,13 @@ struct DesignPass : public Pass { { std::string trg_name = as_name.empty() ? mod->name.str() : RTLIL::escape_id(as_name); - if (copy_to_design->modules_.count(trg_name)) - delete copy_to_design->modules_.at(trg_name); + if (copy_to_design->module(trg_name) != nullptr) + copy_to_design->remove(copy_to_design->module(trg_name)); - copy_to_design->modules_[trg_name] = mod->clone(); - copy_to_design->modules_[trg_name]->name = trg_name; - copy_to_design->modules_[trg_name]->design = copy_to_design; + RTLIL::Module *t = mod->clone(); + t->name = trg_name; + t->design = copy_to_design; + copy_to_design->add(t); } } @@ -307,8 +311,8 @@ struct DesignPass : public Pass { { RTLIL::Design *design_copy = new RTLIL::Design; - for (auto &it : design->modules_) - design_copy->add(it.second->clone()); + for (auto mod : design->modules()) + design_copy->add(mod->clone()); design_copy->selection_stack = design->selection_stack; design_copy->selection_vars = design->selection_vars; @@ -325,9 +329,8 @@ struct DesignPass : public Pass { if (reset_mode || !load_name.empty() || push_mode || pop_mode) { - for (auto &it : design->modules_) - delete it.second; - design->modules_.clear(); + for (auto mod : design->modules()) + design->remove(mod); design->selection_stack.clear(); design->selection_vars.clear(); @@ -346,15 +349,15 @@ struct DesignPass : public Pass { delete node; design->verilog_globals.clear(); - design->verilog_defines.clear(); + design->verilog_defines->clear(); } if (!load_name.empty() || pop_mode) { RTLIL::Design *saved_design = pop_mode ? pushed_designs.back() : saved_designs.at(load_name); - for (auto &it : saved_design->modules_) - design->add(it.second->clone()); + for (auto mod : saved_design->modules()) + design->add(mod->clone()); design->selection_stack = saved_design->selection_stack; design->selection_vars = saved_design->selection_vars; diff --git a/passes/cmds/exec.cc b/passes/cmds/exec.cc new file mode 100644 index 000000000..7eeefe705 --- /dev/null +++ b/passes/cmds/exec.cc @@ -0,0 +1,205 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 - 2020 Claire Wolf <claire@symbioticeda.com> + * + * 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/register.h" +#include "kernel/log.h" +#include <cstdio> + +#if defined(_WIN32) +# include <csignal> +# define WIFEXITED(x) 1 +# define WIFSIGNALED(x) 0 +# define WIFSTOPPED(x) 0 +# define WEXITSTATUS(x) ((x) & 0xff) +# define WTERMSIG(x) SIGTERM +# define WSTOPSIG(x) 0 +#else +# include <sys/wait.h> +#endif + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct ExecPass : public Pass { + ExecPass() : Pass("exec", "execute commands in the operating system shell") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" exec [options] -- [command]\n"); + log("\n"); + log("Execute a command in the operating system shell. All supplied arguments are\n"); + log("concatenated and passed as a command to popen(3). Whitespace is not guaranteed\n"); + log("to be preserved, even if quoted. stdin and stderr are not connected, while stdout is\n"); + log("logged unless the \"-q\" option is specified.\n"); + log("\n"); + log("\n"); + log(" -q\n"); + log(" Suppress stdout and stderr from subprocess\n"); + log("\n"); + log(" -expect-return <int>\n"); + log(" Generate an error if popen() does not return specified value.\n"); + log(" May only be specified once; the final specified value is controlling\n"); + log(" if specified multiple times.\n"); + log("\n"); + log(" -expect-stdout <regex>\n"); + log(" Generate an error if the specified regex does not match any line\n"); + log(" in subprocess's stdout. May be specified multiple times.\n"); + log("\n"); + log(" -not-expect-stdout <regex>\n"); + log(" Generate an error if the specified regex matches any line\n"); + log(" in subprocess's stdout. May be specified multiple times.\n"); + log("\n"); + log("\n"); + log(" Example: exec -q -expect-return 0 -- echo \"bananapie\" | grep \"nana\"\n"); + log("\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + std::string cmd = ""; + char buf[1024] = {}; + std::string linebuf = ""; + bool flag_cmd = false; + bool flag_quiet = false; + bool flag_expect_return = false; + int expect_return_value = 0; + bool flag_expect_stdout = false; + struct expect_stdout_elem { + bool matched; + bool polarity; //true: this regex must match at least one line + //false: this regex must not match any line + std::string str; + YS_REGEX_TYPE re; + + expect_stdout_elem() : matched(false), polarity(true), str(), re(){}; + }; + std::vector<expect_stdout_elem> expect_stdout; + + if(args.size() == 0) + log_cmd_error("No command provided.\n"); + + for(size_t argidx = 1; argidx < args.size(); ++argidx) { + if (flag_cmd) { + cmd += args[argidx] + (argidx != (args.size() - 1)? " " : ""); + } else { + if (args[argidx] == "--") + flag_cmd = true; + else if (args[argidx] == "-q") + flag_quiet = true; + else if (args[argidx] == "-expect-return") { + flag_expect_return = true; + ++argidx; + if (argidx >= args.size()) + log_cmd_error("No expected return value specified.\n"); + + expect_return_value = atoi(args[argidx].c_str()); + } else if (args[argidx] == "-expect-stdout") { + flag_expect_stdout = true; + ++argidx; + if (argidx >= args.size()) + log_cmd_error("No expected regular expression specified.\n"); + + try{ + expect_stdout_elem x; + x.str = args[argidx]; + x.re = YS_REGEX_COMPILE(args[argidx]); + expect_stdout.push_back(x); + } catch (const YS_REGEX_NS::regex_error& e) { + log_cmd_error("Error in regex expression '%s' !\n", args[argidx].c_str()); + } + } else if (args[argidx] == "-not-expect-stdout") { + flag_expect_stdout = true; + ++argidx; + if (argidx >= args.size()) + log_cmd_error("No expected regular expression specified.\n"); + + try{ + expect_stdout_elem x; + x.str = args[argidx]; + x.re = YS_REGEX_COMPILE(args[argidx]); + x.polarity = false; + expect_stdout.push_back(x); + } catch (const YS_REGEX_NS::regex_error& e) { + log_cmd_error("Error in regex expression '%s' !\n", args[argidx].c_str()); + } + + } else + log_cmd_error("Unknown option \"%s\" or \"--\" doesn\'t precede command.", args[argidx].c_str()); + } + } + + log_header(design, "Executing command \"%s\".\n", cmd.c_str()); + log_push(); + + fflush(stdout); + bool keep_reading = true; + int status = 0; + int retval = 0; + +#ifndef EMSCRIPTEN + FILE *f = popen(cmd.c_str(), "r"); + if (f == nullptr) + log_cmd_error("errno %d after popen() returned NULL.\n", errno); + while (keep_reading) { + keep_reading = (fgets(buf, sizeof(buf), f) != nullptr); + linebuf += buf; + memset(buf, 0, sizeof(buf)); + + auto pos = linebuf.find('\n'); + while (pos != std::string::npos) { + std::string line = linebuf.substr(0, pos); + linebuf.erase(0, pos + 1); + if (!flag_quiet) + log("%s\n", line.c_str()); + + if (flag_expect_stdout) + for(auto &x : expect_stdout) + if (YS_REGEX_NS::regex_search(line, x.re)) + x.matched = true; + + pos = linebuf.find('\n'); + } + } + status = pclose(f); +#endif + + if(WIFEXITED(status)) { + retval = WEXITSTATUS(status); + } + else if(WIFSIGNALED(status)) { + retval = WTERMSIG(status); + } + else if(WIFSTOPPED(status)) { + retval = WSTOPSIG(status); + } + + if (flag_expect_return && retval != expect_return_value) + log_cmd_error("Return value %d did not match expected return value %d.\n", retval, expect_return_value); + + if (flag_expect_stdout) + for (auto &x : expect_stdout) + if (x.polarity ^ x.matched) + log_cmd_error("Command stdout did%s have a line matching given regex \"%s\".\n", (x.polarity? " not" : ""), x.str.c_str()); + + log_pop(); + } +} ExecPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc index bd1038a7e..9a27952d4 100644 --- a/passes/cmds/logger.cc +++ b/passes/cmds/logger.cc @@ -96,12 +96,9 @@ struct LoggerPass : public Pass { if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2); try { log("Added regex '%s' for warnings to warn list.\n", pattern.c_str()); - log_warn_regexes.push_back(std::regex(pattern, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep)); + log_warn_regexes.push_back(YS_REGEX_COMPILE(pattern)); } - catch (const std::regex_error& e) { + catch (const YS_REGEX_NS::regex_error& e) { log_cmd_error("Error in regex expression '%s' !\n", pattern.c_str()); } continue; @@ -111,12 +108,9 @@ struct LoggerPass : public Pass { if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2); try { log("Added regex '%s' for warnings to nowarn list.\n", pattern.c_str()); - log_nowarn_regexes.push_back(std::regex(pattern, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep)); + log_nowarn_regexes.push_back(YS_REGEX_COMPILE(pattern)); } - catch (const std::regex_error& e) { + catch (const YS_REGEX_NS::regex_error& e) { log_cmd_error("Error in regex expression '%s' !\n", pattern.c_str()); } continue; @@ -126,12 +120,9 @@ struct LoggerPass : public Pass { if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2); try { log("Added regex '%s' for warnings to werror list.\n", pattern.c_str()); - log_werror_regexes.push_back(std::regex(pattern, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep)); + log_werror_regexes.push_back(YS_REGEX_COMPILE(pattern)); } - catch (const std::regex_error& e) { + catch (const YS_REGEX_NS::regex_error& e) { log_cmd_error("Error in regex expression '%s' !\n", pattern.c_str()); } continue; @@ -168,22 +159,13 @@ struct LoggerPass : public Pass { log("Added regex '%s' for warnings to expected %s list.\n", pattern.c_str(), type.c_str()); try { if (type=="error") - log_expect_error.push_back(std::make_pair(std::regex(pattern, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep), LogExpectedItem(pattern, count))); + log_expect_error.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); else if (type=="warning") - log_expect_warning.push_back(std::make_pair(std::regex(pattern, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep), LogExpectedItem(pattern, count))); + log_expect_warning.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); else - log_expect_log.push_back(std::make_pair(std::regex(pattern, - std::regex_constants::nosubs | - std::regex_constants::optimize | - std::regex_constants::egrep), LogExpectedItem(pattern, count))); + log_expect_log.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); } - catch (const std::regex_error& e) { + catch (const YS_REGEX_NS::regex_error& e) { log_cmd_error("Error in regex expression '%s' !\n", pattern.c_str()); } continue; diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index 0f1f05ccb..b64b077e4 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -58,7 +58,7 @@ static bool match_attr_val(const RTLIL::Const &value, std::string pattern, char { RTLIL::SigSpec sig_value; - if (!RTLIL::SigSpec::parse(sig_value, NULL, pattern)) + if (!RTLIL::SigSpec::parse(sig_value, nullptr, pattern)) return false; RTLIL::Const pattern_value = sig_value.as_const(); @@ -152,27 +152,26 @@ static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs) RTLIL::Selection new_sel(false); - for (auto &mod_it : design->modules_) + for (auto mod : design->modules()) { - if (lhs.selected_whole_module(mod_it.first)) + if (lhs.selected_whole_module(mod->name)) continue; - if (!lhs.selected_module(mod_it.first)) { - new_sel.selected_modules.insert(mod_it.first); + if (!lhs.selected_module(mod->name)) { + new_sel.selected_modules.insert(mod->name); continue; } - RTLIL::Module *mod = mod_it.second; - for (auto &it : mod->wires_) - if (!lhs.selected_member(mod_it.first, it.first)) - new_sel.selected_members[mod->name].insert(it.first); + for (auto wire : mod->wires()) + if (!lhs.selected_member(mod->name, wire->name)) + new_sel.selected_members[mod->name].insert(wire->name); for (auto &it : mod->memories) - if (!lhs.selected_member(mod_it.first, it.first)) - new_sel.selected_members[mod->name].insert(it.first); - for (auto &it : mod->cells_) - if (!lhs.selected_member(mod_it.first, it.first)) + if (!lhs.selected_member(mod->name, it.first)) new_sel.selected_members[mod->name].insert(it.first); + for (auto cell : mod->cells()) + if (!lhs.selected_member(mod->name, cell->name)) + new_sel.selected_members[mod->name].insert(cell->name); for (auto &it : mod->processes) - if (!lhs.selected_member(mod_it.first, it.first)) + if (!lhs.selected_member(mod->name, it.first)) new_sel.selected_members[mod->name].insert(it.first); } @@ -223,15 +222,15 @@ static void select_op_random(RTLIL::Design *design, RTLIL::Selection &lhs, int c static void select_op_submod(RTLIL::Design *design, RTLIL::Selection &lhs) { - for (auto &mod_it : design->modules_) + for (auto mod : design->modules()) { - if (lhs.selected_whole_module(mod_it.first)) + if (lhs.selected_whole_module(mod->name)) { - for (auto &cell_it : mod_it.second->cells_) + for (auto cell : mod->cells()) { - if (design->modules_.count(cell_it.second->type) == 0) + if (design->module(cell->type) == nullptr) continue; - lhs.selected_modules.insert(cell_it.second->type); + lhs.selected_modules.insert(cell->type); } } } @@ -240,21 +239,21 @@ static void select_op_submod(RTLIL::Design *design, RTLIL::Selection &lhs) static void select_op_cells_to_modules(RTLIL::Design *design, RTLIL::Selection &lhs) { RTLIL::Selection new_sel(false); - for (auto &mod_it : design->modules_) - if (lhs.selected_module(mod_it.first)) - for (auto &cell_it : mod_it.second->cells_) - if (lhs.selected_member(mod_it.first, cell_it.first) && design->modules_.count(cell_it.second->type)) - new_sel.selected_modules.insert(cell_it.second->type); + for (auto mod : design->modules()) + if (lhs.selected_module(mod->name)) + for (auto cell : mod->cells()) + if (lhs.selected_member(mod->name, cell->name) && (design->module(cell->type) != nullptr)) + new_sel.selected_modules.insert(cell->type); lhs = new_sel; } static void select_op_module_to_cells(RTLIL::Design *design, RTLIL::Selection &lhs) { RTLIL::Selection new_sel(false); - for (auto &mod_it : design->modules_) - for (auto &cell_it : mod_it.second->cells_) - if (design->modules_.count(cell_it.second->type) && lhs.selected_whole_module(cell_it.second->type)) - new_sel.selected_members[mod_it.first].insert(cell_it.first); + for (auto mod : design->modules()) + for (auto cell : mod->cells()) + if ((design->module(cell->type) != nullptr) && lhs.selected_whole_module(cell->type)) + new_sel.selected_members[mod->name].insert(cell->name); lhs = new_sel; } @@ -268,23 +267,23 @@ static void select_op_fullmod(RTLIL::Design *design, RTLIL::Selection &lhs) static void select_op_alias(RTLIL::Design *design, RTLIL::Selection &lhs) { - for (auto &mod_it : design->modules_) + for (auto mod : design->modules()) { - if (lhs.selected_whole_module(mod_it.first)) + if (lhs.selected_whole_module(mod->name)) continue; - if (!lhs.selected_module(mod_it.first)) + if (!lhs.selected_module(mod->name)) continue; - SigMap sigmap(mod_it.second); + SigMap sigmap(mod); SigPool selected_bits; - for (auto &it : mod_it.second->wires_) - if (lhs.selected_member(mod_it.first, it.first)) - selected_bits.add(sigmap(it.second)); + for (auto wire : mod->wires()) + if (lhs.selected_member(mod->name, wire->name)) + selected_bits.add(sigmap(wire)); - for (auto &it : mod_it.second->wires_) - if (!lhs.selected_member(mod_it.first, it.first) && selected_bits.check_any(sigmap(it.second))) - lhs.selected_members[mod_it.first].insert(it.first); + for (auto wire : mod->wires()) + if (!lhs.selected_member(mod->name, wire->name) && selected_bits.check_any(sigmap(wire))) + lhs.selected_members[mod->name].insert(wire->name); } } @@ -323,8 +322,8 @@ static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const R if (!rhs.full_selection && rhs.selected_modules.size() == 0 && rhs.selected_members.size() == 0) return; lhs.full_selection = false; - for (auto &it : design->modules_) - lhs.selected_modules.insert(it.first); + for (auto mod : design->modules()) + lhs.selected_modules.insert(mod->name); } for (auto &it : rhs.selected_modules) { @@ -334,19 +333,19 @@ static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const R for (auto &it : rhs.selected_members) { - if (design->modules_.count(it.first) == 0) + if (design->module(it.first) == nullptr) continue; - RTLIL::Module *mod = design->modules_[it.first]; + RTLIL::Module *mod = design->module(it.first); if (lhs.selected_modules.count(mod->name) > 0) { - for (auto &it : mod->wires_) - lhs.selected_members[mod->name].insert(it.first); + for (auto wire : mod->wires()) + lhs.selected_members[mod->name].insert(wire->name); for (auto &it : mod->memories) lhs.selected_members[mod->name].insert(it.first); - for (auto &it : mod->cells_) - lhs.selected_members[mod->name].insert(it.first); + for (auto cell : mod->cells()) + lhs.selected_members[mod->name].insert(cell->name); for (auto &it : mod->processes) lhs.selected_members[mod->name].insert(it.first); lhs.selected_modules.erase(mod->name); @@ -367,8 +366,8 @@ static void select_op_intersect(RTLIL::Design *design, RTLIL::Selection &lhs, co if (lhs.full_selection) { lhs.full_selection = false; - for (auto &it : design->modules_) - lhs.selected_modules.insert(it.first); + for (auto mod : design->modules()) + lhs.selected_modules.insert(mod->name); } std::vector<RTLIL::IdString> del_list; @@ -431,18 +430,17 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v { int sel_objects = 0; bool is_input, is_output; - for (auto &mod_it : design->modules_) + for (auto mod : design->modules()) { - if (lhs.selected_whole_module(mod_it.first) || !lhs.selected_module(mod_it.first)) + if (lhs.selected_whole_module(mod->name) || !lhs.selected_module(mod->name)) continue; - RTLIL::Module *mod = mod_it.second; std::set<RTLIL::Wire*> selected_wires; auto selected_members = lhs.selected_members[mod->name]; - for (auto &it : mod->wires_) - if (lhs.selected_member(mod_it.first, it.first) && limits.count(it.first) == 0) - selected_wires.insert(it.second); + for (auto wire : mod->wires()) + if (lhs.selected_member(mod->name, wire->name) && limits.count(wire->name) == 0) + selected_wires.insert(wire); for (auto &conn : mod->connections()) { @@ -450,7 +448,7 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v std::vector<RTLIL::SigBit> conn_rhs = conn.second.to_sigbit_vector(); for (size_t i = 0; i < conn_lhs.size(); i++) { - if (conn_lhs[i].wire == NULL || conn_rhs[i].wire == NULL) + if (conn_lhs[i].wire == nullptr || conn_rhs[i].wire == nullptr) continue; if (mode != 'i' && selected_wires.count(conn_rhs[i].wire) && selected_members.count(conn_lhs[i].wire->name) == 0) lhs.selected_members[mod->name].insert(conn_lhs[i].wire->name), sel_objects++, max_objects--; @@ -459,15 +457,15 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v } } - for (auto &cell : mod->cells_) - for (auto &conn : cell.second->connections()) + for (auto cell : mod->cells()) + for (auto &conn : cell->connections()) { char last_mode = '-'; - if (eval_only && !yosys_celltypes.cell_evaluable(cell.second->type)) + if (eval_only && !yosys_celltypes.cell_evaluable(cell->type)) goto exclude_match; for (auto &rule : rules) { last_mode = rule.mode; - if (rule.cell_types.size() > 0 && rule.cell_types.count(cell.second->type) == 0) + if (rule.cell_types.size() > 0 && rule.cell_types.count(cell->type) == 0) continue; if (rule.port_names.size() > 0 && rule.port_names.count(conn.first) == 0) continue; @@ -479,14 +477,14 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v if (last_mode == '+') goto exclude_match; include_match: - is_input = mode == 'x' || ct.cell_input(cell.second->type, conn.first); - is_output = mode == 'x' || ct.cell_output(cell.second->type, conn.first); + is_input = mode == 'x' || ct.cell_input(cell->type, conn.first); + is_output = mode == 'x' || ct.cell_output(cell->type, conn.first); for (auto &chunk : conn.second.chunks()) - if (chunk.wire != NULL) { - if (max_objects != 0 && selected_wires.count(chunk.wire) > 0 && selected_members.count(cell.first) == 0) + if (chunk.wire != nullptr) { + if (max_objects != 0 && selected_wires.count(chunk.wire) > 0 && selected_members.count(cell->name) == 0) if (mode == 'x' || (mode == 'i' && is_output) || (mode == 'o' && is_input)) - lhs.selected_members[mod->name].insert(cell.first), sel_objects++, max_objects--; - if (max_objects != 0 && selected_members.count(cell.first) > 0 && limits.count(cell.first) == 0 && selected_members.count(chunk.wire->name) == 0) + lhs.selected_members[mod->name].insert(cell->name), sel_objects++, max_objects--; + if (max_objects != 0 && selected_members.count(cell->name) > 0 && limits.count(cell->name) == 0 && selected_members.count(chunk.wire->name) == 0) if (mode == 'x' || (mode == 'i' && is_input) || (mode == 'o' && is_output)) lhs.selected_members[mod->name].insert(chunk.wire->name), sel_objects++, max_objects--; } @@ -627,9 +625,13 @@ static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &se } } -static void select_stmt(RTLIL::Design *design, std::string arg) +static void select_stmt(RTLIL::Design *design, std::string arg, bool disable_empty_warning = false) { std::string arg_mod, arg_memb; + std::unordered_map<std::string, bool> arg_mod_found; + std::unordered_map<std::string, bool> arg_memb_found; + auto isalpha = [](const char &x) { return ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z')); }; + bool prefixed = GetSize(arg) >= 2 && isalpha(arg[0]) && arg[1] == ':'; if (arg.size() == 0) return; @@ -760,19 +762,21 @@ static void select_stmt(RTLIL::Design *design, std::string arg) if (!design->selected_active_module.empty()) { arg_mod = design->selected_active_module; arg_memb = arg; + if (!prefixed) arg_memb_found[arg_memb] = false; } else - if (GetSize(arg) >= 2 && arg[0] >= 'a' && arg[0] <= 'z' && arg[1] == ':') { + if (prefixed && arg[0] >= 'a' && arg[0] <= 'z') { arg_mod = "*", arg_memb = arg; } else { size_t pos = arg.find('/'); if (pos == std::string::npos) { - if (arg.find(':') == std::string::npos || arg.compare(0, 1, "A") == 0) - arg_mod = arg; - else - arg_mod = "*", arg_memb = arg; + arg_mod = arg; + if (!prefixed) arg_mod_found[arg_mod] = false; } else { arg_mod = arg.substr(0, pos); + if (!prefixed) arg_mod_found[arg_mod] = false; arg_memb = arg.substr(pos+1); + bool arg_memb_prefixed = GetSize(arg_memb) >= 2 && isalpha(arg_memb[0]) && arg_memb[1] == ':'; + if (!arg_memb_prefixed) arg_memb_found[arg_memb] = false; } } @@ -785,56 +789,61 @@ static void select_stmt(RTLIL::Design *design, std::string arg) } sel.full_selection = false; - for (auto &mod_it : design->modules_) + for (auto mod : design->modules()) { if (arg_mod.compare(0, 2, "A:") == 0) { - if (!match_attr(mod_it.second->attributes, arg_mod.substr(2))) + if (!match_attr(mod->attributes, arg_mod.substr(2))) + continue; + } else + if (arg_mod.compare(0, 2, "N:") == 0) { + if (!match_ids(mod->name, arg_mod.substr(2))) continue; } else - if (!match_ids(mod_it.first, arg_mod)) + if (!match_ids(mod->name, arg_mod)) continue; + else + arg_mod_found[arg_mod] = true; if (arg_memb == "") { - sel.selected_modules.insert(mod_it.first); + sel.selected_modules.insert(mod->name); continue; } - RTLIL::Module *mod = mod_it.second; if (arg_memb.compare(0, 2, "w:") == 0) { - for (auto &it : mod->wires_) - if (match_ids(it.first, arg_memb.substr(2))) - sel.selected_members[mod->name].insert(it.first); + for (auto wire : mod->wires()) + if (match_ids(wire->name, arg_memb.substr(2))) + sel.selected_members[mod->name].insert(wire->name); } else if (arg_memb.compare(0, 2, "i:") == 0) { - for (auto &it : mod->wires_) - if (it.second->port_input && match_ids(it.first, arg_memb.substr(2))) - sel.selected_members[mod->name].insert(it.first); + for (auto wire : mod->wires()) + if (wire->port_input && match_ids(wire->name, arg_memb.substr(2))) + sel.selected_members[mod->name].insert(wire->name); } else if (arg_memb.compare(0, 2, "o:") == 0) { - for (auto &it : mod->wires_) - if (it.second->port_output && match_ids(it.first, arg_memb.substr(2))) - sel.selected_members[mod->name].insert(it.first); + for (auto wire : mod->wires()) + if (wire->port_output && match_ids(wire->name, arg_memb.substr(2))) + sel.selected_members[mod->name].insert(wire->name); } else if (arg_memb.compare(0, 2, "x:") == 0) { - for (auto &it : mod->wires_) - if ((it.second->port_input || it.second->port_output) && match_ids(it.first, arg_memb.substr(2))) - sel.selected_members[mod->name].insert(it.first); + for (auto wire : mod->wires()) + if ((wire->port_input || wire->port_output) && match_ids(wire->name, arg_memb.substr(2))) + sel.selected_members[mod->name].insert(wire->name); } else if (arg_memb.compare(0, 2, "s:") == 0) { size_t delim = arg_memb.substr(2).find(':'); if (delim == std::string::npos) { int width = atoi(arg_memb.substr(2).c_str()); - for (auto &it : mod->wires_) - if (it.second->width == width) - sel.selected_members[mod->name].insert(it.first); + for (auto wire : mod->wires()) + if (wire->width == width) + sel.selected_members[mod->name].insert(wire->name); } else { std::string min_str = arg_memb.substr(2, delim); std::string max_str = arg_memb.substr(2+delim+1); int min_width = min_str.empty() ? 0 : atoi(min_str.c_str()); int max_width = max_str.empty() ? -1 : atoi(max_str.c_str()); - for (auto &it : mod->wires_) - if (min_width <= it.second->width && (it.second->width <= max_width || max_width == -1)) - sel.selected_members[mod->name].insert(it.first); + for (auto wire : mod->wires()) + if (min_width <= wire->width && (wire->width <= max_width || max_width == -1)) + sel.selected_members[mod->name].insert(wire->name); } } else if (arg_memb.compare(0, 2, "m:") == 0) { @@ -842,15 +851,15 @@ static void select_stmt(RTLIL::Design *design, std::string arg) if (match_ids(it.first, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else - if (arg_memb.compare(0, 2, "c:") ==0) { - for (auto &it : mod->cells_) - if (match_ids(it.first, arg_memb.substr(2))) - sel.selected_members[mod->name].insert(it.first); + if (arg_memb.compare(0, 2, "c:") == 0) { + for (auto cell : mod->cells()) + if (match_ids(cell->name, arg_memb.substr(2))) + sel.selected_members[mod->name].insert(cell->name); } else if (arg_memb.compare(0, 2, "t:") == 0) { - for (auto &it : mod->cells_) - if (match_ids(it.second->type, arg_memb.substr(2))) - sel.selected_members[mod->name].insert(it.first); + for (auto cell : mod->cells()) + if (match_ids(cell->type, arg_memb.substr(2))) + sel.selected_members[mod->name].insert(cell->name); } else if (arg_memb.compare(0, 2, "p:") == 0) { for (auto &it : mod->processes) @@ -858,62 +867,82 @@ static void select_stmt(RTLIL::Design *design, std::string arg) sel.selected_members[mod->name].insert(it.first); } else if (arg_memb.compare(0, 2, "a:") == 0) { - for (auto &it : mod->wires_) - if (match_attr(it.second->attributes, arg_memb.substr(2))) - sel.selected_members[mod->name].insert(it.first); + for (auto wire : mod->wires()) + if (match_attr(wire->attributes, arg_memb.substr(2))) + sel.selected_members[mod->name].insert(wire->name); for (auto &it : mod->memories) if (match_attr(it.second->attributes, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); - for (auto &it : mod->cells_) - if (match_attr(it.second->attributes, arg_memb.substr(2))) - sel.selected_members[mod->name].insert(it.first); + for (auto cell : mod->cells()) + if (match_attr(cell->attributes, arg_memb.substr(2))) + sel.selected_members[mod->name].insert(cell->name); for (auto &it : mod->processes) if (match_attr(it.second->attributes, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else if (arg_memb.compare(0, 2, "r:") == 0) { - for (auto &it : mod->cells_) - if (match_attr(it.second->parameters, arg_memb.substr(2))) - sel.selected_members[mod->name].insert(it.first); + for (auto cell : mod->cells()) + if (match_attr(cell->parameters, arg_memb.substr(2))) + sel.selected_members[mod->name].insert(cell->name); } else { + std::string orig_arg_memb = arg_memb; if (arg_memb.compare(0, 2, "n:") == 0) arg_memb = arg_memb.substr(2); - for (auto &it : mod->wires_) - if (match_ids(it.first, arg_memb)) - sel.selected_members[mod->name].insert(it.first); + for (auto wire : mod->wires()) + if (match_ids(wire->name, arg_memb)) { + sel.selected_members[mod->name].insert(wire->name); + arg_memb_found[orig_arg_memb] = true; + } for (auto &it : mod->memories) - if (match_ids(it.first, arg_memb)) - sel.selected_members[mod->name].insert(it.first); - for (auto &it : mod->cells_) - if (match_ids(it.first, arg_memb)) + if (match_ids(it.first, arg_memb)) { sel.selected_members[mod->name].insert(it.first); + arg_memb_found[orig_arg_memb] = true; + } + for (auto cell : mod->cells()) + if (match_ids(cell->name, arg_memb)) { + sel.selected_members[mod->name].insert(cell->name); + arg_memb_found[orig_arg_memb] = true; + } for (auto &it : mod->processes) - if (match_ids(it.first, arg_memb)) + if (match_ids(it.first, arg_memb)) { sel.selected_members[mod->name].insert(it.first); + arg_memb_found[orig_arg_memb] = true; + } } } select_filter_active_mod(design, work_stack.back()); + + for (auto &it : arg_mod_found) { + if (it.second == false && !disable_empty_warning) { + log_warning("Selection \"%s\" did not match any module.\n", it.first.c_str()); + } + } + for (auto &it : arg_memb_found) { + if (it.second == false && !disable_empty_warning) { + log_warning("Selection \"%s\" did not match any object.\n", it.first.c_str()); + } + } } static std::string describe_selection_for_assert(RTLIL::Design *design, RTLIL::Selection *sel) { std::string desc = "Selection contains:\n"; - for (auto mod_it : design->modules_) + for (auto mod : design->modules()) { - if (sel->selected_module(mod_it.first)) { - for (auto &it : mod_it.second->wires_) - if (sel->selected_member(mod_it.first, it.first)) - desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); - for (auto &it : mod_it.second->memories) - if (sel->selected_member(mod_it.first, it.first)) - desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); - for (auto &it : mod_it.second->cells_) - if (sel->selected_member(mod_it.first, it.first)) - desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); - for (auto &it : mod_it.second->processes) - if (sel->selected_member(mod_it.first, it.first)) - desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); + if (sel->selected_module(mod->name)) { + for (auto wire : mod->wires()) + if (sel->selected_member(mod->name, wire->name)) + desc += stringf("%s/%s\n", id2cstr(mod->name), id2cstr(wire->name)); + for (auto &it : mod->memories) + if (sel->selected_member(mod->name, it.first)) + desc += stringf("%s/%s\n", id2cstr(mod->name), id2cstr(it.first)); + for (auto cell : mod->cells()) + if (sel->selected_member(mod->name, cell->name)) + desc += stringf("%s/%s\n", id2cstr(mod->name), id2cstr(cell->name)); + for (auto &it : mod->processes) + if (sel->selected_member(mod->name, it.first)) + desc += stringf("%s/%s\n", id2cstr(mod->name), id2cstr(it.first)); } } return desc; @@ -928,7 +957,7 @@ void handle_extra_select_args(Pass *pass, vector<string> args, size_t argidx, si work_stack.clear(); for (; argidx < args_size; argidx++) { if (args[argidx].compare(0, 1, "-") == 0) { - if (pass != NULL) + if (pass != nullptr) pass->cmd_error(args, argidx, "Unexpected option in selection arguments."); else log_cmd_error("Unexpected option in selection arguments."); @@ -1077,6 +1106,10 @@ struct SelectPass : public Pass { log(" all modules with an attribute matching the given pattern\n"); log(" in addition to = also <, <=, >=, and > are supported\n"); log("\n"); + log(" N:<pattern>\n"); + log(" all modules with a name matching the given pattern\n"); + log(" (i.e. 'N:' is optional as it is the default matching rule)\n"); + log("\n"); log("An <obj_pattern> can be an object name, wildcard expression, or one of\n"); log("the following:\n"); log("\n"); @@ -1267,7 +1300,7 @@ struct SelectPass : public Pass { } if (arg == "-module" && argidx+1 < args.size()) { RTLIL::IdString mod_name = RTLIL::escape_id(args[++argidx]); - if (design->modules_.count(mod_name) == 0) + if (design->module(mod_name) == nullptr) log_cmd_error("No such module: %s\n", id2cstr(mod_name)); design->selected_active_module = mod_name.str(); got_module = true; @@ -1279,7 +1312,8 @@ struct SelectPass : public Pass { } if (arg.size() > 0 && arg[0] == '-') log_cmd_error("Unknown option %s.\n", arg.c_str()); - select_stmt(design, arg); + bool disable_empty_warning = count_mode || assert_none || assert_any || (assert_count != -1) || (assert_max != -1) || (assert_min != -1); + select_stmt(design, arg, disable_empty_warning); sel_str += " " + arg; } @@ -1353,41 +1387,41 @@ struct SelectPass : public Pass { if (list_mode || count_mode || !write_file.empty()) { - #define LOG_OBJECT(...) { if (list_mode) log(__VA_ARGS__); if (f != NULL) fprintf(f, __VA_ARGS__); total_count++; } + #define LOG_OBJECT(...) { if (list_mode) log(__VA_ARGS__); if (f != nullptr) fprintf(f, __VA_ARGS__); total_count++; } int total_count = 0; - FILE *f = NULL; + FILE *f = nullptr; if (!write_file.empty()) { f = fopen(write_file.c_str(), "w"); yosys_output_files.insert(write_file); - if (f == NULL) + if (f == nullptr) log_error("Can't open '%s' for writing: %s\n", write_file.c_str(), strerror(errno)); } RTLIL::Selection *sel = &design->selection_stack.back(); if (work_stack.size() > 0) sel = &work_stack.back(); sel->optimize(design); - for (auto mod_it : design->modules_) + for (auto mod : design->modules()) { - if (sel->selected_whole_module(mod_it.first) && list_mode) - log("%s\n", id2cstr(mod_it.first)); - if (sel->selected_module(mod_it.first)) { - for (auto &it : mod_it.second->wires_) - if (sel->selected_member(mod_it.first, it.first)) - LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)) - for (auto &it : mod_it.second->memories) - if (sel->selected_member(mod_it.first, it.first)) - LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)) - for (auto &it : mod_it.second->cells_) - if (sel->selected_member(mod_it.first, it.first)) - LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)) - for (auto &it : mod_it.second->processes) - if (sel->selected_member(mod_it.first, it.first)) - LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)) + if (sel->selected_whole_module(mod->name) && list_mode) + log("%s\n", id2cstr(mod->name)); + if (sel->selected_module(mod->name)) { + for (auto wire : mod->wires()) + if (sel->selected_member(mod->name, wire->name)) + LOG_OBJECT("%s/%s\n", id2cstr(mod->name), id2cstr(wire->name)) + for (auto &it : mod->memories) + if (sel->selected_member(mod->name, it.first)) + LOG_OBJECT("%s/%s\n", id2cstr(mod->name), id2cstr(it.first)) + for (auto cell : mod->cells()) + if (sel->selected_member(mod->name, cell->name)) + LOG_OBJECT("%s/%s\n", id2cstr(mod->name), id2cstr(cell->name)) + for (auto &it : mod->processes) + if (sel->selected_member(mod->name, it.first)) + LOG_OBJECT("%s/%s\n", id2cstr(mod->name), id2cstr(it.first)) } } if (count_mode) log("%d objects.\n", total_count); - if (f != NULL) + if (f != nullptr) fclose(f); #undef LOG_OBJECT return; @@ -1448,19 +1482,19 @@ struct SelectPass : public Pass { log_cmd_error("No selection to check.\n"); RTLIL::Selection *sel = &work_stack.back(); sel->optimize(design); - for (auto mod_it : design->modules_) - if (sel->selected_module(mod_it.first)) { - for (auto &it : mod_it.second->wires_) - if (sel->selected_member(mod_it.first, it.first)) + for (auto mod : design->modules()) + if (sel->selected_module(mod->name)) { + for (auto wire : mod->wires()) + if (sel->selected_member(mod->name, wire->name)) total_count++; - for (auto &it : mod_it.second->memories) - if (sel->selected_member(mod_it.first, it.first)) + for (auto &it : mod->memories) + if (sel->selected_member(mod->name, it.first)) total_count++; - for (auto &it : mod_it.second->cells_) - if (sel->selected_member(mod_it.first, it.first)) + for (auto cell : mod->cells()) + if (sel->selected_member(mod->name, cell->name)) total_count++; - for (auto &it : mod_it.second->processes) - if (sel->selected_member(mod_it.first, it.first)) + for (auto &it : mod->processes) + if (sel->selected_member(mod->name, it.first)) total_count++; } if (assert_count >= 0 && assert_count != total_count) @@ -1581,15 +1615,13 @@ struct CdPass : public Pass { std::string modname = RTLIL::escape_id(args[1]); - if (design->modules_.count(modname) == 0 && !design->selected_active_module.empty()) { - RTLIL::Module *module = NULL; - if (design->modules_.count(design->selected_active_module) > 0) - module = design->modules_.at(design->selected_active_module); - if (module != NULL && module->cells_.count(modname) > 0) - modname = module->cells_.at(modname)->type.str(); + if (design->module(modname) == nullptr && !design->selected_active_module.empty()) { + RTLIL::Module *module = design->module(design->selected_active_module); + if (module != nullptr && module->cell(modname) != nullptr) + modname = module->cell(modname)->type.str(); } - if (design->modules_.count(modname) > 0) { + if (design->module(modname) != nullptr) { design->selected_active_module = modname; design->selection_stack.back() = RTLIL::Selection(); select_filter_active_mod(design, design->selection_stack.back()); diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc index a85c3bec0..0f7b4d106 100644 --- a/passes/fsm/fsm_extract.cc +++ b/passes/fsm/fsm_extract.cc @@ -422,11 +422,7 @@ struct FsmExtractPass : public Pass { log_header(design, "Executing FSM_EXTRACT pass (extracting FSM from design).\n"); extra_args(args, 1, design); - CellTypes ct; - ct.setup_internals(); - ct.setup_internals_mem(); - ct.setup_stdcells(); - ct.setup_stdcells_mem(); + CellTypes ct(design); for (auto &mod_it : design->modules_) { diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index fa4a8ea29..3f4fe502d 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -42,11 +42,10 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, { std::set<RTLIL::IdString> found_celltypes; - for (auto i1 : design->modules_) - for (auto i2 : i1.second->cells_) + for (auto mod : design->modules()) + for (auto cell : mod->cells()) { - RTLIL::Cell *cell = i2.second; - if (design->has(cell->type)) + if (design->module(cell->type) != nullptr) continue; if (cell->type.begins_with("$__")) continue; @@ -62,15 +61,15 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, std::map<RTLIL::IdString, int> portwidths; log("Generate module for cell type %s:\n", celltype.c_str()); - for (auto i1 : design->modules_) - for (auto i2 : i1.second->cells_) - if (i2.second->type == celltype) { - for (auto &conn : i2.second->connections()) { + for (auto mod : design->modules()) + for (auto cell : mod->cells()) + if (cell->type == celltype) { + for (auto &conn : cell->connections()) { if (conn.first[0] != '$') portnames.insert(conn.first); portwidths[conn.first] = max(portwidths[conn.first], conn.second.size()); } - for (auto ¶ : i2.second->parameters) + for (auto ¶ : cell->parameters) parameters.insert(para.first); } @@ -168,26 +167,24 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check // If any of the ports are actually interface ports, we will always need to // reprocess the module: if(!module->get_bool_attribute("\\interfaces_replaced_in_module")) { - for (auto &wire : module->wires_) { - if ((wire.second->port_input || wire.second->port_output) && wire.second->get_bool_attribute("\\is_interface")) + for (auto wire : module->wires()) { + if ((wire->port_input || wire->port_output) && wire->get_bool_attribute("\\is_interface")) has_interface_ports = true; } } // Always keep track of all derived interfaces available in the current module in 'interfaces_in_module': dict<RTLIL::IdString, RTLIL::Module*> interfaces_in_module; - for (auto &cell_it : module->cells_) + for (auto cell : module->cells()) { - RTLIL::Cell *cell = cell_it.second; if(cell->get_bool_attribute("\\is_interface")) { - RTLIL::Module *intf_module = design->modules_[cell->type]; + RTLIL::Module *intf_module = design->module(cell->type); interfaces_in_module[cell->name] = intf_module; } } - for (auto &cell_it : module->cells_) + for (auto cell : module->cells()) { - RTLIL::Cell *cell = cell_it.second; bool has_interfaces_not_found = false; std::vector<RTLIL::IdString> connections_to_remove; @@ -208,11 +205,11 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check dict<RTLIL::IdString, RTLIL::Module*> interfaces_to_add_to_submodule; dict<RTLIL::IdString, RTLIL::IdString> modports_used_in_submodule; - if (design->modules_.count(cell->type) == 0) + if (design->module(cell->type) == nullptr) { - if (design->modules_.count("$abstract" + cell->type.str())) + if (design->module("$abstract" + cell->type.str()) != nullptr) { - cell->type = design->modules_.at("$abstract" + cell->type.str())->derive(design, cell->parameters); + cell->type = design->module("$abstract" + cell->type.str())->derive(design, cell->parameters); cell->parameters.clear(); did_something = true; continue; @@ -246,7 +243,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check continue; loaded_module: - if (design->modules_.count(cell->type) == 0) + if (design->module(cell->type) == nullptr) log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str()); did_something = true; } else { @@ -256,7 +253,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check // Go over all connections and see if any of them are SV interfaces. If they are, then add the replacements to // some lists, so that the ports for sub-modules can be replaced further down: for (auto &conn : cell->connections()) { - if(mod->wires_.count(conn.first) != 0 && mod->wire(conn.first)->get_bool_attribute("\\is_interface")) { // Check if the connection is present as an interface in the sub-module's port list + if(mod->wire(conn.first) != nullptr && mod->wire(conn.first)->get_bool_attribute("\\is_interface")) { // Check if the connection is present as an interface in the sub-module's port list //const pool<string> &interface_type_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_type"); //for (auto &d : interface_type_pool) { // TODO: Compare interface type to type in parent module (not crucially important, but good for robustness) //} @@ -285,11 +282,11 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check if (nexactmatch != 0) // Choose the one with the plain name if it exists interface_name2 = interface_name; RTLIL::Module *mod_replace_ports = interfaces_in_module.at(interface_name2); - for (auto &mod_wire : mod_replace_ports->wires_) { // Go over all wires in interface, and add replacements to lists. - std::string signal_name1 = conn.first.str() + "." + log_id(mod_wire.first); - std::string signal_name2 = interface_name.str() + "." + log_id(mod_wire.first); + for (auto mod_wire : mod_replace_ports->wires()) { // Go over all wires in interface, and add replacements to lists. + std::string signal_name1 = conn.first.str() + "." + log_id(mod_wire->name); + std::string signal_name2 = interface_name.str() + "." + log_id(mod_wire); connections_to_add_name.push_back(RTLIL::IdString(signal_name1)); - if(module->wires_.count(signal_name2) == 0) { + if(module->wire(signal_name2) == nullptr) { log_error("Could not find signal '%s' in '%s'\n", signal_name2.c_str(), log_id(module->name)); } else { @@ -344,9 +341,9 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check } } - RTLIL::Module *mod = design->modules_[cell->type]; + RTLIL::Module *mod = design->module(cell->type); - if (design->modules_.at(cell->type)->get_blackbox_attribute()) { + if (design->module(cell->type)->get_blackbox_attribute()) { if (flag_simcheck) log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n", cell->type.c_str(), module->name.c_str(), cell->name.c_str()); @@ -389,7 +386,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check // an interface instance: if (mod->get_bool_attribute("\\is_interface") && cell->get_bool_attribute("\\module_not_derived")) { cell->set_bool_attribute("\\is_interface"); - RTLIL::Module *derived_module = design->modules_[cell->type]; + RTLIL::Module *derived_module = design->module(cell->type); interfaces_in_module[cell->name] = derived_module; did_something = true; } @@ -414,25 +411,25 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check RTLIL::Cell *cell = it.first; int idx = it.second.first, num = it.second.second; - if (design->modules_.count(cell->type) == 0) + if (design->module(cell->type) == nullptr) log_error("Array cell `%s.%s' of unknown type `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); - RTLIL::Module *mod = design->modules_[cell->type]; + RTLIL::Module *mod = design->module(cell->type); for (auto &conn : cell->connections_) { int conn_size = conn.second.size(); RTLIL::IdString portname = conn.first; if (portname.begins_with("$")) { int port_id = atoi(portname.substr(1).c_str()); - for (auto &wire_it : mod->wires_) - if (wire_it.second->port_id == port_id) { - portname = wire_it.first; + for (auto wire : mod->wires()) + if (wire->port_id == port_id) { + portname = wire->name; break; } } - if (mod->wires_.count(portname) == 0) + if (mod->wire(portname) == nullptr) log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first)); - int port_size = mod->wires_.at(portname)->width; + int port_size = mod->wire(portname)->width; if (conn_size == port_size || conn_size == 0) continue; if (conn_size != port_size*num) @@ -470,21 +467,21 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib) hierarchy_worker(design, used, top, 0); std::vector<RTLIL::Module*> del_modules; - for (auto &it : design->modules_) - if (used.count(it.second) == 0) - del_modules.push_back(it.second); + for (auto mod : design->modules()) + if (used.count(mod) == 0) + del_modules.push_back(mod); else { // Now all interface ports must have been exploded, and it is hence // safe to delete all of the remaining dummy interface ports: pool<RTLIL::Wire*> del_wires; - for(auto &wire : it.second->wires_) { - if ((wire.second->port_input || wire.second->port_output) && wire.second->get_bool_attribute("\\is_interface")) { - del_wires.insert(wire.second); + for(auto wire : mod->wires()) { + if ((wire->port_input || wire->port_output) && wire->get_bool_attribute("\\is_interface")) { + del_wires.insert(wire); } } if (del_wires.size() > 0) { - it.second->remove(del_wires); - it.second->fixup_ports(); + mod->remove(del_wires); + mod->fixup_ports(); } } @@ -493,9 +490,8 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib) if (!purge_lib && mod->get_blackbox_attribute()) continue; log("Removing unused module `%s'.\n", mod->name.c_str()); - design->modules_.erase(mod->name); + design->remove(mod); del_counter++; - delete mod; } log("Removed %d unused modules.\n", del_counter); @@ -817,9 +813,9 @@ struct HierarchyPass : public Pass { log_push(); if (top_mod == nullptr) - for (auto &mod_it : design->modules_) - if (mod_it.second->get_bool_attribute("\\top")) - top_mod = mod_it.second; + for (auto mod : design->modules()) + if (mod->get_bool_attribute("\\top")) + top_mod = mod; if (top_mod != nullptr && top_mod->name.begins_with("$abstract")) { IdString top_name = top_mod->name.substr(strlen("$abstract")); @@ -862,11 +858,11 @@ struct HierarchyPass : public Pass { log_error("Design has no top module.\n"); if (top_mod != NULL) { - for (auto &mod_it : design->modules_) - if (mod_it.second == top_mod) - mod_it.second->attributes["\\initial_top"] = RTLIL::Const(1); + for (auto mod : design->modules()) + if (mod == top_mod) + mod->attributes["\\initial_top"] = RTLIL::Const(1); else - mod_it.second->attributes.erase("\\initial_top"); + mod->attributes.erase("\\initial_top"); } bool did_something = true; @@ -900,9 +896,9 @@ struct HierarchyPass : public Pass { // Delete modules marked as 'to_delete': std::vector<RTLIL::Module *> modules_to_delete; - for(auto &mod_it : design->modules_) { - if (mod_it.second->get_bool_attribute("\\to_delete")) { - modules_to_delete.push_back(mod_it.second); + for(auto mod : design->modules()) { + if (mod->get_bool_attribute("\\to_delete")) { + modules_to_delete.push_back(mod); } } for(size_t i=0; i<modules_to_delete.size(); i++) { @@ -917,12 +913,12 @@ struct HierarchyPass : public Pass { } if (top_mod != NULL) { - for (auto &mod_it : design->modules_) { - if (mod_it.second == top_mod) - mod_it.second->attributes["\\top"] = RTLIL::Const(1); + for (auto mod : design->modules()) { + if (mod == top_mod) + mod->attributes["\\top"] = RTLIL::Const(1); else - mod_it.second->attributes.erase("\\top"); - mod_it.second->attributes.erase("\\initial_top"); + mod->attributes.erase("\\top"); + mod->attributes.erase("\\initial_top"); } } @@ -941,22 +937,20 @@ struct HierarchyPass : public Pass { std::map<std::pair<RTLIL::Module*,int>, RTLIL::IdString> pos_map; std::vector<std::pair<RTLIL::Module*,RTLIL::Cell*>> pos_work; - for (auto &mod_it : design->modules_) - for (auto &cell_it : mod_it.second->cells_) { - RTLIL::Cell *cell = cell_it.second; - if (design->modules_.count(cell->type) == 0) + for (auto mod : design->modules()) + for (auto cell : mod->cells()) { + if (design->module(cell->type) == nullptr) continue; for (auto &conn : cell->connections()) if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') { - pos_mods.insert(design->modules_.at(cell->type)); - pos_work.push_back(std::pair<RTLIL::Module*,RTLIL::Cell*>(mod_it.second, cell)); + pos_mods.insert(design->module(cell->type)); + pos_work.push_back(std::pair<RTLIL::Module*,RTLIL::Cell*>(mod, cell)); break; } } for (auto module : pos_mods) - for (auto &wire_it : module->wires_) { - RTLIL::Wire *wire = wire_it.second; + for (auto wire : module->wires()) { if (wire->port_id > 0) pos_map[std::pair<RTLIL::Module*,int>(module, wire->port_id)] = wire->name; } @@ -970,7 +964,7 @@ struct HierarchyPass : public Pass { for (auto &conn : cell->connections()) if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') { int id = atoi(conn.first.c_str()+1); - std::pair<RTLIL::Module*,int> key(design->modules_.at(cell->type), id); + std::pair<RTLIL::Module*,int> key(design->module(cell->type), id); if (pos_map.count(key) == 0) { log(" Failed to map positional argument %d of cell %s.%s (%s).\n", id, RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc index e0bb439f4..148480d55 100644 --- a/passes/sat/eval.cc +++ b/passes/sat/eval.cc @@ -88,25 +88,24 @@ struct BruteForceEquivChecker mod1(mod1), mod2(mod2), counter(0), errors(0), ignore_x_mod1(ignore_x_mod1) { log("Checking for equivalence (brute-force): %s vs %s\n", mod1->name.c_str(), mod2->name.c_str()); - for (auto &w : mod1->wires_) + for (auto w : mod1->wires()) { - RTLIL::Wire *wire1 = w.second; - if (wire1->port_id == 0) + if (w->port_id == 0) continue; - if (mod2->wires_.count(wire1->name) == 0) - log_cmd_error("Port %s in module 1 has no counterpart in module 2!\n", wire1->name.c_str()); + if (mod2->wire(w->name) == nullptr) + log_cmd_error("Port %s in module 1 has no counterpart in module 2!\n", w->name.c_str()); - RTLIL::Wire *wire2 = mod2->wires_.at(wire1->name); - if (wire1->width != wire2->width || wire1->port_input != wire2->port_input || wire1->port_output != wire2->port_output) - log_cmd_error("Port %s in module 1 does not match its counterpart in module 2!\n", wire1->name.c_str()); + RTLIL::Wire *w2 = mod2->wire(w->name); + if (w->width != w2->width || w->port_input != w2->port_input || w->port_output != w2->port_output) + log_cmd_error("Port %s in module 1 does not match its counterpart in module 2!\n", w->name.c_str()); - if (wire1->port_input) { - mod1_inputs.append(wire1); - mod2_inputs.append(wire2); + if (w->port_input) { + mod1_inputs.append(w); + mod2_inputs.append(w2); } else { - mod1_outputs.append(wire1); - mod2_outputs.append(wire2); + mod1_outputs.append(w); + mod2_outputs.append(w2); } } @@ -148,17 +147,17 @@ struct VlogHammerReporter SatGen satgen(ez.get(), &sigmap); satgen.model_undef = model_undef; - for (auto &c : module->cells_) - if (!satgen.importCell(c.second)) - log_error("Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(c.first), RTLIL::id2cstr(c.second->type)); + for (auto c : module->cells()) + if (!satgen.importCell(c)) + log_error("Failed to import cell %s (type %s) to SAT database.\n", log_id(c->name), log_id(c->type)); ez->assume(satgen.signals_eq(recorded_set_vars, recorded_set_vals)); - std::vector<int> y_vec = satgen.importDefSigSpec(module->wires_.at("\\y")); + std::vector<int> y_vec = satgen.importDefSigSpec(module->wire("\\y")); std::vector<bool> y_values; if (model_undef) { - std::vector<int> y_undef_vec = satgen.importUndefSigSpec(module->wires_.at("\\y")); + std::vector<int> y_undef_vec = satgen.importUndefSigSpec(module->wire("\\y")); y_vec.insert(y_vec.end(), y_undef_vec.begin(), y_undef_vec.end()); } @@ -253,7 +252,7 @@ struct VlogHammerReporter std::vector<RTLIL::State> bits(patterns[idx].bits.begin(), patterns[idx].bits.begin() + total_input_width); for (int i = 0; i < int(inputs.size()); i++) { - RTLIL::Wire *wire = module->wires_.at(inputs[i]); + RTLIL::Wire *wire = module->wire(inputs[i]); for (int j = input_widths[i]-1; j >= 0; j--) { ce.set(RTLIL::SigSpec(wire, j), bits.back()); recorded_set_vars.append(RTLIL::SigSpec(wire, j)); @@ -263,21 +262,21 @@ struct VlogHammerReporter if (module == modules.front()) { RTLIL::SigSpec sig(wire); if (!ce.eval(sig)) - log_error("Can't read back value for port %s!\n", RTLIL::id2cstr(inputs[i])); + log_error("Can't read back value for port %s!\n", log_id(inputs[i])); input_pattern_list += stringf(" %s", sig.as_const().as_string().c_str()); - log("++PAT++ %d %s %s #\n", idx, RTLIL::id2cstr(inputs[i]), sig.as_const().as_string().c_str()); + log("++PAT++ %d %s %s #\n", idx, log_id(inputs[i]), sig.as_const().as_string().c_str()); } } - if (module->wires_.count("\\y") == 0) - log_error("No output wire (y) found in module %s!\n", RTLIL::id2cstr(module->name)); + if (module->wire("\\y") == nullptr) + log_error("No output wire (y) found in module %s!\n", log_id(module->name)); - RTLIL::SigSpec sig(module->wires_.at("\\y")); + RTLIL::SigSpec sig(module->wire("\\y")); RTLIL::SigSpec undef; while (!ce.eval(sig, undef)) { - // log_error("Evaluation of y in module %s failed: sig=%s, undef=%s\n", RTLIL::id2cstr(module->name), log_signal(sig), log_signal(undef)); - log_warning("Setting signal %s in module %s to undef.\n", log_signal(undef), RTLIL::id2cstr(module->name)); + // log_error("Evaluation of y in module %s failed: sig=%s, undef=%s\n", log_id(module->name), log_signal(sig), log_signal(undef)); + log_warning("Setting signal %s in module %s to undef.\n", log_signal(undef), log_id(module->name)); ce.set(undef, RTLIL::Const(RTLIL::State::Sx, undef.size())); } @@ -289,7 +288,7 @@ struct VlogHammerReporter sat_check(module, recorded_set_vars, recorded_set_vals, sig, true); } else if (rtl_sig.size() > 0) { if (rtl_sig.size() != sig.size()) - log_error("Output (y) has a different width in module %s compared to rtl!\n", RTLIL::id2cstr(module->name)); + log_error("Output (y) has a different width in module %s compared to rtl!\n", log_id(module->name)); for (int i = 0; i < GetSize(sig); i++) if (rtl_sig[i] == RTLIL::State::Sx) sig[i] = RTLIL::State::Sx; @@ -307,10 +306,10 @@ struct VlogHammerReporter { for (auto name : split(module_list, ",")) { RTLIL::IdString esc_name = RTLIL::escape_id(module_prefix + name); - if (design->modules_.count(esc_name) == 0) + if (design->module(esc_name) == nullptr) log_error("Can't find module %s in current design!\n", name.c_str()); log("Using module %s (%s).\n", esc_name.c_str(), name.c_str()); - modules.push_back(design->modules_.at(esc_name)); + modules.push_back(design->module(esc_name)); module_names.push_back(name); } @@ -319,11 +318,11 @@ struct VlogHammerReporter int width = -1; RTLIL::IdString esc_name = RTLIL::escape_id(name); for (auto mod : modules) { - if (mod->wires_.count(esc_name) == 0) - log_error("Can't find input %s in module %s!\n", name.c_str(), RTLIL::id2cstr(mod->name)); - RTLIL::Wire *port = mod->wires_.at(esc_name); + if (mod->wire(esc_name) == nullptr) + log_error("Can't find input %s in module %s!\n", name.c_str(), log_id(mod->name)); + RTLIL::Wire *port = mod->wire(esc_name); if (!port->port_input || port->port_output) - log_error("Wire %s in module %s is not an input!\n", name.c_str(), RTLIL::id2cstr(mod->name)); + log_error("Wire %s in module %s is not an input!\n", name.c_str(), log_id(mod->name)); if (width >= 0 && width != port->width) log_error("Port %s has different sizes in the different modules!\n", name.c_str()); width = port->width; @@ -415,11 +414,11 @@ struct EvalPass : public Pass { /* this should only be used for regression testing of ConstEval -- see vloghammer */ std::string mod1_name = RTLIL::escape_id(args[++argidx]); std::string mod2_name = RTLIL::escape_id(args[++argidx]); - if (design->modules_.count(mod1_name) == 0) + if (design->module(mod1_name) == nullptr) log_error("Can't find module `%s'!\n", mod1_name.c_str()); - if (design->modules_.count(mod2_name) == 0) + if (design->module(mod2_name) == nullptr) log_error("Can't find module `%s'!\n", mod2_name.c_str()); - BruteForceEquivChecker checker(design->modules_.at(mod1_name), design->modules_.at(mod2_name), args[argidx-2] == "-brute_force_equiv_checker_x"); + BruteForceEquivChecker checker(design->module(mod1_name), design->module(mod2_name), args[argidx-2] == "-brute_force_equiv_checker_x"); if (checker.errors > 0) log_cmd_error("Modules are not equivalent!\n"); log("Verified %s = %s (using brute-force check on %d cases).\n", @@ -441,13 +440,12 @@ struct EvalPass : public Pass { extra_args(args, argidx, design); RTLIL::Module *module = NULL; - for (auto &mod_it : design->modules_) - if (design->selected(mod_it.second)) { - if (module) - log_cmd_error("Only one module must be selected for the EVAL pass! (selected: %s and %s)\n", - RTLIL::id2cstr(module->name), RTLIL::id2cstr(mod_it.first)); - module = mod_it.second; - } + for (auto mod : design->selected_modules()) { + if (module) + log_cmd_error("Only one module must be selected for the EVAL pass! (selected: %s and %s)\n", + log_id(module->name), log_id(mod->name)); + module = mod; + } if (module == NULL) log_cmd_error("Can't perform EVAL on an empty selection!\n"); @@ -468,9 +466,9 @@ struct EvalPass : public Pass { } if (shows.size() == 0) { - for (auto &it : module->wires_) - if (it.second->port_output) - shows.push_back(it.second->name.str()); + for (auto w : module->wires()) + if (w->port_output) + shows.push_back(w->name.str()); } if (tables.empty()) diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc index 29dfc7b19..8fb47f357 100644 --- a/passes/sat/expose.cc +++ b/passes/sat/expose.cc @@ -53,7 +53,7 @@ bool consider_cell(RTLIL::Design *design, std::set<RTLIL::IdString> &dff_cells, { if (cell->name[0] == '$' || dff_cells.count(cell->name)) return false; - if (cell->type[0] == '\\' && !design->modules_.count(cell->type)) + if (cell->type[0] == '\\' && (design->module(cell->type) == nullptr)) return false; return true; } @@ -85,27 +85,24 @@ void find_dff_wires(std::set<RTLIL::IdString> &dff_wires, RTLIL::Module *module) SigMap sigmap(module); SigPool dffsignals; - for (auto &it : module->cells_) { - if (ct.cell_known(it.second->type) && it.second->hasPort("\\Q")) - dffsignals.add(sigmap(it.second->getPort("\\Q"))); + for (auto cell : module->cells()) { + if (ct.cell_known(cell->type) && cell->hasPort("\\Q")) + dffsignals.add(sigmap(cell->getPort("\\Q"))); } - for (auto &it : module->wires_) { - if (dffsignals.check_any(it.second)) - dff_wires.insert(it.first); + for (auto w : module->wires()) { + if (dffsignals.check_any(w)) + dff_wires.insert(w->name); } } -void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::Design *design, RTLIL::Module *module) +void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::Module *module) { std::map<RTLIL::SigBit, dff_map_bit_info_t> bit_info; SigMap sigmap(module); - for (auto &it : module->cells_) + for (auto cell : module->selected_cells()) { - if (!design->selected(module, it.second)) - continue; - dff_map_bit_info_t info; info.bit_d = RTLIL::State::Sm; info.bit_clk = RTLIL::State::Sm; @@ -113,7 +110,7 @@ void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::De info.clk_polarity = false; info.arst_polarity = false; info.arst_value = RTLIL::State::Sm; - info.cell = it.second; + info.cell = cell; if (info.cell->type == "$dff") { info.bit_clk = sigmap(info.cell->getPort("\\CLK")).as_bit(); @@ -164,12 +161,12 @@ void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::De } std::map<RTLIL::IdString, dff_map_info_t> empty_dq_map; - for (auto &it : module->wires_) + for (auto w : module->wires()) { - if (!consider_wire(it.second, empty_dq_map)) + if (!consider_wire(w, empty_dq_map)) continue; - std::vector<RTLIL::SigBit> bits_q = sigmap(it.second).to_sigbit_vector(); + std::vector<RTLIL::SigBit> bits_q = sigmap(w).to_sigbit_vector(); std::vector<RTLIL::SigBit> bits_d; std::vector<RTLIL::State> arst_value; std::set<RTLIL::Cell*> cells; @@ -207,7 +204,7 @@ void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::De info.arst_value = arst_value; for (auto it : cells) info.cells.push_back(it->name); - map[it.first] = info; + map[w->name] = info; } } @@ -314,26 +311,23 @@ struct ExposePass : public Pass { RTLIL::Module *first_module = NULL; std::set<RTLIL::IdString> shared_dff_wires; - for (auto &mod_it : design->modules_) + for (auto mod : design->selected_modules()) { - if (!design->selected(mod_it.second)) - continue; - - create_dff_dq_map(dff_dq_maps[mod_it.second], design, mod_it.second); + create_dff_dq_map(dff_dq_maps[mod], mod); if (!flag_shared) continue; if (first_module == NULL) { - for (auto &it : dff_dq_maps[mod_it.second]) + for (auto &it : dff_dq_maps[mod]) shared_dff_wires.insert(it.first); - first_module = mod_it.second; + first_module = mod; } else { std::set<RTLIL::IdString> new_shared_dff_wires; for (auto &it : shared_dff_wires) { - if (!dff_dq_maps[mod_it.second].count(it)) + if (!dff_dq_maps[mod].count(it)) continue; - if (!compare_wires(first_module->wires_.at(it), mod_it.second->wires_.at(it))) + if (!compare_wires(first_module->wire(it), mod->wire(it))) continue; new_shared_dff_wires.insert(it); } @@ -364,28 +358,23 @@ struct ExposePass : public Pass { { RTLIL::Module *first_module = NULL; - for (auto &mod_it : design->modules_) + for (auto module : design->selected_modules()) { - RTLIL::Module *module = mod_it.second; - - if (!design->selected(module)) - continue; - std::set<RTLIL::IdString> dff_wires; if (flag_dff) find_dff_wires(dff_wires, module); if (first_module == NULL) { - for (auto &it : module->wires_) - if (design->selected(module, it.second) && consider_wire(it.second, dff_dq_maps[module])) - if (!flag_dff || dff_wires.count(it.first)) - shared_wires.insert(it.first); + for (auto w : module->wires()) + if (design->selected(module, w) && consider_wire(w, dff_dq_maps[module])) + if (!flag_dff || dff_wires.count(w->name)) + shared_wires.insert(w->name); if (flag_evert) - for (auto &it : module->cells_) - if (design->selected(module, it.second) && consider_cell(design, dff_cells[module], it.second)) - shared_cells.insert(it.first); + for (auto cell : module->cells()) + if (design->selected(module, cell) && consider_cell(design, dff_cells[module], cell)) + shared_cells.insert(cell->name); first_module = module; } @@ -397,16 +386,16 @@ struct ExposePass : public Pass { { RTLIL::Wire *wire; - if (module->wires_.count(it) == 0) + if (module->wire(it) == nullptr) goto delete_shared_wire; - wire = module->wires_.at(it); + wire = module->wire(it); if (!design->selected(module, wire)) goto delete_shared_wire; if (!consider_wire(wire, dff_dq_maps[module])) goto delete_shared_wire; - if (!compare_wires(first_module->wires_.at(it), wire)) + if (!compare_wires(first_module->wire(it), wire)) goto delete_shared_wire; if (flag_dff && !dff_wires.count(it)) goto delete_shared_wire; @@ -421,16 +410,16 @@ struct ExposePass : public Pass { { RTLIL::Cell *cell; - if (module->cells_.count(it) == 0) + if (module->cell(it) == nullptr) goto delete_shared_cell; - cell = module->cells_.at(it); + cell = module->cell(it); if (!design->selected(module, cell)) goto delete_shared_cell; if (!consider_cell(design, dff_cells[module], cell)) goto delete_shared_cell; - if (!compare_cells(first_module->cells_.at(it), cell)) + if (!compare_cells(first_module->cell(it), cell)) goto delete_shared_cell; if (0) @@ -446,13 +435,8 @@ struct ExposePass : public Pass { } } - for (auto &mod_it : design->modules_) + for (auto module : design->selected_modules()) { - RTLIL::Module *module = mod_it.second; - - if (!design->selected(module)) - continue; - std::set<RTLIL::IdString> dff_wires; if (flag_dff && !flag_shared) find_dff_wires(dff_wires, module); @@ -461,49 +445,49 @@ struct ExposePass : public Pass { SigMap out_to_in_map; - for (auto &it : module->wires_) + for (auto w : module->wires()) { if (flag_shared) { - if (shared_wires.count(it.first) == 0) + if (shared_wires.count(w->name) == 0) continue; } else { - if (!design->selected(module, it.second) || !consider_wire(it.second, dff_dq_maps[module])) + if (!design->selected(module, w) || !consider_wire(w, dff_dq_maps[module])) continue; - if (flag_dff && !dff_wires.count(it.first)) + if (flag_dff && !dff_wires.count(w->name)) continue; } if (flag_input) { - if (!it.second->port_input) { - it.second->port_input = true; - log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name)); - RTLIL::Wire *w = module->addWire(NEW_ID, GetSize(it.second)); - out_to_in_map.add(it.second, w); + if (!w->port_input) { + w->port_input = true; + log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name)); + RTLIL::Wire *in_wire = module->addWire(NEW_ID, GetSize(w)); + out_to_in_map.add(w, in_wire); } } else { - if (!it.second->port_output) { - it.second->port_output = true; - log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name)); + if (!w->port_output) { + w->port_output = true; + log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name)); } if (flag_cut) { - RTLIL::Wire *in_wire = add_new_wire(module, it.second->name.str() + sep + "i", it.second->width); + RTLIL::Wire *in_wire = add_new_wire(module, w->name.str() + sep + "i", w->width); in_wire->port_input = true; - out_to_in_map.add(sigmap(it.second), in_wire); + out_to_in_map.add(sigmap(w), in_wire); } } } if (flag_input) { - for (auto &it : module->cells_) { - if (!ct.cell_known(it.second->type)) + for (auto cell : module->cells()) { + if (!ct.cell_known(cell->type)) continue; - for (auto &conn : it.second->connections_) - if (ct.cell_output(it.second->type, conn.first)) + for (auto &conn : cell->connections_) + if (ct.cell_output(cell->type, conn.first)) conn.second = out_to_in_map(sigmap(conn.second)); } @@ -513,11 +497,11 @@ struct ExposePass : public Pass { if (flag_cut) { - for (auto &it : module->cells_) { - if (!ct.cell_known(it.second->type)) + for (auto cell : module->cells()) { + if (!ct.cell_known(cell->type)) continue; - for (auto &conn : it.second->connections_) - if (ct.cell_input(it.second->type, conn.first)) + for (auto &conn : cell->connections_) + if (ct.cell_input(cell->type, conn.first)) conn.second = out_to_in_map(sigmap(conn.second)); } @@ -529,10 +513,10 @@ struct ExposePass : public Pass { for (auto &dq : dff_dq_maps[module]) { - if (!module->wires_.count(dq.first)) + if (module->wire(dq.first) == nullptr) continue; - RTLIL::Wire *wire = module->wires_.at(dq.first); + RTLIL::Wire *wire = module->wire(dq.first); std::set<RTLIL::SigBit> wire_bits_set = sigmap(wire).to_sigbit_set(); std::vector<RTLIL::SigBit> wire_bits_vec = sigmap(wire).to_sigbit_vector(); @@ -541,7 +525,7 @@ struct ExposePass : public Pass { RTLIL::Wire *wire_dummy_q = add_new_wire(module, NEW_ID, 0); for (auto &cell_name : info.cells) { - RTLIL::Cell *cell = module->cells_.at(cell_name); + RTLIL::Cell *cell = module->cell(cell_name); std::vector<RTLIL::SigBit> cell_q_bits = sigmap(cell->getPort("\\Q")).to_sigbit_vector(); for (auto &bit : cell_q_bits) if (wire_bits_set.count(bit)) @@ -609,25 +593,22 @@ struct ExposePass : public Pass { { std::vector<RTLIL::Cell*> delete_cells; - for (auto &it : module->cells_) + for (auto cell : module->cells()) { if (flag_shared) { - if (shared_cells.count(it.first) == 0) + if (shared_cells.count(cell->name) == 0) continue; } else { - if (!design->selected(module, it.second) || !consider_cell(design, dff_cells[module], it.second)) + if (!design->selected(module, cell) || !consider_cell(design, dff_cells[module], cell)) continue; } - RTLIL::Cell *cell = it.second; - - if (design->modules_.count(cell->type)) + if (design->module(cell->type) != nullptr) { - RTLIL::Module *mod = design->modules_.at(cell->type); + RTLIL::Module *mod = design->module(cell->type); - for (auto &it : mod->wires_) + for (auto p : mod->wires()) { - RTLIL::Wire *p = it.second; if (!p->port_input && !p->port_output) continue; diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc index f29631639..54016e528 100644 --- a/passes/sat/freduce.cc +++ b/passes/sat/freduce.cc @@ -614,29 +614,29 @@ struct FreduceWorker int bits_full_total = 0; std::vector<std::set<RTLIL::SigBit>> batches; - for (auto &it : module->wires_) - if (it.second->port_input) { - batches.push_back(sigmap(it.second).to_sigbit_set()); - bits_full_total += it.second->width; + for (auto w : module->wires()) + if (w->port_input) { + batches.push_back(sigmap(w).to_sigbit_set()); + bits_full_total += w->width; } - for (auto &it : module->cells_) { - if (ct.cell_known(it.second->type)) { + for (auto cell : module->cells()) { + if (ct.cell_known(cell->type)) { std::set<RTLIL::SigBit> inputs, outputs; - for (auto &port : it.second->connections()) { + for (auto &port : cell->connections()) { std::vector<RTLIL::SigBit> bits = sigmap(port.second).to_sigbit_vector(); - if (ct.cell_output(it.second->type, port.first)) + if (ct.cell_output(cell->type, port.first)) outputs.insert(bits.begin(), bits.end()); else inputs.insert(bits.begin(), bits.end()); } - std::pair<RTLIL::Cell*, std::set<RTLIL::SigBit>> drv(it.second, inputs); + std::pair<RTLIL::Cell*, std::set<RTLIL::SigBit>> drv(cell, inputs); for (auto &bit : outputs) drivers[bit] = drv; batches.push_back(outputs); bits_full_total += outputs.size(); } - if (inv_mode && it.second->type == "$_NOT_") - inv_pairs.insert(std::pair<RTLIL::SigBit, RTLIL::SigBit>(sigmap(it.second->getPort("\\A")), sigmap(it.second->getPort("\\Y")))); + if (inv_mode && cell->type == "$_NOT_") + inv_pairs.insert(std::pair<RTLIL::SigBit, RTLIL::SigBit>(sigmap(cell->getPort("\\A")), sigmap(cell->getPort("\\Y")))); } int bits_count = 0; @@ -828,10 +828,8 @@ struct FreducePass : public Pass { extra_args(args, argidx, design); int bitcount = 0; - for (auto &mod_it : design->modules_) { - RTLIL::Module *module = mod_it.second; - if (design->selected(module)) - bitcount += FreduceWorker(design, module).run(); + for (auto module : design->selected_modules()) { + bitcount += FreduceWorker(design, module).run(); } log("Rewired a total of %d signal bits.\n", bitcount); diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc index 49ef40061..742433935 100644 --- a/passes/sat/miter.cc +++ b/passes/sat/miter.cc @@ -66,50 +66,48 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: RTLIL::IdString gate_name = RTLIL::escape_id(args[argidx++]); RTLIL::IdString miter_name = RTLIL::escape_id(args[argidx++]); - if (design->modules_.count(gold_name) == 0) + if (design->module(gold_name) == nullptr) log_cmd_error("Can't find gold module %s!\n", gold_name.c_str()); - if (design->modules_.count(gate_name) == 0) + if (design->module(gate_name) == nullptr) log_cmd_error("Can't find gate module %s!\n", gate_name.c_str()); - if (design->modules_.count(miter_name) != 0) + if (design->module(miter_name) != nullptr) log_cmd_error("There is already a module %s!\n", miter_name.c_str()); - RTLIL::Module *gold_module = design->modules_.at(gold_name); - RTLIL::Module *gate_module = design->modules_.at(gate_name); + RTLIL::Module *gold_module = design->module(gold_name); + RTLIL::Module *gate_module = design->module(gate_name); - for (auto &it : gold_module->wires_) { - RTLIL::Wire *w1 = it.second, *w2; - if (w1->port_id == 0) + for (auto gold_wire : gold_module->wires()) { + if (gold_wire->port_id == 0) continue; - if (gate_module->wires_.count(it.second->name) == 0) + RTLIL::Wire *gate_wire = gate_module->wire(gold_wire->name); + if (gate_wire == nullptr) goto match_gold_port_error; - w2 = gate_module->wires_.at(it.second->name); - if (w1->port_input != w2->port_input) + if (gold_wire->port_input != gate_wire->port_input) goto match_gold_port_error; - if (w1->port_output != w2->port_output) + if (gold_wire->port_output != gate_wire->port_output) goto match_gold_port_error; - if (w1->width != w2->width) + if (gold_wire->width != gate_wire->width) goto match_gold_port_error; continue; match_gold_port_error: - log_cmd_error("No matching port in gate module was found for %s!\n", it.second->name.c_str()); + log_cmd_error("No matching port in gate module was found for %s!\n", gold_wire->name.c_str()); } - for (auto &it : gate_module->wires_) { - RTLIL::Wire *w1 = it.second, *w2; - if (w1->port_id == 0) + for (auto gate_wire : gate_module->wires()) { + if (gate_wire->port_id == 0) continue; - if (gold_module->wires_.count(it.second->name) == 0) + RTLIL::Wire *gold_wire = gold_module->wire(gate_wire->name); + if (gold_wire == nullptr) goto match_gate_port_error; - w2 = gold_module->wires_.at(it.second->name); - if (w1->port_input != w2->port_input) + if (gate_wire->port_input != gold_wire->port_input) goto match_gate_port_error; - if (w1->port_output != w2->port_output) + if (gate_wire->port_output != gold_wire->port_output) goto match_gate_port_error; - if (w1->width != w2->width) + if (gate_wire->width != gold_wire->width) goto match_gate_port_error; continue; match_gate_port_error: - log_cmd_error("No matching port in gold module was found for %s!\n", it.second->name.c_str()); + log_cmd_error("No matching port in gold module was found for %s!\n", gate_wire->name.c_str()); } log("Creating miter cell \"%s\" with gold cell \"%s\" and gate cell \"%s\".\n", RTLIL::id2cstr(miter_name), RTLIL::id2cstr(gold_name), RTLIL::id2cstr(gate_name)); @@ -123,73 +121,71 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: RTLIL::SigSpec all_conditions; - for (auto &it : gold_module->wires_) + for (auto gold_wire : gold_module->wires()) { - RTLIL::Wire *w1 = it.second; - - if (w1->port_input) + if (gold_wire->port_input) { - RTLIL::Wire *w2 = miter_module->addWire("\\in_" + RTLIL::unescape_id(w1->name), w1->width); - w2->port_input = true; + RTLIL::Wire *w = miter_module->addWire("\\in_" + RTLIL::unescape_id(gold_wire->name), gold_wire->width); + w->port_input = true; - gold_cell->setPort(w1->name, w2); - gate_cell->setPort(w1->name, w2); + gold_cell->setPort(gold_wire->name, w); + gate_cell->setPort(gold_wire->name, w); } - if (w1->port_output) + if (gold_wire->port_output) { - RTLIL::Wire *w2_gold = miter_module->addWire("\\gold_" + RTLIL::unescape_id(w1->name), w1->width); - w2_gold->port_output = flag_make_outputs; + RTLIL::Wire *w_gold = miter_module->addWire("\\gold_" + RTLIL::unescape_id(gold_wire->name), gold_wire->width); + w_gold->port_output = flag_make_outputs; - RTLIL::Wire *w2_gate = miter_module->addWire("\\gate_" + RTLIL::unescape_id(w1->name), w1->width); - w2_gate->port_output = flag_make_outputs; + RTLIL::Wire *w_gate = miter_module->addWire("\\gate_" + RTLIL::unescape_id(gold_wire->name), gold_wire->width); + w_gate->port_output = flag_make_outputs; - gold_cell->setPort(w1->name, w2_gold); - gate_cell->setPort(w1->name, w2_gate); + gold_cell->setPort(gold_wire->name, w_gold); + gate_cell->setPort(gold_wire->name, w_gate); RTLIL::SigSpec this_condition; if (flag_ignore_gold_x) { - RTLIL::SigSpec gold_x = miter_module->addWire(NEW_ID, w2_gold->width); - for (int i = 0; i < w2_gold->width; i++) { + RTLIL::SigSpec gold_x = miter_module->addWire(NEW_ID, w_gold->width); + for (int i = 0; i < w_gold->width; i++) { RTLIL::Cell *eqx_cell = miter_module->addCell(NEW_ID, "$eqx"); eqx_cell->parameters["\\A_WIDTH"] = 1; eqx_cell->parameters["\\B_WIDTH"] = 1; eqx_cell->parameters["\\Y_WIDTH"] = 1; eqx_cell->parameters["\\A_SIGNED"] = 0; eqx_cell->parameters["\\B_SIGNED"] = 0; - eqx_cell->setPort("\\A", RTLIL::SigSpec(w2_gold, i)); + eqx_cell->setPort("\\A", RTLIL::SigSpec(w_gold, i)); eqx_cell->setPort("\\B", RTLIL::State::Sx); eqx_cell->setPort("\\Y", gold_x.extract(i, 1)); } - RTLIL::SigSpec gold_masked = miter_module->addWire(NEW_ID, w2_gold->width); - RTLIL::SigSpec gate_masked = miter_module->addWire(NEW_ID, w2_gate->width); + RTLIL::SigSpec gold_masked = miter_module->addWire(NEW_ID, w_gold->width); + RTLIL::SigSpec gate_masked = miter_module->addWire(NEW_ID, w_gate->width); RTLIL::Cell *or_gold_cell = miter_module->addCell(NEW_ID, "$or"); - or_gold_cell->parameters["\\A_WIDTH"] = w2_gold->width; - or_gold_cell->parameters["\\B_WIDTH"] = w2_gold->width; - or_gold_cell->parameters["\\Y_WIDTH"] = w2_gold->width; + or_gold_cell->parameters["\\A_WIDTH"] = w_gold->width; + or_gold_cell->parameters["\\B_WIDTH"] = w_gold->width; + or_gold_cell->parameters["\\Y_WIDTH"] = w_gold->width; or_gold_cell->parameters["\\A_SIGNED"] = 0; or_gold_cell->parameters["\\B_SIGNED"] = 0; - or_gold_cell->setPort("\\A", w2_gold); + or_gold_cell->setPort("\\A", w_gold); or_gold_cell->setPort("\\B", gold_x); or_gold_cell->setPort("\\Y", gold_masked); RTLIL::Cell *or_gate_cell = miter_module->addCell(NEW_ID, "$or"); - or_gate_cell->parameters["\\A_WIDTH"] = w2_gate->width; - or_gate_cell->parameters["\\B_WIDTH"] = w2_gate->width; - or_gate_cell->parameters["\\Y_WIDTH"] = w2_gate->width; + or_gate_cell->parameters["\\A_WIDTH"] = w_gate->width; + or_gate_cell->parameters["\\B_WIDTH"] = w_gate->width; + or_gate_cell->parameters["\\Y_WIDTH"] = w_gate->width; or_gate_cell->parameters["\\A_SIGNED"] = 0; or_gate_cell->parameters["\\B_SIGNED"] = 0; - or_gate_cell->setPort("\\A", w2_gate); + or_gate_cell->setPort("\\A", w_gate); or_gate_cell->setPort("\\B", gold_x); or_gate_cell->setPort("\\Y", gate_masked); RTLIL::Cell *eq_cell = miter_module->addCell(NEW_ID, "$eqx"); - eq_cell->parameters["\\A_WIDTH"] = w2_gold->width; - eq_cell->parameters["\\B_WIDTH"] = w2_gate->width; + eq_cell->parameters["\\A_WIDTH"] = w_gold->width; + eq_cell->parameters["\\B_WIDTH"] = w_gate->width; eq_cell->parameters["\\Y_WIDTH"] = 1; eq_cell->parameters["\\A_SIGNED"] = 0; eq_cell->parameters["\\B_SIGNED"] = 0; @@ -201,20 +197,20 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: else { RTLIL::Cell *eq_cell = miter_module->addCell(NEW_ID, "$eqx"); - eq_cell->parameters["\\A_WIDTH"] = w2_gold->width; - eq_cell->parameters["\\B_WIDTH"] = w2_gate->width; + eq_cell->parameters["\\A_WIDTH"] = w_gold->width; + eq_cell->parameters["\\B_WIDTH"] = w_gate->width; eq_cell->parameters["\\Y_WIDTH"] = 1; eq_cell->parameters["\\A_SIGNED"] = 0; eq_cell->parameters["\\B_SIGNED"] = 0; - eq_cell->setPort("\\A", w2_gold); - eq_cell->setPort("\\B", w2_gate); + eq_cell->setPort("\\A", w_gold); + eq_cell->setPort("\\B", w_gate); eq_cell->setPort("\\Y", miter_module->addWire(NEW_ID)); this_condition = eq_cell->getPort("\\Y"); } if (flag_make_outcmp) { - RTLIL::Wire *w_cmp = miter_module->addWire("\\cmp_" + RTLIL::unescape_id(w1->name)); + RTLIL::Wire *w_cmp = miter_module->addWire("\\cmp_" + RTLIL::unescape_id(gold_wire->name)); w_cmp->port_output = true; miter_module->connect(RTLIL::SigSig(w_cmp, this_condition)); } @@ -285,9 +281,9 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL IdString module_name = RTLIL::escape_id(args[argidx++]); IdString miter_name = argidx < args.size() ? RTLIL::escape_id(args[argidx++]) : ""; - if (design->modules_.count(module_name) == 0) + if (design->module(module_name) == nullptr) log_cmd_error("Can't find module %s!\n", module_name.c_str()); - if (!miter_name.empty() && design->modules_.count(miter_name) != 0) + if (!miter_name.empty() && design->module(miter_name) != nullptr) log_cmd_error("There is already a module %s!\n", miter_name.c_str()); Module *module = design->module(module_name); diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index f63012d1a..8b1862237 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -308,7 +308,9 @@ struct IopadmapPass : public Pass { { log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, tinoutpad_celltype.c_str()); - Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(tinoutpad_celltype)); + Cell *cell = module->addCell( + module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)), + RTLIL::escape_id(tinoutpad_celltype)); cell->setPort(RTLIL::escape_id(tinoutpad_portname_oe), en_sig); cell->attributes[ID::keep] = RTLIL::Const(1); @@ -328,7 +330,9 @@ struct IopadmapPass : public Pass { } else { log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, toutpad_celltype.c_str()); - Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(toutpad_celltype)); + Cell *cell = module->addCell( + module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)), + RTLIL::escape_id(toutpad_celltype)); cell->setPort(RTLIL::escape_id(toutpad_portname_oe), en_sig); cell->setPort(RTLIL::escape_id(toutpad_portname_i), data_sig); @@ -406,7 +410,9 @@ struct IopadmapPass : public Pass { SigBit wire_bit(wire, i); - RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype)); + RTLIL::Cell *cell = module->addCell( + module->uniquify(stringf("$iopadmap$%s.%s", log_id(module->name), log_id(wire->name))), + RTLIL::escape_id(celltype)); cell->setPort(RTLIL::escape_id(portname_int), wire_bit); if (!portname_pad.empty()) @@ -420,12 +426,16 @@ struct IopadmapPass : public Pass { } else { - RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype)); + RTLIL::Cell *cell = module->addCell( + module->uniquify(stringf("$iopadmap$%s.%s", log_id(module->name), log_id(wire->name))), + RTLIL::escape_id(celltype)); cell->setPort(RTLIL::escape_id(portname_int), RTLIL::SigSpec(wire)); if (!portname_pad.empty()) { RTLIL::Wire *new_wire = NULL; - new_wire = module->addWire(NEW_ID, wire); + new_wire = module->addWire( + module->uniquify(stringf("$iopadmap$%s", log_id(wire))), + wire); module->swap_names(new_wire, wire); wire->attributes.clear(); cell->setPort(RTLIL::escape_id(portname_pad), RTLIL::SigSpec(new_wire)); @@ -446,7 +456,9 @@ struct IopadmapPass : public Pass { for (auto &it : rewrite_bits) { RTLIL::Wire *wire = it.first; - RTLIL::Wire *new_wire = module->addWire(NEW_ID, wire); + RTLIL::Wire *new_wire = module->addWire( + module->uniquify(stringf("$iopadmap$%s", log_id(wire))), + wire); module->swap_names(new_wire, wire); wire->attributes.clear(); for (int i = 0; i < wire->width; i++) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 0c57733d4..10001baaa 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -177,10 +177,10 @@ struct TechmapWorker std::string orig_cell_name; pool<string> extra_src_attrs = cell->get_strpool_attribute(ID(src)); + orig_cell_name = cell->name.str(); if (!flatten_mode) { for (auto &it : tpl->cells_) if (it.first == ID(_TECHMAP_REPLACE_)) { - orig_cell_name = cell->name.str(); module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str()); break; } diff --git a/techlibs/common/gate2lut.v b/techlibs/common/gate2lut.v index 99c123f4a..15cea3d8d 100644 --- a/techlibs/common/gate2lut.v +++ b/techlibs/common/gate2lut.v @@ -79,7 +79,7 @@ module _90_lut_mux (A, B, S, Y); // A 1010 1010 // B 1100 1100 // S 1111 0000 - .LUT(8'b_1100_1010) + .LUT(8'b 1100_1010) ) lut ( .A(AA), .Y(Y) diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 17fe2ec99..6a0e3031e 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -2350,16 +2350,19 @@ module SB_SPRAM256KA ( if (off) begin DATAOUT <= 0; end else - if (CHIPSELECT && !STANDBY && !WREN) begin - DATAOUT <= mem[ADDRESS]; - end else begin - if (CHIPSELECT && !STANDBY && WREN) begin + if (STANDBY) begin + DATAOUT <= 'bx; + end else + if (CHIPSELECT) begin + if (!WREN) begin + DATAOUT <= mem[ADDRESS]; + end else begin if (MASKWREN[0]) mem[ADDRESS][ 3: 0] = DATAIN[ 3: 0]; if (MASKWREN[1]) mem[ADDRESS][ 7: 4] = DATAIN[ 7: 4]; if (MASKWREN[2]) mem[ADDRESS][11: 8] = DATAIN[11: 8]; if (MASKWREN[3]) mem[ADDRESS][15:12] = DATAIN[15:12]; + DATAOUT <= 'bx; end - DATAOUT <= 'bx; end end `endif @@ -2379,9 +2382,9 @@ module SB_SPRAM256KA ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13167 //$setup(negedge STANDBY, posedge CLOCK, 1715); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13206 - $setup(WREN, posedge CLK, 289); + $setup(WREN, posedge CLOCK, 289); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13207-L13222 - (posedge RCLK => (DATAOUT : 16'bx)) = 1821; + (posedge CLOCK => (DATAOUT : 16'bx)) = 1821; // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13223-L13238 (posedge SLEEP => (DATAOUT : 16'b0)) = 1099; endspecify diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 80bd05a84..b8aedaadf 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -345,6 +345,7 @@ struct SynthIce40Pass : public ScriptPass if (min_ce_use >= 0) { run("opt_merge"); run(stringf("dff2dffe -unmap-mince %d", min_ce_use)); + run("simplemap t:$dff"); } run("techmap -D NO_LUT -D NO_ADDER -map +/ice40/cells_map.v"); run("opt_expr -mux_undef"); diff --git a/techlibs/xilinx/cells_xtra.py b/techlibs/xilinx/cells_xtra.py index 749b1e0a7..f086291ab 100644 --- a/techlibs/xilinx/cells_xtra.py +++ b/techlibs/xilinx/cells_xtra.py @@ -302,7 +302,7 @@ CELLS = [ Cell('IOBUF_DCIEN', port_attrs={'IO': ['iopad_external_pin']}), Cell('IOBUF_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin']}), Cell('IOBUFE3', port_attrs={'IO': ['iopad_external_pin']}), - Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), Cell('IOBUFDS_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), Cell('IOBUFDS_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), Cell('IOBUFDS_DIFF_OUT', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index ac4ad4e36..3021f6b5a 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -7072,6 +7072,7 @@ module IOBUFDS (...); output O; (* iopad_external_pin *) inout IO; + (* iopad_external_pin *) inout IOB; input I; input T; diff --git a/tests/arch/xilinx/tribuf.sh b/tests/arch/xilinx/tribuf.sh index 636aed12a..bd44395cb 100644 --- a/tests/arch/xilinx/tribuf.sh +++ b/tests/arch/xilinx/tribuf.sh @@ -1,5 +1,5 @@ -! ../../../yosys ../common/tribuf.v -qp "synth_xilinx" -../../../yosys ../common/tribuf.v -qp "synth_xilinx -iopad; \ +! ../../../yosys -qp "synth_xilinx" ../common/tribuf.v +../../../yosys -qp "synth_xilinx -iopad; \ select -assert-count 2 t:IBUF; \ select -assert-count 1 t:INV; \ -select -assert-count 1 t:OBUFT" +select -assert-count 1 t:OBUFT" ../common/tribuf.v diff --git a/tests/select/no_warn_assert.ys b/tests/select/no_warn_assert.ys new file mode 100644 index 000000000..889315826 --- /dev/null +++ b/tests/select/no_warn_assert.ys @@ -0,0 +1,2 @@ +logger -expect-no-warnings +select -assert-count 0 top/t:ff4 top/w:d0 %co:+[d] %i diff --git a/tests/select/no_warn_prefixed_arg_memb.ys b/tests/select/no_warn_prefixed_arg_memb.ys new file mode 100644 index 000000000..596a6ed70 --- /dev/null +++ b/tests/select/no_warn_prefixed_arg_memb.ys @@ -0,0 +1,5 @@ +logger -expect-no-warnings +read_verilog ../../examples/igloo2/example.v +hierarchy +proc +select example/t:$add diff --git a/tests/select/no_warn_prefixed_empty_select_arg.ys b/tests/select/no_warn_prefixed_empty_select_arg.ys new file mode 100644 index 000000000..617e0d63e --- /dev/null +++ b/tests/select/no_warn_prefixed_empty_select_arg.ys @@ -0,0 +1,3 @@ +logger -expect-no-warnings +select n:foo/bar* +select t:$assert diff --git a/tests/select/run-test.sh b/tests/select/run-test.sh new file mode 100755 index 000000000..44ce7e674 --- /dev/null +++ b/tests/select/run-test.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e +for x in *.ys; do + echo "Running $x.." + ../../yosys -ql ${x%.ys}.log $x +done diff --git a/tests/select/warn_empty_select_arg.ys b/tests/select/warn_empty_select_arg.ys new file mode 100644 index 000000000..55aca8eb6 --- /dev/null +++ b/tests/select/warn_empty_select_arg.ys @@ -0,0 +1,3 @@ +logger -expect warning "did not match any module." 1 +logger -expect warning "did not match any object." 1 +select foo/bar diff --git a/tests/svtypes/enum_simple.sv b/tests/svtypes/enum_simple.sv index ccaf50da0..4e4d5871c 100644 --- a/tests/svtypes/enum_simple.sv +++ b/tests/svtypes/enum_simple.sv @@ -5,8 +5,9 @@ module enum_simple(input clk, input rst); typedef enum logic [1:0] { ts0, ts1, ts2, ts3 } states_t; - (states_t) state; - (states_t) enum_const = ts1; + states_t state; + (states_t) state1; + states_t enum_const = ts1; always @(posedge clk) begin if (rst) begin diff --git a/tests/svtypes/typedef_memory.sv b/tests/svtypes/typedef_memory.sv index 577e484ad..37e63c1d0 100644 --- a/tests/svtypes/typedef_memory.sv +++ b/tests/svtypes/typedef_memory.sv @@ -1,7 +1,7 @@ module top(input [3:0] addr, wdata, input clk, wen, output reg [3:0] rdata); typedef logic [3:0] ram16x4_t[0:15]; - (ram16x4_t) mem; + ram16x4_t mem; always @(posedge clk) begin if (wen) mem[addr] <= wdata; diff --git a/tests/svtypes/typedef_memory_2.sv b/tests/svtypes/typedef_memory_2.sv index f3089bf55..6d65131db 100644 --- a/tests/svtypes/typedef_memory_2.sv +++ b/tests/svtypes/typedef_memory_2.sv @@ -1,7 +1,7 @@ module top(input [3:0] addr, wdata, input clk, wen, output reg [3:0] rdata); typedef logic [3:0] nibble; - (nibble) mem[0:15]; + nibble mem[0:15]; always @(posedge clk) begin if (wen) mem[addr] <= wdata; diff --git a/tests/svtypes/typedef_package.sv b/tests/svtypes/typedef_package.sv index b766f10cf..57a78c53a 100644 --- a/tests/svtypes/typedef_package.sv +++ b/tests/svtypes/typedef_package.sv @@ -5,8 +5,8 @@ endpackage module top; - (* keep *) (pkg::uint8_t) a = 8'hAA; - (* keep *) (pkg::enum8_t) b_enum = pkg::bb; + (* keep *) pkg::uint8_t a = 8'hAA; + (* keep *) pkg::enum8_t b_enum = pkg::bb; always @* assert(a == 8'hAA); always @* assert(b_enum == 8'hBB); diff --git a/tests/svtypes/typedef_param.sv b/tests/svtypes/typedef_param.sv index ddbd471e0..d838dd828 100644 --- a/tests/svtypes/typedef_param.sv +++ b/tests/svtypes/typedef_param.sv @@ -6,12 +6,12 @@ module top; typedef logic [1:0] uint2_t; typedef logic signed [3:0] int4_t; typedef logic signed [7:0] int8_t; - typedef (int8_t) char_t; + typedef int8_t char_t; - parameter (uint2_t) int2 = 2'b10; - localparam (int4_t) int4 = -1; - localparam (int8_t) int8 = int4; - localparam (char_t) ch = int8; + parameter uint2_t int2 = 2'b10; + localparam int4_t int4 = -1; + localparam int8_t int8 = int4; + localparam char_t ch = int8; `STATIC_ASSERT(int2 == 2'b10); diff --git a/tests/svtypes/typedef_scopes.sv b/tests/svtypes/typedef_scopes.sv index 1c45c7057..5507d84f2 100644 --- a/tests/svtypes/typedef_scopes.sv +++ b/tests/svtypes/typedef_scopes.sv @@ -4,32 +4,39 @@ typedef enum logic {s0, s1} outer_enum_t; module top; - (outer_uint4_t) u4_i = 8'hA5; - (outer_enum_t) enum4_i = s0; + outer_uint4_t u4_i = 8'hA5; + outer_enum_t enum4_i = s0; always @(*) assert(u4_i == 4'h5); always @(*) assert(enum4_i == 1'b0); typedef logic [3:0] inner_type; typedef enum logic [2:0] {s2=2, s3, s4} inner_enum_t; - (inner_type) inner_i1 = 8'h5A; - (inner_enum_t) inner_enum1 = s3; + inner_type inner_i1 = 8'h5A; + inner_enum_t inner_enum1 = s3; always @(*) assert(inner_i1 == 4'hA); always @(*) assert(inner_enum1 == 3'h3); if (1) begin: genblock typedef logic [7:0] inner_type; - parameter (inner_type) inner_const = 8'hA5; + parameter inner_type inner_const = 8'hA5; typedef enum logic [2:0] {s5=5, s6, s7} inner_enum_t; - (inner_type) inner_gb_i = inner_const; //8'hA5; - (inner_enum_t) inner_gb_enum1 = s7; + inner_type inner_gb_i = inner_const; //8'hA5; + inner_enum_t inner_gb_enum1 = s7; always @(*) assert(inner_gb_i == 8'hA5); always @(*) assert(inner_gb_enum1 == 3'h7); end - (inner_type) inner_i2 = 8'h42; - (inner_enum_t) inner_enum2 = s4; + inner_type inner_i2 = 8'h42; + inner_enum_t inner_enum2 = s4; always @(*) assert(inner_i2 == 4'h2); always @(*) assert(inner_enum2 == 3'h4); +endmodule + +typedef logic[7:0] between_t; +module other; + between_t a = 8'h42; + always @(*) assert(a == 8'h42); endmodule + diff --git a/tests/svtypes/typedef_simple.sv b/tests/svtypes/typedef_simple.sv index 7e760dee4..8f89910e5 100644 --- a/tests/svtypes/typedef_simple.sv +++ b/tests/svtypes/typedef_simple.sv @@ -3,12 +3,12 @@ module top; typedef logic [1:0] uint2_t; typedef logic signed [3:0] int4_t; typedef logic signed [7:0] int8_t; - typedef (int8_t) char_t; + typedef int8_t char_t; - (* keep *) (uint2_t) int2 = 2'b10; - (* keep *) (int4_t) int4 = -1; - (* keep *) (int8_t) int8 = int4; - (* keep *) (char_t) ch = int8; + (* keep *) uint2_t int2 = 2'b10; + (* keep *) int4_t int4 = -1; + (* keep *) int8_t int8 = int4; + (* keep *) char_t ch = int8; always @* assert(int2 == 2'b10); diff --git a/tests/techmap/techmap_replace.ys b/tests/techmap/techmap_replace.ys index c2f42d50b..8403586bd 100644 --- a/tests/techmap/techmap_replace.ys +++ b/tests/techmap/techmap_replace.ys @@ -16,3 +16,21 @@ EOT techmap -map %techmap select -assert-any w:s0.asdf select -assert-any c:s0.blah + +read_verilog <<EOT +module sub(input i, output o, input j); +wire _TECHMAP_REPLACE_.asdf = i ; +barfoo _TECHMAP_REPLACE_.blah (i, o, j); +endmodule +EOT +design -stash techmap + +read_verilog <<EOT +module top(input i, output o); +sub s0(i, o); +endmodule +EOT + +techmap -map %techmap +select -assert-any w:s0.asdf +select -assert-any c:s0.blah diff --git a/tests/various/bug1745.ys b/tests/various/bug1745.ys new file mode 100644 index 000000000..2e5b8c2d4 --- /dev/null +++ b/tests/various/bug1745.ys @@ -0,0 +1,8 @@ +logger -expect error "syntax error, unexpected TOK_CONSTVAL" 1 +read_verilog <<EOT +module inverter(input a, output y); + + assign y = (a == 1'b0? 1'b1 : 1'b0); + +endmodule // inverter +EOT diff --git a/tests/various/bug1781.ys b/tests/various/bug1781.ys new file mode 100644 index 000000000..60dcc0830 --- /dev/null +++ b/tests/various/bug1781.ys @@ -0,0 +1,33 @@ +read_verilog <<EOT + +module top(input clk, input rst); + +reg [1:0] state; + +always @(posedge clk, posedge rst) begin + if (rst) + state <= 0; + else + case (state) + 2'b00: state <= 2'b01; + 2'b01: state <= 2'b10; + 2'b10: state <= 2'b00; + endcase +end + +sub sub_i(.i(state == 0)); + +endmodule + + +(* blackbox, keep *) +module sub(input i); +endmodule + +EOT + +proc +fsm + +# Make sure there is a driver +select -assert-any t:sub %ci %a w:* %i %ci c:* %i diff --git a/tests/various/constcomment.ys b/tests/various/constcomment.ys new file mode 100644 index 000000000..f4f2e75d8 --- /dev/null +++ b/tests/various/constcomment.ys @@ -0,0 +1,16 @@ +read_verilog <<EOT +module top1; + localparam a = 8 /*foo*/ 'h ab; + localparam b = 8 'h /*foo*/ cd; + generate + if (a != 8'b10101011) $error("a incorrect!"); + if (b != 8'b11001101) $error("b incorrect!"); + endgenerate +endmodule +EOT +logger -expect error "syntax error, unexpected TOK_BASE" 1 +read_verilog <<EOT +module top2; + localparam a = 12'h4 /*foo*/'b0; +endmodule +EOT diff --git a/tests/various/exec.ys b/tests/various/exec.ys new file mode 100644 index 000000000..0eec00719 --- /dev/null +++ b/tests/various/exec.ys @@ -0,0 +1,6 @@ +exec -expect-return 0 -- exit 0 +exec -expect-return 27 -- exit 27 +exec -expect-stdout nana -expect-stdout api -not-expect-stdout giraffe -- echo "bananapie" + +logger -expect error "stdout did have a line" 1 +exec -not-expect-stdout giraffe -- echo "giraffe" diff --git a/tests/various/ice40_mince_abc9.ys b/tests/various/ice40_mince_abc9.ys new file mode 100644 index 000000000..408e16f05 --- /dev/null +++ b/tests/various/ice40_mince_abc9.ys @@ -0,0 +1,17 @@ +read_verilog <<EOT + +module top(input clk, ce, input [2:0] a, b, output reg [2:0] q); + + reg [2:0] aa, bb; + + always @(posedge clk) begin + if (ce) begin + aa <= a; + end + bb <= b; + q <= aa + bb; + end +endmodule +EOT + +synth_ice40 -abc9 -dffe_min_ce_use 4 diff --git a/tests/various/logger_error.ys b/tests/various/logger_error.ys new file mode 100644 index 000000000..46fe7f506 --- /dev/null +++ b/tests/various/logger_error.ys @@ -0,0 +1,6 @@ +logger -werror "is implicitly declared." -expect error "is implicitly declared." 1 +read_verilog << EOF +module top(...); + assign b = w; +endmodule +EOF diff --git a/tests/various/logger_nowarning.ys b/tests/various/logger_nowarning.ys new file mode 100644 index 000000000..87cbbc644 --- /dev/null +++ b/tests/various/logger_nowarning.ys @@ -0,0 +1,6 @@ +logger -expect-no-warnings -nowarn "is implicitly declared." +read_verilog << EOF +module top(...); + assign b = w; +endmodule +EOF diff --git a/tests/various/logger_warn.ys b/tests/various/logger_warn.ys new file mode 100644 index 000000000..2316ae4c6 --- /dev/null +++ b/tests/various/logger_warn.ys @@ -0,0 +1,6 @@ +logger -warn "Successfully finished Verilog frontend." -expect warning "Successfully finished Verilog frontend." 1 +read_verilog << EOF +module top(...); + assign b = w; +endmodule +EOF diff --git a/tests/various/logger_warning.ys b/tests/various/logger_warning.ys new file mode 100644 index 000000000..642b1b97b --- /dev/null +++ b/tests/various/logger_warning.ys @@ -0,0 +1,6 @@ +logger -expect warning "is implicitly declared." 2 +read_verilog << EOF +module top(...); + assign b = w; +endmodule +EOF diff --git a/tests/various/src.ys b/tests/various/src.ys new file mode 100644 index 000000000..89d6700ca --- /dev/null +++ b/tests/various/src.ys @@ -0,0 +1,8 @@ +logger -expect warning "wire '\\o' is assigned in a block at <<EOT:2.11-2.17" 1 +logger -expect warning "wire '\\p' is assigned in a block at <<EOT:3.11-3.16" 1 +read_verilog <<EOT +module top(input i, output o, p); +always @* o <= i; +always @* p = i; +endmodule +EOT diff --git a/tests/various/sv_defines.ys b/tests/various/sv_defines.ys new file mode 100644 index 000000000..8e70ee0ee --- /dev/null +++ b/tests/various/sv_defines.ys @@ -0,0 +1,33 @@ +# Check that basic macro expansions do what you'd expect + +read_verilog <<EOT +`define empty_arglist() 123 +`define one_arg(x) 123+x +`define opt_arg(x = 1) 123+x +`define two_args(x, y = (1+23)) x+y +`define nested_comma(x = {31'b0, 1'b1}, y=3) x+y + +module top; + localparam a = `empty_arglist(); + localparam b = `one_arg(10); + localparam c = `opt_arg(10); + localparam d = `opt_arg(); + localparam e = `two_args(1,2); + localparam f = `two_args(1); + localparam g = `nested_comma(1, 2); + localparam h = `nested_comma({31'b0, (1'b0)}); + localparam i = `nested_comma(, 1); + + generate + if (a != 123) $error("a bad"); + if (b != 133) $error("b bad"); + if (c != 133) $error("c bad"); + if (d != 124) $error("d bad"); + if (e != 3) $error("e bad"); + if (f != 25) $error("f bad"); + if (g != 3) $error("g bad"); + if (h != 3) $error("h bad"); + if (i != 2) $error("i bad"); + endgenerate +endmodule +EOT diff --git a/tests/various/sv_defines_dup.ys b/tests/various/sv_defines_dup.ys new file mode 100644 index 000000000..38418ba8f --- /dev/null +++ b/tests/various/sv_defines_dup.ys @@ -0,0 +1,5 @@ +# Check for duplicate arguments +logger -expect error "Duplicate macro arguments with name `x'" 1 +read_verilog <<EOT +`define duplicate_arg(x, x) +EOT diff --git a/tests/various/sv_defines_mismatch.ys b/tests/various/sv_defines_mismatch.ys new file mode 100644 index 000000000..ab6e899de --- /dev/null +++ b/tests/various/sv_defines_mismatch.ys @@ -0,0 +1,5 @@ +# Check that we spot mismatched brackets +logger -expect error "Mismatched brackets in macro argument: \[ and }." 1 +read_verilog <<EOT +`define foo(x=[1,2}) +EOT diff --git a/tests/various/sv_defines_too_few.ys b/tests/various/sv_defines_too_few.ys new file mode 100644 index 000000000..295884809 --- /dev/null +++ b/tests/various/sv_defines_too_few.ys @@ -0,0 +1,7 @@ +# Check that we don't allow passing too few arguments (and, while we're at it, check that passing "no" +# arguments actually passes 1 empty argument). +logger -expect error "Cannot expand macro `foo by giving only 1 argument \(argument 2 has no default\)." 1 +read_verilog <<EOT +`define foo(x=1, y) +`foo() +EOT |