sv: Add support for memory typedefs
authorDavid Shah <dave@ds0.me>
Fri, 20 Sep 2019 10:39:15 +0000 (11:39 +0100)
committerDavid Shah <dave@ds0.me>
Thu, 3 Oct 2019 08:54:14 +0000 (09:54 +0100)
Signed-off-by: David Shah <dave@ds0.me>
frontends/ast/simplify.cc
frontends/verilog/verilog_parser.y
tests/svtypes/typedef_memory.sv [new file with mode: 0644]

index 44e32b29c830872ed9727b70c56f1f89d1c29b82..a6ac0403770e525534133f52e63bd5d98157505a 100644 (file)
@@ -785,8 +785,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
        // resolve typedefs
        if (type == AST_TYPEDEF) {
                log_assert(children.size() == 1);
-               log_assert(children[0]->type == AST_WIRE);
-               while(children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};
+               log_assert(children[0]->type == AST_WIRE || children[0]->type == AST_MEMORY);
+               while(children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {
+                       did_something = true;
+               };
                log_assert(!children[0]->is_custom_type);
        }
 
@@ -807,6 +809,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                        // Ensure typedef itself is fully simplified
                        while(templ->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};
 
+                       type = templ->type;
                        is_reg = templ->is_reg;
                        is_logic = templ->is_logic;
                        is_signed = templ->is_signed;
@@ -819,6 +822,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                        range_right = templ->range_right;
                        for (auto template_child : templ->children)
                                children.push_back(template_child->clone());
+                       did_something = true;
                }
                log_assert(!is_custom_type);
        }
@@ -841,6 +845,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                        // Ensure typedef itself is fully simplified
                        while(templ->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};
 
+                       if (templ->type == AST_MEMORY)
+                               log_file_error(filename, linenum, "unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str());
                        is_signed = templ->is_signed;
                        is_string = templ->is_string;
                        is_custom_type = templ->is_custom_type;
@@ -851,6 +857,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                        range_right = templ->range_right;
                        for (auto template_child : templ->children)
                                children.push_back(template_child->clone());
+                       did_something = true;
                }
                log_assert(!is_custom_type);
        }       
@@ -3074,6 +3081,9 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
        uint32_t children_flags = 0;
        int lhs_children_counter = 0;
 
+       if (type == AST_TYPEDEF)
+               return; // don't touch content of typedefs
+
        if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
        {
                // mark all memories that are used in a complex expression on the left side of an assignment
@@ -3231,6 +3241,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
        if (type == AST_FUNCTION || type == AST_TASK)
                return false;
 
+       if (type == AST_TYPEDEF)
+               return false;
+
        if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast))
        {
                log_assert(children[0]->type == AST_CONSTANT);
index 8cc084fe08d43c3bbcc391f0908b1a434332f9cc..ba44d7f3d58ebfd810e1f0caf5fc0a7580436cd5 100644 (file)
@@ -1400,7 +1400,7 @@ assign_expr:
        };
 
 typedef_decl:
-       TOK_TYPEDEF wire_type range TOK_ID ';' {
+       TOK_TYPEDEF wire_type range TOK_ID range_or_multirange ';' {
                astbuf1 = $2;
                astbuf2 = $3;
                if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
@@ -1416,6 +1416,24 @@ typedef_decl:
                        frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]");
                if (astbuf2)
                        astbuf1->children.push_back(astbuf2);
+
+               if ($5 != NULL) {
+                       if (!astbuf2) {
+                               AstNode *rng = new AstNode(AST_RANGE);
+                               rng->children.push_back(AstNode::mkconst_int(0, true));
+                               rng->children.push_back(AstNode::mkconst_int(0, true));
+                               astbuf1->children.push_back(rng);
+                       }
+                       astbuf1->type = AST_MEMORY;
+                       auto *rangeNode = $5;
+                       if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) {
+                               // SV array size [n], rewrite as [n-1:0]
+                               rangeNode->children[0] = new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true));
+                               rangeNode->children.push_back(AstNode::mkconst_int(0, false));
+                       }
+                       astbuf1->children.push_back(rangeNode);
+               }
+
                ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1));
                ast_stack.back()->children.back()->str = *$4;
        };
diff --git a/tests/svtypes/typedef_memory.sv b/tests/svtypes/typedef_memory.sv
new file mode 100644 (file)
index 0000000..c848c32
--- /dev/null
@@ -0,0 +1,10 @@
+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;
+
+       always @(posedge clk) begin
+               if (wen) mem[addr] <= wdata;
+               rdata <= mem[addr];
+       end
+endmodule
\ No newline at end of file