From: David Shah Date: Thu, 19 Sep 2019 19:43:13 +0000 (+0100) Subject: sv: Switch parser to glr, prep for typedef X-Git-Tag: working-ls180~995^2^2~12 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f6b5e47e40b4a2bda6e5d928480ea218a6a911c2;p=yosys.git sv: Switch parser to glr, prep for typedef Signed-off-by: David Shah --- diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 21279cbfa..937dad9be 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -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; diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 93fee913e..fcc661b4c 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -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 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; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 407a34472..94f5c0a04 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -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' diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index b1ee22f42..b94662bcd 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -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 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 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); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 4afd72b73..eb091bea6 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -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: [:], [+:], or [-:]"); + 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 index 000000000..9e5d02364 --- /dev/null +++ b/tests/svtypes/typedef1.sv @@ -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