From 0f22f106e9d89e7fff15aad2889ae4169d5ffabc Mon Sep 17 00:00:00 2001 From: Yannick Lamarre Date: Fri, 23 Feb 2024 21:33:14 -0500 Subject: [PATCH 1/2] Add tests for implicit wires in generate blocks. Signed-off-by: Yannick Lamarre --- tests/verilog/genblk_wire.sv | 20 ++++++++++++++++++++ tests/verilog/genblk_wire.ys | 16 ++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/verilog/genblk_wire.sv create mode 100644 tests/verilog/genblk_wire.ys diff --git a/tests/verilog/genblk_wire.sv b/tests/verilog/genblk_wire.sv new file mode 100644 index 000000000..ef95fa98a --- /dev/null +++ b/tests/verilog/genblk_wire.sv @@ -0,0 +1,20 @@ +module gold(a, b); + output wire [1:0] a; + input wire [1:0] b; + genvar i; + for (i = 0; i < 2; i++) begin + wire x; + assign x = b[i]; + assign a[i] = x; + end +endmodule + +module gate(a, b); + output wire [1:0] a; + input wire [1:0] b; + genvar i; + for (i = 0; i < 2; i++) begin + assign x = b[i]; + assign a[i] = x; + end +endmodule diff --git a/tests/verilog/genblk_wire.ys b/tests/verilog/genblk_wire.ys new file mode 100644 index 000000000..84c559cbb --- /dev/null +++ b/tests/verilog/genblk_wire.ys @@ -0,0 +1,16 @@ +#logger -expect warning "Identifier `\\genblk1[0].x' is implicitly declared." 1 +#logger -expect warning "Identifier `\\genblk1[1].x' is implicitly declared." 1 +read_verilog -sv genblk_wire.sv + +select -assert-count 1 gate/genblk1[0].x +select -assert-count 1 gate/genblk1[1].x +select -assert-count 0 gate/genblk1[2].x + +select -assert-count 1 gold/genblk1[0].x +select -assert-count 1 gold/genblk1[1].x +select -assert-count 0 gold/genblk1[2].x + +proc +equiv_make gold gate equiv +equiv_simple +equiv_status -assert From 73618d862ba5e71be7750c32006810831b267d41 Mon Sep 17 00:00:00 2001 From: Yannick Lamarre Date: Fri, 23 Feb 2024 21:42:16 -0500 Subject: [PATCH 2/2] Add autowires in genblk/for expension Signed-off-by: Yannick Lamarre --- frontends/ast/simplify.cc | 88 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 43a4e03a2..63db83cc2 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -4557,6 +4557,7 @@ void AstNode::expand_genblock(const std::string &prefix) switch (child->type) { case AST_WIRE: + case AST_AUTOWIRE: case AST_MEMORY: case AST_STRUCT: case AST_UNION: @@ -4585,6 +4586,93 @@ void AstNode::expand_genblock(const std::string &prefix) } break; + case AST_IDENTIFIER: + if (!child->str.empty() && prefix.size() > 0) { + bool is_resolved = false; + std::string identifier_str = child->str; + if (current_ast_mod != nullptr && identifier_str.compare(0, current_ast_mod->str.size(), current_ast_mod->str) == 0) { + if (identifier_str.at(current_ast_mod->str.size()) == '.') { + identifier_str = '\\' + identifier_str.substr(current_ast_mod->str.size()+1, identifier_str.size()); + } + } + // search starting in the innermost scope and then stepping outward + for (size_t ppos = prefix.size() - 1; ppos; --ppos) { + if (prefix.at(ppos) != '.') continue; + + std::string new_prefix = prefix.substr(0, ppos + 1); + auto attempt_resolve = [&new_prefix](const std::string &ident) -> std::string { + std::string new_name = prefix_id(new_prefix, ident); + if (current_scope.count(new_name)) + return new_name; + return {}; + }; + + // attempt to resolve the full identifier + std::string resolved = attempt_resolve(identifier_str); + if (!resolved.empty()) { + is_resolved = true; + break; + } + // attempt to resolve hierarchical prefixes within the identifier, + // as the prefix could refer to a local scope which exists but + // hasn't yet been elaborated + for (size_t spos = identifier_str.size() - 1; spos; --spos) { + if (identifier_str.at(spos) != '.') continue; + resolved = attempt_resolve(identifier_str.substr(0, spos)); + if (!resolved.empty()) { + is_resolved = true; + identifier_str = resolved + identifier_str.substr(spos); + ppos = 1; // break outer loop + break; + } + } + if (current_scope.count(identifier_str) == 0) { + AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod; + for (auto node : current_scope_ast->children) { + switch (node->type) { + case AST_PARAMETER: + case AST_LOCALPARAM: + case AST_WIRE: + case AST_AUTOWIRE: + case AST_GENVAR: + case AST_MEMORY: + case AST_FUNCTION: + case AST_TASK: + case AST_DPI_FUNCTION: + if (prefix_id(new_prefix, identifier_str) == node->str) { + is_resolved = true; + current_scope[node->str] = node; + } + break; + case AST_ENUM: + current_scope[node->str] = node; + for (auto enum_node : node->children) { + log_assert(enum_node->type==AST_ENUM_ITEM); + if (prefix_id(new_prefix, identifier_str) == enum_node->str) { + is_resolved = true; + current_scope[enum_node->str] = enum_node; + } + } + break; + default: + break; + } + } + } + } + if ((current_scope.count(identifier_str) == 0) && is_resolved == false) { + if (current_ast_mod == nullptr) { + input_error("Identifier `%s' is implicitly declared outside of a module.\n", child->str.c_str()); + } else if (flag_autowire || identifier_str == "\\$global_clock") { + AstNode *auto_wire = new AstNode(AST_AUTOWIRE); + auto_wire->str = identifier_str; + children.push_back(auto_wire); + } else { + input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", identifier_str.c_str()); + } + } + } + break; default: break; }