aboutsummaryrefslogtreecommitdiffstats
path: root/frontends/verilog/verilog_parser.y
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/verilog/verilog_parser.y')
-rw-r--r--frontends/verilog/verilog_parser.y218
1 files changed, 186 insertions, 32 deletions
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 2c7304cc4..bb2a10e9a 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -108,6 +108,20 @@ struct specify_rise_fall {
specify_triple fall;
};
+static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true)
+{
+ auto range = new AstNode(AST_RANGE);
+ range->children.push_back(AstNode::mkconst_int(msb, true));
+ range->children.push_back(AstNode::mkconst_int(lsb, true));
+ range->is_signed = isSigned;
+ return range;
+}
+
+static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = true)
+{
+ auto range = makeRange(msb, lsb, isSigned);
+ parent->children.push_back(range);
+}
%}
%define api.prefix {frontend_verilog_yy}
@@ -146,7 +160,7 @@ struct specify_rise_fall {
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
-%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND
+%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND TOK_IGNORED_SPECIFY_AND
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
@@ -157,13 +171,14 @@ struct specify_rise_fall {
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id
+%type <ast> opt_enum_init
%type <boolean> opt_signed opt_property unique_case_attr always_comb_or_latch always_or_always_ff
%type <al> attr case_attr
%type <specify_target_ptr> specify_target
-%type <specify_triple_ptr> specify_triple
+%type <specify_triple_ptr> specify_triple specify_opt_triple
%type <specify_rise_fall_ptr> specify_rise_fall
-%type <ast> specify_if specify_condition specify_opt_arg
+%type <ast> specify_if specify_condition
%type <ch> specify_edge
// operator precedence from low to high
@@ -428,7 +443,9 @@ package:
};
package_body:
- package_body package_body_stmt |;
+ package_body package_body_stmt
+ | // optional
+ ;
package_body_stmt:
typedef_decl |
@@ -476,7 +493,7 @@ wire_type:
astbuf3 = new AstNode(AST_WIRE);
current_wire_rand = false;
current_wire_const = false;
- } wire_type_token_list delay {
+ } wire_type_token_list {
$$ = astbuf3;
};
@@ -604,6 +621,7 @@ module_body:
module_body_stmt:
task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
+ enum_decl |
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl:
@@ -855,7 +873,7 @@ specify_item:
delete target;
delete timing;
} |
- TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' {
+ TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' specify_triple specify_opt_triple ')' ';' {
if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&
*$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")
frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
@@ -868,8 +886,8 @@ specify_item:
AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
- AstNode *limit = $11;
- AstNode *limit2 = $12;
+ specify_triple *limit = $11;
+ specify_triple *limit2 = $12;
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
@@ -880,11 +898,23 @@ specify_item:
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1)));
cell->children.back()->str = "\\TYPE";
- cell->children.push_back(new AstNode(AST_PARASET, limit));
- cell->children.back()->str = "\\T_LIMIT";
+ cell->children.push_back(new AstNode(AST_PARASET, limit->t_min));
+ cell->children.back()->str = "\\T_LIMIT_MIN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit->t_avg));
+ cell->children.back()->str = "\\T_LIMIT_TYP";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit->t_max));
+ cell->children.back()->str = "\\T_LIMIT_MAX";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_min : AstNode::mkconst_int(0, true)));
+ cell->children.back()->str = "\\T_LIMIT2_MIN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_avg : AstNode::mkconst_int(0, true)));
+ cell->children.back()->str = "\\T_LIMIT2_TYP";
- cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true)));
- cell->children.back()->str = "\\T_LIMIT2";
+ cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_max : AstNode::mkconst_int(0, true)));
+ cell->children.back()->str = "\\T_LIMIT2_MAX";
cell->children.push_back(new AstNode(AST_PARASET, src_pen));
cell->children.back()->str = "\\SRC_PEN";
@@ -913,8 +943,8 @@ specify_item:
delete $1;
};
-specify_opt_arg:
- ',' expr {
+specify_opt_triple:
+ ',' specify_triple {
$$ = $2;
} |
/* empty */ {
@@ -983,7 +1013,46 @@ specify_rise_fall:
$$->fall = *$4;
delete $2;
delete $4;
- };
+ } |
+ '(' specify_triple ',' specify_triple ',' specify_triple ')' {
+ $$ = new specify_rise_fall;
+ $$->rise = *$2;
+ $$->fall = *$4;
+ delete $2;
+ delete $4;
+ delete $6;
+ log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n");
+ } |
+ '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' {
+ $$ = new specify_rise_fall;
+ $$->rise = *$2;
+ $$->fall = *$4;
+ delete $2;
+ delete $4;
+ delete $6;
+ delete $8;
+ delete $10;
+ delete $12;
+ log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n");
+ } |
+ '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' {
+ $$ = new specify_rise_fall;
+ $$->rise = *$2;
+ $$->fall = *$4;
+ delete $2;
+ delete $4;
+ delete $6;
+ delete $8;
+ delete $10;
+ delete $12;
+ delete $14;
+ delete $16;
+ delete $18;
+ delete $20;
+ delete $22;
+ delete $24;
+ log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n");
+ }
specify_triple:
expr {
@@ -1031,7 +1100,7 @@ list_of_specparam_assignments:
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
specparam_assignment:
- ignspec_id '=' constant_mintypmax_expression ;
+ ignspec_id '=' ignspec_expr ;
ignspec_opt_cond:
TOK_IF '(' ignspec_expr ')' | /* empty */;
@@ -1048,13 +1117,15 @@ simple_path_declaration :
;
path_delay_value :
- '(' path_delay_expression list_of_path_delay_extra_expressions ')'
- | path_delay_expression
- | path_delay_expression list_of_path_delay_extra_expressions
+ '(' ignspec_expr list_of_path_delay_extra_expressions ')'
+ | ignspec_expr
+ | ignspec_expr list_of_path_delay_extra_expressions
;
list_of_path_delay_extra_expressions :
- ',' path_delay_expression | ',' path_delay_expression list_of_path_delay_extra_expressions;
+ ',' ignspec_expr
+ | ',' ignspec_expr list_of_path_delay_extra_expressions
+ ;
specify_edge_identifier :
TOK_POSEDGE | TOK_NEGEDGE ;
@@ -1105,16 +1176,9 @@ system_timing_arg :
system_timing_args :
system_timing_arg |
+ system_timing_args TOK_IGNORED_SPECIFY_AND system_timing_arg |
system_timing_args ',' system_timing_arg ;
-path_delay_expression :
- ignspec_constant_expression;
-
-constant_mintypmax_expression :
- ignspec_constant_expression
- | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression
- ;
-
// for the time being this is OK, but we may write our own expr here.
// as I'm not sure it is legal to use a full expr here (probably not)
// On the other hand, other rules requiring constant expressions also use 'expr'
@@ -1123,10 +1187,16 @@ ignspec_constant_expression:
expr { delete $1; };
ignspec_expr:
- expr { delete $1; };
+ expr { delete $1; } |
+ expr ':' expr ':' expr {
+ delete $1;
+ delete $3;
+ delete $5;
+ };
ignspec_id:
- TOK_ID { delete $1; };
+ TOK_ID { delete $1; }
+ range_or_multirange { delete $3; };
/**********************************************************************/
@@ -1224,6 +1294,85 @@ single_defparam_decl:
ast_stack.back()->children.push_back(node);
};
+enum_type: TOK_ENUM {
+ static int enum_count;
+ // create parent node for the enum
+ astbuf2 = new AstNode(AST_ENUM);
+ ast_stack.back()->children.push_back(astbuf2);
+ astbuf2->str = std::string("$enum");
+ astbuf2->str += std::to_string(enum_count++);
+ // create the template for the names
+ astbuf1 = new AstNode(AST_ENUM_ITEM);
+ astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ } param_signed enum_base_type '{' enum_name_list '}' { // create template for the enum vars
+ auto tnode = astbuf1->clone();
+ delete astbuf1;
+ astbuf1 = tnode;
+ tnode->type = AST_WIRE;
+ tnode->attributes["\\enum_type"] = AstNode::mkconst_str(astbuf2->str);
+ // drop constant but keep any range
+ delete tnode->children[0];
+ tnode->children.erase(tnode->children.begin()); }
+ ;
+
+enum_base_type: int_vec param_range
+ | int_atom
+ | /* nothing */ {astbuf1->is_reg = true; addRange(astbuf1); }
+ ;
+
+int_atom: TOK_INTEGER {astbuf1->is_reg=true; addRange(astbuf1); } // probably should do byte, range [7:0] here
+ ;
+
+int_vec: TOK_REG {astbuf1->is_reg = true;}
+ | TOK_LOGIC {astbuf1->is_logic = true;}
+ ;
+
+enum_name_list:
+ enum_name_decl
+ | enum_name_list ',' enum_name_decl
+ ;
+
+enum_name_decl:
+ TOK_ID opt_enum_init {
+ // put in fn
+ log_assert(astbuf1);
+ log_assert(astbuf2);
+ auto node = astbuf1->clone();
+ node->str = *$1;
+ delete $1;
+ delete node->children[0];
+ node->children[0] = $2 ?: new AstNode(AST_NONE);
+ astbuf2->children.push_back(node);
+ }
+ ;
+
+opt_enum_init:
+ '=' basic_expr { $$ = $2; } // TODO: restrict this
+ | /* optional */ { $$ = NULL; }
+ ;
+
+enum_var_list:
+ enum_var
+ | enum_var_list ',' enum_var
+ ;
+
+enum_var: TOK_ID {
+ log_assert(astbuf1);
+ log_assert(astbuf2);
+ auto node = astbuf1->clone();
+ ast_stack.back()->children.push_back(node);
+ node->str = *$1;
+ delete $1;
+ node->is_enum = true;
+ }
+ ;
+
+enum_decl: enum_type enum_var_list ';' {
+ //enum_type creates astbuf1 for use by typedef only
+ delete astbuf1;
+ }
+ ;
+
wire_decl:
attr wire_type range {
albuf = $1;
@@ -1240,7 +1389,7 @@ wire_decl:
}
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>]");
- } wire_name_list {
+ } delay wire_name_list {
delete astbuf1;
if (astbuf2 != NULL)
delete astbuf2;
@@ -1434,7 +1583,12 @@ typedef_decl:
ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1));
ast_stack.back()->children.back()->str = *$4;
- };
+ } |
+ TOK_TYPEDEF enum_type TOK_ID ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1));
+ ast_stack.back()->children.back()->str = *$3;
+ }
+ ;
cell_stmt:
attr TOK_ID {