verilog: check for module scope identifiers during width detection
authorZachary Snow <zach@zachjs.com>
Sat, 5 Jun 2021 20:21:09 +0000 (16:21 -0400)
committerZachary Snow <zachary.j.snow@gmail.com>
Tue, 8 Jun 2021 19:03:16 +0000 (15:03 -0400)
The recent fix for case expression width detection causes the width of
the expressions to be queried before they are simplified. Because the
logic supporting module scope identifiers only existed in simplify,
looking them up would fail during width detection. This moves the logic
to a common helper used in both simplify() and detectSignWidthWorker().

frontends/ast/ast.h
frontends/ast/genrtlil.cc
frontends/ast/simplify.cc
tests/simple/module_scope_case.v [new file with mode: 0644]

index 9887d24ead16c630c8a8b05123acff78eab8b61d..b6b15b7388215f7476aa6341b2980a71fac44c83 100644 (file)
@@ -326,6 +326,9 @@ namespace AST
 
                // helpers for locations
                std::string loc_string() const;
+
+               // Helper for looking up identifiers which are prefixed with the current module name
+               std::string try_pop_module_prefix() const;
        };
 
        // process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
index b8b9f715e8f2b7615fe788b41d44c6458ee59dea..e886844be1c7fe41ba0d13ae7d90483a11921330 100644 (file)
@@ -767,8 +767,15 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
 
        case AST_IDENTIFIER:
                id_ast = id2ast;
-               if (id_ast == NULL && current_scope.count(str))
-                       id_ast = current_scope.at(str);
+               if (!id_ast) {
+                       if (current_scope.count(str))
+                               id_ast = current_scope[str];
+                       else {
+                               std::string alt = try_pop_module_prefix();
+                               if (current_scope.count(alt))
+                                       id_ast = current_scope[alt];
+                       }
+               }
                if (!id_ast)
                        log_file_error(filename, location.first_line, "Failed to resolve identifier %s for width detection!\n", str.c_str());
                if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM || id_ast->type == AST_ENUM_ITEM) {
index 44b11da74059c2374b9a65a819d85f999db1ae5c..cd27a720a9dd5d8b6a442f436f7e01ca93f6a224 100644 (file)
@@ -1698,17 +1698,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
        if (type == AST_IDENTIFIER) {
                if (current_scope.count(str) == 0) {
                        AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod;
-                       size_t pos = str.find('.', 1);
-                       if (str[0] == '\\' && pos != std::string::npos) {
-                               std::string new_str = "\\" + str.substr(pos + 1);
-                               if (current_scope.count(new_str)) {
-                                       std::string prefix = str.substr(0, pos);
-                                       auto it = current_scope_ast->attributes.find(ID::hdlname);
-                                       if ((it != current_scope_ast->attributes.end() && it->second->str == prefix)
-                                                       || prefix == current_scope_ast->str)
-                                               str = new_str;
-                               }
-                       }
+                       str = try_pop_module_prefix();
                        for (auto node : current_scope_ast->children) {
                                //log("looking at mod scope child %s\n", type2str(node->type).c_str());
                                switch (node->type) {
@@ -5124,4 +5114,21 @@ std::pair<AstNode*, AstNode*> AstNode::get_tern_choice()
        return {choice, not_choice};
 }
 
+std::string AstNode::try_pop_module_prefix() const
+{
+       AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod;
+       size_t pos = str.find('.', 1);
+       if (str[0] == '\\' && pos != std::string::npos) {
+               std::string new_str = "\\" + str.substr(pos + 1);
+               if (current_scope.count(new_str)) {
+                       std::string prefix = str.substr(0, pos);
+                       auto it = current_scope_ast->attributes.find(ID::hdlname);
+                       if ((it != current_scope_ast->attributes.end() && it->second->str == prefix)
+                                       || prefix == current_scope_ast->str)
+                               return new_str;
+               }
+       }
+       return str;
+}
+
 YOSYS_NAMESPACE_END
diff --git a/tests/simple/module_scope_case.v b/tests/simple/module_scope_case.v
new file mode 100644 (file)
index 0000000..1472b69
--- /dev/null
@@ -0,0 +1,11 @@
+module top(
+       input wire x,
+       output reg y
+);
+       always @* begin
+               case (top.x)
+                       1: top.y = 0;
+                       0: top.y = 1;
+               endcase
+       end
+endmodule