From 5880a3ad8f7a72e7700f94e885d103ec4b8d9736 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 18 Feb 2012 10:02:54 -0800 Subject: [PATCH 01/23] Parse program blocks / Fix module end-name syntax. --- parse.y | 112 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 34 deletions(-) diff --git a/parse.y b/parse.y index 149f19af7..49499db6a 100644 --- a/parse.y +++ b/parse.y @@ -460,7 +460,7 @@ static void current_task_set_statement(vector*s) %type udp_initial udp_init_opt %type udp_initial_expr_opt -%type register_variable net_variable real_variable +%type register_variable net_variable real_variable endname_opt %type register_variable_list net_variable_list %type real_variable_list list_of_identifiers %type list_of_port_identifiers @@ -535,6 +535,7 @@ static void current_task_set_statement(vector*s) %type specify_edge_path specify_edge_path_decl %type atom2_type +%type module_start module_end %token K_TAND %right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ @@ -2680,40 +2681,83 @@ local_timeunit_prec_decl section, with optional ports, then an optional list of module items, and finally an end marker. */ -module : attribute_list_opt module_start IDENTIFIER - { pform_startmodule($3, @2.text, @2.first_line, $1); } - module_parameter_port_list_opt - module_port_list_opt - module_attribute_foreign ';' - { pform_module_set_ports($6); } - local_timeunit_prec_decl_opt - { have_timeunit_decl = true; // Every thing past here is - have_timeprec_decl = true; // a check! - pform_check_timeunit_prec(); - } - module_item_list_opt - K_endmodule - { Module::UCDriveType ucd; - switch (uc_drive) { - case UCD_NONE: - default: - ucd = Module::UCD_NONE; - break; - case UCD_PULL0: - ucd = Module::UCD_PULL0; - break; - case UCD_PULL1: - ucd = Module::UCD_PULL1; - break; - } - pform_endmodule($3, in_celldefine, ucd); - delete[]$3; - have_timeunit_decl = false; // We will allow decls again. - have_timeprec_decl = false; - } - ; +module + : attribute_list_opt module_start IDENTIFIER + { pform_startmodule($3, @2.text, @2.first_line, $1); } + module_parameter_port_list_opt + module_port_list_opt + module_attribute_foreign ';' + { pform_module_set_ports($6); } + local_timeunit_prec_decl_opt + { have_timeunit_decl = true; // Every thing past here is + have_timeprec_decl = true; // a check! + pform_check_timeunit_prec(); + } + module_item_list_opt + module_end endname_opt + { Module::UCDriveType ucd; + // The lexor detected `unconnected_drive directives and + // marked what it found in the uc_drive variable. Use that + // to generate a UCD flag for the module. + switch (uc_drive) { + case UCD_NONE: + default: + ucd = Module::UCD_NONE; + break; + case UCD_PULL0: + ucd = Module::UCD_PULL0; + break; + case UCD_PULL1: + ucd = Module::UCD_PULL1; + break; + } + // Check that program/endprogram and module/endmodule + // keywords match. + if ($2 != $13) { + switch ($2) { + case K_module: + yyerror(@13, "error: module not closed by endmodule."); + break; + case K_program: + yyerror(@13, "error: program not closed by endprogram."); + break; + default: + break; + } + } + if ($14 && (strcmp($3,$14) != 0)) { + yyerror(@14, "error: End name doesn't match module/program name"); + } + if ($2 == K_program) { + yyerror(@2, "sorry: Program blocks not supported yet."); + } + pform_endmodule($3, in_celldefine, ucd); + delete[]$3; + if ($14) delete[]$14; + have_timeunit_decl = false; // We will allow decls again. + have_timeprec_decl = false; + } + ; -module_start : K_module | K_macromodule ; + /* Modules start with module/macromodule or program keyword, and end + with the endmodule or endprogram keyword. The syntax for modules + and programs is almost identical, so let semantics sort out the + differences. */ +module_start + : K_module { $$ = K_module; } + | K_macromodule { $$ = K_module; } + | K_program { $$ = K_program; } + ; + +module_end + : K_endmodule { $$ = K_module; } + | K_endprogram { $$ = K_program; } + ; + +endname_opt + : ':' IDENTIFIER { $$ = $2; } + | { $$ = 0; } + ; module_attribute_foreign : K_PSTAR IDENTIFIER K_integer IDENTIFIER '=' STRING ';' K_STARP { $$ = 0; } From 8456252c0cbf00630f4f4a6521631a1f4824ff93 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 19 Feb 2012 10:29:50 -0800 Subject: [PATCH 02/23] More class syntax Part of ongoing parser work to support SystemVerilog classes. --- parse.y | 662 ++++++++++++++++++++------------------------------ parse_misc.cc | 12 +- parse_misc.h | 2 +- pform.cc | 21 ++ pform.h | 7 + pform_types.h | 7 + 6 files changed, 306 insertions(+), 405 deletions(-) diff --git a/parse.y b/parse.y index 49499db6a..01a496634 100644 --- a/parse.y +++ b/parse.y @@ -49,8 +49,9 @@ static struct { ivl_variable_type_t var_type; bool sign_flag; list* range; + data_type_t* data_type; } port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, - IVL_VT_NO_TYPE, false, 0}; + IVL_VT_NO_TYPE, false, 0, 0}; /* The task and function rules need to briefly hold the pointer to the task/function that is currently in progress. */ @@ -106,7 +107,7 @@ static list >* make_port_list(list* make_range_from_width(uint64_t wid) +list* make_range_from_width(uint64_t wid) { list*range = new list; @@ -447,8 +448,8 @@ static void current_task_set_statement(vector*s) %type from_exclude %type number pos_neg_number %type unsigned_signed_opt signed_unsigned_opt -%type K_packed_opt K_reg_opt -%type udp_reg_opt edge_operator automatic_opt +%type K_automatic_opt K_packed_opt K_reg_opt K_virtual_opt +%type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym %type udp_input_list udp_sequ_entry udp_comb_entry @@ -472,7 +473,7 @@ static void current_task_set_statement(vector*s) %type list_of_ports module_port_list_opt list_of_port_declarations module_attribute_foreign %type parameter_value_range parameter_value_ranges %type parameter_value_ranges_opt -%type value_range_expression +%type task_port_decl_expr_opt value_range_expression %type enum_name_list enum_name %type enum_data_type @@ -514,7 +515,7 @@ static void current_task_set_statement(vector*s) %type dimensions_opt dimensions %type net_type var_type net_type_opt %type gatetype switchtype -%type port_type +%type port_direction port_direction_opt %type primitive_type primitive_type_opt bit_logic %type parameter_value_opt @@ -573,6 +574,73 @@ source_file | source_file description ; +class_declaration /* IEEE1800-2005: A.1.2 */ + : K_virtual_opt K_class IDENTIFIER ';' + class_items_opt K_endclass endname_opt + { // Process a class + if ($7 && strcmp($3,$7)!=0) { + yyerror(@7, "error: Class end name doesn't match class name."); + delete[]$7; + } + yyerror(@2, "sorry: Class declarations not supported yet."); + } + ; + +class_items_opt + : class_items + | + ; + +class_items + : class_items class_item + | class_item + ; + +class_item /* IEEE1800-2005: A.1.8 */ + + /* class_constructor_declaration */ + : K_function K_new '(' task_port_decl_list_opt ')' ';' + K_endfunction endnew_opt + + /* Class properties... */ + + | data_type list_of_variable_decl_assignments ';' + + /* Here are some error matching rules to help recover from various + syntax errors within a class declaration. */ + + | K_function K_new error K_endfunction endnew_opt + { yyerror(@1, "error: I give up on this class constructor declaration."); + yyerrok; + } + + ; + +data_type /* IEEE1800-2005: A.2.2.1 */ + : struct_data_type + { $$ = $1; } + | enum_data_type + { $$ = $1; } + | atom2_type signed_unsigned_opt + { atom2_type_t*tmp = new atom2_type_t($1, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | TYPE_IDENTIFIER + { $$ = $1; } + | K_string + { yyerror(@1, "sorry: String data type not supported."); + $$ = 0; + } + ; + +endnew_opt : ':' K_new | ; + +implicit_class_handle /* IEEE1800-2005: A.8.4 */ + : K_this + | K_super + ; + number : BASED_NUMBER { $$ = $1; based_size = 0;} | DEC_NUMBER @@ -703,11 +771,6 @@ block_item_decl if ($1) delete $1; } - | attribute_list_opt atom2_type signed_unsigned_opt register_variable_list ';' - { pform_set_integer_2atom($2, $3, $4); - if ($1) delete $1; - } - /* variable declarations. Note that data_type can be 0 if we are recovering from an error. */ @@ -782,21 +845,27 @@ block_item_decls_opt | ; -data_type - : struct_data_type - { $$ = $1; } - | enum_data_type - { $$ = $1; } - | TYPE_IDENTIFIER - { $$ = $1; } - ; - + /* Type declarations are parsed here. The rule actions call pform + functions that add the declaration to the current lexical scope. */ type_declaration : K_typedef data_type IDENTIFIER ';' { perm_string name = lex_strings.make($3); pform_set_typedef(name, $2); delete[]$3; } + + /* These are forward declarations... */ + + | K_typedef K_class IDENTIFIER ';' + { yyerror(@1, "sorry: Class forward declarations not supported yet.") } + | K_typedef K_enum IDENTIFIER ';' + { yyerror(@1, "sorry: Enum forward declarations not supported yet.") } + | K_typedef K_struct IDENTIFIER ';' + { yyerror(@1, "sorry: Struct forward declarations not supported yet.") } + | K_typedef K_union IDENTIFIER ';' + { yyerror(@1, "sorry: Union forward declarations not supported yet.") } + | K_typedef IDENTIFIER ';' + { yyerror(@1, "sorry: Class forward declarations not supported yet.") } ; /* The structure for an enumeration data type is the keyword "enum", @@ -2620,19 +2689,28 @@ atom2_type assignments. It is more limited than the general expr_primary rule to reflect the rules for assignment l-values. */ lpvalue - : hierarchy_identifier - { PEIdent*tmp = new PEIdent(*$1); - FILE_NAME(tmp, @1); - $$ = tmp; - delete $1; - } - | '{' expression_list_proper '}' - { PEConcat*tmp = new PEConcat(*$2); - FILE_NAME(tmp, @1); - delete $2; - $$ = tmp; - } - ; + : hierarchy_identifier + { PEIdent*tmp = new PEIdent(*$1); + FILE_NAME(tmp, @1); + $$ = tmp; + delete $1; + } + + | implicit_class_handle '.' hierarchy_identifier + { yyerror(@1, "sorry: implicit class handles (this/super) not supported."); + PEIdent*tmp = new PEIdent(*$3); + FILE_NAME(tmp, @1); + $$ = tmp; + delete $3; + } + + | '{' expression_list_proper '}' + { PEConcat*tmp = new PEConcat(*$2); + FILE_NAME(tmp, @1); + delete $2; + $$ = tmp; + } + ; /* Continuous assignments have a list of individual assignments. */ @@ -2694,7 +2772,7 @@ module pform_check_timeunit_prec(); } module_item_list_opt - module_end endname_opt + module_end { Module::UCDriveType ucd; // The lexor detected `unconnected_drive directives and // marked what it found in the uc_drive variable. Use that @@ -2725,18 +2803,25 @@ module break; } } - if ($14 && (strcmp($3,$14) != 0)) { - yyerror(@14, "error: End name doesn't match module/program name"); - } if ($2 == K_program) { yyerror(@2, "sorry: Program blocks not supported yet."); } pform_endmodule($3, in_celldefine, ucd); delete[]$3; - if ($14) delete[]$14; have_timeunit_decl = false; // We will allow decls again. have_timeprec_decl = false; } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($15 && (strcmp($3,$15) != 0)) { + yyerror(@15, "error: End name doesn't match module/program name"); + } + if ($15) delete[]$15; + } ; /* Modules start with module/macromodule or program keyword, and end @@ -2890,7 +2975,7 @@ module_item delete $4; } - | port_type unsigned_signed_opt range_opt delay3_opt list_of_identifiers ';' + | port_direction unsigned_signed_opt range_opt delay3_opt list_of_identifiers ';' { pform_set_port_type(@1, $5, $3, $2, $1); } @@ -2898,7 +2983,7 @@ module_item input wire signed [h:l] ; This creates the wire and sets the port type all at once. */ - | port_type net_type unsigned_signed_opt range_opt list_of_identifiers ';' + | port_direction net_type unsigned_signed_opt range_opt list_of_identifiers ';' { pform_makewire(@1, $4, $3, $5, $2, $1, IVL_VT_NO_TYPE, 0, SR_BOTH); } @@ -2919,7 +3004,7 @@ module_item delete $5; } - | port_type K_wreal list_of_identifiers ';' + | port_direction K_wreal list_of_identifiers ';' { pform_makewire(@1, 0, true, $3, NetNet::WIRE, $1, IVL_VT_REAL, 0, SR_BOTH); } @@ -2940,7 +3025,7 @@ module_item yyerror(@2, "error: reg variables cannot be inouts."); } - | port_type unsigned_signed_opt range_opt delay3_opt error ';' + | port_direction unsigned_signed_opt range_opt delay3_opt error ';' { yyerror(@1, "error: Invalid variable list" " in port declaration."); if ($3) delete $3; @@ -3072,6 +3157,8 @@ module_item | attribute_list_opt K_analog analog_statement { pform_make_analog_behavior(@2, IVL_PR_ALWAYS, $3); } + | class_declaration + /* The task declaration rule matches the task declaration header, then pushes the function scope. This causes the definitions in the task_body to take on the scope of the task @@ -3080,7 +3167,7 @@ module_item statements in the task body. But we continue to accept it as an extension. */ - | K_task automatic_opt IDENTIFIER ';' + | K_task K_automatic_opt IDENTIFIER ';' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -3098,7 +3185,7 @@ module_item delete $7; } - | K_task automatic_opt IDENTIFIER '(' + | K_task K_automatic_opt IDENTIFIER '(' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -3117,7 +3204,7 @@ module_item delete $10; } - | K_task automatic_opt IDENTIFIER '(' ')' ';' + | K_task K_automatic_opt IDENTIFIER '(' ')' ';' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -3137,7 +3224,7 @@ module_item delete $9; } - | K_task automatic_opt IDENTIFIER error K_endtask + | K_task K_automatic_opt IDENTIFIER error K_endtask { assert(current_task == 0); delete[]$3; @@ -3148,7 +3235,7 @@ module_item definitions in the func_body to take on the scope of the function instead of the module. */ - | K_function automatic_opt function_range_or_type_opt IDENTIFIER ';' + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER ';' { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } @@ -3175,7 +3262,7 @@ module_item delete[]$4; } - | K_function automatic_opt function_range_or_type_opt IDENTIFIER + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } @@ -3206,7 +3293,7 @@ module_item yyerror(@4, "error: Empty parenthesis syntax requires SystemVerilog."); } } - | K_function automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction { /* */ if (current_function) { pform_pop_scope(); @@ -3347,11 +3434,6 @@ module_item { pform_set_timeprecision($2, true, true); } ; -automatic_opt - : K_automatic { $$ = true; } - | { $$ = false;} - ; - generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); } generate_case_items @@ -3962,11 +4044,16 @@ port_reference_list } ; -port_type - : K_input { $$ = NetNet::PINPUT; } - | K_output { $$ = NetNet::POUTPUT; } - | K_inout { $$ = NetNet::PINOUT; } - ; +port_direction /* IEEE1800-2005 A.1.3 */ + : K_input { $$ = NetNet::PINPUT; } + | K_output { $$ = NetNet::POUTPUT; } + | K_inout { $$ = NetNet::PINOUT; } + ; + +port_direction_opt + : port_direction { $$ = $1; } + | { $$ = NetNet::PINPUT; } + ; range : '[' expression ':' expression ']' @@ -5024,24 +5111,8 @@ task_item ; task_port_item - : K_input K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(NetNet::PINPUT, - $2 ? IVL_VT_LOGIC : - IVL_VT_NO_TYPE, - $3, $4, $5, - @1.text, @1.first_line); - $$ = tmp; - } - | K_output K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - $2 ? IVL_VT_LOGIC : - IVL_VT_NO_TYPE, - $3, $4, $5, - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(NetNet::PINOUT, + : port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + { svector*tmp = pform_make_task_ports($1, $2 ? IVL_VT_LOGIC : IVL_VT_NO_TYPE, $3, $4, $5, @@ -5052,26 +5123,9 @@ task_port_item /* When the port is an integer, infer a signed vector of the integer shape. Generate a range ([31:0]) to make it work. */ - | K_input K_integer list_of_identifiers ';' + | port_direction K_integer list_of_identifiers ';' { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, true, - range_stub, $3, - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_output K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, true, - range_stub, $3, - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_inout K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, true, + svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, true, range_stub, $3, @1.text, @1.first_line, true); $$ = tmp; @@ -5079,26 +5133,9 @@ task_port_item /* Ports can be time with a width of [63:0] (unsigned). */ - | K_input K_time list_of_identifiers ';' + | port_direction K_time list_of_identifiers ';' { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, false, - range_stub, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_output K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, false, - range_stub, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, false, + svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, false, range_stub, $3, @1.text, @1.first_line); $$ = tmp; @@ -5106,31 +5143,13 @@ task_port_item /* Ports can be real or realtime. */ - | K_input real_or_realtime list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_REAL, false, - 0, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_output real_or_realtime list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_REAL, true, - 0, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout real_or_realtime list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_REAL, true, - 0, $3, - @1.text, @1.first_line); - $$ = tmp; - } - ; + | port_direction real_or_realtime list_of_identifiers ';' + { svector*tmp = pform_make_task_ports($1, IVL_VT_REAL, false, + 0, $3, @1.text, @1.first_line); + $$ = tmp; + } + + ; task_item_list : task_item_list task_item @@ -5152,173 +5171,56 @@ task_item_list_opt task_port_decl - : K_input K_reg_opt unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp - = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } + : port_direction K_reg_opt unsigned_signed_opt range_opt IDENTIFIER + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = $3; + delete port_declaration_context.range; + port_declaration_context.range = copy_range($4); + svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, $3, + $4, list_from_identifier($5), + @1.text, @1.first_line); + $$ = tmp; + } - | K_output K_reg_opt unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp - = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout K_reg_opt unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp - = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_input bit_logic unsigned_signed_opt range_opt IDENTIFIER - { - port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = - pform_make_task_ports(NetNet::PINPUT, $2, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_output bit_logic unsigned_signed_opt range_opt IDENTIFIER - { - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = - pform_make_task_ports(NetNet::POUTPUT, $2, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_inout bit_logic unsigned_signed_opt range_opt IDENTIFIER - { - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = - pform_make_task_ports(NetNet::PINOUT, $2, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } + | port_direction_opt bit_logic unsigned_signed_opt range_opt IDENTIFIER + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = $2; + port_declaration_context.sign_flag = $3; + delete port_declaration_context.range; + port_declaration_context.range = copy_range($4); + svector*tmp = pform_make_task_ports($1, $2, $3, + $4, list_from_identifier($5), + @1.text, @1.first_line); + $$ = tmp; + } /* Ports can be integer with a width of [31:0]. */ - | K_input K_integer IDENTIFIER + | port_direction_opt K_integer IDENTIFIER { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = NetNet::PINPUT; + port_declaration_context.port_type = $1; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = true; delete port_declaration_context.range; port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, true, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_output K_integer IDENTIFIER - { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, true, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_inout K_integer IDENTIFIER - { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, true, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line, true); + svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, true, + range_stub, + list_from_identifier($3), + @1.text, @1.first_line, true); $$ = tmp; } /* Ports can be time with a width of [63:0] (unsigned). */ - | K_input K_time IDENTIFIER + | port_direction_opt K_time IDENTIFIER { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = NetNet::PINPUT; + port_declaration_context.port_type = $1; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = false; delete port_declaration_context.range; port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_output K_time IDENTIFIER - { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout K_time IDENTIFIER - { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, false, + svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, false, range_stub, list_from_identifier($3), @1.text, @1.first_line); @@ -5327,90 +5229,40 @@ task_port_decl /* Ports can be real or realtime. */ - | K_input real_or_realtime IDENTIFIER - { port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp - = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_REAL, false, - 0, list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_output real_or_realtime IDENTIFIER - { port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp - = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_REAL, false, - 0, list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout real_or_realtime IDENTIFIER - { port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp - = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_REAL, false, - 0, list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } + | port_direction_opt real_or_realtime IDENTIFIER + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_REAL; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = 0; + svector*tmp = pform_make_task_ports($1, IVL_VT_REAL, false, + 0, list_from_identifier($3), + @1.text, @1.first_line); + $$ = tmp; + } - /* Ports can be 2-value atom types. */ - - | K_input atom2_type signed_unsigned_opt IDENTIFIER - { list*range_stub = make_range_from_width($2); - port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $3; + | port_direction_opt data_type IDENTIFIER task_port_decl_expr_opt + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_NO_TYPE; + port_declaration_context.sign_flag = false; delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_BOOL, $3, - range_stub, list_from_identifier($4), - @1.text, @1.first_line); + port_declaration_context.range = 0; + port_declaration_context.data_type = $2; + svector*tmp = pform_make_task_ports(@1, $1, $2, + list_from_identifier($3)); $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port default expressions not supported yet."); + delete $4; + } } - | K_output atom2_type signed_unsigned_opt IDENTIFIER - { list*range_stub = make_range_from_width($2); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_BOOL, $3, - range_stub, list_from_identifier($4), - @1.text, @1.first_line); - $$ = tmp; - } + ; - | K_inout atom2_type signed_unsigned_opt IDENTIFIER - { list*range_stub = make_range_from_width($2); - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_BOOL, $3, - range_stub, list_from_identifier($4), - @1.text, @1.first_line); - $$ = tmp; - } -; +task_port_decl_expr_opt + : '=' expression { $$ = $2; } + | { $$ = 0; } + ; task_port_decl_list_opt : task_port_decl_list { $$ = $1; } @@ -5418,40 +5270,40 @@ task_port_decl_list_opt ; task_port_decl_list - : task_port_decl_list ',' task_port_decl - { svector*tmp = new svector(*$1, *$3); - delete $1; - delete $3; - $$ = tmp; - } - | task_port_decl - { $$ = $1; } - | task_port_decl_list ',' IDENTIFIER - { svector*new_decl - = pform_make_task_ports( - port_declaration_context.port_type, - port_declaration_context.var_type, - port_declaration_context.sign_flag, - copy_range(port_declaration_context.range), - list_from_identifier($3), - @3.text, @3.first_line); - svector*tmp = new svector(*$1, *new_decl); - delete $1; - delete new_decl; - $$ = tmp; - } - | task_port_decl_list ',' - { - yyerror(@2, "error: NULL port declarations are not " - "allowed."); - } - | task_port_decl_list ';' - { - yyerror(@2, "error: ';' is an invalid port declaration " - "separator."); - } - ; - ; + : task_port_decl_list ',' task_port_decl + { svector*tmp = new svector(*$1, *$3); + delete $1; + delete $3; + $$ = tmp; + } + | task_port_decl + { $$ = $1; } + | task_port_decl_list ',' IDENTIFIER + { // The declaration is already parsed, apply it to IDENTIFIER + svector*new_decl; + if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { + assert(port_declaration_context.data_type); + new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, + port_declaration_context.data_type, + list_from_identifier($3)); + } else { + new_decl = pform_make_task_ports(port_declaration_context.port_type, + port_declaration_context.var_type, + port_declaration_context.sign_flag, + copy_range(port_declaration_context.range), + list_from_identifier($3), + @3.text, @3.first_line); + } + svector*tmp = new svector(*$1, *new_decl); + delete $1; + delete new_decl; + $$ = tmp; + } + | task_port_decl_list ',' + { yyerror(@2, "error: NULL port declarations are not allowed."); } + | task_port_decl_list ';' + { yyerror(@2, "error: ';' is an invalid port declaration separator."); } + ; udp_body : K_table { lex_start_table(); } @@ -5703,5 +5555,11 @@ udp_primitive } ; -K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; -K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; + /* Many keywords can be optional in the syntax, although their + presence is significant. This is a fairly common pattern so + collect those rules here. */ + +K_automatic_opt: K_automatic { $$ = true; } | { $$ = false;} ; +K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; +K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; +K_virtual_opt : K_virtual { $$ = true; } | { $$ = false; } ; diff --git a/parse_misc.cc b/parse_misc.cc index ed631d0b3..241341564 100644 --- a/parse_misc.cc +++ b/parse_misc.cc @@ -20,6 +20,8 @@ # include "config.h" # include "parse_misc.h" +# include +# include # include extern const char*vl_file; @@ -42,10 +44,16 @@ void VLerror(const char*msg) cerr << yylloc.text << ":" << yylloc.first_line << ": " << msg << endl; } -void VLerror(const YYLTYPE&loc, const char*msg) +void VLerror(const YYLTYPE&loc, const char*msg, ...) { + va_list ap; + va_start(ap, msg); + + fprintf(stderr, "%s:%d: ", loc.text, loc.first_line); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + error_count += 1; - cerr << loc << ": " << msg << endl; based_size = 0; /* Clear the base information if we have an error. */ } diff --git a/parse_misc.h b/parse_misc.h index e9d642dfc..6d1aed925 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -56,7 +56,7 @@ extern YYLTYPE yylloc; */ extern int VLlex(); extern void VLerror(const char*msg); -extern void VLerror(const YYLTYPE&loc, const char*msg); +extern void VLerror(const YYLTYPE&loc, const char*msg, ...) __attribute__((format(printf,2,3))); #define yywarn VLwarn extern void VLwarn(const YYLTYPE&loc, const char*msg); diff --git a/pform.cc b/pform.cc index 9716ffdd9..4f349e9af 100644 --- a/pform.cc +++ b/pform.cc @@ -2193,6 +2193,22 @@ svector*pform_make_task_ports(NetNet::PortType pt, return res; } +svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, + data_type_t*vtype, + list*names) +{ + atom2_type_t*atype = dynamic_cast (vtype); + if (atype == 0) { + VLerror(loc, "sorry: Given type not supported here."); + return 0; + } + + list*range_tmp = make_range_from_width(atype->type_code); + return pform_make_task_ports(pt, IVL_VT_BOOL, atype->signed_flag, + range_tmp, names, loc.text, loc.first_line); +} + void pform_set_attrib(perm_string name, perm_string key, char*value) { if (PWire*cur = lexical_scope->wires_find(name)) { @@ -2541,6 +2557,11 @@ void pform_set_integer_2atom(uint64_t width, bool signed_flag, list */ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list*names) { + if (atom2_type_t*atom2_type = dynamic_cast (data_type)) { + pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names); + return; + } + if (struct_type_t*struct_type = dynamic_cast (data_type)) { pform_set_struct_type(struct_type, names); return; diff --git a/pform.h b/pform.h index b32ccce70..bc0c7115d 100644 --- a/pform.h +++ b/pform.h @@ -117,6 +117,8 @@ struct lgate { unsigned lineno; }; +extern std::list* make_range_from_width(uint64_t wid); + /* Use this function to transform the parted form of the attribute list to the attribute map that is used later. */ extern void pform_bind_attributes(map&attributes, @@ -392,6 +394,11 @@ extern svector*pform_make_task_ports(NetNet::PortType pt, unsigned lineno, bool isint = false); +extern svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, + data_type_t*vtype, + list*names); + /* * These are functions that the outside-the-parser code uses the do diff --git a/pform_types.h b/pform_types.h index 354353dd4..047592edf 100644 --- a/pform_types.h +++ b/pform_types.h @@ -100,6 +100,13 @@ struct struct_type_t : public data_type_t { std::auto_ptr< list > members; }; +struct atom2_type_t : public data_type_t { + inline explicit atom2_type_t(int tc, bool flag) + : type_code(tc), signed_flag(flag) { } + int type_code; + bool signed_flag; +}; + /* * The pform_name_t is the general form for a hierarchical * identifier. It is an ordered list of name components. Each name From 6b4251626b17d9714d280381438f193fd21a76aa Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 19 Feb 2012 17:31:15 -0800 Subject: [PATCH 03/23] Parse array literals / rearrange task declaration rules. --- lexor.lex | 2 +- parse.y | 573 ++++++++++++++++++++++++++++++-------------------- pform.cc | 11 +- pform.h | 5 +- pform_dump.cc | 10 + 5 files changed, 361 insertions(+), 240 deletions(-) diff --git a/lexor.lex b/lexor.lex index 259a8fcd1..b44d47166 100644 --- a/lexor.lex +++ b/lexor.lex @@ -191,7 +191,7 @@ TU [munpf] ">>>=" { return K_RSS_EQ; } "++" { return K_INCR; } "--" {return K_DECR; } - +"'{" { return K_LP; } /* Watch out for the tricky case of (*). Cannot parse this as "(*" and ")", but since I know that this is really ( * ), replace it diff --git a/parse.y b/parse.y index 01a496634..31d8fcd27 100644 --- a/parse.y +++ b/parse.y @@ -355,7 +355,7 @@ static void current_task_set_statement(vector*s) %token BASED_NUMBER DEC_NUMBER %token REALTIME %token K_PLUS_EQ K_MINUS_EQ K_INCR K_DECR -%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LS K_RS K_RSS K_SG +%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LP K_LS K_RS K_RSS K_SG /* K_CONTRIBUTE is <+, the contribution assign. */ %token K_CONTRIBUTE %token K_PO_POS K_PO_NEG K_POW @@ -473,13 +473,13 @@ static void current_task_set_statement(vector*s) %type list_of_ports module_port_list_opt list_of_port_declarations module_attribute_foreign %type parameter_value_range parameter_value_ranges %type parameter_value_ranges_opt -%type task_port_decl_expr_opt value_range_expression +%type tf_port_item_expr_opt value_range_expression %type enum_name_list enum_name %type enum_data_type %type task_item task_item_list task_item_list_opt -%type task_port_item task_port_decl task_port_decl_list task_port_decl_list_opt +%type task_port_item tf_port_item tf_port_list tf_port_list_opt %type function_item function_item_list %type port_name parameter_value_byname @@ -495,7 +495,7 @@ static void current_task_set_statement(vector*s) %type gate_instance_list %type hierarchy_identifier -%type expression expr_primary expr_mintypmax +%type assignment_pattern expression expr_primary expr_mintypmax %type lpvalue %type branch_probe_expression %type delay_value delay_value_simple @@ -511,7 +511,7 @@ static void current_task_set_statement(vector*s) %type struct_union_member_list %type struct_data_type -%type range range_opt +%type range range_opt variable_dimension %type dimensions_opt dimensions %type net_type var_type net_type_opt %type gatetype switchtype @@ -574,6 +574,21 @@ source_file | source_file description ; +assignment_pattern /* IEEE1800-2005: A.6.7.1 */ + : K_LP expression_list_proper '}' + { PEVoid*tmp = new PEVoid; + FILE_NAME(tmp, @1); + yyerror(@1, "sorry: Assignment patterns (array literals) not supported."); + $$ = tmp; + } + | K_LP '}' + { PEVoid*tmp = new PEVoid; + FILE_NAME(tmp, @1); + yyerror(@1, "sorry: Assignment patterns (array literals) not supported."); + $$ = tmp; + } + ; + class_declaration /* IEEE1800-2005: A.1.2 */ : K_virtual_opt K_class IDENTIFIER ';' class_items_opt K_endclass endname_opt @@ -599,13 +614,22 @@ class_items class_item /* IEEE1800-2005: A.1.8 */ /* class_constructor_declaration */ - : K_function K_new '(' task_port_decl_list_opt ')' ';' + : K_function K_new '(' tf_port_list_opt ')' ';' + statement_list_or_null K_endfunction endnew_opt + { yyerror(@1, "sorry: Class constructors not supported yet."); + yyerrok; + } /* Class properties... */ | data_type list_of_variable_decl_assignments ';' + + /* Class methods... */ + + | task_declaration + /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ @@ -657,6 +681,297 @@ real_or_realtime | K_realtime ; + /* The task declaration rule matches the task declaration + header, then pushes the function scope. This causes the + definitions in the task_body to take on the scope of the task + instead of the module. */ + +task_declaration /* IEEE1800-2005: A.2.7 */ + + : K_task K_automatic_opt IDENTIFIER ';' + { assert(current_task == 0); + current_task = pform_push_task_scope(@1, $3, $2); + } + task_item_list_opt + statement_or_null_list + K_endtask + { current_task->set_ports($6); + current_task_set_statement($7); + pform_pop_scope(); + current_task = 0; + delete[]$3; + if ($7->size() > 1 && !gn_system_verilog()) { + yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); + } + delete $7; + } + + | K_task K_automatic_opt IDENTIFIER '(' + { assert(current_task == 0); + current_task = pform_push_task_scope(@1, $3, $2); + } + tf_port_list ')' ';' + block_item_decls_opt + statement_or_null_list + K_endtask + { current_task->set_ports($6); + current_task_set_statement($10); + pform_pop_scope(); + current_task = 0; + delete[]$3; + if ($10->size() > 1 && !gn_system_verilog()) { + yyerror(@10, "error: Task body with multiple statements requres SystemVerilog."); + } + delete $10; + } + + | K_task K_automatic_opt IDENTIFIER '(' ')' ';' + { assert(current_task == 0); + current_task = pform_push_task_scope(@1, $3, $2); + } + block_item_decls_opt + statement_or_null_list + K_endtask + { current_task->set_ports(0); + current_task_set_statement($9); + pform_pop_scope(); + current_task = 0; + cerr << @3 << ": warning: task definition for \"" << $3 + << "\" has an empty port declaration list!" << endl; + delete[]$3; + if ($9->size() > 1 && !gn_system_verilog()) { + yyerror(@9, "error: Task body with multiple statements requres SystemVerilog."); + } + delete $9; + } + + | K_task K_automatic_opt IDENTIFIER error K_endtask + { + assert(current_task == 0); + delete[]$3; + } + + ; + + + /* These rules for tf_port_item are slightly expanded from the + strict rules in the LRM to help with LALR parsing. + + NOTE: Some of these rules should be folded into the "data_type" + variant which uses the data_type rule to match data type + declarations. That some rules do not use the data_type production + is a consequence of legacy. */ + +tf_port_item /* IEEE1800-2005: A.2.7 */ + + : port_direction K_reg_opt unsigned_signed_opt range_opt IDENTIFIER range_opt tf_port_item_expr_opt + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = $3; + delete port_declaration_context.range; + port_declaration_context.range = copy_range($4); + svector*tmp = pform_make_task_ports(@5, $1, IVL_VT_LOGIC, $3, + $4, list_from_identifier($5)); + $$ = tmp; + if ($6) { + yyerror(@6, "sorry: Port variable dimensions not supported yet."); + delete $6; + } + if ($7) { + yyerror(@7, "sorry: Port default expressions not supported yet."); + delete $7; + } + } + + | port_direction_opt bit_logic unsigned_signed_opt range_opt IDENTIFIER range_opt tf_port_item_expr_opt + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = $2; + port_declaration_context.sign_flag = $3; + delete port_declaration_context.range; + port_declaration_context.range = copy_range($4); + svector*tmp = pform_make_task_ports(@5, $1, $2, $3, + $4, list_from_identifier($5)); + $$ = tmp; + if ($6) { + yyerror(@6, "sorry: Port variable dimensions not supported yet."); + delete $6; + } + if ($7) { + yyerror(@7, "sorry: Port default expressions not supported yet."); + delete $7; + } + } + + /* Ports can be integer with a width of [31:0]. */ + + | port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt + { list*range_stub = make_range_from_width(integer_width); + port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = true; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_LOGIC, true, + range_stub, + list_from_identifier($3), true); + $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port variable dimensions not supported yet."); + delete $4; + } + if ($5) { + yyerror(@5, "sorry: Port default expressions not supported yet."); + delete $5; + } + } + + /* Ports can be time with a width of [63:0] (unsigned). */ + + | port_direction_opt K_time IDENTIFIER range_opt tf_port_item_expr_opt + { list*range_stub = make_range_from_width(64); + port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_LOGIC, false, + range_stub, + list_from_identifier($3)); + $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port variable dimensions not supported yet."); + delete $4; + } + if ($5) { + yyerror(@5, "sorry: Port default expressions not supported yet."); + delete $5; + } + } + + /* Ports can be real or realtime. */ + + | port_direction_opt real_or_realtime IDENTIFIER range_opt tf_port_item_expr_opt + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_REAL; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = 0; + svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_REAL, false, + 0, list_from_identifier($3)); + $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port variable dimensions not supported yet."); + delete $4; + } + if ($5) { + yyerror(@5, "sorry: Port default expressions not supported yet."); + delete $5; + } + } + + | port_direction_opt data_type IDENTIFIER range_opt tf_port_item_expr_opt + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_NO_TYPE; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = 0; + port_declaration_context.data_type = $2; + svector*tmp = pform_make_task_ports(@3, $1, $2, + list_from_identifier($3)); + $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port variable dimensions not supported yet."); + delete $4; + } + if ($5) { + yyerror(@5, "sorry: Port default expressions not supported yet."); + delete $5; + } + } + + ; + + /* This rule matches the [ = ] part of the tf_port_item rules. */ + +tf_port_item_expr_opt + : '=' expression { $$ = $2; } + | { $$ = 0; } + ; + +tf_port_list /* IEEE1800-2005: A.2.7 */ + + : tf_port_list ',' tf_port_item + { svector*tmp; + if ($3) { + tmp = new svector(*$1, *$3); + delete $1; + delete $3; + } else { + tmp = $1; + } + $$ = tmp; + } + + | tf_port_item + { $$ = $1; } + + /* This rule handles the special case of a set of port items leading + an undecorated identifier. Undeconated identifiers in this case + pick up the details from the list to its lift. */ + + | tf_port_list ',' IDENTIFIER + { // The declaration is already parsed, apply it to IDENTIFIER + svector*new_decl; + if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { + assert(port_declaration_context.data_type); + new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, + port_declaration_context.data_type, + list_from_identifier($3)); + } else { + new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, + port_declaration_context.var_type, + port_declaration_context.sign_flag, + copy_range(port_declaration_context.range), + list_from_identifier($3)); + } + svector*tmp = new svector(*$1, *new_decl); + delete $1; + delete new_decl; + $$ = tmp; + } + + /* Rules to handle some errors in tf_port_list items. */ + + | error ',' tf_port_item + { yyerror(@2, "error: Syntax error in task/function port declaration."); + $$ = $3; + } + | tf_port_list ',' + { yyerror(@2, "error: NULL port declarations are not allowed."); + $$ = $1; + } + | tf_port_list ';' + { yyerror(@2, "error: ';' is an invalid port declaration separator."); + $$ = $1; + } + ; + + +variable_dimension /* IEEE1800-2005: A.2.5 */ + : '[' expression ':' expression ']' + { list*tmp = new list; + tmp->push_back($2); + tmp->push_back($4); + $$ = tmp; + } + | '[' ']' + { list*tmp = new list; + tmp->push_back(0); + tmp->push_back(0); + $$ = tmp; + } +; + /* Verilog-2001 supports attribute lists, which can be attached to a variety of different objects. The syntax inside the (* *) is a comma separated list of names or names with assigned values. */ @@ -2079,6 +2394,12 @@ expr_primary $$ = base; } } + + /* Aggregate literals are primaries. */ + + | assignment_pattern + { $$ = $1; } + ; /* A function_item_list borrows the task_port_item run to match @@ -3159,76 +3480,7 @@ module_item | class_declaration - /* The task declaration rule matches the task declaration - header, then pushes the function scope. This causes the - definitions in the task_body to take on the scope of the task - instead of the module. Note that these runs accept for the task - body statement_or_null, although the standard does not allow null - statements in the task body. But we continue to accept it as an - extension. */ - - | K_task K_automatic_opt IDENTIFIER ';' - { assert(current_task == 0); - current_task = pform_push_task_scope(@1, $3, $2); - } - task_item_list_opt - statement_or_null_list - K_endtask - { current_task->set_ports($6); - current_task_set_statement($7); - pform_pop_scope(); - current_task = 0; - delete[]$3; - if ($7->size() > 1 && !gn_system_verilog()) { - yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); - } - delete $7; - } - - | K_task K_automatic_opt IDENTIFIER '(' - { assert(current_task == 0); - current_task = pform_push_task_scope(@1, $3, $2); - } - task_port_decl_list ')' ';' - block_item_decls_opt - statement_or_null_list - K_endtask - { current_task->set_ports($6); - current_task_set_statement($10); - pform_pop_scope(); - current_task = 0; - delete[]$3; - if ($10->size() > 1 && !gn_system_verilog()) { - yyerror(@10, "error: Task body with multiple statements requres SystemVerilog."); - } - delete $10; - } - - | K_task K_automatic_opt IDENTIFIER '(' ')' ';' - { assert(current_task == 0); - current_task = pform_push_task_scope(@1, $3, $2); - } - block_item_decls_opt - statement_or_null_list - K_endtask - { current_task->set_ports(0); - current_task_set_statement($9); - pform_pop_scope(); - current_task = 0; - cerr << @3 << ": warning: task definition for \"" << $3 - << "\" has an empty port declaration list!" << endl; - delete[]$3; - if ($9->size() > 1 && !gn_system_verilog()) { - yyerror(@9, "error: Task body with multiple statements requres SystemVerilog."); - } - delete $9; - } - - | K_task K_automatic_opt IDENTIFIER error K_endtask - { - assert(current_task == 0); - delete[]$3; - } + | task_declaration /* The function declaration rule matches the function declaration header, then pushes the function scope. This causes the @@ -3266,7 +3518,7 @@ module_item { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } - '(' task_port_decl_list_opt ')' ';' + '(' tf_port_list_opt ')' ';' block_item_decls_opt statement_list K_endfunction @@ -4055,17 +4307,12 @@ port_direction_opt | { $$ = NetNet::PINPUT; } ; + /* The range is a list of variable dimensions. */ range - : '[' expression ':' expression ']' - { list*tmp = new list; - tmp->push_back($2); - tmp->push_back($4); - $$ = tmp; - } - | range '[' expression ':' expression ']' + : variable_dimension + | range variable_dimension { list*tmp = $1; - tmp->push_back($3); - tmp->push_back($5); + if ($2) tmp->splice(tmp->end(), *$2); $$ = tmp; } ; @@ -5112,11 +5359,10 @@ task_item task_port_item : port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports($1, + { svector*tmp = pform_make_task_ports(@1, $1, $2 ? IVL_VT_LOGIC : IVL_VT_NO_TYPE, - $3, $4, $5, - @1.text, @1.first_line); + $3, $4, $5); $$ = tmp; } @@ -5125,9 +5371,8 @@ task_port_item | port_direction K_integer list_of_identifiers ';' { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, true, - range_stub, $3, - @1.text, @1.first_line, true); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, + range_stub, $3, true); $$ = tmp; } @@ -5135,17 +5380,16 @@ task_port_item | port_direction K_time list_of_identifiers ';' { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, false, - range_stub, $3, - @1.text, @1.first_line); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, + range_stub, $3); $$ = tmp; } /* Ports can be real or realtime. */ | port_direction real_or_realtime list_of_identifiers ';' - { svector*tmp = pform_make_task_ports($1, IVL_VT_REAL, false, - 0, $3, @1.text, @1.first_line); + { svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, false, + 0, $3); $$ = tmp; } @@ -5169,142 +5413,11 @@ task_item_list_opt { $$ = 0; } ; -task_port_decl - - : port_direction K_reg_opt unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | port_direction_opt bit_logic unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = pform_make_task_ports($1, $2, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - /* Ports can be integer with a width of [31:0]. */ - - | port_direction_opt K_integer IDENTIFIER - { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, true, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line, true); - $$ = tmp; - } - - /* Ports can be time with a width of [63:0] (unsigned). */ - - | port_direction_opt K_time IDENTIFIER - { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - - /* Ports can be real or realtime. */ - - | port_direction_opt real_or_realtime IDENTIFIER - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp = pform_make_task_ports($1, IVL_VT_REAL, false, - 0, list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - - | port_direction_opt data_type IDENTIFIER task_port_decl_expr_opt - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_NO_TYPE; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - port_declaration_context.data_type = $2; - svector*tmp = pform_make_task_ports(@1, $1, $2, - list_from_identifier($3)); - $$ = tmp; - if ($4) { - yyerror(@4, "sorry: Port default expressions not supported yet."); - delete $4; - } - } - - ; - -task_port_decl_expr_opt - : '=' expression { $$ = $2; } - | { $$ = 0; } - ; - -task_port_decl_list_opt - : task_port_decl_list { $$ = $1; } +tf_port_list_opt + : tf_port_list { $$ = $1; } | { $$ = 0; } ; -task_port_decl_list - : task_port_decl_list ',' task_port_decl - { svector*tmp = new svector(*$1, *$3); - delete $1; - delete $3; - $$ = tmp; - } - | task_port_decl - { $$ = $1; } - | task_port_decl_list ',' IDENTIFIER - { // The declaration is already parsed, apply it to IDENTIFIER - svector*new_decl; - if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { - assert(port_declaration_context.data_type); - new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, - port_declaration_context.data_type, - list_from_identifier($3)); - } else { - new_decl = pform_make_task_ports(port_declaration_context.port_type, - port_declaration_context.var_type, - port_declaration_context.sign_flag, - copy_range(port_declaration_context.range), - list_from_identifier($3), - @3.text, @3.first_line); - } - svector*tmp = new svector(*$1, *new_decl); - delete $1; - delete new_decl; - $$ = tmp; - } - | task_port_decl_list ',' - { yyerror(@2, "error: NULL port declarations are not allowed."); } - | task_port_decl_list ';' - { yyerror(@2, "error: ';' is an invalid port declaration separator."); } - ; - udp_body : K_table { lex_start_table(); } udp_entry_list diff --git a/pform.cc b/pform.cc index 4f349e9af..9629be7bc 100644 --- a/pform.cc +++ b/pform.cc @@ -2145,13 +2145,12 @@ void pform_set_port_type(perm_string name, NetNet::PortType pt, * constraints as those of tasks, so this works fine. Functions have * no output or inout ports. */ -svector*pform_make_task_ports(NetNet::PortType pt, +svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, list*range, list*names, - const char* file, - unsigned lineno, bool isint) { assert(names); @@ -2168,7 +2167,7 @@ svector*pform_make_task_ports(NetNet::PortType pt, curw->set_port_type(pt); } else { curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype); - FILE_NAME(curw, file, lineno); + FILE_NAME(curw, loc); pform_put_wire_in_scope(name, curw); } @@ -2205,8 +2204,8 @@ svector*pform_make_task_ports(const struct vlltype&loc, } list*range_tmp = make_range_from_width(atype->type_code); - return pform_make_task_ports(pt, IVL_VT_BOOL, atype->signed_flag, - range_tmp, names, loc.text, loc.first_line); + return pform_make_task_ports(loc, pt, IVL_VT_BOOL, atype->signed_flag, + range_tmp, names); } void pform_set_attrib(perm_string name, perm_string key, char*value) diff --git a/pform.h b/pform.h index bc0c7115d..19b0f72b5 100644 --- a/pform.h +++ b/pform.h @@ -385,13 +385,12 @@ extern void pform_make_pgassign_list(list*alist, /* Given a port type and a list of names, make a list of wires that can be used as task port information. */ -extern svector*pform_make_task_ports(NetNet::PortType pt, +extern svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, list*range, list*names, - const char* file, - unsigned lineno, bool isint = false); extern svector*pform_make_task_ports(const struct vlltype&loc, diff --git a/pform_dump.cc b/pform_dump.cc index 9d13320f1..ac34927a4 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -860,6 +860,10 @@ void PTask::dump(ostream&out, unsigned ind) const out << pscope_name() << ";" << endl; if (ports_) for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) { + if ((*ports_)[idx] == 0) { + out << setw(ind) << "" << "ERROR PORT" << endl; + continue; + } out << setw(ind) << ""; switch ((*ports_)[idx]->get_port_type()) { case NetNet::PINPUT: @@ -871,6 +875,12 @@ void PTask::dump(ostream&out, unsigned ind) const case NetNet::PINOUT: out << "inout "; break; + case NetNet::PIMPLICIT: + out << "PIMPLICIT"; + break; + case NetNet::NOT_A_PORT: + out << "NOT_A_PORT"; + break; default: assert(0); break; From f8e346f1086aa5c41a8bf17ebc08d6da1345c45f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 19 Feb 2012 18:54:58 -0800 Subject: [PATCH 04/23] Implement increment/decrement statements. During parse/pform processing, convert increment statements to the equivalent compressed assignment statement. This is less weird for elaboration processing and better expresses what is going on. --- PExpr.h | 4 +++ parse.y | 97 +++++++++++++++++++++++++++++++++++--------------------- pform.cc | 37 +++++++++++++++++++++ pform.h | 7 ++++ 4 files changed, 109 insertions(+), 36 deletions(-) diff --git a/PExpr.h b/PExpr.h index 7691b44d1..03c9e3284 100644 --- a/PExpr.h +++ b/PExpr.h @@ -509,6 +509,10 @@ class PEUnary : public PExpr { unsigned flags) const; virtual verinum* eval_const(Design*des, NetScope*sc) const; + public: + inline char get_op() const { return op_; } + inline PExpr*get_expr() const { return expr_; } + private: NetExpr* elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const; diff --git a/parse.y b/parse.y index 31d8fcd27..38dc2d0bb 100644 --- a/parse.y +++ b/parse.y @@ -496,7 +496,7 @@ static void current_task_set_statement(vector*s) %type hierarchy_identifier %type assignment_pattern expression expr_primary expr_mintypmax -%type lpvalue +%type inc_or_dec_expression lpvalue %type branch_probe_expression %type delay_value delay_value_simple %type delay1 delay3 delay3_opt delay_value_list @@ -665,6 +665,35 @@ implicit_class_handle /* IEEE1800-2005: A.8.4 */ | K_super ; + /* SystemVerilog adds support for the increment/decrement + expressions, which look like a++, --a, etc. These are primaries + but are in their own rules because they can also be + statements. Note that the operator can only take l-value + expressions. */ + +inc_or_dec_expression /* IEEE1800-2005: A.4.3 */ + : K_INCR lpvalue %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('I', $2); + FILE_NAME(tmp, @2); + $$ = tmp; + } + | lpvalue K_INCR %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('i', $1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_DECR lpvalue %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('D', $2); + FILE_NAME(tmp, @2); + $$ = tmp; + } + | lpvalue K_DECR %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('d', $1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + number : BASED_NUMBER { $$ = $1; based_size = 0;} | DEC_NUMBER @@ -1790,32 +1819,10 @@ branch_probe_expression expression : expr_primary { $$ = $1; } + | inc_or_dec_expression + { $$ = $1; } | '+' expr_primary %prec UNARY_PREC { $$ = $2; } - | K_INCR expr_primary %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('I', $2); - FILE_NAME(tmp, @2); - $$ = tmp; - } - | expr_primary K_INCR %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('i', $1); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_DECR expr_primary %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('D', $2); - FILE_NAME(tmp, @2); - $$ = tmp; - } - | expr_primary K_DECR %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('d', $1); - FILE_NAME(tmp, @1); - $$ = tmp; - } | '-' expr_primary %prec UNARY_PREC { PEUnary*tmp = new PEUnary('-', $2); FILE_NAME(tmp, @2); @@ -4897,7 +4904,7 @@ spec_notifier ; -statement +statement /* This is roughly statement_item in the LRM */ /* assign and deassign statements are procedural code to do structural assignments, and to turn that structural assignment @@ -5094,16 +5101,29 @@ statement { $$ = 0; yyerror(@1, "error: Error in while loop condition."); } - | compressed_statement ';' - { $$ = $1; } - | delay1 statement_or_null - { PExpr*del = $1->front(); - assert($1->size() == 1); - delete $1; - PDelayStatement*tmp = new PDelayStatement(del, $2); - FILE_NAME(tmp, @1); - $$ = tmp; - } + + /* SytemVerilog adds the compressed_statement */ + + | compressed_statement ';' + { $$ = $1; } + + /* increment/decrement expressions can also be statements. When used + as statements, we can rewrite a++ as a += 1, and so on. */ + + | inc_or_dec_expression ';' + { $$ = pform_compressed_assign_from_inc_dec(@1, $1); } + + /* */ + + | delay1 statement_or_null + { PExpr*del = $1->front(); + assert($1->size() == 1); + delete $1; + PDelayStatement*tmp = new PDelayStatement(del, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | event_control attribute_list_opt statement_or_null { PEventStatement*tmp = $1; if (tmp == 0) { @@ -5129,6 +5149,9 @@ statement tmp->set_statement($6); $$ = tmp; } + + /* Various assignment statements */ + | lpvalue '=' expression ';' { PAssign*tmp = new PAssign($1,$3); FILE_NAME(tmp, @1); @@ -5184,6 +5207,8 @@ statement FILE_NAME(tmp, @1); $$ = tmp; } + + | K_wait '(' expression ')' statement_or_null { PEventStatement*tmp; PEEvent*etmp = new PEEvent(PEEvent::POSITIVE, $3); diff --git a/pform.cc b/pform.cc index 9629be7bc..cd909fb74 100644 --- a/pform.cc +++ b/pform.cc @@ -2208,6 +2208,43 @@ svector*pform_make_task_ports(const struct vlltype&loc, range_tmp, names); } +/* + * The parser calls this in the rule that matches increment/decrement + * statements. The rule that does the matching creates a PEUnary with + * all the information we need, but here we convert that expression to + * a compressed assignment statement. + */ +PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, PExpr*exp) +{ + PEUnary*expu = dynamic_cast (exp); + ivl_assert(*exp, expu != 0); + + char use_op = 0; + switch (expu->get_op()) { + case 'i': + case 'I': + use_op = '+'; + break; + case 'd': + case 'D': + use_op = '-'; + break; + default: + ivl_assert(*exp, 0); + break; + } + + PExpr*lval = expu->get_expr(); + PExpr*rval = new PENumber(new verinum((uint64_t)1, 1)); + FILE_NAME(rval, loc); + + PAssign*tmp = new PAssign(lval, use_op, rval); + FILE_NAME(tmp, loc); + + delete exp; + return tmp; +} + void pform_set_attrib(perm_string name, perm_string key, char*value) { if (PWire*cur = lexical_scope->wires_find(name)) { diff --git a/pform.h b/pform.h index 19b0f72b5..addf61c94 100644 --- a/pform.h +++ b/pform.h @@ -398,6 +398,13 @@ extern svector*pform_make_task_ports(const struct vlltype&loc, data_type_t*vtype, list*names); +/* + * The parser uses this function to convert a unary + * increment/decrement expression to the equivilent compressed + * assignment statement. + */ +extern PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, + PExpr*exp); /* * These are functions that the outside-the-parser code uses the do From cad7c74680dc2f4c0bf75e7a026e6f4c20d4c791 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 24 Feb 2012 17:04:49 -0800 Subject: [PATCH 05/23] System Verilog supports closing names after endtask keyword. --- parse.y | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/parse.y b/parse.y index 38dc2d0bb..b3b23c72e 100644 --- a/parse.y +++ b/parse.y @@ -728,12 +728,26 @@ task_declaration /* IEEE1800-2005: A.2.7 */ current_task_set_statement($7); pform_pop_scope(); current_task = 0; - delete[]$3; if ($7->size() > 1 && !gn_system_verilog()) { yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); } delete $7; } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($10 && (strcmp($3,$10) != 0)) { + yyerror(@10, "error: End name doesn't match module/program name"); + } + if ($10 && !gn_system_verilog()) { + yyerror(@10, "error: Task end names require System Verilog."); + } + delete[]$3; + if ($10) delete[]$10; + } | K_task K_automatic_opt IDENTIFIER '(' { assert(current_task == 0); @@ -747,12 +761,26 @@ task_declaration /* IEEE1800-2005: A.2.7 */ current_task_set_statement($10); pform_pop_scope(); current_task = 0; - delete[]$3; if ($10->size() > 1 && !gn_system_verilog()) { yyerror(@10, "error: Task body with multiple statements requres SystemVerilog."); } delete $10; } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($13 && (strcmp($3,$13) != 0)) { + yyerror(@13, "error: End name doesn't match module/program name"); + } + if ($13 && !gn_system_verilog()) { + yyerror(@13, "error: Task end names require System Verilog."); + } + delete[]$3; + if ($13) delete[]$13; + } | K_task K_automatic_opt IDENTIFIER '(' ')' ';' { assert(current_task == 0); @@ -767,17 +795,45 @@ task_declaration /* IEEE1800-2005: A.2.7 */ current_task = 0; cerr << @3 << ": warning: task definition for \"" << $3 << "\" has an empty port declaration list!" << endl; - delete[]$3; if ($9->size() > 1 && !gn_system_verilog()) { yyerror(@9, "error: Task body with multiple statements requres SystemVerilog."); } delete $9; } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($12 && (strcmp($3,$12) != 0)) { + yyerror(@12, "error: End name doesn't match module/program name"); + } + if ($12 && !gn_system_verilog()) { + yyerror(@12, "error: Task end names require System Verilog."); + } + delete[]$3; + if ($12) delete[]$12; + } | K_task K_automatic_opt IDENTIFIER error K_endtask { assert(current_task == 0); + } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($7 && (strcmp($3,$7) != 0)) { + yyerror(@7, "error: End name doesn't match module/program name"); + } + if ($7 && !gn_system_verilog()) { + yyerror(@7, "error: Task end names require System Verilog."); + } delete[]$3; + if ($7) delete[]$7; } ; From d000147392379075e2f5fcb69d1f7bc5994d74af Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 25 Feb 2012 09:28:20 -0800 Subject: [PATCH 06/23] Parse for declarations, implement for_step statements. for-statement declarations still generate a "sorry" message, but the for_step statements work in general now. --- Statement.cc | 5 +- Statement.h | 5 +- elaborate.cc | 29 ++--------- parse.y | 134 ++++++++++++++++++++++++++++++++------------------ pform_dump.cc | 4 +- 5 files changed, 98 insertions(+), 79 deletions(-) diff --git a/Statement.cc b/Statement.cc index e726099bb..a99e8b37e 100644 --- a/Statement.cc +++ b/Statement.cc @@ -276,9 +276,8 @@ PForever::~PForever() } PForStatement::PForStatement(PExpr*n1, PExpr*e1, PExpr*cond, - PExpr*n2, PExpr*e2, Statement*st) -: name1_(n1), expr1_(e1), cond_(cond), name2_(n2), expr2_(e2), - statement_(st) + Statement*step, Statement*st) +: name1_(n1), expr1_(e1), cond_(cond), step_(step), statement_(st) { } diff --git a/Statement.h b/Statement.h index cef5833c1..5caf9644d 100644 --- a/Statement.h +++ b/Statement.h @@ -403,7 +403,7 @@ class PForStatement : public Statement { public: PForStatement(PExpr*n1, PExpr*e1, PExpr*cond, - PExpr*n2, PExpr*e2, Statement*st); + Statement*step, Statement*body); ~PForStatement(); virtual NetProc* elaborate(Design*des, NetScope*scope) const; @@ -417,8 +417,7 @@ class PForStatement : public Statement { PExpr*cond_; - PExpr* name2_; - PExpr* expr2_; + Statement*step_; Statement*statement_; }; diff --git a/elaborate.cc b/elaborate.cc index e2bf04e64..ba5d8f019 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3780,8 +3780,6 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const const PEIdent*id1 = dynamic_cast(name1_); assert(id1); - const PEIdent*id2 = dynamic_cast(name2_); - assert(id2); NetBlock*top = new NetBlock(NetBlock::SEQU, 0); top->set_line(*this); @@ -3826,32 +3824,15 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const body->append(tmp); - /* Elaborate the increment assignment statement at the end of - the for loop. This is also a very specific assignment - statement. Put this into the "body" block. */ - sig = des->find_signal(scope, id2->path()); - if (sig == 0) { - cerr << get_fileline() << ": error: Unable to find variable " - << id2->path() << " in for-loop increment expression." << endl; - des->errors += 1; - return body; - } - - assert(sig); - lv = new NetAssign_(sig); - - /* Make the r-value of the increment assignment, and size it - properly. Then use it to build the assignment statement. */ - etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(), - expr2_); - + /* Now elaborate the for_step statement. I really should do + some error checking here to make sure the step statement + really does step the variable. */ if (debug_elaborate) { - cerr << get_fileline() << ": debug: FOR increment assign: " + cerr << get_fileline() << ": debug: Elaborate for_step statement " << sig->name() << " = " << *etmp << endl; } - NetAssign*step = new NetAssign(lv, etmp); - step->set_line(*this); + NetProc*step = step_->elaborate(des, scope); body->append(step); diff --git a/parse.y b/parse.y index b3b23c72e..5118dd2c6 100644 --- a/parse.y +++ b/parse.y @@ -524,6 +524,7 @@ static void current_task_set_statement(vector*s) %type event_expression %type event_control %type statement statement_or_null compressed_statement +%type loop_statement for_step %type statement_list statement_or_null_list %type statement_list_or_null @@ -660,6 +661,19 @@ data_type /* IEEE1800-2005: A.2.2.1 */ endnew_opt : ':' K_new | ; +for_step /* IEEE1800-2005: A.6.8 */ + : lpvalue '=' expression + { PAssign*tmp = new PAssign($1,$3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | inc_or_dec_expression + { $$ = pform_compressed_assign_from_inc_dec(@1, $1); } + | compressed_statement + { $$ = $1; } + ; + + implicit_class_handle /* IEEE1800-2005: A.8.4 */ : K_this | K_super @@ -694,6 +708,66 @@ inc_or_dec_expression /* IEEE1800-2005: A.4.3 */ } ; + /* Loop statements are kinds of statements. */ + +loop_statement /* IEEE1800-2005: A.6.8 */ + : K_for '(' lpvalue '=' expression ';' expression ';' for_step ')' + statement_or_null + { PForStatement*tmp = new PForStatement($3, $5, $7, $9, $11); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + | K_for '(' data_type IDENTIFIER '=' expression ';' expression ';' for_step ')' + statement_or_null + { $$ = 0; + yyerror(@3, "sorry: for_variable_declaration not supported"); + } + + | K_forever statement_or_null + { PForever*tmp = new PForever($2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + | K_repeat '(' expression ')' statement_or_null + { PRepeat*tmp = new PRepeat($3, $5); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + | K_while '(' expression ')' statement_or_null + { PWhile*tmp = new PWhile($3, $5); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + /* Error forms for loop statements. */ + + | K_for '(' lpvalue '=' expression ';' expression ';' error ')' + statement_or_null + { $$ = 0; + yyerror(@1, "error: Error in for loop step assignment."); + } + + | K_for '(' lpvalue '=' expression ';' error ';' for_step ')' + statement_or_null + { $$ = 0; + yyerror(@1, "error: Error in for loop condition expression."); + } + + | K_for '(' error ')' statement_or_null + { $$ = 0; + yyerror(@1, "error: Incomprehensible for loop."); + } + + | K_while '(' error ')' statement_or_null + { $$ = 0; + yyerror(@1, "error: Error in while loop condition."); + } + + ; + number : BASED_NUMBER { $$ = $1; based_size = 0;} | DEC_NUMBER @@ -710,6 +784,16 @@ real_or_realtime | K_realtime ; + /* Many places where statements are allowed can actually take a + statement or a null statement marked with a naked semi-colon. */ + +statement_or_null /* IEEE1800-2005: A.6.4 */ + : statement + { $$ = $1; } + | ';' + { $$ = 0; } + ; + /* The task declaration rule matches the task declaration header, then pushes the function scope. This causes the definitions in the task_body to take on the scope of the task @@ -5079,16 +5163,9 @@ statement /* This is roughly statement_item in the LRM */ delete $2; $$ = tmp; } - | K_forever statement - { PForever*tmp = new PForever($2); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_repeat '(' expression ')' statement - { PRepeat*tmp = new PRepeat($3, $5); - FILE_NAME(tmp, @1); - $$ = tmp; - } + + | loop_statement { $$ = $1; } + | K_case '(' expression ')' case_items K_endcase { PCase*tmp = new PCase(NetCase::EQ, $3, $5); FILE_NAME(tmp, @1); @@ -5128,36 +5205,6 @@ statement /* This is roughly statement_item in the LRM */ { yyerror(@1, "error: Malformed conditional expression."); $$ = $5; } - | K_for '(' lpvalue '=' expression ';' expression ';' - lpvalue '=' expression ')' statement - { PForStatement*tmp = new PForStatement($3, $5, $7, $9, $11, $13); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_for '(' lpvalue '=' expression ';' expression ';' - error ')' statement - { $$ = 0; - yyerror(@1, "error: Error in for loop step assignment."); - } - | K_for '(' lpvalue '=' expression ';' error ';' - lpvalue '=' expression ')' statement - { $$ = 0; - yyerror(@1, "error: Error in for loop condition expression."); - } - | K_for '(' error ')' statement - { $$ = 0; - yyerror(@1, "error: Incomprehensible for loop."); - } - | K_while '(' expression ')' statement - { PWhile*tmp = new PWhile($3, $5); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_while '(' error ')' statement - { $$ = 0; - yyerror(@1, "error: Error in while loop condition."); - } - /* SytemVerilog adds the compressed_statement */ | compressed_statement ';' @@ -5406,13 +5453,6 @@ statement_list } ; -statement_or_null - : statement - { $$ = $1; } - | ';' - { $$ = 0; } - ; - statement_or_null_list : statement_or_null_list statement_or_null { vector*tmp = $1; diff --git a/pform_dump.cc b/pform_dump.cc index ac34927a4..d9fa1286e 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -774,8 +774,8 @@ void PForever::dump(ostream&out, unsigned ind) const void PForStatement::dump(ostream&out, unsigned ind) const { out << setw(ind) << "" << "for (" << *name1_ << " = " << *expr1_ - << "; " << *cond_ << "; " << *name2_ << " = " << *expr2_ << - ")" << endl; + << "; " << *cond_ << "; )" << endl; + step_->dump(out, ind+6); statement_->dump(out, ind+3); } From dd3a7411cd099843bf510bd779a87200e2d934fd Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 25 Feb 2012 10:19:48 -0800 Subject: [PATCH 07/23] Parse SystemVerilog ref ports. --- design_dump.cc | 3 +++ elab_net.cc | 4 ++++ elab_sig.cc | 8 ++++++++ elaborate.cc | 14 ++++++++++++++ netlist.h | 2 +- parse.y | 32 +++++++++++++++++++++----------- pform_dump.cc | 3 +++ 7 files changed, 54 insertions(+), 12 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 5da7f9047..e3d14f3b0 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -221,6 +221,9 @@ void NetNet::dump_net(ostream&o, unsigned ind) const case NetNet::PINOUT: o << " inout"; break; + case NetNet::PREF: + o <<" ref"; + break; } if (ivl_discipline_t dis = get_discipline()) diff --git a/elab_net.cc b/elab_net.cc index 98180dab5..221769451 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -702,6 +702,7 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const case NetNet::PINPUT: case NetNet::POUTPUT: case NetNet::PINOUT: + case NetNet::PREF: break; /* If the name matches, but the signal is not a port, @@ -769,6 +770,9 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const sig = tmp; break; + case NetNet::PREF: + // For the purposes of module ports, treat ref ports + // just like inout ports. case NetNet::PINOUT: ps = new NetTran(scope, scope->local_symbol(), sig->vector_width(), swid, lidx); diff --git a/elab_sig.cc b/elab_sig.cc index 336a8e97e..42ed8c355 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -85,6 +85,14 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const PWire*cur = (*wt).second; NetNet*sig = cur->elaborate_sig(des, scope); + if (sig && (sig->scope() == scope) + && (sig->port_type() == NetNet::PREF)) { + + cerr << cur->get_fileline() << ": sorry: " + << "Reference ports not supported yet." << endl; + des->errors += 1; + } + /* If the signal is an input and is also declared as a reg, then report an error. */ diff --git a/elaborate.cc b/elaborate.cc index ba5d8f019..e256a4df8 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1069,6 +1069,10 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope, ivl_assert(*this, 0); break; + case NetNet::PREF: + ivl_assert(*this, 0); + break; + default: ivl_assert(*this, 0); } @@ -1506,6 +1510,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } else { /* Port type must be OUTPUT here. */ + ivl_assert(*this, prts[0]->port_type() == NetNet::POUTPUT); /* Output from module. Elaborate the port expression as the l-value of a continuous @@ -1640,6 +1645,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const /* This may not be correct! */ as_signed = prts[0]->get_signed() && sig->get_signed(); break; + case NetNet::PREF: + ivl_assert(*this, 0); + break; default: ivl_assert(*this, 0); } @@ -1786,6 +1794,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } break; + case NetNet::PREF: + cerr << get_fileline() << ": sorry: " + << "Reference ports not supported yet." << endl; + des->errors += 1; + break; + case NetNet::PIMPLICIT: cerr << get_fileline() << ": internal error: " << "Unexpected IMPLICIT port" << endl; diff --git a/netlist.h b/netlist.h index 36f531dac..a99a41730 100644 --- a/netlist.h +++ b/netlist.h @@ -561,7 +561,7 @@ class NetNet : public NetObj { SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG, UNRESOLVED_WIRE }; - enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT }; + enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT, PREF }; struct range_t { inline range_t() : msb(0), lsb(0) { } diff --git a/parse.y b/parse.y index 5118dd2c6..81c71d14e 100644 --- a/parse.y +++ b/parse.y @@ -777,6 +777,27 @@ number : BASED_NUMBER based_size = 0; } ; +port_direction /* IEEE1800-2005 A.1.3 */ + : K_input { $$ = NetNet::PINPUT; } + | K_output { $$ = NetNet::POUTPUT; } + | K_inout { $$ = NetNet::PINOUT; } + | K_ref + { $$ = NetNet::PREF; + if (!gn_system_verilog()) { + yyerror(@1, "error: Reference ports (ref) require SystemVerilog."); + $$ = NetNet::PINPUT; + } + } + ; + + /* port_direction_opt is used in places where the prot direction is + option, and defaults to input. */ + +port_direction_opt + : port_direction { $$ = $1; } + | { $$ = NetNet::PINPUT; } + ; + /* real and realtime are exactly the same so save some code * with a common matching rule. */ real_or_realtime @@ -4443,17 +4464,6 @@ port_reference_list } ; -port_direction /* IEEE1800-2005 A.1.3 */ - : K_input { $$ = NetNet::PINPUT; } - | K_output { $$ = NetNet::POUTPUT; } - | K_inout { $$ = NetNet::PINOUT; } - ; - -port_direction_opt - : port_direction { $$ = $1; } - | { $$ = NetNet::PINPUT; } - ; - /* The range is a list of variable dimensions. */ range : variable_dimension diff --git a/pform_dump.cc b/pform_dump.cc index d9fa1286e..1ca78a67e 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -336,6 +336,9 @@ void PWire::dump(ostream&out, unsigned ind) const case NetNet::PINOUT: out << " inout"; break; + case NetNet::PREF: + out << " ref"; + break; case NetNet::NOT_A_PORT: break; } From 410350ae5a28d907bc9868240cc39cce1cebfc0f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 25 Feb 2012 22:05:00 -0800 Subject: [PATCH 08/23] Rework data_type parsing to bring integer vectors into data_type_t method. This adds the vector_type_t and real_type_t types to handle vector and real types in tf_port items. This cleans up a lot of the parsing for these items. --- parse.y | 221 ++++++++++++-------------------------------------- pform.cc | 46 ++++++++--- pform.h | 5 +- pform_types.h | 13 +++ 4 files changed, 101 insertions(+), 184 deletions(-) diff --git a/parse.y b/parse.y index 81c71d14e..eaf4064d5 100644 --- a/parse.y +++ b/parse.y @@ -157,7 +157,7 @@ static list* list_from_identifier(list*tmp, char*id) return tmp; } -static list* copy_range(list* orig) +list* copy_range(list* orig) { list*copy = 0; @@ -317,7 +317,7 @@ static void current_task_set_statement(vector*s) NetNet::Type nettype; PGBuiltin::Type gatetype; NetNet::PortType porttype; - ivl_variable_type_t datatype; + ivl_variable_type_t vartype; PWire*wire; svector*wires; @@ -461,9 +461,9 @@ static void current_task_set_statement(vector*s) %type udp_initial udp_init_opt %type udp_initial_expr_opt -%type register_variable net_variable real_variable endname_opt +%type register_variable net_variable endname_opt %type register_variable_list net_variable_list -%type real_variable_list list_of_identifiers +%type list_of_identifiers %type list_of_port_identifiers %type net_decl_assign net_decl_assigns @@ -506,7 +506,7 @@ static void current_task_set_statement(vector*s) %type variable_decl_assignment %type list_of_variable_decl_assignments -%type data_type +%type data_type data_type_or_implicit %type struct_union_member %type struct_union_member_list %type struct_data_type @@ -516,7 +516,8 @@ static void current_task_set_statement(vector*s) %type net_type var_type net_type_opt %type gatetype switchtype %type port_direction port_direction_opt -%type primitive_type primitive_type_opt bit_logic +%type primitive_type primitive_type_opt bit_logic +%type integer_vector_type %type parameter_value_opt %type function_range_or_type_opt @@ -536,7 +537,7 @@ static void current_task_set_statement(vector*s) %type specify_simple_path specify_simple_path_decl %type specify_edge_path specify_edge_path_decl -%type atom2_type +%type atom2_type non_integer_type %type module_start module_end %token K_TAND @@ -642,7 +643,17 @@ class_item /* IEEE1800-2005: A.1.8 */ ; data_type /* IEEE1800-2005: A.2.2.1 */ - : struct_data_type + : integer_vector_type unsigned_signed_opt range_opt + { vector_type_t*tmp = new vector_type_t($1, $2, $3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | non_integer_type + { real_type_t*tmp = new real_type_t($1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | struct_data_type { $$ = $1; } | enum_data_type { $$ = $1; } @@ -659,6 +670,16 @@ data_type /* IEEE1800-2005: A.2.2.1 */ } ; +data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ + : data_type + { $$ = $1; } + | unsigned_signed_opt range_opt + { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $1, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + endnew_opt : ':' K_new | ; for_step /* IEEE1800-2005: A.6.8 */ @@ -708,6 +729,13 @@ inc_or_dec_expression /* IEEE1800-2005: A.4.3 */ } ; +integer_vector_type /* IEEE1800-2005: A.2.2.1 */ + : K_reg { $$ = IVL_VT_LOGIC; } + | K_bit { $$ = IVL_VT_BOOL; } + | K_logic { $$ = IVL_VT_LOGIC; } + | K_bool { $$ = IVL_VT_BOOL; } /* Icarus Verilog xtypes extension */ + ; + /* Loop statements are kinds of statements. */ loop_statement /* IEEE1800-2005: A.6.8 */ @@ -768,6 +796,12 @@ loop_statement /* IEEE1800-2005: A.6.8 */ ; +non_integer_type /* IEEE1800-2005: A.2.2.1 */ + : K_real { $$ = K_real; } + | K_realtime { $$ = K_real; } + | K_shortreal { $$ = K_shortreal; } + ; + number : BASED_NUMBER { $$ = $1; based_size = 0;} | DEC_NUMBER @@ -954,47 +988,9 @@ task_declaration /* IEEE1800-2005: A.2.7 */ tf_port_item /* IEEE1800-2005: A.2.7 */ - : port_direction K_reg_opt unsigned_signed_opt range_opt IDENTIFIER range_opt tf_port_item_expr_opt - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = pform_make_task_ports(@5, $1, IVL_VT_LOGIC, $3, - $4, list_from_identifier($5)); - $$ = tmp; - if ($6) { - yyerror(@6, "sorry: Port variable dimensions not supported yet."); - delete $6; - } - if ($7) { - yyerror(@7, "sorry: Port default expressions not supported yet."); - delete $7; - } - } - - | port_direction_opt bit_logic unsigned_signed_opt range_opt IDENTIFIER range_opt tf_port_item_expr_opt - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = pform_make_task_ports(@5, $1, $2, $3, - $4, list_from_identifier($5)); - $$ = tmp; - if ($6) { - yyerror(@6, "sorry: Port variable dimensions not supported yet."); - delete $6; - } - if ($7) { - yyerror(@7, "sorry: Port default expressions not supported yet."); - delete $7; - } - } - /* Ports can be integer with a width of [31:0]. */ - | port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt + : port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt { list*range_stub = make_range_from_width(integer_width); port_declaration_context.port_type = $1; port_declaration_context.var_type = IVL_VT_LOGIC; @@ -1038,28 +1034,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ } } - /* Ports can be real or realtime. */ - - | port_direction_opt real_or_realtime IDENTIFIER range_opt tf_port_item_expr_opt - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_REAL, false, - 0, list_from_identifier($3)); - $$ = tmp; - if ($4) { - yyerror(@4, "sorry: Port variable dimensions not supported yet."); - delete $4; - } - if ($5) { - yyerror(@5, "sorry: Port default expressions not supported yet."); - delete $5; - } - } - - | port_direction_opt data_type IDENTIFIER range_opt tf_port_item_expr_opt + | port_direction data_type_or_implicit IDENTIFIER range_opt tf_port_item_expr_opt { port_declaration_context.port_type = $1; port_declaration_context.var_type = IVL_VT_NO_TYPE; port_declaration_context.sign_flag = false; @@ -1111,7 +1086,7 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ | tf_port_list ',' IDENTIFIER { // The declaration is already parsed, apply it to IDENTIFIER - svector*new_decl; + svector*new_decl; if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { assert(port_declaration_context.data_type); new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, @@ -1226,47 +1201,12 @@ attribute rule has presumably set up the scope. */ block_item_decl - : attribute_list_opt K_reg - primitive_type_opt unsigned_signed_opt range - register_variable_list ';' - { ivl_variable_type_t dtype = $3; - if (dtype == IVL_VT_NO_TYPE) - dtype = IVL_VT_LOGIC; - pform_set_net_range($6, $5, $4, dtype); - if ($1) delete $1; - } - /* This differs from the above pattern only in the absence of the - range. This is the rule for a scalar. */ - - | attribute_list_opt K_reg - primitive_type_opt unsigned_signed_opt - register_variable_list ';' - { ivl_variable_type_t dtype = $3; - if (dtype == IVL_VT_NO_TYPE) - dtype = IVL_VT_LOGIC; - pform_set_net_range($5, 0, $4, dtype); - if ($1) delete $1; - } - - | attribute_list_opt K_bit unsigned_signed_opt range_opt - register_variable_list ';' - { - pform_set_net_range($5, $4, $3, IVL_VT_BOOL); - if ($1) delete $1; - } - - | attribute_list_opt K_logic unsigned_signed_opt range_opt - register_variable_list ';' - { - pform_set_net_range($5, $4, $3, IVL_VT_LOGIC); - if ($1) delete $1; - } /* Integer atom declarations are simpler in that they do not have all the trappings of a general variable declaration. All of that is implicit in the "integer" of the declaration. */ - | attribute_list_opt K_integer signed_unsigned_opt register_variable_list ';' + : attribute_list_opt K_integer signed_unsigned_opt register_variable_list ';' { pform_set_reg_integer($4); if ($1) delete $1; } @@ -1284,15 +1224,10 @@ block_item_decl if ($1) delete $1; } - /* real declarations are fairly simple as there is no range of - signed flag in the declaration. Create the real as a NetNet::REG - with real value. Note that real and realtime are interchangeable - in this context. */ - - | attribute_list_opt K_real real_variable_list ';' - { delete $3; } - | attribute_list_opt K_realtime real_variable_list ';' - { delete $3; } + | attribute_list_opt K_reg data_type register_variable_list ';' + { if ($3) pform_set_data_type(@3, $3, $4); + if ($1) delete $1; + } | K_event list_of_identifiers ';' { pform_make_events($2, @1.text, @1.first_line); @@ -1307,12 +1242,6 @@ block_item_decl /* Recover from errors that happen within variable lists. Use the trailing semi-colon to resync the parser. */ - - | attribute_list_opt K_reg error ';' - { yyerror(@2, "error: syntax error in reg variable list."); - yyerrok; - if ($1) delete $1; - } | attribute_list_opt K_integer error ';' { yyerror(@2, "error: syntax error in integer variable list."); yyerrok; @@ -1322,14 +1251,7 @@ block_item_decl { yyerror(@2, "error: syntax error in time variable list."); yyerrok; } - | attribute_list_opt K_real error ';' - { yyerror(@2, "error: syntax error in real variable list."); - yyerrok; - } - | attribute_list_opt K_realtime error ';' - { yyerror(@2, "error: syntax error in realtime variable list."); - yyerrok; - } + | K_parameter error ';' { yyerror(@1, "error: syntax error in parameter list."); yyerrok; @@ -3531,7 +3453,7 @@ module_item /* block_item_decl rule is shared with task blocks and named begin/end. */ - | block_item_decl + | block_item_decl /* */ @@ -4648,45 +4570,6 @@ variable_decl_assignment } ; -real_variable - : IDENTIFIER dimensions_opt - { perm_string name = lex_strings.make($1); - pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); - if ($2 != 0) { - index_component_t index; - if ($2->size() > 1) { - yyerror(@2, "sorry: only 1 dimensional arrays " - "are currently supported."); - } - index = $2->front(); - pform_set_reg_idx(name, index.msb, index.lsb); - delete $2; - } - $$ = $1; - } - | IDENTIFIER '=' expression - { perm_string name = lex_strings.make($1); - pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); - pform_make_reginit(@1, name, $3); - $$ = $1; - } - ; - -real_variable_list - : real_variable - { list*tmp = new list; - tmp->push_back(lex_strings.make($1)); - $$ = tmp; - delete[]$1; - } - | real_variable_list ',' real_variable - { list*tmp = $1; - tmp->push_back(lex_strings.make($3)); - $$ = tmp; - delete[]$3; - } - ; - net_variable : IDENTIFIER dimensions_opt { perm_string name = lex_strings.make($1); diff --git a/pform.cc b/pform.cc index cd909fb74..2a8653c60 100644 --- a/pform.cc +++ b/pform.cc @@ -1527,10 +1527,10 @@ static void pform_set_net_range(perm_string name, cur->set_data_type(dt); } -void pform_set_net_range(list*names, - list*range, - bool signed_flag, - ivl_variable_type_t dt) +static void pform_set_net_range(list*names, + list*range, + bool signed_flag, + ivl_variable_type_t dt) { assert((range == 0) || (range->size()%2 == 0)); @@ -2197,15 +2197,27 @@ svector*pform_make_task_ports(const struct vlltype&loc, data_type_t*vtype, list*names) { - atom2_type_t*atype = dynamic_cast (vtype); - if (atype == 0) { - VLerror(loc, "sorry: Given type not supported here."); - return 0; + if (atom2_type_t*atype = dynamic_cast (vtype)) { + list*range_tmp = make_range_from_width(atype->type_code); + return pform_make_task_ports(loc, pt, IVL_VT_BOOL, + atype->signed_flag, + range_tmp, names); } - list*range_tmp = make_range_from_width(atype->type_code); - return pform_make_task_ports(loc, pt, IVL_VT_BOOL, atype->signed_flag, - range_tmp, names); + if (vector_type_t*vec_type = dynamic_cast (vtype)) { + return pform_make_task_ports(loc, pt, vec_type->base_type, + vec_type->signed_flag, + copy_range(vec_type->pdims.get()), + names); + } + + if (real_type_t*real_type = dynamic_cast (vtype)) { + return pform_make_task_ports(loc, pt, IVL_VT_REAL, + true, 0, names); + } + + VLerror(loc, "sorry: Given type not supported here."); + return 0; } /* @@ -2608,6 +2620,18 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { + pform_set_net_range(names, vec_type->pdims.get(), + vec_type->signed_flag, + vec_type->base_type); + return; + } + + if (real_type_t*real_type = dynamic_cast (data_type)) { + pform_set_net_range(names, 0, true, IVL_VT_REAL); + return; + } + assert(0); } diff --git a/pform.h b/pform.h index addf61c94..0e2613715 100644 --- a/pform.h +++ b/pform.h @@ -118,6 +118,7 @@ struct lgate { }; extern std::list* make_range_from_width(uint64_t wid); +extern list* copy_range(list* orig); /* Use this function to transform the parted form of the attribute list to the attribute map that is used later. */ @@ -286,10 +287,6 @@ extern void pform_set_port_type(const struct vlltype&li, extern void pform_set_port_type(perm_string nm, NetNet::PortType pt, const char*file, unsigned lineno); -extern void pform_set_net_range(list*names, - list*, - bool signed_flag, - ivl_variable_type_t); extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); extern void pform_set_reg_time(list*names); diff --git a/pform_types.h b/pform_types.h index 047592edf..8ec228eaa 100644 --- a/pform_types.h +++ b/pform_types.h @@ -107,6 +107,19 @@ struct atom2_type_t : public data_type_t { bool signed_flag; }; +struct vector_type_t : public data_type_t { + inline explicit vector_type_t(ivl_variable_type_t bt, bool sf, list*pd) + : base_type(bt), signed_flag(sf), pdims(pd) { } + ivl_variable_type_t base_type; + bool signed_flag; + std::auto_ptr< list > pdims; +}; + +struct real_type_t : public data_type_t { + inline explicit real_type_t(int tc) : type_code(tc) { } + int type_code; +}; + /* * The pform_name_t is the general form for a hierarchical * identifier. It is an ordered list of name components. Each name From 481a9dec69f6bb05e6266b41780be4d2debbc678 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 26 Feb 2012 10:57:03 -0800 Subject: [PATCH 09/23] More rework to canonicalize tf_port_item rules. --- parse.y | 121 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 45 deletions(-) diff --git a/parse.y b/parse.y index eaf4064d5..d75a8fbe1 100644 --- a/parse.y +++ b/parse.y @@ -447,7 +447,7 @@ static void current_task_set_statement(vector*s) %type from_exclude %type number pos_neg_number -%type unsigned_signed_opt signed_unsigned_opt +%type signing unsigned_signed_opt signed_unsigned_opt %type K_automatic_opt K_packed_opt K_reg_opt K_virtual_opt %type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 @@ -670,18 +670,34 @@ data_type /* IEEE1800-2005: A.2.2.1 */ } ; + /* The data_type_or_implicit rule is a little more complex then the + rule documented in the IEEE format syntax in order to allow for + signaling the special case that the data_type is completely + absent. The context may need that information to decide to resort + to left context. */ + data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ : data_type { $$ = $1; } - | unsigned_signed_opt range_opt + | signing range_opt { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $1, $2); FILE_NAME(tmp, @1); $$ = tmp; } + | range + { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, false, $1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | + { $$ = 0; } ; + /* This implements the [ : INDENTIFIER ] part of the constructure + rule documented in IEEE1800-2005: A.1.8 */ endnew_opt : ':' K_new | ; + for_step /* IEEE1800-2005: A.6.8 */ : lpvalue '=' expression { PAssign*tmp = new PAssign($1,$3); @@ -824,12 +840,13 @@ port_direction /* IEEE1800-2005 A.1.3 */ } ; - /* port_direction_opt is used in places where the prot direction is - option, and defaults to input. */ + /* port_direction_opt is used in places where the port direction is + optional. The default direction is selected by the context, + which needs to notice the PIMPLICIT direction. */ port_direction_opt : port_direction { $$ = $1; } - | { $$ = NetNet::PINPUT; } + | { $$ = NetNet::PIMPLICIT; } ; /* real and realtime are exactly the same so save some code @@ -839,6 +856,11 @@ real_or_realtime | K_realtime ; +signing /* IEEE1800-2005: A.2.2.1 */ + : K_signed { $$ = true; } + | K_unsigned { $$ = false; } + ; + /* Many places where statements are allowed can actually take a statement or a null statement marked with a naked semi-colon. */ @@ -992,7 +1014,9 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ : port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = $1; + NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; + + port_declaration_context.port_type = use_port_type; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = true; delete port_declaration_context.range; @@ -1015,13 +1039,15 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ | port_direction_opt K_time IDENTIFIER range_opt tf_port_item_expr_opt { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = $1; + NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; + + port_declaration_context.port_type = use_port_type; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = false; delete port_declaration_context.range; port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_LOGIC, false, - range_stub, + svector*tmp = pform_make_task_ports(@3, use_port_type, IVL_VT_LOGIC, + false, range_stub, list_from_identifier($3)); $$ = tmp; if ($4) { @@ -1034,15 +1060,43 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ } } - | port_direction data_type_or_implicit IDENTIFIER range_opt tf_port_item_expr_opt - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_NO_TYPE; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - port_declaration_context.data_type = $2; - svector*tmp = pform_make_task_ports(@3, $1, $2, - list_from_identifier($3)); + | port_direction_opt data_type_or_implicit IDENTIFIER range_opt tf_port_item_expr_opt + { svector*tmp; + NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; + list* ilist = list_from_identifier($3); + + if (($2 == 0) && ($1==NetNet::PIMPLICIT)) { + // Detect special case this is an undecorated + // identifier and we need to get the declaration from + // left context. + if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { + tmp = pform_make_task_ports(@3, use_port_type, + port_declaration_context.data_type, + ilist); + } else { + tmp = pform_make_task_ports(@3, use_port_type, + port_declaration_context.var_type, + port_declaration_context.sign_flag, + copy_range(port_declaration_context.range), + ilist); + } + + } else { + // Otherwise, the decorations for this identifier + // indicate the type. Save the type for any right + // context thta may come later. + port_declaration_context.port_type = use_port_type; + port_declaration_context.var_type = IVL_VT_NO_TYPE; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = 0; + if ($2 == 0) { + $2 = new vector_type_t(IVL_VT_LOGIC, false, 0); + FILE_NAME($2, @3); + } + port_declaration_context.data_type = $2; + tmp = pform_make_task_ports(@3, $1, $2, ilist); + } $$ = tmp; if ($4) { yyerror(@4, "sorry: Port variable dimensions not supported yet."); @@ -1067,12 +1121,14 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ : tf_port_list ',' tf_port_item { svector*tmp; - if ($3) { + if ($1 && $3) { tmp = new svector(*$1, *$3); delete $1; delete $3; - } else { + } else if ($1) { tmp = $1; + } else { + tmp = $3; } $$ = tmp; } @@ -1080,31 +1136,6 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ | tf_port_item { $$ = $1; } - /* This rule handles the special case of a set of port items leading - an undecorated identifier. Undeconated identifiers in this case - pick up the details from the list to its lift. */ - - | tf_port_list ',' IDENTIFIER - { // The declaration is already parsed, apply it to IDENTIFIER - svector*new_decl; - if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { - assert(port_declaration_context.data_type); - new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, - port_declaration_context.data_type, - list_from_identifier($3)); - } else { - new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, - port_declaration_context.var_type, - port_declaration_context.sign_flag, - copy_range(port_declaration_context.range), - list_from_identifier($3)); - } - svector*tmp = new svector(*$1, *new_decl); - delete $1; - delete new_decl; - $$ = tmp; - } - /* Rules to handle some errors in tf_port_list items. */ | error ',' tf_port_item From ebda9777ccedec5c32b8211e5e85e75b53ffe419 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 26 Feb 2012 11:28:44 -0800 Subject: [PATCH 10/23] Parse foreach loops. --- parse.y | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/parse.y b/parse.y index d75a8fbe1..dbe116041 100644 --- a/parse.y +++ b/parse.y @@ -463,7 +463,7 @@ static void current_task_set_statement(vector*s) %type register_variable net_variable endname_opt %type register_variable_list net_variable_list -%type list_of_identifiers +%type list_of_identifiers loop_variables %type list_of_port_identifiers %type net_decl_assign net_decl_assigns @@ -786,6 +786,14 @@ loop_statement /* IEEE1800-2005: A.6.8 */ $$ = tmp; } + | K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' statement_or_null + { yyerror(@1, "sorry: foreach loops not supported"); + delete[]$3; + delete $5; + delete $8; + $$ = 0; + } + /* Error forms for loop statements. */ | K_for '(' lpvalue '=' expression ';' expression ';' error ')' @@ -810,6 +818,25 @@ loop_statement /* IEEE1800-2005: A.6.8 */ yyerror(@1, "error: Error in while loop condition."); } + | K_foreach '(' IDENTIFIER '[' error ']' ')' statement_or_null + { $$ = 0; + yyerror(@4, "error: Errors in foreach loop variables list."); + } + ; + +loop_variables /* IEEE1800-2005: A.6.8 */ + : loop_variables ',' IDENTIFIER + { list*tmp = $1; + tmp->push_back(lex_strings.make($3)); + delete[]$3; + $$ = tmp; + } + | IDENTIFIER + { list*tmp = new list; + tmp->push_back(lex_strings.make($1)); + delete[]$1; + $$ = tmp; + } ; non_integer_type /* IEEE1800-2005: A.2.2.1 */ From f33086fed4e4d07ffb78f109a55c873d3c7565ec Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 26 Feb 2012 18:45:22 -0800 Subject: [PATCH 11/23] Parse dynamic_array_new statements. --- parse.y | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/parse.y b/parse.y index dbe116041..d6f195985 100644 --- a/parse.y +++ b/parse.y @@ -496,7 +496,7 @@ static void current_task_set_statement(vector*s) %type hierarchy_identifier %type assignment_pattern expression expr_primary expr_mintypmax -%type inc_or_dec_expression lpvalue +%type dynamic_array_new inc_or_dec_expression lpvalue %type branch_probe_expression %type delay_value delay_value_simple %type delay1 delay3 delay3_opt delay_value_list @@ -697,6 +697,19 @@ data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ rule documented in IEEE1800-2005: A.1.8 */ endnew_opt : ':' K_new | ; + /* The dynamic_array_new rule is kinda like an expression, but it is + treated differently by rules that use this "expression". Watch out! */ + +dynamic_array_new /* IEEE1800-2005: A.2.4 */ + : K_new '[' expression ']' + { yyerror(@1, "sorry: Dynamic array new expression not supported."); + $$ = 0; + } + | K_new '[' expression ']' '(' expression ')' + { yyerror(@1, "sorry: Dynamic array new expression not supported."); + $$ = 0; + } + ; for_step /* IEEE1800-2005: A.6.8 */ : lpvalue '=' expression @@ -5262,6 +5275,16 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } + /* The IEEE1800 standard defines dynamic_array_new assignment as a + different rule from regular assignment. That implies that the + dynamic_array_new is not an expression in general, which makes + some sense. Elaboration should make sure the lpvalue is an array name. */ + + | lpvalue '=' dynamic_array_new ';' + { PAssign*tmp = new PAssign($1,$3); + FILE_NAME(tmp, @1); + $$ = tmp; + } | K_wait '(' expression ')' statement_or_null { PEventStatement*tmp; From 68eab8c66482b0eccc0aa1e6a824d322362c3d7b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 26 Feb 2012 19:16:10 -0800 Subject: [PATCH 12/23] Parse function declarations in classes. Also add support for function end names when parsing SystemVerilog. --- parse.y | 187 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 113 insertions(+), 74 deletions(-) diff --git a/parse.y b/parse.y index d6f195985..628def334 100644 --- a/parse.y +++ b/parse.y @@ -632,6 +632,8 @@ class_item /* IEEE1800-2005: A.1.8 */ | task_declaration + | function_declaration + /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ @@ -724,6 +726,116 @@ for_step /* IEEE1800-2005: A.6.8 */ ; + /* The function declaration rule matches the function declaration + header, then pushes the function scope. This causes the + definitions in the func_body to take on the scope of the function + instead of the module. */ +function_declaration /* IEEE1800-2005: A.2.6 */ + : K_function K_automatic_opt function_range_or_type_opt IDENTIFIER ';' + { assert(current_function == 0); + current_function = pform_push_function_scope(@1, $4, $2); + } + function_item_list statement_list + K_endfunction + { current_function->set_ports($7); + current_function->set_return($3); + assert($8 && $8->size() > 0); + if ($8->size() == 1) { + current_function->set_statement((*$8)[0]); + delete $8; + } else { + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, @8); + tmp->set_statement( *$8 ); + current_function->set_statement(tmp); + delete $8; + if (!gn_system_verilog()) { + yyerror(@8, "error: Function body with multiple statements requres SystemVerilog."); + } + } + pform_pop_scope(); + current_function = 0; + } + endname_opt + { // Last step: check any closing name. + if ($11 && (strcmp($4,$11) != 0)) { + yyerror(@11, "error: End name doesn't match function name"); + } + if ($11 && !gn_system_verilog()) { + yyerror(@11, "error: Function end names require System Verilog."); + } + delete[]$4; + if ($11) delete[]$11; + } + + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER + { assert(current_function == 0); + current_function = pform_push_function_scope(@1, $4, $2); + } + '(' tf_port_list_opt ')' ';' + block_item_decls_opt + statement_list + K_endfunction + { current_function->set_ports($7); + current_function->set_return($3); + assert($11 && $11->size() > 0); + if ($11->size() == 1) { + current_function->set_statement((*$11)[0]); + delete $11; + } else { + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, @11); + tmp->set_statement( *$11 ); + current_function->set_statement(tmp); + delete $11; + if (!gn_system_verilog()) { + yyerror(@11, "error: Function body with multiple statements requres SystemVerilog."); + } + } + pform_pop_scope(); + current_function = 0; + if ($7==0 && !gn_system_verilog()) { + yyerror(@4, "error: Empty parenthesis syntax requires SystemVerilog."); + } + } + endname_opt + { // Last step: check any closing name. + if ($14 && (strcmp($4,$14) != 0)) { + yyerror(@14, "error: End name doesn't match function name"); + } + if ($14 && !gn_system_verilog()) { + yyerror(@14, "error: Function end names require System Verilog."); + } + delete[]$4; + if ($14) delete[]$14; + } + + /* Detect and recover from some errors. */ + + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction + { /* */ + if (current_function) { + pform_pop_scope(); + current_function = 0; + } + assert(current_function == 0); + yyerror(@1, "error: Syntax error defining function."); + yyerrok; + } + endname_opt + { // Last step: check any closing name. + if ($8 && (strcmp($4,$8) != 0)) { + yyerror(@4, "error: End name doesn't match function name"); + } + if ($8 && !gn_system_verilog()) { + yyerror(@8, "error: Function end names require System Verilog."); + } + delete[]$4; + if ($8) delete[]$8; + } + + ; + implicit_class_handle /* IEEE1800-2005: A.8.4 */ : K_this | K_super @@ -3643,80 +3755,7 @@ module_item | task_declaration - /* The function declaration rule matches the function declaration - header, then pushes the function scope. This causes the - definitions in the func_body to take on the scope of the function - instead of the module. */ - - | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER ';' - { assert(current_function == 0); - current_function = pform_push_function_scope(@1, $4, $2); - } - function_item_list statement_list - K_endfunction - { current_function->set_ports($7); - current_function->set_return($3); - assert($8 && $8->size() > 0); - if ($8->size() == 1) { - current_function->set_statement((*$8)[0]); - delete $8; - } else { - PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @8); - tmp->set_statement( *$8 ); - current_function->set_statement(tmp); - delete $8; - if (!gn_system_verilog()) { - yyerror(@8, "error: Function body with multiple statements requres SystemVerilog."); - } - } - pform_pop_scope(); - current_function = 0; - delete[]$4; - } - - | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER - { assert(current_function == 0); - current_function = pform_push_function_scope(@1, $4, $2); - } - '(' tf_port_list_opt ')' ';' - block_item_decls_opt - statement_list - K_endfunction - { current_function->set_ports($7); - current_function->set_return($3); - assert($11 && $11->size() > 0); - if ($11->size() == 1) { - current_function->set_statement((*$11)[0]); - delete $11; - } else { - PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @11); - tmp->set_statement( *$11 ); - current_function->set_statement(tmp); - delete $11; - if (!gn_system_verilog()) { - yyerror(@11, "error: Function body with multiple statements requres SystemVerilog."); - } - } - pform_pop_scope(); - current_function = 0; - delete[]$4; - if ($7==0 && !gn_system_verilog()) { - yyerror(@4, "error: Empty parenthesis syntax requires SystemVerilog."); - } - } - | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction - { /* */ - if (current_function) { - pform_pop_scope(); - current_function = 0; - } - assert(current_function == 0); - yyerror(@1, "error: Syntax error defining function."); - yyerrok; - delete[]$4; - } + | function_declaration /* A generate region can contain further module items. Actually, it is supposed to be limited to certain kinds of module items, but From dbc58838d5cde832c0201f74578c620146bcd6f2 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 1 Mar 2012 18:17:52 -0800 Subject: [PATCH 13/23] Parse class extends syntax and property qualifiers. --- parse.y | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/parse.y b/parse.y index 628def334..15b6685c8 100644 --- a/parse.y +++ b/parse.y @@ -462,6 +462,7 @@ static void current_task_set_statement(vector*s) %type udp_initial_expr_opt %type register_variable net_variable endname_opt +%type class_declaration_extends_opt %type register_variable_list net_variable_list %type list_of_identifiers loop_variables %type list_of_port_identifiers @@ -592,23 +593,44 @@ assignment_pattern /* IEEE1800-2005: A.6.7.1 */ ; class_declaration /* IEEE1800-2005: A.1.2 */ - : K_virtual_opt K_class IDENTIFIER ';' - class_items_opt K_endclass endname_opt + : K_virtual_opt K_class IDENTIFIER class_declaration_extends_opt ';' + class_items_opt K_endclass { // Process a class - if ($7 && strcmp($3,$7)!=0) { - yyerror(@7, "error: Class end name doesn't match class name."); - delete[]$7; + if ($4) { + yyerror(@4, "sorry: Class extends not supported yet."); + delete[]$4; } yyerror(@2, "sorry: Class declarations not supported yet."); } + endname_opt + { + if ($9 && strcmp($3,$9)!=0) { + yyerror(@9, "error: Class end name doesn't match class name."); + delete[]$9; + } + delete[]$3; + } ; -class_items_opt + /* This rule implements [ extends class_type ] in the + class_declaration. It is not a rule of its own in the LRM. */ + +class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */ + : K_extends IDENTIFIER + { $$ = $2; } + | + { $$ = 0; } + ; + + /* The class_items_opt and class_items rules together implement the + rule snippet { class_item } (zero or more class_item) of the + class_declaration. */ +class_items_opt /* IEEE1800-2005: A.1.2 */ : class_items | ; -class_items +class_items /* IEEE1800-2005: A.1.2 */ : class_items class_item | class_item ; @@ -625,7 +647,7 @@ class_item /* IEEE1800-2005: A.1.8 */ /* Class properties... */ - | data_type list_of_variable_decl_assignments ';' + | property_qualifier_opt data_type list_of_variable_decl_assignments ';' /* Class methods... */ @@ -642,6 +664,17 @@ class_item /* IEEE1800-2005: A.1.8 */ yyerrok; } + | error ';' + { yyerror(@2, "error: invalid class item."); + yyerrok; + } + + ; + +class_item_qualifier /* IEEE1800-2005 A.1.8 */ + : K_static + | K_protected + | K_local ; data_type /* IEEE1800-2005: A.2.2.1 */ @@ -1001,6 +1034,30 @@ port_direction_opt | { $$ = NetNet::PIMPLICIT; } ; + /* The property_qualifier rule is as literally described in the LRM, + but the use is usually as { property_qualifier }, which is + implemented bt the property_qualifier_opt rule below. */ + +property_qualifier /* IEEE1800-2005 A.1.8 */ + : class_item_qualifier + | random_qualifier + ; + +property_qualifier_opt /* IEEE1800-2005 A.1.8: ... { property_qualifier } */ + : property_qualifier_list + | + ; + +property_qualifier_list /* IEEE1800-2005 A.1.8 */ + : property_qualifier_list property_qualifier + | property_qualifier + ; + +random_qualifier /* IEEE1800-2005 A.1.8 */ + : K_rand + | K_randc + ; + /* real and realtime are exactly the same so save some code * with a common matching rule. */ real_or_realtime From 64ea3288233b3701f60d1e54550f1a654159fdbc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 1 Mar 2012 18:48:16 -0800 Subject: [PATCH 14/23] Parse dynamic array declarations. --- parse.y | 84 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/parse.y b/parse.y index 15b6685c8..02a458b28 100644 --- a/parse.y +++ b/parse.y @@ -982,6 +982,56 @@ loop_statement /* IEEE1800-2005: A.6.8 */ } ; + +/* TODO: Replace register_variable_list with list_of_variable_decl_assignments. */ +list_of_variable_decl_assignments /* IEEE1800-2005 A.2.3 */ + : variable_decl_assignment + { list*tmp = new list; + tmp->push_back($1); + $$ = tmp; + } + | list_of_variable_decl_assignments ',' variable_decl_assignment + { list*tmp = $1; + tmp->push_back($3); + $$ = tmp; + } + ; + +variable_decl_assignment /* IEEE1800-2005 A.2.3 */ + : IDENTIFIER dimensions_opt + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + if ($2) { + tmp->index = *$2; + delete $2; + } + delete[]$1; + $$ = tmp; + } + | IDENTIFIER '=' expression + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + tmp->expr .reset($3); + delete[]$1; + $$ = tmp; + } + | IDENTIFIER '[' ']' + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + yyerror("sorry: Dynamic arrays not yet supported here."); + delete[]$1; + $$ = tmp; + } + | IDENTIFIER '[' '$' ']' + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + yyerror("sorry: Queue dimensions not yet supported here."); + delete[]$1; + $$ = tmp; + } + ; + + loop_variables /* IEEE1800-2005: A.6.8 */ : loop_variables ',' IDENTIFIER { list*tmp = $1; @@ -4703,40 +4753,6 @@ register_variable_list } ; -/* TODO: Replace register_variable_list with list_of_variable_decl_assignments. */ -list_of_variable_decl_assignments - : variable_decl_assignment - { list*tmp = new list; - tmp->push_back($1); - $$ = tmp; - } - | list_of_variable_decl_assignments ',' variable_decl_assignment - { list*tmp = $1; - tmp->push_back($3); - $$ = tmp; - } - ; - -variable_decl_assignment - : IDENTIFIER dimensions_opt - { decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = lex_strings.make($1); - if ($2) { - tmp->index = *$2; - delete $2; - } - delete[]$1; - $$ = tmp; - } - | IDENTIFIER '=' expression - { decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = lex_strings.make($1); - tmp->expr .reset($3); - delete[]$1; - $$ = tmp; - } - ; - net_variable : IDENTIFIER dimensions_opt { perm_string name = lex_strings.make($1); From f749867369a26bb52c7b9d3ba8af9c19b601eeac Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 2 Mar 2012 18:34:43 -0800 Subject: [PATCH 15/23] Rework rules for variable_dimensions, and support more syntax. --- PTask.h | 4 +- elab_scope.cc | 9 +- elab_sig.cc | 33 +++--- parse.y | 316 ++++++++++++++++++++++++-------------------------- pform.cc | 77 ++++++------ pform.h | 26 ++--- pform_types.h | 11 +- 7 files changed, 229 insertions(+), 247 deletions(-) diff --git a/PTask.h b/PTask.h index b06375dfc..4cd6a9a22 100644 --- a/PTask.h +++ b/PTask.h @@ -1,7 +1,7 @@ #ifndef __PTask_H #define __PTask_H /* - * Copyright (c) 1999-2008,2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2008,2010,2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -46,7 +46,7 @@ enum PTaskFuncEnum { struct PTaskFuncArg { PTaskFuncEnum type; - vector*range; + std::list*range; }; /* diff --git a/elab_scope.cc b/elab_scope.cc index a93c9a08c..efce812c6 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -133,9 +133,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, enum_type_t*enum_type) { bool rc_flag; - assert(enum_type->range->size() == 2); - NetExpr*msb_ex = elab_and_eval(des, scope, enum_type->range->front(), -1); - NetExpr*lsb_ex = elab_and_eval(des, scope, enum_type->range->back(), -1); + assert(enum_type->range->size() == 1); + index_component_t index = enum_type->range->front(); + NetExpr*msb_ex = elab_and_eval(des, scope, index.msb, -1); + NetExpr*lsb_ex = elab_and_eval(des, scope, index.lsb, -1); long msb = 0; rc_flag = eval_as_long(msb, msb_ex); diff --git a/elab_sig.cc b/elab_sig.cc index 42ed8c355..1a00cb786 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -476,15 +476,12 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const case PTF_REG: case PTF_REG_S: if (return_type_.range) { - ivl_assert(*this, return_type_.range->size() == 2); + ivl_assert(*this, return_type_.range->size() == 1); + index_component_t index = return_type_.range->front(); - NetExpr*me = elab_and_eval(des, scope, - return_type_.range->at(0), -1, - true); + NetExpr*me = elab_and_eval(des, scope, index.msb, -1, true); assert(me); - NetExpr*le = elab_and_eval(des, scope, - return_type_.range->at(1), -1, - true); + NetExpr*le = elab_and_eval(des, scope, index.lsb, -1, true); assert(le); long mnum = 0, lnum = 0; @@ -550,17 +547,14 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const case PTF_ATOM2: case PTF_ATOM2_S: - ivl_assert(*this, return_type_.range != 0); long use_wid; { - NetExpr*me = elab_and_eval(des, scope, - (*return_type_.range)[0], -1, - true); - assert(me); - NetExpr*le = elab_and_eval(des, scope, - (*return_type_.range)[1], -1, - true); - assert(le); + ivl_assert(*this, return_type_.range->size() == 1); + index_component_t index = return_type_.range->front(); + NetExpr*me = elab_and_eval(des, scope, index.msb, -1, true); + ivl_assert(*this, me); + NetExpr*le = elab_and_eval(des, scope, index.lsb, -1, true); + ivl_assert(*this, le); long mnum = 0, lnum = 0; if ( ! get_const_argument(me, mnum) ) { @@ -805,9 +799,10 @@ static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, long use_msb = 0; long use_lsb = 0; if (curp->range.get() && ! curp->range->empty()) { - ivl_assert(*curp, curp->range->size() == 2); - PExpr*msb_pex = curp->range->front(); - PExpr*lsb_pex = curp->range->back(); + ivl_assert(*curp, curp->range->size() == 1); + index_component_t index = curp->range->front(); + PExpr*msb_pex = index.msb; + PExpr*lsb_pex = index.lsb; NetExpr*tmp = elab_and_eval(des, scope, msb_pex, -2, true); ivl_assert(*curp, tmp); diff --git a/parse.y b/parse.y index 02a458b28..411875217 100644 --- a/parse.y +++ b/parse.y @@ -38,7 +38,7 @@ extern void lex_end_table(); bool have_timeunit_decl = false; bool have_timeprec_decl = false; -static list* param_active_range = 0; +static list* param_active_range = 0; static bool param_active_signed = false; static ivl_variable_type_t param_active_type = IVL_VT_LOGIC; @@ -48,7 +48,7 @@ static struct { NetNet::PortType port_type; ivl_variable_type_t var_type; bool sign_flag; - list* range; + list* range; data_type_t* data_type; } port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, false, 0, 0}; @@ -98,8 +98,7 @@ static list >* make_port_list(char*id, PExpr*expr) delete[]id; return tmp; } -static list >* make_port_list(list >*tmp, +static list >* make_port_list(list >*tmp, char*id, PExpr*expr) { tmp->push_back(make_pair(lex_strings.make(id), expr)); @@ -107,16 +106,19 @@ static list >* make_port_list(list* make_range_from_width(uint64_t wid) +list* make_range_from_width(uint64_t wid) { - list*range = new list; + list*range = new list; - range->push_back(new PENumber(new verinum(wid-1, integer_width))); - range->push_back(new PENumber(new verinum((uint64_t)0, integer_width))); + index_component_t tmp; + tmp.msb = new PENumber(new verinum(wid-1, integer_width)); + tmp.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); + range->push_back(tmp); return range; } +#if 0 /* * Make a range vector from an existing pair of expressions. */ @@ -129,7 +131,8 @@ static vector* make_range_vector(list*that) delete that; return tmp; } - +#endif +#if 0 /* * Make a range vector from a width. Generate the msb and lsb * expressions to get the canonical range for the given width. @@ -141,7 +144,7 @@ static vector* make_range_vector(uint64_t wid) tmp->at(1) = new PENumber(new verinum((uint64_t)0, integer_width)); return tmp; } - +#endif static list* list_from_identifier(char*id) { list*tmp = new list; @@ -157,12 +160,12 @@ static list* list_from_identifier(list*tmp, char*id) return tmp; } -list* copy_range(list* orig) +list* copy_range(list* orig) { - list*copy = 0; + list*copy = 0; if (orig) - copy = new list (*orig); + copy = new list (*orig); return copy; } @@ -512,8 +515,8 @@ static void current_task_set_statement(vector*s) %type struct_union_member_list %type struct_data_type -%type range range_opt variable_dimension -%type dimensions_opt dimensions +%type range range_opt +%type dimensions_opt dimensions variable_dimension %type net_type var_type net_type_opt %type gatetype switchtype %type port_direction port_direction_opt @@ -1015,13 +1018,6 @@ variable_decl_assignment /* IEEE1800-2005 A.2.3 */ delete[]$1; $$ = tmp; } - | IDENTIFIER '[' ']' - { decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = lex_strings.make($1); - yyerror("sorry: Dynamic arrays not yet supported here."); - delete[]$1; - $$ = tmp; - } | IDENTIFIER '[' '$' ']' { decl_assignment_t*tmp = new decl_assignment_t; tmp->name = lex_strings.make($1); @@ -1272,7 +1268,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ /* Ports can be integer with a width of [31:0]. */ : port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt - { list*range_stub = make_range_from_width(integer_width); + { list*range_stub = make_range_from_width(integer_width); NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; port_declaration_context.port_type = use_port_type; @@ -1297,7 +1293,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ /* Ports can be time with a width of [63:0] (unsigned). */ | port_direction_opt K_time IDENTIFIER range_opt tf_port_item_expr_opt - { list*range_stub = make_range_from_width(64); + { list*range_stub = make_range_from_width(64); NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; port_declaration_context.port_type = use_port_type; @@ -1414,18 +1410,39 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ variable_dimension /* IEEE1800-2005: A.2.5 */ : '[' expression ':' expression ']' - { list*tmp = new list; - tmp->push_back($2); - tmp->push_back($4); + { list *tmp = new list; + index_component_t index; + index.sel = index_component_t::SEL_PART; + index.msb = $2; + index.lsb = $4; + tmp->push_back(index); + $$ = tmp; + } + | '[' expression ']' + { // SystemVerilog canonical range + if (generation_flag < GN_VER2005_SV) { + warn_count += 1; + cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. " + << "Use at least -g2005-sv to remove this warning." << endl; + } + list *tmp = new list; + index_component_t index; + index.sel = index_component_t::SEL_PART; + index.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); + index.msb = new PEBinary('-', $2, new PENumber(new verinum((uint64_t)1, integer_width))); + tmp->push_back(index); $$ = tmp; } | '[' ']' - { list*tmp = new list; - tmp->push_back(0); - tmp->push_back(0); + { list *tmp = new list; + index_component_t index; + index.msb = 0; + index.lsb = 0; + yyerror("sorry: Dynamic array ranges not supported."); + tmp->push_back(index); $$ = tmp; } -; + ; /* Verilog-2001 supports attribute lists, which can be attached to a variety of different objects. The syntax inside the (* *) is a @@ -2822,20 +2839,21 @@ gate_instance $$ = tmp; } - | IDENTIFIER range '(' expression_list_with_nuls ')' - { lgate*tmp = new lgate; - list*rng = $2; - tmp->name = $1; - tmp->parms = $4; - tmp->range[0] = rng->front(); rng->pop_front(); - tmp->range[1] = rng->front(); rng->pop_front(); - assert(rng->empty()); - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - delete rng; - $$ = tmp; - } + | IDENTIFIER range '(' expression_list_with_nuls ')' + { lgate*tmp = new lgate; + list*rng = $2; + tmp->name = $1; + tmp->parms = $4; + tmp->range = rng->front(); + rng->pop_front(); + assert(rng->empty()); + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + delete rng; + $$ = tmp; + } + | '(' expression_list_with_nuls ')' { lgate*tmp = new lgate; tmp->name = ""; @@ -2847,50 +2865,50 @@ gate_instance /* Degenerate modules can have no ports. */ - | IDENTIFIER range - { lgate*tmp = new lgate; - list*rng = $2; - tmp->name = $1; - tmp->parms = 0; - tmp->parms_by_name = 0; - tmp->range[0] = rng->front(); rng->pop_front(); - tmp->range[1] = rng->front(); rng->pop_front(); - assert(rng->empty()); - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - delete rng; - $$ = tmp; - } + | IDENTIFIER range + { lgate*tmp = new lgate; + list*rng = $2; + tmp->name = $1; + tmp->parms = 0; + tmp->parms_by_name = 0; + tmp->range = rng->front(); + rng->pop_front(); + assert(rng->empty()); + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + delete rng; + $$ = tmp; + } /* Modules can also take ports by port-name expressions. */ - | IDENTIFIER '(' port_name_list ')' - { lgate*tmp = new lgate; - tmp->name = $1; - tmp->parms = 0; - tmp->parms_by_name = $3; - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - $$ = tmp; - } + | IDENTIFIER '(' port_name_list ')' + { lgate*tmp = new lgate; + tmp->name = $1; + tmp->parms = 0; + tmp->parms_by_name = $3; + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + $$ = tmp; + } - | IDENTIFIER range '(' port_name_list ')' - { lgate*tmp = new lgate; - list*rng = $2; - tmp->name = $1; - tmp->parms = 0; - tmp->parms_by_name = $4; - tmp->range[0] = rng->front(); rng->pop_front(); - tmp->range[1] = rng->front(); rng->pop_front(); - assert(rng->empty()); - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - delete rng; - $$ = tmp; - } + | IDENTIFIER range '(' port_name_list ')' + { lgate*tmp = new lgate; + list*rng = $2; + tmp->name = $1; + tmp->parms = 0; + tmp->parms_by_name = $4; + tmp->range = rng->front(); + rng->pop_front(); + assert(rng->empty()); + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + delete rng; + $$ = tmp; + } | IDENTIFIER '(' error ')' { lgate*tmp = new lgate; @@ -3143,7 +3161,7 @@ port_declaration K_input atom2_type signed_unsigned_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list*use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::PINPUT, @@ -3289,7 +3307,7 @@ port_declaration K_output atom2_type signed_unsigned_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list*use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::POUTPUT, @@ -3308,7 +3326,7 @@ port_declaration K_output atom2_type signed_unsigned_opt IDENTIFIER '=' expression { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list*use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::POUTPUT, @@ -4606,9 +4624,13 @@ port_reference_list /* The range is a list of variable dimensions. */ range : variable_dimension + { $$ = $1; } | range variable_dimension - { list*tmp = $1; - if ($2) tmp->splice(tmp->end(), *$2); + { list*tmp = $1; + if ($2) { + tmp->splice(tmp->end(), *$2); + delete $2; + } $$ = tmp; } ; @@ -4623,88 +4645,54 @@ dimensions_opt | dimensions { $$ = $1; } dimensions - : '[' expression ':' expression ']' - { list *tmp = new list; - index_component_t index; - index.msb = $2; - index.lsb = $4; - tmp->push_back(index); - $$ = tmp; - } - | '[' expression ']' - { if (generation_flag < GN_VER2005_SV) { - warn_count += 1; - cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. " - << "Use at least -g2005-sv to remove this warning." << endl; - } - list *tmp = new list; - index_component_t index; - index.msb = new PENumber(new verinum((uint64_t)0, integer_width)); - index.lsb = new PEBinary('-', $2, new PENumber(new verinum((uint64_t)1, integer_width))); - tmp->push_back(index); - $$ = tmp; - } - | dimensions '[' expression ':' expression ']' - { list *tmp = $1; - index_component_t index; - index.msb = $3; - index.lsb = $5; - tmp->push_back(index); - $$ = tmp; - } - | dimensions '[' expression ']' - { if (generation_flag < GN_VER2005_SV) { - warn_count += 1; - cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. " - << "Use at least -g2005-sv to remove this warning." << endl; - } - list *tmp = $1; - index_component_t index; - index.msb = new PENumber(new verinum((uint64_t)0, integer_width)); - index.lsb = new PEBinary('-', $3, new PENumber(new verinum((uint64_t)1, integer_width))); - tmp->push_back(index); - $$ = tmp; - } + : variable_dimension + { $$ = $1; } + | dimensions variable_dimension + { list *tmp = $1; + if ($2) { + tmp->splice(tmp->end(), *$2); + delete $2; + } + $$ = tmp; + } + ; /* This is used to express the return type of a function. */ function_range_or_type_opt : unsigned_signed_opt range_opt - { - /* the default type is reg unsigned and no range */ - $$.type = PTF_REG; - $$.range = 0; - if ($1) - $$.type = PTF_REG_S; - if ($2) - $$.range = make_range_vector($2); - } + { /* the default type is reg unsigned and no range */ + $$.type = PTF_REG; + $$.range = 0; + if ($1) + $$.type = PTF_REG_S; + if ($2) + $$.range = $2; + } | K_reg unsigned_signed_opt range_opt - { - /* the default type is reg unsigned and no range */ - $$.type = PTF_REG; - $$.range = 0; - if ($2) - $$.type = PTF_REG_S; - if ($3) - $$.range = make_range_vector($3); - } + { /* the default type is reg unsigned and no range */ + $$.type = PTF_REG; + $$.range = 0; + if ($2) + $$.type = PTF_REG_S; + if ($3) + $$.range = $3; + } | bit_logic unsigned_signed_opt range_opt - { - /* the default type is bit/logic unsigned and no range */ - $$.type = PTF_REG; - $$.range = 0; - if ($2) - $$.type = PTF_REG_S; - if ($3) - $$.range = make_range_vector($3); - } + { /* the default type is bit/logic unsigned and no range */ + $$.type = PTF_REG; + $$.range = 0; + if ($2) + $$.type = PTF_REG_S; + if ($3) + $$.range = $3; + } | K_integer { $$.range = 0; $$.type = PTF_INTEGER; } | K_real { $$.range = 0; $$.type = PTF_REAL; } | K_realtime { $$.range = 0; $$.type = PTF_REALTIME; } | K_time { $$.range = 0; $$.type = PTF_TIME; } - | atom2_type { $$.range = make_range_vector($1); $$.type = PTF_ATOM2_S; } - | atom2_type K_signed { $$.range = make_range_vector($1); $$.type = PTF_ATOM2_S; } - | atom2_type K_unsigned { $$.range = make_range_vector($1); $$.type = PTF_ATOM2; } + | atom2_type { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } + | atom2_type K_signed { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } + | atom2_type K_unsigned { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2; } ; /* The register_variable rule is matched only when I am parsing @@ -5577,7 +5565,7 @@ task_port_item shape. Generate a range ([31:0]) to make it work. */ | port_direction K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); + { list*range_stub = make_range_from_width(integer_width); svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, range_stub, $3, true); $$ = tmp; @@ -5586,7 +5574,7 @@ task_port_item /* Ports can be time with a width of [63:0] (unsigned). */ | port_direction K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); + { list*range_stub = make_range_from_width(64); svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, range_stub, $3); $$ = tmp; diff --git a/pform.cc b/pform.cc index 2a8653c60..d500bf7ff 100644 --- a/pform.cc +++ b/pform.cc @@ -1480,16 +1480,15 @@ void pform_make_udp(perm_string name, bool synchronous_flag, delete init_expr; } -static void ranges_from_list(list&rlist, const list*range) +static void ranges_from_list(list&rlist, + const list*range) { - // There must be an even number of expressions in the - // range. The parser will assure that for us. - assert(range->size()%2 == 0); - list::const_iterator rcur = range->begin(); - while (rcur != range->end()) { + // Convert a list of index_component_t to PWire::range_t. + for (list::const_iterator rcur = range->begin() + ; rcur != range->end() ; ++rcur) { PWire::range_t rng; - rng.msb = *rcur; ++rcur; - rng.lsb = *rcur; ++rcur; + rng.msb = rcur->msb; + rng.lsb = rcur->lsb; rlist.push_back(rng); } } @@ -1500,7 +1499,7 @@ static void ranges_from_list(list&rlist, const list*rang * and the name that I receive only has the tail component. */ static void pform_set_net_range(perm_string name, - const list*range, + const list*range, bool signed_flag, ivl_variable_type_t dt, PWSRType rt) @@ -1528,12 +1527,10 @@ static void pform_set_net_range(perm_string name, } static void pform_set_net_range(list*names, - list*range, + list*range, bool signed_flag, ivl_variable_type_t dt) { - assert((range == 0) || (range->size()%2 == 0)); - for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; @@ -1601,8 +1598,8 @@ static void pform_makegate(PGBuiltin::Type type, perm_string dev_name = lex_strings.make(info.name); PGBuiltin*cur = new PGBuiltin(type, dev_name, info.parms, delay); - if (info.range[0]) - cur->set_range(info.range[0], info.range[1]); + if (info.range.msb) + cur->set_range(info.range.msb, info.range.lsb); // The pform_makegates() that calls me will take care of // deleting the attr pointer, so tell the @@ -1741,7 +1738,7 @@ void pform_make_modgates(perm_string type, if (cur.parms_by_name) { pform_make_modgate(type, cur_name, overrides, cur.parms_by_name, - cur.range[0], cur.range[1], + cur.range.msb, cur.range.lsb, cur.file, cur.lineno); } else if (cur.parms) { @@ -1755,14 +1752,14 @@ void pform_make_modgates(perm_string type, } pform_make_modgate(type, cur_name, overrides, cur.parms, - cur.range[0], cur.range[1], + cur.range.msb, cur.range.lsb, cur.file, cur.lineno); } else { list*wires = new list; pform_make_modgate(type, cur_name, overrides, wires, - cur.range[0], cur.range[1], + cur.range.msb, cur.range.lsb, cur.file, cur.lineno); } } @@ -1875,7 +1872,7 @@ void pform_module_define_port(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t data_type, bool signed_flag, - list*range, + list*range, list*attr) { PWire*cur = pform_get_wire_in_scope(name); @@ -2011,7 +2008,7 @@ void pform_makewire(const vlltype&li, perm_string name, * pform_makewire above. */ void pform_makewire(const vlltype&li, - list*range, + list*range, bool signed_flag, list*names, NetNet::Type type, @@ -2038,7 +2035,7 @@ void pform_makewire(const vlltype&li, * This form makes nets with delays and continuous assignments. */ void pform_makewire(const vlltype&li, - list*range, + list*range, bool signed_flag, list*delay, str_pair_t str, @@ -2149,7 +2146,7 @@ svector*pform_make_task_ports(const struct vlltype&loc, NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, - list*range, + list*range, list*names, bool isint) { @@ -2198,7 +2195,7 @@ svector*pform_make_task_ports(const struct vlltype&loc, list*names) { if (atom2_type_t*atype = dynamic_cast (vtype)) { - list*range_tmp = make_range_from_width(atype->type_code); + list*range_tmp = make_range_from_width(atype->type_code); return pform_make_task_ports(loc, pt, IVL_VT_BOOL, atype->signed_flag, range_tmp, names); @@ -2211,7 +2208,7 @@ svector*pform_make_task_ports(const struct vlltype&loc, names); } - if (real_type_t*real_type = dynamic_cast (vtype)) { + if (/*real_type_t*real_type = */ dynamic_cast (vtype)) { return pform_make_task_ports(loc, pt, IVL_VT_REAL, true, 0, names); } @@ -2325,7 +2322,7 @@ LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag, void pform_set_parameter(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, - bool signed_flag, list*range, PExpr*expr, + bool signed_flag, list*range, PExpr*expr, LexicalScope::range_t*value_range) { LexicalScope*scope = lexical_scope; @@ -2360,11 +2357,12 @@ void pform_set_parameter(const struct vlltype&loc, parm.type = type; if (range) { - assert(range->size() == 2); - assert(range->front()); - assert(range->back()); - parm.msb = range->front(); - parm.lsb = range->back(); + assert(range->size() == 1); + index_component_t index = range->front(); + assert(index.msb); + assert(index.lsb); + parm.msb = index.msb; + parm.lsb = index.lsb; } else { parm.msb = 0; parm.lsb = 0; @@ -2378,7 +2376,7 @@ void pform_set_parameter(const struct vlltype&loc, void pform_set_localparam(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, - bool signed_flag, list*range, PExpr*expr) + bool signed_flag, list*range, PExpr*expr) { LexicalScope*scope = lexical_scope; @@ -2408,11 +2406,12 @@ void pform_set_localparam(const struct vlltype&loc, parm.type = type; if (range) { - assert(range->size() == 2); - assert(range->front()); - assert(range->back()); - parm.msb = range->front(); - parm.lsb = range->back(); + assert(range->size() == 1); + index_component_t index = range->front(); + assert(index.msb); + assert(index.lsb); + parm.msb = index.msb; + parm.lsb = index.lsb; } else { parm.msb = 0; parm.lsb = 0; @@ -2511,7 +2510,7 @@ extern void pform_module_specify_path(PSpecPath*obj) void pform_set_port_type(const struct vlltype&li, list*names, - list*range, + list*range, bool signed_flag, NetNet::PortType pt) { @@ -2627,7 +2626,7 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { + if (/*real_type_t*real_type =*/ dynamic_cast (data_type)) { pform_set_net_range(names, 0, true, IVL_VT_REAL); return; } @@ -2645,7 +2644,7 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, cur->set_signed(enum_type->signed_flag); assert(enum_type->range.get() != 0); - assert(enum_type->range->size() == 2); + assert(enum_type->range->size() == 1); listrlist; ranges_from_list(rlist, enum_type->range.get()); cur->set_range(rlist, SR_NET); @@ -2659,7 +2658,7 @@ void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, listbase_type==IVL_VT_LOGIC || enum_type->base_type==IVL_VT_BOOL); assert(enum_type->range.get() != 0); - assert(enum_type->range->size() == 2); + assert(enum_type->range->size() == 1); // Add the file and line information to the enumeration type. FILE_NAME(&(enum_type->li), li); diff --git a/pform.h b/pform.h index 0e2613715..85039e7df 100644 --- a/pform.h +++ b/pform.h @@ -101,24 +101,22 @@ struct net_decl_assign_t { /* The lgate is gate instantiation information. */ struct lgate { - lgate(int =0) + inline lgate(int =0) : parms(0), parms_by_name(0), file(NULL), lineno(0) - { range[0] = 0; - range[1] = 0; - } + { } string name; list*parms; list*parms_by_name; - PExpr*range[2]; + index_component_t range; const char* file; unsigned lineno; }; -extern std::list* make_range_from_width(uint64_t wid); -extern list* copy_range(list* orig); +extern std::list* make_range_from_width(uint64_t wid); +extern std::list* copy_range(std::list* orig); /* Use this function to transform the parted form of the attribute list to the attribute map that is used later. */ @@ -161,7 +159,7 @@ extern void pform_module_define_port(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t data_type, bool signed_flag, - list*range, + list*range, list*attr); extern Module::port_t* pform_module_port_reference(perm_string name, @@ -241,7 +239,7 @@ extern void pform_makewire(const struct vlltype&li, perm_string name, /* This form handles simple declarations */ extern void pform_makewire(const struct vlltype&li, - list*range, + list*range, bool signed_flag, list*names, NetNet::Type type, @@ -258,7 +256,7 @@ extern void pform_makewire(const struct vlltype&li, /* This form handles assignment declarations. */ extern void pform_makewire(const struct vlltype&li, - list*range, + list*range, bool signed_flag, list*delay, str_pair_t str, @@ -281,7 +279,7 @@ extern void pform_make_reginit(const struct vlltype&li, it. The second form takes a single name. */ extern void pform_set_port_type(const struct vlltype&li, list*names, - list*range, + list*range, bool signed_flag, NetNet::PortType); extern void pform_set_port_type(perm_string nm, NetNet::PortType pt, @@ -316,13 +314,13 @@ extern void pform_set_parameter(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, bool signed_flag, - list*range, + list*range, PExpr*expr, LexicalScope::range_t*value_range); extern void pform_set_localparam(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, bool signed_flag, - list*range, + list*range, PExpr*expr); extern void pform_set_defparam(const pform_name_t&name, PExpr*expr); @@ -386,7 +384,7 @@ extern svector*pform_make_task_ports(const struct vlltype&loc, NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, - list*range, + list*range, list*names, bool isint = false); diff --git a/pform_types.h b/pform_types.h index 8ec228eaa..ab700cadc 100644 --- a/pform_types.h +++ b/pform_types.h @@ -1,7 +1,7 @@ #ifndef __pform_types_H #define __pform_types_H /* - * Copyright (c) 2007-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -84,14 +84,14 @@ struct data_type_t : public LineInfo { struct enum_type_t : public data_type_t { ivl_variable_type_t base_type; bool signed_flag; - std::auto_ptr< list > range; + std::auto_ptr< list > range; std::auto_ptr< list > names; LineInfo li; }; struct struct_member_t : public LineInfo { ivl_variable_type_t type; - std::auto_ptr< list > range; + std::auto_ptr< list > range; std::auto_ptr< list > names; }; @@ -108,11 +108,12 @@ struct atom2_type_t : public data_type_t { }; struct vector_type_t : public data_type_t { - inline explicit vector_type_t(ivl_variable_type_t bt, bool sf, list*pd) + inline explicit vector_type_t(ivl_variable_type_t bt, bool sf, + std::list*pd) : base_type(bt), signed_flag(sf), pdims(pd) { } ivl_variable_type_t base_type; bool signed_flag; - std::auto_ptr< list > pdims; + std::auto_ptr< list > pdims; }; struct real_type_t : public data_type_t { From 31d4aa9a77636c80f9617b2e73ba996eea3432ba Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 2 Mar 2012 21:16:53 -0800 Subject: [PATCH 16/23] Handle complexities of class name pre-declarations Class names can be declared early, before definitions, so that the name can be used as a type name. This thus allows class definitions to be separate from the declaration. This creates some complexity in the parser, since the lexor knows about the class names. --- lexor.lex | 2 +- parse.y | 118 +++++++++++++++++++++++++++++++++----------------- parse_misc.h | 2 + pform_types.h | 7 +++ 4 files changed, 88 insertions(+), 41 deletions(-) diff --git a/lexor.lex b/lexor.lex index b44d47166..64d6f2e3c 100644 --- a/lexor.lex +++ b/lexor.lex @@ -51,7 +51,7 @@ */ extern YYLTYPE yylloc; -static char* strdupnew(char const *str) +char* strdupnew(char const *str) { return str ? strcpy(new char [strlen(str)+1], str) : 0; } diff --git a/parse.y b/parse.y index 411875217..6874ba872 100644 --- a/parse.y +++ b/parse.y @@ -118,33 +118,6 @@ list* make_range_from_width(uint64_t wid) return range; } -#if 0 -/* - * Make a range vector from an existing pair of expressions. - */ -static vector* make_range_vector(list*that) -{ - assert(that->size() == 2); - vector*tmp = new vector (2); - tmp->at(0) = that->front(); - tmp->at(1) = that->back(); - delete that; - return tmp; -} -#endif -#if 0 -/* - * Make a range vector from a width. Generate the msb and lsb - * expressions to get the canonical range for the given width. - */ -static vector* make_range_vector(uint64_t wid) -{ - vector*tmp = new vector (2); - tmp->at(0) = new PENumber(new verinum(wid-1, integer_width)); - tmp->at(1) = new PENumber(new verinum((uint64_t)0, integer_width)); - return tmp; -} -#endif static list* list_from_identifier(char*id) { list*tmp = new list; @@ -342,6 +315,7 @@ static void current_task_set_statement(vector*s) struct_type_t*struct_type; data_type_t*data_type; + class_type_t*class_type; verinum* number; @@ -464,8 +438,7 @@ static void current_task_set_statement(vector*s) %type udp_initial udp_init_opt %type udp_initial_expr_opt -%type register_variable net_variable endname_opt -%type class_declaration_extends_opt +%type register_variable net_variable endname_opt class_declaration_endname_opt %type register_variable_list net_variable_list %type list_of_identifiers loop_variables %type list_of_port_identifiers @@ -511,6 +484,8 @@ static void current_task_set_statement(vector*s) %type list_of_variable_decl_assignments %type data_type data_type_or_implicit +%type class_declaration_extends_opt +%type class_identifier %type struct_union_member %type struct_union_member_list %type struct_data_type @@ -596,30 +571,71 @@ assignment_pattern /* IEEE1800-2005: A.6.7.1 */ ; class_declaration /* IEEE1800-2005: A.1.2 */ - : K_virtual_opt K_class IDENTIFIER class_declaration_extends_opt ';' + : K_virtual_opt K_class class_identifier class_declaration_extends_opt ';' class_items_opt K_endclass - { // Process a class + { // Process a class. if ($4) { yyerror(@4, "sorry: Class extends not supported yet."); - delete[]$4; } yyerror(@2, "sorry: Class declarations not supported yet."); } - endname_opt - { - if ($9 && strcmp($3,$9)!=0) { + class_declaration_endname_opt + { // Wrap up the class. + if ($9 && $3 && $3->name != $9) { yyerror(@9, "error: Class end name doesn't match class name."); delete[]$9; } - delete[]$3; } ; +class_identifier + : IDENTIFIER + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($1); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$1; + $$ = tmp; + } + | TYPE_IDENTIFIER + { class_type_t*tmp = dynamic_cast($1); + if (tmp == 0) { + yyerror(@1, "Type name is not a predeclared class name."); + } + $$ = tmp; + } + ; + + /* The endname after a class declaration is a little tricky because + the class name is detected by the lexor as a TYPE_IDENTIFER if it + does indeed match a name. */ +class_declaration_endname_opt + : ':' TYPE_IDENTIFIER + { class_type_t*tmp = dynamic_cast ($2); + if (tmp == 0) { + yyerror(@2, "error: class declaration endname is not a class name\n"); + $$ = 0; + } else { + $$ = strdupnew(tmp->name.str()); + } + } + | ':' IDENTIFIER + { $$ = $2; } + | + { $$ = 0; } + ; + /* This rule implements [ extends class_type ] in the - class_declaration. It is not a rule of its own in the LRM. */ + class_declaration. It is not a rule of its own in the LRM. + + Note that for this to be correct, the identifier after the + extends keyword must be a class name. Therefore, match + TYPE_IDENTIFIER instead of IDENTIFIER, and this rule will return + a data_type. */ class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */ - : K_extends IDENTIFIER + : K_extends TYPE_IDENTIFIER { $$ = $2; } | { $$ = 0; } @@ -662,6 +678,16 @@ class_item /* IEEE1800-2005: A.1.8 */ /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ + | property_qualifier_opt data_type error ';' + { yyerror(@3, "error: Errors in variable names after data type."); + yyerrok; + } + + | property_qualifier_opt IDENTIFIER error ';' + { yyerror(@3, "error: %s doesn't name a type.", $2); + yyerrok; + } + | K_function K_new error K_endfunction endnew_opt { yyerror(@1, "error: I give up on this class constructor declaration."); yyerrok; @@ -1591,7 +1617,13 @@ type_declaration /* These are forward declarations... */ | K_typedef K_class IDENTIFIER ';' - { yyerror(@1, "sorry: Class forward declarations not supported yet.") } + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($3); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$3; + } | K_typedef K_enum IDENTIFIER ';' { yyerror(@1, "sorry: Enum forward declarations not supported yet.") } | K_typedef K_struct IDENTIFIER ';' @@ -1599,7 +1631,13 @@ type_declaration | K_typedef K_union IDENTIFIER ';' { yyerror(@1, "sorry: Union forward declarations not supported yet.") } | K_typedef IDENTIFIER ';' - { yyerror(@1, "sorry: Class forward declarations not supported yet.") } + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($2); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$2; + } ; /* The structure for an enumeration data type is the keyword "enum", diff --git a/parse_misc.h b/parse_misc.h index 6d1aed925..037fefffe 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -95,4 +95,6 @@ extern verinum*make_unsized_binary(const char*txt); extern verinum*make_unsized_octal(const char*txt); extern verinum*make_unsized_hex(const char*txt); +extern char* strdupnew(char const *str); + #endif diff --git a/pform_types.h b/pform_types.h index ab700cadc..5e5a4a48f 100644 --- a/pform_types.h +++ b/pform_types.h @@ -121,6 +121,13 @@ struct real_type_t : public data_type_t { int type_code; }; +struct class_type_t : public data_type_t { + inline explicit class_type_t(perm_string n) + : name(n) { } + + perm_string name; +}; + /* * The pform_name_t is the general form for a hierarchical * identifier. It is an ordered list of name components. Each name From 0e01dcf2b957f00c12233a7551c906c1733fc3d5 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 4 Mar 2012 19:33:16 -0800 Subject: [PATCH 17/23] Miscellaneous SystemVerilog syntax. ... and sorry messages. --- PTask.h | 4 +- elab_sig.cc | 9 +++ parse.y | 161 +++++++++++++++++++++++++++++++++----------------- pform.cc | 15 +++-- pform_dump.cc | 8 ++- 5 files changed, 136 insertions(+), 61 deletions(-) diff --git a/PTask.h b/PTask.h index 4cd6a9a22..249573213 100644 --- a/PTask.h +++ b/PTask.h @@ -41,7 +41,9 @@ enum PTaskFuncEnum { PTF_REALTIME, PTF_TIME, PTF_ATOM2, - PTF_ATOM2_S + PTF_ATOM2_S, + PTF_STRING, + PTF_VOID }; struct PTaskFuncArg { diff --git a/elab_sig.cc b/elab_sig.cc index 1a00cb786..9c799dccd 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -582,6 +582,15 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const ret_sig->data_type(IVL_VT_BOOL); break; + case PTF_STRING: + cerr << get_fileline() << ": sorry: String functions are not supported yet" << endl; + break; + + case PTF_VOID: + // Void functions have no return value, so there is no + // signal to create here. + break; + default: if (ports_) { cerr << get_fileline() << ": internal error: I don't know " diff --git a/parse.y b/parse.y index 6874ba872..b237a6caa 100644 --- a/parse.y +++ b/parse.y @@ -505,8 +505,7 @@ static void current_task_set_statement(vector*s) %type event_control %type statement statement_or_null compressed_statement %type loop_statement for_step -%type statement_list statement_or_null_list -%type statement_list_or_null +%type statement_or_null_list statement_or_null_list_opt %type analog_statement @@ -656,11 +655,23 @@ class_items /* IEEE1800-2005: A.1.2 */ class_item /* IEEE1800-2005: A.1.8 */ - /* class_constructor_declaration */ - : K_function K_new '(' tf_port_list_opt ')' ';' - statement_list_or_null + /* IEEE1800 A.1.8: class_constructor_declaration */ + : method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + statement_or_null_list_opt K_endfunction endnew_opt - { yyerror(@1, "sorry: Class constructors not supported yet."); + { yyerror(@3, "sorry: Class constructors not supported yet."); + yyerrok; + } + + /* IEEE1800 A.1.8: class_constructor_declaration with a call to + parent constructor. Note that the implicit_class_handle must + be K_super ("this.new" makes little sense) but that would + cause a conflict. */ + | method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + implicit_class_handle '.' K_new '(' ')' + statement_or_null_list_opt + K_endfunction endnew_opt + { yyerror(@3, "sorry: Class constructors not supported yet."); yyerrok; } @@ -671,9 +682,9 @@ class_item /* IEEE1800-2005: A.1.8 */ /* Class methods... */ - | task_declaration + | method_qualifier_opt task_declaration - | function_declaration + | method_qualifier_opt function_declaration /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ @@ -688,7 +699,7 @@ class_item /* IEEE1800-2005: A.1.8 */ yyerrok; } - | K_function K_new error K_endfunction endnew_opt + | method_qualifier_opt K_function K_new error K_endfunction endnew_opt { yyerror(@1, "error: I give up on this class constructor declaration."); yyerrok; } @@ -797,7 +808,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } - function_item_list statement_list + function_item_list statement_or_null_list K_endfunction { current_function->set_ports($7); current_function->set_return($3); @@ -836,7 +847,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ } '(' tf_port_list_opt ')' ';' block_item_decls_opt - statement_list + statement_or_null_list K_endfunction { current_function->set_ports($7); current_function->set_return($3); @@ -1044,6 +1055,13 @@ variable_decl_assignment /* IEEE1800-2005 A.2.3 */ delete[]$1; $$ = tmp; } + | IDENTIFIER '=' K_new '(' ')' + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + yyerror("sorry: Class initialization assignment not supported here."); + delete[]$1; + $$ = tmp; + } | IDENTIFIER '[' '$' ']' { decl_assignment_t*tmp = new decl_assignment_t; tmp->name = lex_strings.make($1); @@ -1069,6 +1087,17 @@ loop_variables /* IEEE1800-2005: A.6.8 */ } ; +method_qualifier /* IEEE1800-2005: A.1.8 */ + : K_virtual + | class_item_qualifier + ; + +method_qualifier_opt + : method_qualifier + | + ; + + non_integer_type /* IEEE1800-2005: A.2.2.1 */ : K_real { $$ = K_real; } | K_realtime { $$ = K_real; } @@ -1389,6 +1418,19 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ } } + | port_direction_opt data_type_or_implicit IDENTIFIER '[' '$' ']' + { yyerror(@5, "sorry: Queues not supported here."); + delete[]$3; + $$ = 0; + } + + /* Rules to match error cases... */ + + | port_direction_opt data_type_or_implicit IDENTIFIER error + { yyerror(@3, "error: Error in task/function port item after port name %s.", $3); + yyerrok; + $$ = 0; + } ; /* This rule matches the [ = ] part of the tf_port_item rules. */ @@ -2612,6 +2654,11 @@ expr_primary } } + | implicit_class_handle + { yyerror(@1, "sorry: Implicit class handles (this/super) are not supported."); + $$ = 0; + } + /* Many of the VAMS built-in functions are available as builtin functions with $system_function equivalents. */ @@ -4695,7 +4742,9 @@ dimensions } ; - /* This is used to express the return type of a function. */ + /* This is used to express the return type of a function. This is + not quite right, and should be replaced with a variant that uses + the data_type rule. This will get us by for now. */ function_range_or_type_opt : unsigned_signed_opt range_opt { /* the default type is reg unsigned and no range */ @@ -4727,7 +4776,9 @@ function_range_or_type_opt | K_integer { $$.range = 0; $$.type = PTF_INTEGER; } | K_real { $$.range = 0; $$.type = PTF_REAL; } | K_realtime { $$.range = 0; $$.type = PTF_REALTIME; } + | K_string { $$.range = 0; $$.type = PTF_STRING; } | K_time { $$.range = 0; $$.type = PTF_TIME; } + | K_void { $$.range = 0; $$.type = PTF_VOID; } | atom2_type { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } | atom2_type K_signed { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } | atom2_type K_unsigned { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2; } @@ -5191,7 +5242,7 @@ statement /* This is roughly statement_item in the LRM */ FILE_NAME(tmp, @1); $$ = tmp; } - | K_begin statement_list K_end + | K_begin statement_or_null_list K_end { PBlock*tmp = new PBlock(PBlock::BL_SEQ); FILE_NAME(tmp, @1); tmp->set_statement(*$2); @@ -5204,7 +5255,7 @@ statement /* This is roughly statement_item in the LRM */ current_block_stack.push(tmp); } block_item_decls_opt - statement_list_or_null K_end + statement_or_null_list_opt K_end { pform_pop_scope(); assert(! current_block_stack.empty()); PBlock*tmp = current_block_stack.top(); @@ -5227,7 +5278,7 @@ statement /* This is roughly statement_item in the LRM */ FILE_NAME(tmp, @1); $$ = tmp; } - | K_fork statement_list K_join + | K_fork statement_or_null_list K_join { PBlock*tmp = new PBlock(PBlock::BL_PAR); FILE_NAME(tmp, @1); tmp->set_statement(*$2); @@ -5240,7 +5291,7 @@ statement /* This is roughly statement_item in the LRM */ current_block_stack.push(tmp); } block_item_decls_opt - statement_list_or_null K_join + statement_or_null_list_opt K_join { pform_pop_scope(); assert(! current_block_stack.empty()); PBlock*tmp = current_block_stack.top(); @@ -5362,6 +5413,7 @@ statement /* This is roughly statement_item in the LRM */ FILE_NAME(tmp, @1); $$ = tmp; } + | error '=' expression ';' { yyerror(@2, "Syntax in assignment statement l-value."); yyerrok; @@ -5446,25 +5498,46 @@ statement /* This is roughly statement_item in the LRM */ delete[]$1; $$ = tmp; } - | hierarchy_identifier '(' expression_list_proper ')' ';' - { PCallTask*tmp = new PCallTask(*$1, *$3); - FILE_NAME(tmp, @1); - delete $1; - delete $3; - $$ = tmp; - } + + | hierarchy_identifier '(' expression_list_proper ')' ';' + { PCallTask*tmp = new PCallTask(*$1, *$3); + FILE_NAME(tmp, @1); + delete $1; + delete $3; + $$ = tmp; + } + + | implicit_class_handle '.' hierarchy_identifier '(' expression_list_proper ')' ';' + { PCallTask*tmp = new PCallTask(*$3, *$5); + yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); + FILE_NAME(tmp, @1); + delete $3; + delete $5; + $$ = tmp; + } /* NOTE: The standard doesn't really support an empty argument list between parentheses, but it seems natural, and people commonly want it. So accept it explicitly. */ - | hierarchy_identifier '(' ')' ';' - { listpt; - PCallTask*tmp = new PCallTask(*$1, pt); - FILE_NAME(tmp, @1); - delete $1; - $$ = tmp; - } + | hierarchy_identifier '(' ')' ';' + { listpt; + PCallTask*tmp = new PCallTask(*$1, pt); + FILE_NAME(tmp, @1); + delete $1; + $$ = tmp; + } + + + | implicit_class_handle '.' hierarchy_identifier '(' ')' ';' + { listpt; + yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); + PCallTask*tmp = new PCallTask(*$3, pt); + FILE_NAME(tmp, @3); + delete $3; + $$ = tmp; + } + | hierarchy_identifier ';' { listpt; PCallTask*tmp = new PCallTask(*$1, pt); @@ -5537,34 +5610,14 @@ compressed_statement } ; -statement_list_or_null - : statement_list_or_null statement - { vector*tmp = $1; - if (tmp) { - tmp->push_back($2); - } else { - tmp = new vector(1); - tmp->at(0) = $2; - } - $$ = tmp; - } + +statement_or_null_list_opt + : statement_or_null_list + { $$ = $1; } | { $$ = 0; } ; -statement_list - : statement_list statement - { vector*tmp = $1; - tmp->push_back($2); - $$ = tmp; - } - | statement - { vector*tmp = new vector(1); - tmp->at(0) = $1; - $$ = tmp; - } - ; - statement_or_null_list : statement_or_null_list statement_or_null { vector*tmp = $1; diff --git a/pform.cc b/pform.cc index d500bf7ff..99d44719e 100644 --- a/pform.cc +++ b/pform.cc @@ -416,11 +416,16 @@ data_type_t* pform_test_type_identifier(const char*txt) return false; perm_string name = lex_strings.make(txt); - map::iterator cur = lexical_scope->typedefs.find(name); - if (cur != lexical_scope->typedefs.end()) - return cur->second; - else - return 0; + map::iterator cur; + LexicalScope*cur_scope = lexical_scope; + do { + cur = cur_scope->typedefs.find(name); + if (cur != cur_scope->typedefs.end()) + return cur->second; + + cur_scope = cur_scope->parent_scope(); + } while (cur_scope); + return 0; } static void pform_put_behavior_in_scope(PProcess*pp) diff --git a/pform_dump.cc b/pform_dump.cc index 1ca78a67e..6f1840842 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -812,7 +812,13 @@ void PFunction::dump(ostream&out, unsigned ind) const out << "int unsigned "; break; case PTF_ATOM2_S: - cout << "int signed "; + out << "int signed "; + break; + case PTF_STRING: + out << "string "; + break; + case PTF_VOID: + out << "void "; break; } From 8c2e4a089241ad2404d9d4fbff7671a6b3d4ffa8 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 4 Mar 2012 20:04:07 -0800 Subject: [PATCH 18/23] Support tasks with no behavioral statements (System Verilog) --- parse.y | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/parse.y b/parse.y index b237a6caa..f9cfbfa17 100644 --- a/parse.y +++ b/parse.y @@ -230,15 +230,37 @@ static long check_enum_seq_value(const YYLTYPE&loc, verinum *arg, bool zero_ok) return value; } -static void current_task_set_statement(vector*s) +static void current_task_set_statement(const YYLTYPE&loc, vector*s) { + if (s == 0) { + /* if the statement list is null, then the parser + detected the case that there are no statements in the + task. If this is System Verilog, handle it as an + an empty block. */ + if (!gn_system_verilog()) { + yyerror(loc, "error: Support for empty tasks requires SystemVerilog."); + } + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); + current_task->set_statement(tmp); + return; + } + + /* The parser assures that there is a non-empty vector. */ assert(s && !s->empty()); + + /* A vector of 1 is handled as a simple statement. */ if (s->size() == 1) { current_task->set_statement((*s)[0]); return; } + if (!gn_system_verilog()) { + yyerror(loc, "error: Task body with multiple statements requires SystemVerilog."); + } + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); tmp->set_statement(*s); current_task->set_statement(tmp); } @@ -1193,10 +1215,10 @@ task_declaration /* IEEE1800-2005: A.2.7 */ current_task = pform_push_task_scope(@1, $3, $2); } task_item_list_opt - statement_or_null_list + statement_or_null_list_opt K_endtask { current_task->set_ports($6); - current_task_set_statement($7); + current_task_set_statement(@3, $7); pform_pop_scope(); current_task = 0; if ($7->size() > 1 && !gn_system_verilog()) { @@ -1226,16 +1248,13 @@ task_declaration /* IEEE1800-2005: A.2.7 */ } tf_port_list ')' ';' block_item_decls_opt - statement_or_null_list + statement_or_null_list_opt K_endtask { current_task->set_ports($6); - current_task_set_statement($10); + current_task_set_statement(@3, $10); pform_pop_scope(); current_task = 0; - if ($10->size() > 1 && !gn_system_verilog()) { - yyerror(@10, "error: Task body with multiple statements requres SystemVerilog."); - } - delete $10; + if ($10) delete $10; } endname_opt { // Last step: check any closing name. This is done late so @@ -1261,7 +1280,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ statement_or_null_list K_endtask { current_task->set_ports(0); - current_task_set_statement($9); + current_task_set_statement(@3, $9); pform_pop_scope(); current_task = 0; cerr << @3 << ": warning: task definition for \"" << $3 From da743c3b2cb4f273e4dfbc59b93f5f5baed8f5bb Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 9 Mar 2012 18:54:05 -0800 Subject: [PATCH 19/23] Bunches more SystemVerilog syntax. --- parse.y | 293 ++++++++++++++++++++++++++++++++++++++++---------- pform.cc | 75 +++++++------ pform.h | 3 +- pform_dump.cc | 5 +- 4 files changed, 285 insertions(+), 91 deletions(-) diff --git a/parse.y b/parse.y index f9cfbfa17..6bcfffff2 100644 --- a/parse.y +++ b/parse.y @@ -265,6 +265,41 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) current_task->set_statement(tmp); } +static void current_function_set_statement(const YYLTYPE&loc, vector*s) +{ + if (s == 0) { + /* if the statement list is null, then the parser + detected the case that there are no statements in the + task. If this is System Verilog, handle it as an + an empty block. */ + if (!gn_system_verilog()) { + yyerror(loc, "error: Support for empty functions requires SystemVerilog."); + } + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); + current_function->set_statement(tmp); + return; + } + + /* The parser assures that there is a non-empty vector. */ + assert(s && !s->empty()); + + /* A vector of 1 is handled as a simple statement. */ + if (s->size() == 1) { + current_function->set_statement((*s)[0]); + return; + } + + if (!gn_system_verilog()) { + yyerror(loc, "error: Function body with multiple statements requires SystemVerilog."); + } + + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); + tmp->set_statement(*s); + current_function->set_statement(tmp); +} + %} %union { @@ -447,7 +482,7 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) %type from_exclude %type number pos_neg_number %type signing unsigned_signed_opt signed_unsigned_opt -%type K_automatic_opt K_packed_opt K_reg_opt K_virtual_opt +%type K_automatic_opt K_packed_opt K_reg_opt K_static_opt K_virtual_opt %type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym @@ -495,8 +530,8 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) %type hierarchy_identifier %type assignment_pattern expression expr_primary expr_mintypmax -%type dynamic_array_new inc_or_dec_expression lpvalue -%type branch_probe_expression +%type class_new dynamic_array_new inc_or_dec_expression inside_expression lpvalue +%type branch_probe_expression streaming_concatenation %type delay_value delay_value_simple %type delay1 delay3 delay3_opt delay_value_list %type expression_list_with_nuls expression_list_proper @@ -526,7 +561,7 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) %type event_expression %type event_control %type statement statement_or_null compressed_statement -%type loop_statement for_step +%type loop_statement for_step jump_statement %type statement_or_null_list statement_or_null_list_opt %type analog_statement @@ -543,7 +578,7 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) %token K_TAND %right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ %right K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ -%right '?' ':' +%right '?' ':' K_inside %left K_LOR %left K_LAND %left '|' @@ -609,6 +644,11 @@ class_declaration /* IEEE1800-2005: A.1.2 */ } ; +class_constraint /* IEEE1800-2005: A.1.8 */ + : constraint_prototype + | constraint_declaration + ; + class_identifier : IDENTIFIER { // Create a synthetic typedef for the class name so that the @@ -690,7 +730,7 @@ class_item /* IEEE1800-2005: A.1.8 */ be K_super ("this.new" makes little sense) but that would cause a conflict. */ | method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' - implicit_class_handle '.' K_new '(' ')' + implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' statement_or_null_list_opt K_endfunction endnew_opt { yyerror(@3, "sorry: Class constructors not supported yet."); @@ -708,6 +748,11 @@ class_item /* IEEE1800-2005: A.1.8 */ | method_qualifier_opt function_declaration + + /* Class constraints... */ + + | class_constraint + /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ @@ -739,6 +784,65 @@ class_item_qualifier /* IEEE1800-2005 A.1.8 */ | K_local ; +class_new /* IEEE1800-2005 A.2.4 */ + : K_new '(' ')' + { yyerror(@1, "sorry: class_new not implemented yet."); + $$ = 0; + } + | K_new '(' expression_list_proper ')' + { yyerror(@1, "sorry: class_new not implemented yet."); + $$ = 0; + } + ; + +constraint_block_item /* IEEE1800-2005 A.1.9 */ + : constraint_expression + ; + +constraint_block_item_list + : constraint_block_item_list constraint_block_item + | constraint_block_item + ; + +constraint_block_item_list_opt + : + | constraint_block_item_list + ; + +constraint_declaration /* IEEE1800-2005: A.1.9 */ + : K_static_opt K_constraint IDENTIFIER '{' constraint_block_item_list_opt '}' + { yyerror(@2, "sorry: Constraint declarations not supported.") } + + /* Error handling rules... */ + + | K_static_opt K_constraint IDENTIFIER '{' error '}' + { yyerror(@4, "error: Errors in the constraint block item list."); } + ; + +constraint_expression /* IEEE1800-2005 A.1.9 */ + : expression ';' + | expression K_dist '{' '}' ';' + | expression K_TRIGGER constraint_set + | K_if '(' expression ')' constraint_set %prec less_than_K_else + | K_if '(' expression ')' constraint_set K_else constraint_set + | K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' constraint_set + ; + +constraint_expression_list /* */ + : constraint_expression_list constraint_expression + | constraint_expression + ; + +constraint_prototype /* IEEE1800-2005: A.1.9 */ + : K_static_opt K_constraint IDENTIFIER ';' + { yyerror(@2, "sorry: Constraint prototypes not supported.") } + ; + +constraint_set /* IEEE1800-2005 A.1.9 */ + : constraint_expression + | '{' constraint_expression_list '}' + ; + data_type /* IEEE1800-2005: A.2.2.1 */ : integer_vector_type unsigned_signed_opt range_opt { vector_type_t*tmp = new vector_type_t($1, $2, $3); @@ -830,24 +934,11 @@ function_declaration /* IEEE1800-2005: A.2.6 */ { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } - function_item_list statement_or_null_list + function_item_list statement_or_null_list_opt K_endfunction { current_function->set_ports($7); current_function->set_return($3); - assert($8 && $8->size() > 0); - if ($8->size() == 1) { - current_function->set_statement((*$8)[0]); - delete $8; - } else { - PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @8); - tmp->set_statement( *$8 ); - current_function->set_statement(tmp); - delete $8; - if (!gn_system_verilog()) { - yyerror(@8, "error: Function body with multiple statements requres SystemVerilog."); - } - } + current_function_set_statement($8? @8 : @4, $8); pform_pop_scope(); current_function = 0; } @@ -869,24 +960,11 @@ function_declaration /* IEEE1800-2005: A.2.6 */ } '(' tf_port_list_opt ')' ';' block_item_decls_opt - statement_or_null_list + statement_or_null_list_opt K_endfunction { current_function->set_ports($7); current_function->set_return($3); - assert($11 && $11->size() > 0); - if ($11->size() == 1) { - current_function->set_statement((*$11)[0]); - delete $11; - } else { - PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @11); - tmp->set_statement( *$11 ); - current_function->set_statement(tmp); - delete $11; - if (!gn_system_verilog()) { - yyerror(@11, "error: Function body with multiple statements requres SystemVerilog."); - } - } + current_function_set_statement($11? @11 : @4, $11); pform_pop_scope(); current_function = 0; if ($7==0 && !gn_system_verilog()) { @@ -965,6 +1043,13 @@ inc_or_dec_expression /* IEEE1800-2005: A.4.3 */ } ; +inside_expression /* IEEE1800-2005 A.8.3 */ + : expression K_inside '{' open_range_list '}' + { yyerror(@2, "sorry: \"inside\" expressions not supported yet."); + $$ = 0; + } + ; + integer_vector_type /* IEEE1800-2005: A.2.2.1 */ : K_reg { $$ = IVL_VT_LOGIC; } | K_bit { $$ = IVL_VT_BOOL; } @@ -972,6 +1057,21 @@ integer_vector_type /* IEEE1800-2005: A.2.2.1 */ | K_bool { $$ = IVL_VT_BOOL; } /* Icarus Verilog xtypes extension */ ; +jump_statement /* IEEE1800-2005: A.6.5 */ + : K_break ';' + { yyerror(@1, "sorry: break statements not supported."); + $$ = 0; + } + | K_return ';' + { yyerror(@1, "sorry: return statements not supported."); + $$ = 0; + } + | K_return expression ';' + { yyerror(@1, "sorry: return statements not supported."); + $$ = 0; + } + ; + /* Loop statements are kinds of statements. */ loop_statement /* IEEE1800-2005: A.6.8 */ @@ -1084,13 +1184,6 @@ variable_decl_assignment /* IEEE1800-2005 A.2.3 */ delete[]$1; $$ = tmp; } - | IDENTIFIER '[' '$' ']' - { decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = lex_strings.make($1); - yyerror("sorry: Queue dimensions not yet supported here."); - delete[]$1; - $$ = tmp; - } ; @@ -1135,6 +1228,11 @@ number : BASED_NUMBER based_size = 0; } ; +open_range_list /* IEEE1800-2005 A.2.11 */ + : open_range_list ',' value_range + | value_range + ; + port_direction /* IEEE1800-2005 A.1.3 */ : K_input { $$ = NetNet::PINPUT; } | K_output { $$ = NetNet::POUTPUT; } @@ -1203,6 +1301,33 @@ statement_or_null /* IEEE1800-2005: A.6.4 */ { $$ = 0; } ; +stream_expression + : expression + ; + +stream_expression_list + : stream_expression_list ',' stream_expression + | stream_expression + ; + +stream_operator + : K_LS + | K_RS + ; + +streaming_concatenation /* IEEE1800-2005: A.8.1 */ + : '{' stream_operator '{' stream_expression_list '}' '}' + { /* streaming concatenation is a SystemVerilog thing. */ + if (gn_system_verilog()) { + yyerror(@2, "sorry: Streaming concatenation not supported."); + $$ = 0; + } else { + yyerror(@2, "error: Streaming concatenation requires SystemVerilog"); + $$ = 0; + } + } + ; + /* The task declaration rule matches the task declaration header, then pushes the function scope. This causes the definitions in the task_body to take on the scope of the task @@ -1350,7 +1475,8 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ port_declaration_context.sign_flag = true; delete port_declaration_context.range; port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_LOGIC, true, + svector*tmp = pform_make_task_ports(@3, use_port_type, + IVL_VT_LOGIC, true, range_stub, list_from_identifier($3), true); $$ = tmp; @@ -1424,7 +1550,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ FILE_NAME($2, @3); } port_declaration_context.data_type = $2; - tmp = pform_make_task_ports(@3, $1, $2, ilist); + tmp = pform_make_task_ports(@3, use_port_type, $2, ilist); } $$ = tmp; if ($4) { @@ -1437,12 +1563,6 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ } } - | port_direction_opt data_type_or_implicit IDENTIFIER '[' '$' ']' - { yyerror(@5, "sorry: Queues not supported here."); - delete[]$3; - $$ = 0; - } - /* Rules to match error cases... */ | port_direction_opt data_type_or_implicit IDENTIFIER error @@ -1495,6 +1615,13 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ ; +value_range /* IEEE1800-2005: A.8.3 */ + : expression + { } + | '[' expression ':' expression ']' + { } + ; + variable_dimension /* IEEE1800-2005: A.2.5 */ : '[' expression ':' expression ']' { list *tmp = new list; @@ -1529,6 +1656,20 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ tmp->push_back(index); $$ = tmp; } + | '[' '$' ']' + { // SystemVerilog queue + list *tmp = new list; + index_component_t index; + index.msb = 0; + index.lsb = 0; + if (gn_system_verilog()) { + yyerror("sorry: Dynamic array ranges not supported."); + } else { + yyerror("error: Queue declarations require System Verilog."); + } + tmp->push_back(index); + $$ = tmp; + } ; /* Verilog-2001 supports attribute lists, which can be attached to a @@ -2306,10 +2447,12 @@ branch_probe_expression ; expression - : expr_primary - { $$ = $1; } - | inc_or_dec_expression - { $$ = $1; } + : expr_primary + { $$ = $1; } + | inc_or_dec_expression + { $$ = $1; } + | inside_expression + { $$ = $1; } | '+' expr_primary %prec UNARY_PREC { $$ = $2; } | '-' expr_primary %prec UNARY_PREC @@ -2678,6 +2821,11 @@ expr_primary $$ = 0; } + | implicit_class_handle '.' hierarchy_identifier + { yyerror(@1, "sorry: Implicit class handles (this/super) are not supported."); + $$ = 0; + } + /* Many of the VAMS built-in functions are available as builtin functions with $system_function equivalents. */ @@ -2881,6 +3029,16 @@ expr_primary yyerrok; } + | '{' '}' + { // This is the empty queue syntax. + if (gn_system_verilog()) { + yyerror(@1, "sorry: Expty queue expressions not supported."); + } else { + yyerror(@1, "error: Concatenations are not allowed to be empty."); + } + $$ = 0; + } + /* Cast expressions are primaries */ | DEC_NUMBER '\'' '(' expression ')' @@ -2901,6 +3059,14 @@ expr_primary | assignment_pattern { $$ = $1; } + /* SystemVerilog supports streaming concatenation */ + | streaming_concatenation + { $$ = $1; } + + | K_null + { yyerror("sorry: null expressions not supported yet."); + $$ = 0; + } ; /* A function_item_list borrows the task_port_item run to match @@ -3533,6 +3699,11 @@ lpvalue delete $2; $$ = tmp; } + + | streaming_concatenation + { yyerror(@1, "sorry: streaming concatenation not supported in l-values."); + $$ = 0; + } ; @@ -5338,6 +5509,8 @@ statement /* This is roughly statement_item in the LRM */ | loop_statement { $$ = $1; } + | jump_statement { $$ = $1; } + | K_case '(' expression ')' case_items K_endcase { PCase*tmp = new PCase(NetCase::EQ, $3, $5); FILE_NAME(tmp, @1); @@ -5495,6 +5668,15 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } + /* The class new and dynamic array new expressions are special, so + sit in rules of their own. */ + + | lpvalue '=' class_new ';' + { PAssign*tmp = new PAssign($1,$3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_wait '(' expression ')' statement_or_null { PEventStatement*tmp; PEEvent*etmp = new PEEvent(PEEvent::POSITIVE, $3); @@ -5980,4 +6162,5 @@ udp_primitive K_automatic_opt: K_automatic { $$ = true; } | { $$ = false;} ; K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; +K_static_opt : K_static { $$ = true; } | { $$ = false; } ; K_virtual_opt : K_virtual { $$ = true; } | { $$ = false; } ; diff --git a/pform.cc b/pform.cc index 99d44719e..a8569ff01 100644 --- a/pform.cc +++ b/pform.cc @@ -2075,39 +2075,6 @@ void pform_makewire(const vlltype&li, } } -void pform_set_port_type(perm_string name, NetNet::PortType pt, - const char*file, unsigned lineno) -{ - PWire*cur = pform_get_wire_in_scope(name); - if (cur == 0) { - cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE); - FILE_NAME(cur, file, lineno); - pform_put_wire_in_scope(name, cur); - } - - switch (cur->get_port_type()) { - case NetNet::PIMPLICIT: - if (! cur->set_port_type(pt)) - VLerror("error setting port direction."); - break; - - case NetNet::NOT_A_PORT: - cerr << file << ":" << lineno << ": error: " - << "port " << name << " is not in the port list." - << endl; - error_count += 1; - break; - - default: - cerr << file << ":" << lineno << ": error: " - << "port " << name << " already has a port declaration." - << endl; - error_count += 1; - break; - } - -} - /* * This function is called by the parser to create task ports. The * resulting wire (which should be a register) is put into a list to @@ -2155,6 +2122,7 @@ svector*pform_make_task_ports(const struct vlltype&loc, list*names, bool isint) { + assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); assert(names); svector*res = new svector(0); for (list::iterator cur = names->begin() @@ -2513,12 +2481,48 @@ extern void pform_module_specify_path(PSpecPath*obj) pform_cur_module->specify_paths.push_back(obj); } + +static void pform_set_port_type(perm_string name, NetNet::PortType pt, + const char*file, unsigned lineno) +{ + PWire*cur = pform_get_wire_in_scope(name); + if (cur == 0) { + cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE); + FILE_NAME(cur, file, lineno); + pform_put_wire_in_scope(name, cur); + } + + switch (cur->get_port_type()) { + case NetNet::PIMPLICIT: + if (! cur->set_port_type(pt)) + VLerror("error setting port direction."); + break; + + case NetNet::NOT_A_PORT: + cerr << file << ":" << lineno << ": error: " + << "port " << name << " is not in the port list." + << endl; + error_count += 1; + break; + + default: + cerr << file << ":" << lineno << ": error: " + << "port " << name << " already has a port declaration." + << endl; + error_count += 1; + break; + } + +} + void pform_set_port_type(const struct vlltype&li, list*names, list*range, bool signed_flag, NetNet::PortType pt) { + assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); + for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; @@ -2636,6 +2640,11 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { + VLerror(li, "sorry: Class types not supported."); + return; + } + assert(0); } diff --git a/pform.h b/pform.h index 85039e7df..6af305314 100644 --- a/pform.h +++ b/pform.h @@ -282,8 +282,7 @@ extern void pform_set_port_type(const struct vlltype&li, list*range, bool signed_flag, NetNet::PortType); -extern void pform_set_port_type(perm_string nm, NetNet::PortType pt, - const char*file, unsigned lineno); + extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); diff --git a/pform_dump.cc b/pform_dump.cc index 6f1840842..808ba4372 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -577,7 +577,10 @@ void PAssign::dump(ostream&out, unsigned ind) const if (delay_) out << "#" << *delay_ << " "; if (count_) out << "repeat(" << *count_ << ") "; if (event_) out << *event_ << " "; - out << *rval() << ";" << " /* " << get_fileline() << " */" << endl; + PExpr*rexpr = rval(); + if (rexpr) out << *rval() << ";"; + else out << ";"; + out << " /* " << get_fileline() << " */" << endl; } void PAssignNB::dump(ostream&out, unsigned ind) const From dbc6f0cff2ef726ee5ab8e4b01131c927a202216 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 10 Mar 2012 09:50:41 -0800 Subject: [PATCH 20/23] Parse SystemVerilog syntax for task calls. Tasks call arguments may be dropped in favor of default values. Allow for that in the syntax. This requires a little handling of the non-SystemVerilog case during elaboration. --- Statement.h | 12 ---- elaborate.cc | 45 +++++++++++--- parse.y | 170 +++++++++++++++++++++++++-------------------------- 3 files changed, 121 insertions(+), 106 deletions(-) diff --git a/Statement.h b/Statement.h index 5caf9644d..049aa118e 100644 --- a/Statement.h +++ b/Statement.h @@ -196,18 +196,6 @@ class PCallTask : public Statement { const pform_name_t& path() const; - unsigned nparms() const { return parms_.size(); } - - PExpr*&parm(unsigned idx) - { assert(idx < parms_.size()); - return parms_[idx]; - } - - PExpr* parm(unsigned idx) const - { assert(idx < parms_.size()); - return parms_[idx]; - } - virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; diff --git a/elaborate.cc b/elaborate.cc index e256a4df8..cd3ef2d73 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2825,12 +2825,12 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const des->errors += 1; } - unsigned parm_count = nparms(); + unsigned parm_count = parms_.size(); /* Catch the special case that the system task has no parameters. The "()" string will be parsed as a single empty parameter, when we really mean no parameters at all. */ - if ((nparms() == 1) && (parm(0) == 0)) + if ((parm_count== 1) && (parms_[0] == 0)) parm_count = 0; svectoreparms (parm_count); @@ -2838,7 +2838,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const perm_string name = peek_tail_name(path_); for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { - PExpr*ex = parm(idx); + PExpr*ex = parms_[idx]; if (ex != 0) { eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex); } else { @@ -2930,9 +2930,20 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const } assert(def); - if (nparms() != def->port_count()) { + + unsigned parm_count = parms_.size(); + + // Handle special case that the definition has no arguments + // but the parser found a simgle nul argument. This is an + // argument of the parser allowing for the possibility of + // default values for argumets: The parser cannot tell the + // difference between "func()" and "func()". + if (def->port_count() == 0 && parm_count == 1 && parms_[0] == 0) + parm_count = 0; + + if (parm_count != def->port_count()) { cerr << get_fileline() << ": error: Port count mismatch in call to ``" - << path_ << "''. Got " << nparms() + << path_ << "''. Got " << parm_count << " ports, expecting " << def->port_count() << " ports." << endl; des->errors += 1; return 0; @@ -2942,7 +2953,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const /* Handle non-automatic tasks with no parameters specially. There is no need to make a sequential block to hold the generated code. */ - if ((nparms() == 0) && !task->is_auto()) { + if ((parm_count == 0) && !task->is_auto()) { cur = new NetUTask(task); cur->set_line(*this); return cur; @@ -2974,7 +2985,23 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const expression the r-value. We know by definition that the port is a reg type, so this elaboration is pretty obvious. */ - for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { + for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { + + if (parms_[idx] == 0 && !gn_system_verilog()) { + cerr << get_fileline() << ": error: " + << "Missing argument " << (idx+1) + << " of call to task." << endl; + des->errors += 1; + continue; + } + + if (parms_[idx] == 0) { + cerr << get_fileline() << ": sorry: " + << "Implicit arguments (arg " << (idx+1) + << ") not supported." << endl; + des->errors += 1; + continue; + } NetNet*port = def->port(idx); assert(port->port_type() != NetNet::NOT_A_PORT); @@ -2985,7 +3012,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const unsigned wid = count_lval_width(lv); ivl_variable_type_t lv_type = lv->expr_type(); - NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_[idx]); + NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_ [idx]); if (NetEEvent*evt = dynamic_cast (rv)) { cerr << evt->get_fileline() << ": error: An event '" << evt->event()->name() << "' can not be a user " @@ -3015,7 +3042,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const expression that can be a target to a procedural assignment, including a memory word. */ - for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { + for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { NetNet*port = def->port(idx); diff --git a/parse.y b/parse.y index 6bcfffff2..79a1ae6c4 100644 --- a/parse.y +++ b/parse.y @@ -513,8 +513,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type enum_data_type %type task_item task_item_list task_item_list_opt -%type task_port_item tf_port_item tf_port_list tf_port_list_opt -%type function_item function_item_list +%type tf_port_declaration tf_port_item tf_port_list tf_port_list_opt +%type function_item function_item_list function_item_list_opt %type port_name parameter_value_byname %type port_name_list parameter_value_byname_list @@ -719,6 +719,7 @@ class_item /* IEEE1800-2005: A.1.8 */ /* IEEE1800 A.1.8: class_constructor_declaration */ : method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + function_item_list_opt statement_or_null_list_opt K_endfunction endnew_opt { yyerror(@3, "sorry: Class constructors not supported yet."); @@ -730,6 +731,7 @@ class_item /* IEEE1800-2005: A.1.8 */ be K_super ("this.new" makes little sense) but that would cause a conflict. */ | method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + function_item_list_opt implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' statement_or_null_list_opt K_endfunction endnew_opt @@ -1454,6 +1456,45 @@ task_declaration /* IEEE1800-2005: A.2.7 */ ; +tf_port_declaration /* IEEE1800-2005: A.2.7 */ + : port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + { svector*tmp = pform_make_task_ports(@1, $1, + $2 ? IVL_VT_LOGIC : + IVL_VT_NO_TYPE, + $3, $4, $5); + $$ = tmp; + } + + /* When the port is an integer, infer a signed vector of the integer + shape. Generate a range ([31:0]) to make it work. */ + + | port_direction K_integer list_of_identifiers ';' + { list*range_stub = make_range_from_width(integer_width); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, + range_stub, $3, true); + $$ = tmp; + } + + /* Ports can be time with a width of [63:0] (unsigned). */ + + | port_direction K_time list_of_identifiers ';' + { list*range_stub = make_range_from_width(64); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, + range_stub, $3); + $$ = tmp; + } + + /* Ports can be real or realtime. */ + + | port_direction real_or_realtime list_of_identifiers ';' + { svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, false, + 0, $3); + $$ = tmp; + } + + ; + + /* These rules for tf_port_item are slightly expanded from the strict rules in the LRM to help with LALR parsing. @@ -3071,26 +3112,34 @@ expr_primary /* A function_item_list borrows the task_port_item run to match declarations of ports. We check later to make sure there are no - output or inout ports actually used. */ + output or inout ports actually used. + + The function_item is the same as tf_item_declaration. */ +function_item_list_opt + : function_item_list { $$ = $1; } + | { $$ = 0; } + ; + function_item_list - : function_item - { $$ = $1; } - | function_item_list function_item - { if ($1 && $2) { - svector*tmp = new svector(*$1, *$2); - delete $1; - delete $2; - $$ = tmp; - } else if ($1) { - $$ = $1; - } else { - $$ = $2; - } - } - ; + : function_item + { $$ = $1; } + | function_item_list function_item + { /* */ + if ($1 && $2) { + svector*tmp = new svector(*$1, *$2); + delete $1; + delete $2; + $$ = tmp; + } else if ($1) { + $$ = $1; + } else { + $$ = $2; + } + } + ; function_item - : task_port_item + : tf_port_declaration { $$ = $1; } | block_item_decl { $$ = 0; } @@ -5700,7 +5749,7 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - | hierarchy_identifier '(' expression_list_proper ')' ';' + | hierarchy_identifier '(' expression_list_with_nuls ')' ';' { PCallTask*tmp = new PCallTask(*$1, *$3); FILE_NAME(tmp, @1); delete $1; @@ -5708,7 +5757,7 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - | implicit_class_handle '.' hierarchy_identifier '(' expression_list_proper ')' ';' + | implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' ';' { PCallTask*tmp = new PCallTask(*$3, *$5); yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); FILE_NAME(tmp, @1); @@ -5717,11 +5766,7 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - /* NOTE: The standard doesn't really support an empty argument list - between parentheses, but it seems natural, and people commonly - want it. So accept it explicitly. */ - - | hierarchy_identifier '(' ')' ';' + | hierarchy_identifier ';' { listpt; PCallTask*tmp = new PCallTask(*$1, pt); FILE_NAME(tmp, @1); @@ -5729,29 +5774,22 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - - | implicit_class_handle '.' hierarchy_identifier '(' ')' ';' - { listpt; - yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); - PCallTask*tmp = new PCallTask(*$3, pt); - FILE_NAME(tmp, @3); - delete $3; + | hierarchy_identifier '(' error ')' ';' + { yyerror(@3, "error: Syntax error in task arguments."); + listpt; + PCallTask*tmp = new PCallTask(*$1, pt); + FILE_NAME(tmp, @1); + delete $1; $$ = tmp; } - | hierarchy_identifier ';' - { listpt; - PCallTask*tmp = new PCallTask(*$1, pt); - FILE_NAME(tmp, @1); - delete $1; - $$ = tmp; - } - | error ';' - { yyerror(@2, "error: malformed statement"); - yyerrok; - $$ = new PNoop; - } - ; + | error ';' + { yyerror(@2, "error: malformed statement"); + yyerrok; + $$ = new PNoop; + } + + ; compressed_statement : lpvalue K_PLUS_EQ expression @@ -5841,47 +5879,9 @@ analog_statement other block items. */ task_item : block_item_decl { $$ = new svector(0); } - | task_port_item { $$ = $1; } + | tf_port_declaration { $$ = $1; } ; -task_port_item - : port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(@1, $1, - $2 ? IVL_VT_LOGIC : - IVL_VT_NO_TYPE, - $3, $4, $5); - $$ = tmp; - } - - /* When the port is an integer, infer a signed vector of the integer - shape. Generate a range ([31:0]) to make it work. */ - - | port_direction K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, - range_stub, $3, true); - $$ = tmp; - } - - /* Ports can be time with a width of [63:0] (unsigned). */ - - | port_direction K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, - range_stub, $3); - $$ = tmp; - } - - /* Ports can be real or realtime. */ - - | port_direction real_or_realtime list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, false, - 0, $3); - $$ = tmp; - } - - ; - task_item_list : task_item_list task_item { svector*tmp = new svector(*$1, *$2); From b80afdf1f17aee33403e78de685d184fd29152bf Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 10 Mar 2012 10:27:02 -0800 Subject: [PATCH 21/23] SystemVerilog randomize method syntax. --- parse.y | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/parse.y b/parse.y index 79a1ae6c4..5be1b2eca 100644 --- a/parse.y +++ b/parse.y @@ -5757,6 +5757,23 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } + | hierarchy_identifier K_with '{' constraint_block_item_list_opt '}' ';' + { /* ....randomize with { } */ + if ($1 && peek_tail_name(*$1) == "randomize") { + if (!gn_system_verilog()) + yyerror(@2, "error: Randomize with constraint requires SystemVerilog."); + else + yyerror(@2, "sorry: Randomize with constraint not supported."); + } else { + yyerror(@2, "error: Constraint block can only be applied to randomize method."); + } + listpt; + PCallTask*tmp = new PCallTask(*$1, pt); + FILE_NAME(tmp, @1); + delete $1; + $$ = tmp; + } + | implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' ';' { PCallTask*tmp = new PCallTask(*$3, *$5); yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); From b0d61813b23c56c0033d313bbca0ee4282d45bfc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 11 Mar 2012 13:18:24 -0700 Subject: [PATCH 22/23] Get the scope of class methods right Class methods belong in a class scope, not the containing module. So create a lexical scope that carries tasks and functions and create a PClass to represent classes. --- Makefile.in | 5 +++-- Module.cc | 2 +- Module.h | 6 +----- PClass.cc | 30 ++++++++++++++++++++++++++++++ PClass.h | 40 ++++++++++++++++++++++++++++++++++++++++ PScope.cc | 15 +++++++++++++++ PScope.h | 19 +++++++++++++++++++ parse.y | 15 +++++++++------ pform.cc | 45 ++++++++++++++++++++++++++++++++++++--------- pform.h | 6 ++++++ pform_pclass.cc | 37 +++++++++++++++++++++++++++++++++++++ 11 files changed, 197 insertions(+), 23 deletions(-) create mode 100644 PClass.cc create mode 100644 PClass.h create mode 100644 pform_pclass.cc diff --git a/Makefile.in b/Makefile.in index ba3663735..7bd62d4f1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -110,9 +110,10 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ netenum.o netstruct.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \ net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \ net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \ - pform_disciplines.o pform_dump.o pform_struct_type.o pform_types.o \ + pform_disciplines.o pform_dump.o pform_pclass.o pform_struct_type.o \ + pform_types.o \ symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \ - Attrib.o HName.o Module.o PDelays.o PEvent.o PExpr.o PGate.o \ + Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PGate.o \ PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \ Statement.o AStatement.o $M $(FF) $(TT) diff --git a/Module.cc b/Module.cc index 40871d059..66efe26b0 100644 --- a/Module.cc +++ b/Module.cc @@ -28,7 +28,7 @@ list Module::user_defparms; /* n is a permallocated string. */ Module::Module(perm_string n) -: PScope(n) +: PScopeExtra(n) { library_flag = false; is_cell = false; diff --git a/Module.h b/Module.h index 307836edf..a791a6be2 100644 --- a/Module.h +++ b/Module.h @@ -49,7 +49,7 @@ class NetScope; * therefore the handle for grasping the described circuit. */ -class Module : public PScope, public LineInfo { +class Module : public PScopeExtra, public LineInfo { /* The module ports are in general a vector of port_t objects. Each port has a name and an ordered list of @@ -112,10 +112,6 @@ class Module : public PScope, public LineInfo { bool time_from_timescale; bool timescale_warn_done; - /* Task definitions within this module */ - map tasks; - map funcs; - /* The module has a list of generate schemes that appear in the module definition. These are used at elaboration time. */ list generate_schemes; diff --git a/PClass.cc b/PClass.cc new file mode 100644 index 000000000..9a9a62355 --- /dev/null +++ b/PClass.cc @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "PClass.h" + +PClass::PClass(perm_string name, LexicalScope*parent) +: PScopeExtra(name, parent) +{ +} + + +PClass::~PClass() +{ +} diff --git a/PClass.h b/PClass.h new file mode 100644 index 000000000..b4578ad68 --- /dev/null +++ b/PClass.h @@ -0,0 +1,40 @@ +#ifndef __PClass_H +#define __PClass_H +/* + * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "PScope.h" +# include "LineInfo.h" +# include "StringHeap.h" + +/* + * SystemVerilog supports class declarations with their own lexical + * scope, etc. The parser arranges for these to be created and + * collected. + */ + +class PClass : public PScopeExtra, public LineInfo { + + public: + explicit PClass (perm_string name, LexicalScope*parent); + ~PClass(); + +}; + +#endif diff --git a/PScope.cc b/PScope.cc index f23a506ee..0e5dd4abe 100644 --- a/PScope.cc +++ b/PScope.cc @@ -41,3 +41,18 @@ PWire* LexicalScope::wires_find(perm_string name) else return (*cur).second; } + +PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent) +: PScope(n, parent) +{ +} + +PScopeExtra::PScopeExtra(perm_string n) +: PScope(n) +{ +} + +PScopeExtra::~PScopeExtra() +{ +} + diff --git a/PScope.h b/PScope.h index d2b0feb53..e14cb6b4e 100644 --- a/PScope.h +++ b/PScope.h @@ -27,8 +27,10 @@ class PEvent; class PExpr; +class PFunction; class AProcess; class PProcess; +class PTask; class PWire; class Design; @@ -150,4 +152,21 @@ class PScope : public LexicalScope { perm_string name_; }; +/* + * Some scopes can carry definitions. These include Modules and PClass + * scopes. These derive from PScopeExtra so that they hold the maps of + * extra definitions. + */ +class PScopeExtra : public PScope { + + public: + PScopeExtra(perm_string, LexicalScope*parent); + PScopeExtra(perm_string); + ~PScopeExtra(); + + /* Task definitions within this module */ + map tasks; + map funcs; +}; + #endif diff --git a/parse.y b/parse.y index 5be1b2eca..6b97c6364 100644 --- a/parse.y +++ b/parse.y @@ -628,18 +628,21 @@ assignment_pattern /* IEEE1800-2005: A.6.7.1 */ class_declaration /* IEEE1800-2005: A.1.2 */ : K_virtual_opt K_class class_identifier class_declaration_extends_opt ';' - class_items_opt K_endclass - { // Process a class. + { pform_start_class_declaration(@2, $3); if ($4) { yyerror(@4, "sorry: Class extends not supported yet."); } + } + class_items_opt K_endclass + { // Process a class. + pform_end_class_declaration(); yyerror(@2, "sorry: Class declarations not supported yet."); } class_declaration_endname_opt { // Wrap up the class. - if ($9 && $3 && $3->name != $9) { - yyerror(@9, "error: Class end name doesn't match class name."); - delete[]$9; + if ($10 && $3 && $3->name != $10) { + yyerror(@10, "error: Class end name doesn't match class name."); + delete[]$10; } } ; @@ -1348,7 +1351,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ current_task_set_statement(@3, $7); pform_pop_scope(); current_task = 0; - if ($7->size() > 1 && !gn_system_verilog()) { + if ($7 && $7->size() > 1 && !gn_system_verilog()) { yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); } delete $7; diff --git a/pform.cc b/pform.cc index a8569ff01..d34877855 100644 --- a/pform.cc +++ b/pform.cc @@ -23,6 +23,7 @@ # include "pform.h" # include "parse_misc.h" # include "parse_api.h" +# include "PClass.h" # include "PEvent.h" # include "PUdp.h" # include "PGenerate.h" @@ -267,12 +268,30 @@ void pform_pop_scope() lexical_scope = lexical_scope->parent_scope(); } +PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name) +{ + PClass*class_scope = new PClass(name, lexical_scope); + FILE_NAME(class_scope, loc); + + lexical_scope = class_scope; + return class_scope; +} + PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) { perm_string task_name = lex_strings.make(name); PTask*task = new PTask(task_name, lexical_scope, is_auto); FILE_NAME(task, loc); + + LexicalScope*scope = lexical_scope; + PScopeExtra*scopex = dynamic_cast (scope); + while (scope && !scopex) { + scope = scope->parent_scope(); + scopex = dynamic_cast (scope); + } + assert(scopex); + if (pform_cur_generate) { // Check if the task is already in the dictionary. if (pform_cur_generate->tasks.find(task->pscope_name()) != @@ -286,15 +305,15 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) pform_cur_generate->tasks[task->pscope_name()] = task; } else { // Check if the task is already in the dictionary. - if (pform_cur_module->tasks.find(task->pscope_name()) != - pform_cur_module->tasks.end()) { + if (scopex->tasks.find(task->pscope_name()) != scopex->tasks.end()) { cerr << task->get_fileline() << ": error: duplicate " "definition for task '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << scopex->pscope_name() << "'." << endl; error_count += 1; } - pform_cur_module->tasks[task->pscope_name()] = task; + scopex->tasks[task->pscope_name()] = task; } + lexical_scope = task; return task; @@ -307,6 +326,15 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, char*name, PFunction*func = new PFunction(func_name, lexical_scope, is_auto); FILE_NAME(func, loc); + + LexicalScope*scope = lexical_scope; + PScopeExtra*scopex = dynamic_cast (scope); + while (scope && !scopex) { + scope = scope->parent_scope(); + scopex = dynamic_cast (scope); + } + assert(scopex); + if (pform_cur_generate) { // Check if the function is already in the dictionary. if (pform_cur_generate->funcs.find(func->pscope_name()) != @@ -320,14 +348,13 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, char*name, pform_cur_generate->funcs[func->pscope_name()] = func; } else { // Check if the function is already in the dictionary. - if (pform_cur_module->funcs.find(func->pscope_name()) != - pform_cur_module->funcs.end()) { + if (scopex->funcs.find(func->pscope_name()) != scopex->funcs.end()) { cerr << func->get_fileline() << ": error: duplicate " "definition for function '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << scopex->pscope_name() << "'." << endl; error_count += 1; } - pform_cur_module->funcs[func->pscope_name()] = func; + scopex->funcs[func->pscope_name()] = func; } lexical_scope = func; @@ -2640,7 +2667,7 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { + if (/*class_type_t*class_type =*/ dynamic_cast (data_type)) { VLerror(li, "sorry: Class types not supported."); return; } diff --git a/pform.h b/pform.h index 6af305314..941f5f7d3 100644 --- a/pform.h +++ b/pform.h @@ -58,6 +58,7 @@ class PGate; class PExpr; class PSpecPath; +class PClass; struct vlltype; /* @@ -168,6 +169,10 @@ extern Module::port_t* pform_module_port_reference(perm_string name, extern void pform_endmodule(const char*, bool inside_celldefine, Module::UCDriveType uc_drive_def); +extern void pform_start_class_declaration(const struct vlltype&loc, + class_type_t*type); +extern void pform_end_class_declaration(void); + extern void pform_make_udp(perm_string name, list*parms, svector*decl, list*table, Statement*init, @@ -187,6 +192,7 @@ extern void pform_make_udp(perm_string name, */ extern void pform_pop_scope(); +extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name); extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto); extern PFunction*pform_push_function_scope(const struct vlltype&loc, char*name, diff --git a/pform_pclass.cc b/pform_pclass.cc new file mode 100644 index 000000000..935734a62 --- /dev/null +++ b/pform_pclass.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "pform.h" +# include "PClass.h" + +static PClass*pform_cur_class = 0; + +void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type) +{ + PClass*class_scope = pform_push_class_scope(loc, type->name); + assert(pform_cur_class == 0); + pform_cur_class = class_scope; +} + +void pform_end_class_declaration(void) +{ + assert(pform_cur_class); + pform_cur_class = 0; + pform_pop_scope(); +} From 5dbe68829636b138b34ff4bda9c4b5a8b28ee5ab Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 11 Mar 2012 15:08:42 -0700 Subject: [PATCH 23/23] Allow variable initialization in any scope. This is a SystemVerilog feature, so only allow it when compiling SystemVerilog files. --- pform.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pform.cc b/pform.cc index d34877855..d6acae6d4 100644 --- a/pform.cc +++ b/pform.cc @@ -1864,8 +1864,8 @@ void pform_make_pgassign_list(list*alist, void pform_make_reginit(const struct vlltype&li, perm_string name, PExpr*expr) { - if (! pform_at_module_level()) { - VLerror(li, "variable declaration assignments are only " + if (! pform_at_module_level() && !gn_system_verilog()) { + VLerror(li, "error: variable declaration assignments are only " "allowed at the module level."); delete expr; return;