sv: Switch parser to glr, prep for typedef
authorDavid Shah <dave@ds0.me>
Thu, 19 Sep 2019 19:43:13 +0000 (20:43 +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/ast.cc
frontends/ast/ast.h
frontends/ast/genrtlil.cc
frontends/ast/simplify.cc
frontends/verilog/verilog_parser.y
tests/svtypes/typedef1.sv [new file with mode: 0644]

index 21279cbfa583996ffca5aeba227dfef240d2fb10..937dad9bea9f44bff2076cded1486c64fa5f8c33 100644 (file)
@@ -164,6 +164,8 @@ std::string AST::type2str(AstNodeType type)
        X(AST_MODPORT)
        X(AST_MODPORTMEMBER)
        X(AST_PACKAGE)
+       X(AST_WIRETYPE)
+       X(AST_TYPEDEF)
 #undef X
        default:
                log_abort();
@@ -206,6 +208,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
        was_checked = false;
        range_valid = false;
        range_swapped = false;
+       is_custom_type = false;
        port_id = 0;
        range_left = -1;
        range_right = 0;
index 93fee913edeb4708973952ed222c17e99cdb67c8..fcc661b4c5337360bd02b256dc546f2674a2d282 100644 (file)
@@ -148,7 +148,10 @@ namespace AST
                AST_INTERFACEPORTTYPE,
                AST_MODPORT,
                AST_MODPORTMEMBER,
-               AST_PACKAGE
+               AST_PACKAGE,
+
+               AST_WIRETYPE,
+               AST_TYPEDEF
        };
 
        // convert an node type to a string (e.g. for debug output)
@@ -174,7 +177,7 @@ namespace AST
                // node content - most of it is unused in most node types
                std::string str;
                std::vector<RTLIL::State> bits;
-               bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized;
+               bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized, is_custom_type;
                int port_id, range_left, range_right;
                uint32_t integer;
                double realvalue;
index 407a3447213207c8f8f8840bca8d5d289ab1a41e..94f5c0a044d14b42f4f051d1842509a8e88e7367 100644 (file)
@@ -863,6 +863,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
        case AST_PACKAGE:
        case AST_MODPORT:
        case AST_MODPORTMEMBER:
+       case AST_TYPEDEF:
                break;
        case AST_INTERFACEPORT: {
                // If a port in a module with unknown type is found, mark it with the attribute 'is_interface'
index b1ee22f4215884d987c71afddc2d43dbf72b1f4e..b94662bcd3e811f40224225cff6e0917e0e63554 100644 (file)
@@ -318,7 +318,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
        }
 
        // activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.)
-       if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX)
+       if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX || type == AST_TYPEDEF)
                const_fold = true;
        if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM))
                const_fold = true;
@@ -336,6 +336,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                std::map<std::string, AstNode*> this_wire_scope;
                for (size_t i = 0; i < children.size(); i++) {
                        AstNode *node = children[i];
+
                        if (node->type == AST_WIRE) {
                                if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
                                        for (auto c : node->children[0]->children) {
@@ -405,14 +406,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                                this_wire_scope[node->str] = node;
                        }
                        if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR ||
-                                       node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION || node->type == AST_CELL) {
+                                       node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION || node->type == AST_CELL ||
+                                       node->type == AST_TYPEDEF) {
                                backup_scope[node->str] = current_scope[node->str];
                                current_scope[node->str] = node;
                        }
                }
                for (size_t i = 0; i < children.size(); i++) {
                        AstNode *node = children[i];
-                       if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY)
+                       if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY || node->type == AST_TYPEDEF)
                                while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM))
                                        did_something = true;
                }
@@ -780,6 +782,44 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
                delete_children();
        }
 
+       // 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]->is_custom_type);
+       }
+
+       // resolve types of wires and parameters
+       if (type == AST_WIRE || type == AST_LOCALPARAM || type == AST_PARAMETER) {
+               if (is_custom_type) {
+                       log_assert(children.size() == 1);
+                       log_assert(children[0]->type == AST_WIRETYPE);
+                       if (!current_scope.count(children[0]->str))
+                               log_file_error(filename, linenum, "Unknown identifier `%s' used as type name", children[0]->str.c_str());
+                       AstNode *resolved_type = current_scope.at(children[0]->str);
+                       if (resolved_type->type != AST_TYPEDEF)
+                               log_file_error(filename, linenum, "`%s' does not name a type", children[0]->str.c_str());
+                       log_assert(resolved_type->children.size() == 1);
+                       AstNode *templ = resolved_type->children[0];
+                       delete_children(); // type reference no longer needed
+
+                       is_reg = templ->is_reg;
+                       is_logic = templ->is_logic;
+                       is_signed = templ->is_signed;
+                       is_string = templ->is_string;
+                       is_custom_type = templ->is_custom_type;
+
+                       range_valid = templ->range_valid;
+                       range_swapped = templ->range_swapped;
+                       range_left = templ->range_left;
+                       range_right = templ->range_right;
+                       for (auto template_child : templ->children)
+                               children.push_back(template_child->clone());
+               }
+               log_assert(!is_custom_type);
+       }
+
        // resolve constant prefixes
        if (type == AST_PREFIX) {
                if (children[0]->type != AST_CONSTANT) {
@@ -1194,7 +1234,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
        if (type == AST_BLOCK && str.empty())
        {
                for (size_t i = 0; i < children.size(); i++)
-                       if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM)
+                       if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF)
                                log_file_error(children[i]->filename, children[i]->linenum, "Local declaration in unnamed block is an unsupported SystemVerilog feature!\n");
        }
 
