Support parameters using struct as a wiretype (#3050)
authorKamil Rakoczy <krakoczy@antmicro.com>
Tue, 16 Nov 2021 09:59:54 +0000 (10:59 +0100)
committerGitHub <noreply@github.com>
Tue, 16 Nov 2021 09:59:54 +0000 (10:59 +0100)
Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>
frontends/ast/simplify.cc
tests/various/param_struct.ys [new file with mode: 0644]

index 64d0fe475baa31e393e946d4dbff7360ab641c02..777f46bd7d3b55d73a25b6b95be17de57e6dcb6f 100644 (file)
@@ -1613,6 +1613,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                        if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) {
                                // replace with wire representing the packed structure
                                newNode = make_packed_struct(template_node, str);
+                               newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str);
                                // add original input/output attribute to resolved wire
                                newNode->is_input = this->is_input;
                                newNode->is_output = this->is_output;
@@ -1661,18 +1662,33 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                if (is_custom_type) {
                        log_assert(children.size() == 2);
                        log_assert(children[1]->type == AST_WIRETYPE);
-                       if (!current_scope.count(children[1]->str))
-                               log_file_error(filename, location.first_line, "Unknown identifier `%s' used as type name\n", children[1]->str.c_str());
-                       AstNode *resolved_type_node = current_scope.at(children[1]->str);
+                       auto type_name = children[1]->str;
+                       if (!current_scope.count(type_name)) {
+                               log_file_error(filename, location.first_line, "Unknown identifier `%s' used as type name\n", type_name.c_str());
+                       }
+                       AstNode *resolved_type_node = current_scope.at(type_name);
                        if (resolved_type_node->type != AST_TYPEDEF)
-                               log_file_error(filename, location.first_line, "`%s' does not name a type\n", children[1]->str.c_str());
+                               log_file_error(filename, location.first_line, "`%s' does not name a type\n", type_name.c_str());
                        log_assert(resolved_type_node->children.size() == 1);
                        AstNode *template_node = resolved_type_node->children[0];
-                       delete children[1];
-                       children.pop_back();
 
                        // Ensure typedef itself is fully simplified
-                       while(template_node->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};
+                       while (template_node->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};
+
+                       if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) {
+                               // replace with wire representing the packed structure
+                               newNode = make_packed_struct(template_node, str);
+                               newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str);
+                               newNode->type = type;
+                               current_scope[str] = this;
+                               // copy param value, it needs to be 1st value
+                               delete children[1];
+                               children.pop_back();
+                               newNode->children.insert(newNode->children.begin(), children[0]->clone());
+                               goto apply_newNode;
+                       }
+                       delete children[1];
+                       children.pop_back();
 
                        if (template_node->type == AST_MEMORY)
                                log_file_error(filename, location.first_line, "unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str());
diff --git a/tests/various/param_struct.ys b/tests/various/param_struct.ys
new file mode 100644 (file)
index 0000000..6d7a7c6
--- /dev/null
@@ -0,0 +1,51 @@
+read_verilog -sv << EOF
+package p;
+typedef struct packed {
+  logic a;
+  logic b;
+} struct_t;
+
+typedef struct packed {
+  struct_t g;
+  logic [2:0] h;
+} nested_struct_t;
+
+typedef union packed {
+  logic [4:0] x;
+} nested_union_t;
+
+parameter struct_t c = {1'b1, 1'b0};
+parameter nested_struct_t x = {{1'b1, 1'b0}, 1'b1, 1'b1, 1'b1};
+endpackage
+
+module dut ();
+parameter p::struct_t d = p::c;
+parameter p::nested_struct_t i = p::x;
+
+parameter p::nested_union_t u = {5'b11001};
+
+localparam e = d.a;
+localparam f = d.b;
+
+localparam j = i.g.a;
+localparam k = i.g.b;
+localparam l = i.h;
+localparam m = i.g;
+
+localparam o = u.x;
+
+always_comb begin
+  assert(d == 2'b10);
+  assert(e == 1'b1);
+  assert(f == 1'b0);
+  assert(j == 1'b1);
+  assert(k == 1'b0);
+  assert(l == 3'b111);
+// TODO: support access to whole sub-structs and unions
+//  assert(m == 2'b10);
+  assert(u == 5'b11001);
+end
+endmodule
+EOF
+hierarchy; proc; opt
+sat -verify -seq 1 -tempinduct -prove-asserts -show-all