@@ -1206,7 +1246,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 
                std::vector<AstNode*> new_children;
                for (size_t i = 0; i < children.size(); i++)
-                       if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) {
+                       if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) {
                                children[i]->simplify(false, false, false, stage, -1, false, false);
                                current_ast_mod->children.push_back(children[i]);
                                current_scope[children[i]->str] = children[i];
@@ -2945,6 +2985,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
                        child->expand_genblock(index_var, prefix, name_map);
        }
 
+
        if (backup_name_map.size() > 0)
                name_map.swap(backup_name_map);
 }
index 4afd72b734b2aadebaf75d86683e8928f29b87e4..eb091bea6cb2b7566d51b30c4de133bec97e6562 100644 (file)
@@ -112,6 +112,8 @@ struct specify_rise_fall {
 
 %define api.prefix {frontend_verilog_yy}
 
+%glr-parser
+
 /* The union is defined in the header, so we need to provide all the
  * includes it requires
  */
@@ -180,7 +182,7 @@ struct specify_rise_fall {
 %right UNARY_OPS
 
 %define parse.error verbose
-%define parse.lac full
+// %define parse.lac full
 
 %nonassoc FAKE_THEN
 %nonassoc TOK_ELSE
@@ -206,6 +208,7 @@ design:
        task_func_decl design |
        param_decl design |
        localparam_decl design |
+       typedef_decl design |
        package design |
        interface design |
        /* empty */;
@@ -426,6 +429,7 @@ package_body:
        package_body package_body_stmt |;
 
 package_body_stmt:
+       typedef_decl |
        localparam_decl;
 
 interface:
@@ -452,7 +456,7 @@ interface_body:
        interface_body interface_body_stmt |;
 
 interface_body_stmt:
-       param_decl | localparam_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
+       param_decl | localparam_decl | typedef_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
        modport_stmt;
 
 non_opt_delay:
@@ -529,6 +533,11 @@ wire_type_token:
        } |
        TOK_CONST {
                current_wire_const = true;
+       } |
+       hierarchical_id {
+               astbuf3->is_custom_type = true;
+               astbuf3->children.push_back(new AstNode(AST_WIRETYPE));
+               astbuf3->children.back()->str = *$1;
        };
 
 non_opt_range:
@@ -591,7 +600,7 @@ module_body:
        /* empty */;
 
 module_body_stmt:
-       task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
+       task_func_decl | specify_block |param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
        always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
 
 checker_decl:
@@ -1377,6 +1386,27 @@ assign_expr:
                ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3));
        };
 
+typedef_decl:
+       TOK_TYPEDEF wire_type range TOK_ID ';' {
+               astbuf1 = $2;
+               astbuf2 = $3;
+               if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
+                       if (astbuf2) {
+                               frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions.");
+                       } else {
+                               astbuf2 = new AstNode(AST_RANGE);
+                               astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
+                               astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_right, true));
+                       }
+               }
+               if (astbuf2 && astbuf2->children.size() != 2)
+                       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);
+               ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1));
+               ast_stack.back()->children.back()->str = *$4;
+       };
+
 cell_stmt:
        attr TOK_ID {
                astbuf1 = new AstNode(AST_CELL);
@@ -1823,7 +1853,7 @@ simple_behavioral_stmt:
 
 // this production creates the obligatory if-else shift/reduce conflict
 behavioral_stmt:
-       defattr | assert | wire_decl | param_decl | localparam_decl |
+       defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl |
        non_opt_delay behavioral_stmt |
        simple_behavioral_stmt ';' | ';' |
        hierarchical_id attr {
diff --git a/tests/svtypes/typedef1.sv b/tests/svtypes/typedef1.sv
new file mode 100644 (file)
index 0000000..9e5d023
--- /dev/null
@@ -0,0 +1,22 @@
+`define STRINGIFY(x) `"x`"
+`define STATIC_ASSERT(x) if(!(x)) $error({"assert failed: ", `STRINGIFY(x)})
+
+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;
+
+       (* 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);
+       always @* assert(int4 == 4'b1111);
+       always @* assert(int8 == 8'b11111111);
+       always @* assert(ch   == 8'b11111111);
+
+endmodule
\ No newline at end of file