Following are some problems I found in the "System-Verilog 3.0 Accellera's Extensions to Verilog" publication published on June the 3rd 2002. Please note that these problems are view through the eyes of a person who is implementing a System-Verilog parser. Therefore most of this document refers to the syntactic definition of the System-Verilog 3.0 Language. Parts of the publication are quoted in this document. Please note that these parts are copyrighted by the Accellera organization. Most of the suggested changes are typo fixes and removal of redundant rules in the System-Verilog BNF (Annex A). All the changes can be tracked using the Microsoft Word changes tracking tool. (Use the "Reviewing" toolbar (from the Microsoft word menu - View > Toolbars > check in the Reviewing tool bar). Sections 7 and 8 contain more changes (these can not be tracked using the tracking tool). Thanks Dan Jacobi - CAD Engineer Intel Corporation 1. Contact Information For Any questions, clarifications or remarks you can contact me at : Mail : Dan Jacobi Intel Israel (74) LTD. Mail Stop - IDC-4D M.T.M Scientific Center P.O.Box 1659 Haifa 31015 Israel E-mail : dan.jacobi@intel.com Tel : (972)-4-8655855 2. Conventions The conventions used in this document are: * Text that was a part of the Accellera publication and should be removed is stroke out using the "Double strikethrough" - removed text. * My comments and explanations are in blue italic text. They should not be part of the publication. * Changed and added text is sometimes colored in red. * Lingual features added to the Accellera publication or removed from the publication are highlighted in blue. See more details about these features under sections 7 and 8 of this Document. * Page numbers, table numbers and chapter numbers from the original Accellera publication are in purple italic text. 3. Operators - Chapter 7 The second form of the xnor (not exclusive or) operator ^~ is missing in the precedence table. Pages 23-24 Table 7-2 should be modified to: Table 7-2-Operator precedence and associativity () [] . Left Unary ! ~ ++ -- + - & ~& && | ~| || ^ ~^ ^~ Right ** Left Table 7-2-Operator precedence and associativity (continued) * / % Left + - Left << >> <<< >>> Left < <= > >= Left == != === !== Left & Left ^ ~^ ^~ Left | Left && Left || Left ?: right = += -= *= /= %= &= ^= |= <<= >>= <<<= >>>= none 4. Interfaces - Chapter 13 According to the BNF in Annex A sub-bullets A.4.1.1 and A.4.1.2 the proper way to instantiate an interface is using the following syntax: [#] ( ); Braces "( )" must be used after the instance name even if the port list is empty. Quoting the BNF : interface_instantiation ::= interface_identifier [ parameter_value_assignment ] module_instance { , module_instance } ; module_instance ::= name_of_instance ( [ list_of_port_connections ] ) In the some of the RTL examples in chapter 13 that instantiate interfaces with out any ports the braces are missing. I suggest that the BNF will not be changed. If the addition of the braces for interfaces with out any ports will be optional this might cause some confusion between when trying to distinguish between interface instantiations on one-side and interface port declarations and user defined data-types signal declarations on the other side. As shown in the following RTL : typedef logic t1; interface i1(...) ... endinetrface interface i2(...) ... endinterface module m1 (port1) i1 port1; // This is a interface port declaration t1 myt1; // This is a user defined data-type signal declaration i2 i2instance(); // This is an Interface instantiation ... The examples in chapter 13 should be modified as described : Page 67 sub-bullet 13.2.2 first RTL example : module top; logic clk = 0; simple_bus sb_intf(); // Instantiate the interface memMod mem(sb_intf, clk); // Connect the interface to the module instance cpuMod cpu(.b(sb_intf), .clk(clk)); // Either by position or by name endmodule Page 67 sub-bullet 13.2.2 second RTL example : module top; logic clk = 0; simple_bus sb_intf(); memMod mem (.*); // implicit port connections cpuMod cpu (.*); // implicit port connections endmodule Page 68 sub-bullet 13.2.3 first RTL example : module top; logic clk = 0; simple_bus sb_intf(); // Instantiate the interface Page 68 sub-bullet 13.2.3 second RTL example : module top; logic clk = 0; simple_bus sb_intf(); Page 70 sub-bullet 13.4 second RTL example : module top; i2 i(); Page 70 sub-bullet 13.4 third RTL example : module top; i2 i(); Page 80 sub-bullet 13.7 : module mod1(input int in, output int out); intf_mutex mutex(); 5. The BNF - Annex A This Section refers to the BND described in Annex A pages 91-117 in the Accellera publications. Most of the proposed changes come to solve redundant rules or small typos. Following are the proposed changes : Annex A Formal Syntax (Normative) The formal syntax of SystemVerilog is described using Backus-Naur Form (BNF). The conventions used are: - Keywords and punctuation are in bold text. - Syntactic categories are named in non-bold text. - A vertical bar ( | ) separates alternatives. - Square brackets ( [ ] ) enclose optional items. - Braces ( { } ) enclose items which may be repeated zero or more times. The full syntax and semantics of Verilog and SystemVerilog are not described solely using BNF. The normative text description contained within the chapters of the IEEE 1364-2001 Verilog standard and this System- Verilog document provide additional details on the syntax and semantics described in this BNF. A.1 Source text A.1.1 Library source text library_text ::= { library_descriptions } library_descriptions ::= library_declaration | include_statement | config_declaration library_declaration ::= library library_identifier file_path_spec [ { , file_path_spec } ] [ -incdir file_path_spec [ { , file_path_spec } ] ] ; No need to put square brackets ( [ ] ) around braces - making an item, repeated zero or more times, optional is redundant. file_path_spec ::= file_path include_statement ::= `include ; A back tick ( ` ) should come before the include directive. A.1.2 Configuration source text config_declaration ::= config config_identifier ; design_statement {config_rule_statement} endconfig design_statement ::= design { [library_identifier.]cell_identifier } ; config_rule_statement ::= default_clause liblist_clause | inst_clause liblist_clause | inst_clause use_clause | cell_clause liblist_clause | cell_clause use_clause default_clause ::= default inst_clause ::= instance inst_name inst_name ::= topmodule_identifier{.instance_identifier} cell_clause ::= cell [ library_identifier.]cell_identifier liblist_clause ::= liblist [{library_identifier}] No need to put square brackets ( [ ] ) around braces - making an item, repeated zero or more times, optional is redundant. use_clause ::= use [library_identifier.]cell_identifier[:config] A.1.3 Module and primitive source text source_text ::= [ timeunits_declaration ] { description } description ::= module_declaration | udp_declaration | module_root_item | statement module_declaration ::= { attribute_instance } module_keyword module_identifier [ parameter_port_list ] [ list_of_ports ] ; [ timeunits_declaration ] { module_item } endmodule | { attribute_instance } module_keyword module_identifier [ parameter_port_list ] [ list_of_port_declarations ] ; [ timeunits_declaration ] { non_port_module_item } endmodule In case of a module declaration that isn't followed by neither a port list nor a port declaration list then the module declaration should be parsed using the second rule. module_keyword ::= module | macromodule interface_declaration ::= { attribute_instance } interface interface_identifier [ parameter_port_list ] [ list_of_ports ] ; [ timeunits_declaration ] { interface_item } endinterface [: interface_identifier] | { attribute_instance } interface interface_identifier [ parameter_port_list ] [ list_of_port_declarations ] ; [ timeunits_declaration ] { non_port_interface_item } endinterface [: interface_identifier] In case of a interface declaration that isn't followed by neither a port list nor a port declaration list then the interface declaration should be parsed using the second rule. timeunits_declaration ::= timeunit time_literal ; | timeprecision time_literal ; | timeunit time_literal ; timeprecision time_literal ; | timeprecision time_literal ; timeunit time_literal ; A.1.4 Module parameters and ports parameter_port_list ::= # ( parameter_declaration { , parameter_declaration } ) list_of_ports ::= ( port { , port } ) list_of_port_declarations ::= ( port_declaration { , port_declaration } ) | ( ) port ::= [ port_expression ] | . port_identifier ( [ port_expression ] ) port_expression ::= port_reference | { port_reference { , port_reference } } The outer braces ( {} ) should be in bold in order to enable concatenated ports (same as the IEEE 1364-2001 standard) port_reference ::= port_identifier | port_identifier [ constant_expression ] | port_identifier [ range_expression ] port_declaration ::= { attribute_instance } inout_declaration | { attribute_instance } input_declaration | { attribute_instance } output_declaration | { attribute_instance } interface_port_declaration A.1.5 Module items module_common_item ::= { attribute_instance } module_or_generate_item_declaration | { attribute_instance } interface_instantiation module_item ::= port_declaration ; | non_port_module_item module_or_generate_item ::= { attribute_instance } parameter_override | { attribute_instance } continuous_assign | { attribute_instance } gate_instantiation | { attribute_instance } udp_instantiation | { attribute_instance } module_instantiation | { attribute_instance } initial_construct | { attribute_instance } always_construct | { attribute_instance } combinational_statement | { attribute_instance } latch_statement | { attribute_instance } ff_statement | module_common_item module_root_item ::= { attribute_instance } module_instantiation | { attribute_instance } local_parameter_declaration | interface_declaration | module_common_item module_or_generate_item_declaration ::= net_declaration | data_declaration | event_declaration | genvar_declaration | task_declaration | function_declaration non_port_module_item ::= { attribute_instance } generated_module_instantiation | { attribute_instance } local_parameter_declaration | module_or_generate_item | { attribute_instance } parameter_declaration ; | { attribute_instance } specify_block | { attribute_instance } specparam_declaration | module_declaration parameter_override ::= defparam list_of_param_assignments ; A.1.6 Interface items interface_or_generate_item ::= { attribute_instance } continuous_assign | { attribute_instance } initial_construct | { attribute_instance } always_construct | { attribute_instance } combinational_statement | { attribute_instance } latch_statement | { attribute_instance } ff_statement | { attribute_instance } local_parameter_declaration | { attribute_instance } parameter_declaration ; | module_common_item | { attribute_instance } modport_declaration interface_item ::= port_declaration ; | non_port_interface_item A semi-colon (;) is missing after the port declaration non_port_interface_item ::= { attribute_instance } generated_interface_instantiation | { attribute_instance } local_parameter_declaration | { attribute_instance } parameter_declaration ; | { attribute_instance } specparam_declaration | interface_or_generate_item | interface_declaration The syntactic categories "parameter_declaration" and "local_parameter_declaration" can be parsed by parsing the "interface_or_generate_item" syntactic category A.2 Declarations A.2.1 Declaration types A.2.1.1 Module parameter declarations local_parameter_declaration ::= localparam [ signing ] { packed_dimension } [ range ] list_of_param_assignments ; | localparam data_type list_of_param_assignments ; parameter_declaration ::= parameter [ signing ] { packed_dimension } [ range ] list_of_param_assignments | parameter data_type list_of_param_assignments | parameter type list_of_type_assignments specparam_declaration ::= specparam [ range ] list_of_specparam_assignments ; A.2.1.2 Port declarations inout_declaration ::= inout [ port_type ] list_of_port_identifiers input_declaration ::= input [ port_type ] list_of_port_identifiers output_declaration ::= output [ port_type ] list_of_port_identifiers | output data_type list_of_variable_port_identifiers interface_port_declaration ::= interface list_of_interface_identifiers | interface . modport_identifier list_of_interface_identifiers | identifier list_of_interface_identifiers | identifier . modport_identifier list_of_interface_identifiers The token identifier is not a keyword therefore it should not be printed in bold text A.2.1.3 Type declarations block_data_declaration ::= block_variable_declaration | constant_declaration | type_declaration constant_declaration ::= const data_type const_assignment ; data_declaration ::= variable_declaration | constant_declaration | type_declaration event_declaration ::= event list_of_event_identifiers ; genvar_declaration ::= genvar list_of_genvar_identifiers ; net_declaration ::= net_type [ signing ] [ delay3 ] list_of_net_identifiers ; | net_type [ drive_strength ] [ signing ] [ delay3 ] list_of_net_decl_assignments ; | net_type [ vectored | scalared ] [ signing ] { packed_dimension } range [ delay3 ] list_of_net_identifiers ; | net_type [ drive_strength ] [ vectored | scalared ] [ signing ] { packed_dimension } range [ delay3 ] list_of_net_decl_assignments ; | trireg [ charge_strength ] [ signing ] [ delay3 ] list_of_net_identifiers ; | trireg [ drive_strength ] [ signing ] [ delay3 ] list_of_net_decl_assignments ; | trireg [ charge_strength ] [ vectored | scalared ] [ signing ] { packed_dimension } range [ delay3 ] list_of_net_identifiers ; | trireg [ drive_strength ] [ vectored | scalared ] [ signing ] { packed_dimension } range [ delay3 ] list_of_net_decl_assignments ; type_declaration ::= typedef data_type type_declaration_identifier ; | typedef interface_identifier { [ constant_expression ] } . type_identifier type_declaration_identifier ; I'm not sure what the original intention was however one of the following fixes is needed 1. No need to put square brackets ( [ ] ) around braces - making an item, repeated zero or more times, optional is redundant. - Any way this doesn't look right 2. The brackets should be in bold indicating brackets in the RTL. block_variable_declaration ::= [ lifetime ] data_type list_of_variable_identifiers ; | lifetime data_type list_of_variable_decl_assignments ; variable_declaration ::= [ lifetime ] data_type list_of_variable_identifiers_or_assignments ; lifetime ::= static | automatic A.2.2 Declaration data types A.2.2.1 Net and variable types data_type ::= integer_vector_type [ signing ] { packed_dimension } [ range ] | integer_atom_type [ signing ] { packed_dimension } | type_declaration_identifier | non_integer_type | struct [ packed ] [ signing ] { { struct_union_member } } | union [ packed ] [ signing ] { { struct_union_member } } | enum [ integer_type [ signing ] { packed_dimension } ] { enum_identifier [ = constant_expression ] { , enum_identifier [ = constant_expression ] } } | void integer_type ::= integer_vector_type | integer_atom_type integer_atom_type ::= byte | char | shortint | int | longint | integer integer_vector_type ::= bit | logic | reg non_integer_type ::= time | shortreal | real | realtime | $built-in net_type ::= supply0 | supply1 | tri | triand | trior | tri0 | tri1 | wire | wand | wor port_type ::= data_type { packed_dimension } | net_type [ signing ] { packed_dimension } | trireg [ signing ] { packed_dimension } | event | [ signing ] { packed_dimension } range The port_type syntactic category already parses the packed dimensions if needed how ever the optional packed dimension addition in this rule will enable illegal port declarations such as: "output integer [10:0] a;" signing ::= [ signed ] | [ unsigned ] The square brackets are not needed due to the fact that every rule that parses the "signing" token already encloses the token with square brackets. simple_type_or_number ::= simple_type | number simple_type ::= integer_type | non_integer_type | type_identifier struct_union_member ::= data_type list_of_variable_identifiers_or_assignments ; A.2.2.2 Strengths drive_strength ::= ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength0 , highz1 ) | ( strength1 , highz0 ) | ( highz0 , strength1 ) | ( highz1 , strength0 ) strength0 ::= supply0 | strong0 | pull0 | weak0 strength1 ::= supply1 | strong1 | pull1 | weak1 charge_strength ::= ( small ) | ( medium ) | ( large ) A.2.2.3 Delays delay3 ::= # delay_value | # ( delay_value [ , delay_value [ , delay_value ] ] ) delay2 ::= # delay_value | # ( delay_value [ , delay_value ] ) delay_value ::= unsigned_number | parameter_identifier | specparam_identifier | ( mintypmax_expression ) Parsing the mintypmax_expression syntactic category (with out braces) and the identifier tokens are redundant (the mintypemax expression parses the identifiers) Also the brackets are needed to avoid ambiguity when parsing the fallowing blocking assignments: out = #delay ++ data; // can be interpreted as a = #(delay++) data; or a = #delay (++data); See section 7.2 for more information. A.2.3 Declaration lists list_of_event_identifiers ::= event_identifier [ unpacked_dimension { unpacked_dimension }] { , event_identifier [ unpacked_dimension { unpacked_dimension }] } The suggested rule is equivalent to the original rule but is simpler. list_of_genvar_identifiers ::= genvar_identifier { , genvar_identifier } list_of_interface_identifiers ::= interface_identifier { unpacked_dimension } { , interface_identifier { unpacked_dimension } } list_of_net_decl_assignments ::= net_decl_assignment { , net_decl_assignment } list_of_net_identifiers ::= net_identifier [ unpacked_dimension { unpacked_dimension }] { , net_identifier [ unpacked_dimension { unpacked_dimension }] } The suggested rule is equivalent to the original rule but is simpler. list_of_param_assignments ::= param_assignment { , param_assignment } list_of_port_identifiers ::= port_identifier { unpacked_dimension } { , port_identifier { unpacked_dimension } } list_of_udp_port_identifiers ::= port_identifier { , port_identifier } list_of_specparam_assignments ::= specparam_assignment { , specparam_assignment } list_of_type_assignments ::= type_assignment { , type_assignment } list_of_variable_decl_assignments ::= variable_decl_assign_identifier { , variable_decl_assign_identifier } list_of_variable_identifiers ::= variable_declaration_identifier { , variable_declaration_identifier } list_of_variable_identifiers_or_assignments ::= list_of_variable_decl_assignments | list_of_variable_identifiers list_of_variable_port_identifiers ::= port_identifier { unpacked_dimension } [ = constant_expression ] { , port_identifier { unpacked_dimension } [ = constant_expression ] } A.2.4 Declaration assignments const_assignment ::= const_identifier = constant_expression net_decl_assignment ::= net_identifier = expression param_assignment ::= parameter_identifier = constant_param_expression specparam_assignment ::= specparam_identifier = constant_mintypmax_expression | pulse_control_specparam type_assignment ::= type_identifier = data_type pulse_control_specparam ::= PATHPULSE$ = ( reject_limit_value [ , error_limit_value ] ) ; | PATHPULSE$specify_input_terminal_descriptor$specify_output_terminal_descriptor = ( reject_limit_value [ , error_limit_value ] ) ; error_limit_value ::= limit_value reject_limit_value ::= limit_value limit_value ::= constant_mintypmax_expression A.2.5 Declaration ranges unpacked_dimension ::= [ dimension_constant_expression : dimension_constant_expression ] packed_dimension ::= [ dimension_constant_expression : dimension_constant_expression ] range ::= [ msb_constant_expression : lsb_constant_expression ] A.2.6 Function declarations function_declaration ::= function [ automatic ] [ signing ] [ range_or_type ] [ interface_identifier . ] function_identifier ; { function_item_declaration } { function_statement } endfunction [ : function_identifier ] | function [ automatic ] [ signing ] [ range_or_type ] [ interface_identifier . ] function_identifier ( function_port_list ) ; { block_item_declaration } { function_statement } endfunction [ : function_identifier ] function_item_declaration ::= block_item_declaration | { attribute_instance } input_declaration ; | { attribute_instance } output_declaration ; | { attribute_instance } inout_declaration ; function_port_item ::= { attribute_instance } input_declaration | { attribute_instance } output_declaration | { attribute_instance } inout_declaration | { attribute_instance } port_type list_of_port_identifiers function_port_list ::= function_port_item { , function_port_item } list_of_port_identifiers { , function_port_item } This change is needed to support function default port types as described in page 40 of the System-Verilog LRM. This will enable the parsing of function declarations such as : "function logic [15:0] myfunc3(int a, int b, output logic [15:0] u, v);" function_prototype ::= function data_type ( list_of_function_proto_formals ) named_function_proto ::= function data_type function_identifier ( list_of_function_proto_formals ) list_of_function_proto_formals ::= [ { attribute_instance } function_proto_formal { , { attribute_instance } function_proto_formal } ] function_proto_formal ::= input data_type [ variable_declaration_identifier ] | inout data_type [ variable_declaration_identifier ] | output data_type [ variable_declaration_identifier ] | variable_declaration_identifier range_or_type ::= { packed_dimension } range | data_type A.2.7 Task declarations task_declaration ::= task [ automatic ] [ interface_identifier . ] task_identifier ; { task_item_declaration } { statement } endtask [ : task_identifier ] | task [ automatic ] [ interface_identifier . ] task_identifier ( task_port_list ) ; { block_item_declaration } { statement } endtask [ : task_identifier ] task_item_declaration ::= block_item_declaration | { attribute_instance } input_declaration ; | { attribute_instance } output_declaration ; | { attribute_instance } inout_declaration ; task_port_list ::= task_port_item { , task_port_item } list_of_port_identifiers { , task_port_item } task_port_item ::= { attribute_instance } input_declaration | { attribute_instance } output_declaration | { attribute_instance } inout_declaration | { attribute_instance } port_type list_of_port_identifiers This change is needed to support default port types as described in page 38 of the System-Verilog LRM. This will enable the parsing of task declarations such as : "task mytask3(a, b, output logic [15:0] u, v);" and "task mytask3(logic a, b, output logic [15:0] u, v);" task_prototype ::= task ( { attribute_instance } task_proto_formal { , { attribute_instance } task_proto_formal } ) named_task_proto ::= task task_identifier ( task_proto_formal { , task_proto_formal } ) task_proto_formal ::= input data_type [ variable_declaration_identifier ] | inout data_type [ variable_declaration_identifier ] | output data_type [ variable_declaration_identifier ] A.2.8 Block item declarations block_item_declaration ::= { attribute_instance } block_data_declaration | { attribute_instance } event_declaration | { attribute_instance } local_parameter_declaration | { attribute_instance } parameter_declaration ; A.2.9 Interface declarations modport_declaration ::= modport list_of_modport_identifiers ; list_of_modport_identifiers ::= modport_item { , modport_item } modport_item ::= modport_identifier ( modport_port { , modport_port } ) modport_port ::= input [port_type] port_identifier | output [port_type] port_identifier | inout [port_type] port_identifier | interface_identifier . port_identifier | import_export task named_task_proto | import_export function named_function_proto | import_export task_or_function_identifier { , task_or_function_identifier } Fixing a typo the syntactic category is named "named_function_proto". import_export ::= import | export A.3 Primitive instances A.3.1 Primitive instantiation and instances gate_instantiation ::= cmos_switchtype [delay3] cmos_switch_instance { , cmos_switch_instance } ; | enable_gatetype [drive_strength] [delay3] enable_gate_instance { , enable_gate_instance } ; | mos_switchtype [delay3] mos_switch_instance { , mos_switch_instance } ; | n_input_gatetype [drive_strength] [delay2] n_input_gate_instance { , n_input_gate_instance } ; | n_output_gatetype [drive_strength] [delay2] n_output_gate_instance { , n_output_gate_instance } ; | pass_en_switchtype [delay2] pass_enable_switch_instance { , pass_enable_switch_instance } ; | pass_switchtype pass_switch_instance { , pass_switch_instance } ; | pulldown [pulldown_strength] pull_gate_instance { , pull_gate_instance } ; | pullup [pullup_strength] pull_gate_instance { , pull_gate_instance } ; cmos_switch_instance ::= [ name_of_gate_instance ] ( output_terminal , input_terminal , ncontrol_terminal , pcontrol_terminal ) enable_gate_instance ::= [ name_of_gate_instance ] ( output_terminal , input_terminal , enable_terminal ) mos_switch_instance ::= [ name_of_gate_instance ] ( output_terminal , input_terminal , enable_terminal ) n_input_gate_instance ::= [ name_of_gate_instance ] ( output_terminal , input_terminal { , input_terminal } ) n_output_gate_instance ::= [ name_of_gate_instance ] ( output_terminal { , output_terminal } , input_terminal ) pass_switch_instance ::= [ name_of_gate_instance ] ( inout_terminal , inout_terminal ) pass_enable_switch_instance ::= [ name_of_gate_instance ] ( inout_terminal , inout_terminal , enable_terminal ) pull_gate_instance ::= [ name_of_gate_instance ] ( output_terminal ) name_of_gate_instance ::= gate_instance_identifier { range } The token "gate_instance_identifier" already parses the range when reducing the "arrayed_identifier" token. A.3.2 Primitive strengths pulldown_strength ::= ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength0 ) pullup_strength ::= ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength1 ) A.3.3 Primitive terminals enable_terminal ::= expression inout_terminal ::= net_lvalue input_terminal ::= expression ncontrol_terminal ::= expression output_terminal ::= net_lvalue pcontrol_terminal ::= expression A.3.4 Primitive gate and switch types cmos_switchtype ::= cmos | rcmos enable_gatetype ::= bufif0 | bufif1 | notif0 | notif1 mos_switchtype ::= nmos | pmos | rnmos | rpmos n_input_gatetype ::= and | nand | or | nor | xor | xnor n_output_gatetype ::= buf | not pass_en_switchtype ::= tranif0 | tranif1 | rtranif1 | rtranif0 pass_switchtype ::= tran | rtran A.4 Module, interface and generated instantiation A.4.1 Instantiation A.4.1.1 Module instantiation module_instantiation ::= module_identifier [ parameter_value_assignment ] module_instance { , module_instance } ; parameter_value_assignment ::= # ( list_of_parameter_assignments ) list_of_parameter_assignments ::= ordered_parameter_assignment { , ordered_parameter_assignment } | named_parameter_assignment { , named_parameter_assignment } ordered_parameter_assignment ::= expression | data_type named_parameter_assignment ::= . parameter_identifier ( [ expression ] ) | . parameter_identifier ( [ data_type ] ) An empty parameter assignment can be parsed using both rules module_instance ::= name_of_instance ( [ list_of_port_connections ] ) The token squared brackets are redundant an empty port list can be parsed by the 'list_of_port_connections' syntactic category when parsing the ordered port connection. name_of_instance ::= module_instance_identifier { range } The token "module_instance_identifier" already parses the range when reducing the "arrayed_identifier" token. list_of_port_connections ::= ordered_port_connection { , ordered_port_connection } | dot_named_port_connection { , dot_named_port_connection } | { named_port_connection , } dot_star_port_connection { , named_port_connection } ordered_port_connection ::= { attribute_instance } [ expression ] named_port_connection ::= { attribute_instance } .port_identifier ( [ expression ] ) dot_named_port_connection ::= { attribute_instance } .port_identifier | named_port_connection dot_star_port_connection ::= { attribute_instance } .* A.4.1.2 Interface instantiation interface_instantiation ::= interface_identifier [ parameter_value_assignment ] module_instance { , module_instance } ; A.4.2 Generated instantiation A.4.2.1 Generated module instantiation generated_module_instantiation ::= generate { generate_module_item } endgenerate generate_module_item_or_null ::= generate_module_item | ; generate_module_item ::= generate_module_conditional_statement | generate_module_case_statement | generate_module_loop_statement | [ generate_block_identifier : ] generate_module_block | module_or_generate_item generate_module_conditional_statement ::= if ( constant_expression ) generate_module_item_or_null [ else generate_module_item_or_null ] generate_module_case_statement ::= case ( constant_expression ) genvar_module_case_item { genvar_module_case_item }endcase genvar_module_case_item ::= constant_expression { , constant_expression } : generate_module_item_or_null | default [ : ] generate_module_item_or_null generate_module_loop_statement ::= for ( genvar_decl_assignment ; constant_expression ; genvar_assignment ) generate_module_named_block genvar_assignment ::= genvar_identifier = constant_expression | genvar_identifier assignment_operator constant_expression | inc_or_dec_operator genvar_identifier | genvar_identifier inc_or_dec_operator The rule 'genvar_assignment ::= genvar_identifier = constant_expression' is redundant to the rule 'genvar_assignment ::= genvar_identifier assignment_operator constant_expression' due to the fact that the assignment operator includes the equal sign (=). genvar_decl_assignment ::= [ genvar ] genvar_identifier = constant_expression generate_module_named_block ::= begin : generate_block_identifier { generate_module_item } end [ : generate_block_identifier ] | generate_block_identifier : generate_module_block generate_module_block ::= begin [ : generate_block_identifier ] { generate_module_item } end [ : generate_block_identifier ] A.4.2.2 Generated interface instantiation generated_interface_instantiation ::= generate { generate_interface_item } endgenerate generate_interface_item_or_null ::= generate_interface_item | ; generate_interface_item ::= generate_interface_conditional_statement | generate_interface_case_statement | generate_interface_loop_statement | [ generate_block_identifier : ] generate_interface_block | interface_or_generate_item generate_interface_conditional_statement ::= if ( constant_expression ) generate_interface_item_or_null [ else generate_interface_item_or_null ] generate_interface_case_statement ::= case ( constant_expression ) genvar_interface_case_item { genvar_interface_case_item } endcase genvar_interface_case_item ::= constant_expression { , constant_expression } : generate_interface_item_or_null | default [ : ] generate_interface_item_or_null generate_interface_loop_statement ::= for ( genvar_decl_assignment ; constant_expression ; genvar_assignment ) generate_interface_named_block generate_interface_named_block ::= begin : generate_block_identifier { generate_interface_item } end [ : generate_block_identifier ] | generate_block_identifier : generate_interface_block generate_interface_block ::= begin [ : generate_block_identifier ] { generate_interface_item } end [ : generate_block_identifier ] A.5 UDP declaration and instantiation A.5.1 UDP declaration udp_declaration ::= { attribute_instance } primitive udp_identifier ( udp_port_list ) ; udp_port_declaration { udp_port_declaration } udp_body endprimitive | { attribute_instance } primitive udp_identifier ( udp_declaration_port_list ) ; udp_body endprimitive A.5.2 UDP ports udp_port_list ::= output_port_identifier , input_port_identifier { , input_port_identifier } udp_declaration_port_list ::= udp_output_declaration , udp_input_declaration { , udp_input_declaration } udp_port_declaration ::= udp_output_declaration ; | udp_input_declaration ; | udp_reg_declaration ; udp_output_declaration ::= { attribute_instance } output port_identifier | { attribute_instance } output reg port_identifier [ = constant_expression ] udp_input_declaration ::= { attribute_instance } input list_of_udp_port_identifiers udp_reg_declaration ::= { attribute_instance } reg variable_identifier A.5.3 UDP body udp_body ::= combinational_body | sequential_body combinational_body ::= table combinational_entry { combinational_entry } endtable combinational_entry ::= level_input_list : output_symbol ; sequential_body ::= [ udp_initial_statement ] table sequential_entry { sequential_entry } endtable udp_initial_statement ::= initial output_port_identifier = init_val ; init_val ::= 1'b0 | 1'b1 | 1'bx | 1'bX | 1'B0 | 1'B1 | 1'Bx | 1'BX | 1 | 0 sequential_entry ::= seq_input_list : current_state : next_state ; seq_input_list ::= level_input_list | edge_input_list level_input_list ::= level_symbol { level_symbol } edge_input_list ::= { level_symbol } edge_indicator { level_symbol } edge_indicator ::= ( level_symbol level_symbol ) | edge_symbol current_state ::= level_symbol next_state ::= output_symbol | - output_symbol ::= 0 | 1 | x | X level_symbol ::= 0 | 1 | x | X | ? | b | B edge_symbol ::= r | R | f | F | p | P | n | N | * A.5.4 UDP instantiation udp_instantiation ::= udp_identifier [ drive_strength ] [ delay2 ] udp_instance { , udp_instance } ; udp_instance ::= [ name_of_udp_instance ] { range } ( output_terminal , input_terminal { , input_terminal } ) name_of_udp_instance ::= udp_instance_identifier [ range ] The square brackets should not be in bold text the square brackets ( [ ] ) punctuations are parsed in the rule parsing the "range" token. However I think that the range in optional therefore the square brackets should not be bold. A.6 Behavioral statements A.6.1 Continuous assignment statements continuous_assign ::= assign [ drive_strength ] [ delay3 ] list_of_net_assignments ; list_of_net_assignments ::= net_assignment { , net_assignment } net_assignment ::= net_lvalue = expression A.6.2 Procedural blocks and assignments initial_construct ::= initial statement always_construct ::= always statement combinational_statement ::= always_comb statement latch_statement ::= always_latch statement ff_statement ::= always_ff statement blocking_assignment ::= variable_lvalue = delay_or_event_control expression | operator_assignment operator_assignment ::= variable_lvalue assignment_operator expression assignment_operator ::= = | += | -= | *= | /= | %= | &= | |= | ^= | <<= | >>= | <<<= | >>>= nonblocking_assignment ::= variable_lvalue <= [ delay_or_event_control ] expression procedural_continuous_assignments ::= assign variable_assignment | deassign variable_lvalue | force variable_assignment | force net_assignment | release variable_lvalue | release net_lvalue function_blocking_assignment ::= variable_lvalue = expression function_statement_or_null ::= function_statement | { attribute_instance } ; variable_assignment ::= variable_lvalue = expression A.6.3 Parallel and sequential blocks function_seq_block ::= begin [ : block_identifier { block_item_declaration } ] { function_statement } end par_block ::= fork [ : block_identifier ] { block_item_declaration } { statement } join [ : block_identifier ] seq_block ::= begin [ : block_identifier ] { block_item_declaration } { statement } end [ : block_identifier ] A.6.4 Statements statement ::= [ block_identifier : ] statement_item statement_item ::= { attribute_instance } blocking_assignment ; | { attribute_instance } nonblocking_assignment ; | { attribute_instance } procedural_continuous_assignments ; | { attribute_instance } case_statement | { attribute_instance } conditional_statement | { attribute_instance } inc_or_dec_expression ; A semi-colon (;) is needed here | { attribute_instance } function_call_statement7 The rule that parses the "function_call_statement" can be found under the sub-bullet A.6.9.1. The function call statement is needed due to the following: 1. A semi-colon (;) is needed at the end of the statement. 2. The' {attribute instance}' should not be parsed twice (once in this rule and once in the rule that parses the "function_call" syntactic category. | { attribute_instance } disable_statement | { attribute_instance } event_trigger | { attribute_instance } loop_statement | { attribute_instance } jump_statement | { attribute_instance } par_block | { attribute_instance } procedural_timing_control_statement | { attribute_instance } seq_block | { attribute_instance } system_task_enable | { attribute_instance } task_enable | { attribute_instance } wait_statement | { attribute_instance } process statement | { attribute_instance } proc_assertion statement_or_null ::= statement | { attribute_instance } ; function_statement ::= [ block_identifier : ] function_statement_item function_statement_item ::= { attribute_instance } function_blocking_assignment ; | { attribute_instance } function_case_statement | { attribute_instance } function_conditional_statement | { attribute_instance } inc_or_dec_expression ; A semi-colon (;) is needed here | { attribute_instance } function_call_statement 7 The rule that parses the "function_call_statement" can be found under the sub-bullet A.6.9.1. The function call statement is needed due to the following: 1. A semi-colon (;) is needed at the end of the statement. 2. The' {attribute instance}' should not be parsed twice (once in this rule and once in the rule that parses the "function_call" syntactic category. | { attribute_instance } function_loop_statement | { attribute_instance } jump_statement | { attribute_instance } function_seq_block | { attribute_instance } disable_statement | { attribute_instance } system_task_enable A.6.5 Timing control statements procedural_timing_control_statement ::= delay_or_event_control statement_or_null delay_or_event_control ::= delay_control | event_control | repeat ( expression ) event_control delay_control ::= # delay_value | # ( mintypmax_expression ) event_control ::= @ event_identifier | @ ( event_expression ) | @* | @ (*) event_expression ::= expression [ iff expression ] | hierarchical_identifier [ iff expression ] | [ edge ] expression [ iff expression ] | event_expression or event_expression | event_expression , event_expression The two rules "event_expression::= expression [iff expression]" and "event_expression::= hierarchical_identifier [iff expression]"are redundant due to the fact that they can be parsed using the rule "event_expression::=[edge] expression [iff expression]" edge ::= posedge | negedge | changed jump_statement ::= return [ expression ] ; | break ; | continue ; wait_statement ::= wait ( expression ) statement_or_null event_trigger ::= -> hierarchical_event_identifier ; disable_statement ::= disable hierarchical_task_identifier ; | disable hierarchical_block_identifier ; A.6.6 Conditional statements conditional_statement ::= [ unique_priority ] if ( expression ) statement_or_null [ else statement_or_null ] | if_else_if_statement if_else_if_statement ::= [ unique_priority ] if ( expression ) statement_or_null { else [ unique_priority ] if ( expression ) statement_or_null } [ else statement_or_null ] The "statement_or_null" token takes care of the nested ifs function_conditional_statement ::= [ unique_priority ] if ( expression ) function_statement_or_null [ else function_statement_or_null ] | function_if_else_if_statement function_if_else_if_statement ::= [ unique_priority ] if ( expression ) function_statement_or_null { else [ unique_priority ] if ( expression ) function_statement_or_null } [ else function_statement_or_null ] The "function_statement_or_null" token takes care of the nested ifs unique_priority ::= unique | priority A.6.7 Case statements case_statement ::= [ unique_priority ] case ( expression ) case_item { case_item } endcase | [ unique_priority ] casez ( expression ) case_item { case_item } endcase | [ unique_priority ] casex ( expression ) case_item { case_item } endcase case_item ::= expression { , expression } : statement_or_null | default [ : ] statement_or_null function_case_statement ::= [ unique_priority ] case ( expression ) function_case_item { function_case_item } endcase | [ unique_priority ] casez ( expression ) function_case_item { function_case_item } endcase | [ unique_priority ] casex ( expression ) function_case_item { function_case_item } endcase function_case_item ::= expression { , expression } : function_statement_or_null | default [ : ] function_statement_or_null A.6.8 Looping statements function_loop_statement ::= forever function_statement | repeat ( expression ) function_statement_or_null | while ( expression ) function_statement_or_null | for ( variable_decl_or_assignment ; expression ; for_variable_assignment ) function_statement_or_null | do function_statement while ( expression ) loop_statement ::= forever statement | repeat ( expression ) statement_or_null | while ( expression ) statement_or_null | for ( variable_decl_or_assignment ; expression ; for_variable_assignment ) statement_or_null | do statement while ( expression ) for_variable_assignment ::= operator_assignment | inc_or_dec_expression 1. These changes will enable such for statements as : for (cnt =0;cnt < 99;cnt++) ... and for (cnt =0;cnt < 99;cnt += 1) ... See more information under section 8.2. 2. the rule parsing the repeat statement was removed due to the fact that it redundant and can be parsed by the syntactic category 'procedural_timing_control_statement' when it parses the 'delay_or_event_control' syntactic category. variable_decl_or_assignment ::= data_type list_of_variable_identifiers_or_assignments ; | variable_assignment The semi-colon (;) should be removed using the semi-colon the following rule will be parsed for (int a = 0 ; ; a <1;a=a+1) ... // two semi-colons after the variable declaration. A.6.9 Task enable statements system_task_enable ::= system_task_identifier [ ( system_task_enable_argument_list ) ] ; system_task_enable_argument_list ::= { [expression] , } These changes are needed to support the "null arguments" as described in the IEEE-1364-2001 standard page278 under sub-bullet 17.1.1.This will enable the parsing of task enables such as "$monitor (time ,,"set=",set);" however an empty argument list is illegal therefore the following should not be parsed "$monitor();" task_enable ::= hierarchical_task_identifier [ ( expression { , expression } ) ] ; A.6.9.1 function call statements function_call_statement ::= hierarchical_function_identifier ( expression { , expression } ) ; The function call statement is needed due to the following: 1. A semi-colon (;) is needed at the end of the statement. 2. The' {attribute instance}' should not be parsed twice (once in this rule and once in the rule that parses the "function_call" syntactic category. A.6.10 Assertion statements proc_assertion ::= immediate_assert | strobed_assert | clocked_immediate_assert | clocked_strobed_assert immediate_assert ::= assert ( expression ) statement_or_null [ else statement_or_null ] strobed_assert ::= assert_strobe ( expression ) restricted_statement_or_null [ else restricted_statement_or_null ] clocked_immediate_assert ::= assert ( expr_sequence ) step_control statement_or_null [ else statement_or_null ] clocked_strobed_assert ::= assert_strobe ( expr_sequence ) step_control restricted_statement_or_null [ else restricted_statement_or_null ] All the clocked and non-clocked assertions were merged proc_assertion ::= immediate_assert | strobed_assert immediate_assert ::= assert ( expression ) [step_control ] statement_or_null [ else statement_or_null ] strobed_assert ::= assert_strobe ( expression ) [step_control ] restricted_statement_or_null [ else restricted_statement_or_null ] restricted_statement_or_null ::= restricted_statement | { attribute_instance } ; restricted_statement ::= [ block_identifier : ] restricted_statement_item restricted_statement_item ::= { attribute_instance } proc_assertion | { attribute_instance } system_task_enable | { attribute_instance } delay_or_event_control statement | { attribute_instance } restricted_seq_block restricted_seq_block ::= begin [ : block_identifier ] { block_item_declaration }{ restricted_statement } end [ : block_identifier ] expr_sequence ::= expression | [ constant_expression ] | range | expr_sequence ; expr_sequence | expr_sequence * [ constant_expression ] | expr_sequence * range | ( expr_sequence ) Squared brackets around the constant_expression should be in bold. step_control ::= @@ event_identifier | @@ ( event_expression ) A.7 Specify section A.7.1 Specify block declaration specify_block ::= specify { specify_item } endspecify specify_item ::= specparam_declaration | pulsestyle_declaration | showcancelled_declaration | path_declaration | system_timing_check pulsestyle_declaration ::= pulsestyle_onevent list_of_path_outputs ; | pulsestyle_ondetect list_of_path_outputs ; showcancelled_declaration ::= showcancelled list_of_path_outputs ; | noshowcancelled list_of_path_outputs ; A.7.2 Specify path declarations path_declaration ::= simple_path_declaration ; | edge_sensitive_path_declaration ; | state_dependent_path_declaration ; simple_path_declaration ::= parallel_path_description = path_delay_value | full_path_description = path_delay_value parallel_path_description ::= ( specify_input_terminal_descriptor [ polarity_operator ] => specify_output_terminal_descriptor ) full_path_description ::= ( list_of_path_inputs [ polarity_operator ] *> list_of_path_outputs ) list_of_path_inputs ::= specify_input_terminal_descriptor { , specify_input_terminal_descriptor } list_of_path_outputs ::= specify_output_terminal_descriptor { , specify_output_terminal_descriptor } A.7.3 Specify block terminals specify_input_terminal_descriptor ::= input_identifier | input_identifier [ constant_expression ] | input_identifier [ range_expression ] specify_output_terminal_descriptor ::= output_identifier | output_identifier [ constant_expression ] | output_identifier [ range_expression ] input_identifier ::= input_port_identifier | inout_port_identifier output_identifier ::= output_port_identifier | inout_port_identifier A.7.4 Specify path delays path_delay_value ::= list_of_path_delay_expressions | ( list_of_path_delay_expressions ) list_of_path_delay_expressions ::= t_path_delay_expression | trise_path_delay_expression , tfall_path_delay_expression | trise_path_delay_expression , tfall_path_delay_expression , tz_path_delay_expression | t01_path_delay_expression , t10_path_delay_expression , t0z_path_delay_expression , tz1_path_delay_expression , t1z_path_delay_expression , tz0_path_delay_expression | t01_path_delay_expression , t10_path_delay_expression , t0z_path_delay_expression , tz1_path_delay_expression , t1z_path_delay_expression , tz0_path_delay_expression t0x_path_delay_expression , tx1_path_delay_expression , t1x_path_delay_expression , tx0_path_delay_expression , txz_path_delay_expression , tzx_path_delay_expression t_path_delay_expression ::= path_delay_expression trise_path_delay_expression ::= path_delay_expression tfall_path_delay_expression ::= path_delay_expression tz_path_delay_expression ::= path_delay_expression t01_path_delay_expression ::= path_delay_expression t10_path_delay_expression ::= path_delay_expression t0z_path_delay_expression ::= path_delay_expression tz1_path_delay_expression ::= path_delay_expression t1z_path_delay_expression ::= path_delay_expression tz0_path_delay_expression ::= path_delay_expression t0x_path_delay_expression ::= path_delay_expression tx1_path_delay_expression ::= path_delay_expression t1x_path_delay_expression ::= path_delay_expression tx0_path_delay_expression ::= path_delay_expression txz_path_delay_expression ::= path_delay_expression tzx_path_delay_expression ::= path_delay_expression path_delay_expression ::= constant_mintypmax_expression edge_sensitive_path_declaration ::= parallel_edge_sensitive_path_description = path_delay_value | full_edge_sensitive_path_description = path_delay_value parallel_edge_sensitive_path_description ::= ( [ edge_identifier ] specify_input_terminal_descriptor => specify_output_terminal_descriptor [ polarity_operator ] : data_source_expression ) full_edge_sensitive_path_description ::= ( [ edge_identifier ] list_of_path_inputs *> list_of_path_outputs [ polarity_operator ] : data_source_expression ) data_source_expression ::= expression edge_identifier ::= posedge | negedge state_dependent_path_declaration ::= if ( module_path_expression ) simple_path_declaration | if ( module_path_expression ) edge_sensitive_path_declaration | ifnone simple_path_declaration polarity_operator ::= + | - A.7.5 System timing checks A.7.5.1 System timing check commands system_timing_check ::= $setup_timing_check | $hold_timing_check | $setuphold_timing_check | $recovery_timing_check | $removal_timing_check | $recrem_timing_check | $skew_timing_check | $timeskew_timing_check | $fullskew_timing_check | $period_timing_check | $width_timing_check | $nochange_timing_check $setup_timing_check ::= $setup ( data_event , reference_event , timing_check_limit [ , [ notify_reg ] ] ) ; $hold_timing_check ::= $hold ( reference_event , data_event , timing_check_limit [ , [ notify_reg ] ] ) ; $setuphold_timing_check ::= $setuphold ( reference_event , data_event , timing_check_limit , timing_check_limit [ , [ notify_reg ] [ , [ stamptime_condition ] [ , [ checktime_condition ] [ , [ delayed_reference ] [ , [ delayed_data ] ] ] ] ] ] ) ; $recovery_timing_check ::= $recovery ( reference_event , data_event , timing_check_limit [ , [ notify_reg ] ] ) ; $removal_timing_check ::= $removal ( reference_event , data_event , timing_check_limit [ , [ notify_reg ] ] ) ; $recrem_timing_check ::= $recrem ( reference_event , data_event , timing_check_limit , timing_check_limit [ , [ notify_reg ] [ , [ stamptime_condition ] [ , [ checktime_condition ] [ , [ delayed_reference ] [ , [ delayed_data ] ] ] ] ] ] ) ; $skew_timing_check ::= $skew ( reference_event , data_event , timing_check_limit [ , [ notify_reg ] ] ) ; $timeskew_timing_check ::= $timeskew ( reference_event , data_event , timing_check_limit [ , [ notify_reg ] [ , [ event_based_flag ] [ , [ remain_active_flag ] ] ] ] ) ; $fullskew_timing_check ::= $fullskew ( reference_event , data_event , timing_check_limit , timing_check_limit [ , [ notify_reg ] [ , [ event_based_flag ] [ , [ remain_active_flag ] ] ] ] ) ; $period_timing_check ::= $period ( controlled_reference_event , timing_check_limit [ , [ notify_reg ] ] ) ; $width_timing_check ::= $width ( controlled_reference_event , timing_check_limit , threshold [ , [ notify_reg ] ] ) ; $nochange_timing_check ::= $nochange ( reference_event , data_event , start_edge_offset , end_edge_offset [ , [ notify_reg ] ] ) ; A.7.5.2 System timing check command arguments checktime_condition ::= mintypmax_expression controlled_reference_event ::= controlled_timing_check_event data_event ::= timing_check_event delayed_data ::= terminal_identifier | terminal_identifier [ constant_mintypmax_expression ] delayed_reference ::= terminal_identifier | terminal_identifier [ constant_mintypmax_expression ] end_edge_offset ::= mintypmax_expression event_based_flag ::= constant_expression notify_reg ::= variable_identifier reference_event ::= timing_check_event remain_active_flag ::= constant_mintypmax_expression stamptime_condition ::= mintypmax_expression start_edge_offset ::= mintypmax_expression threshold ::=constant_expression timing_check_limit ::= expression A.7.5.3 System timing check event definitions timing_check_event ::= [timing_check_event_control] specify_terminal_descriptor [ &&& timing_check_condition ] controlled_timing_check_event ::= timing_check_event_control specify_terminal_descriptor [ &&& timing_check_condition ] timing_check_event_control ::= posedge | negedge | edge_control_specifier The 'posedge' and 'negedge' keywords are redundant due to the fact that they can be parsed when parsing the 'edge_control_specifier' token. specify_terminal_descriptor ::= specify_input_terminal_descriptor | specify_output_terminal_descriptor edge_control_specifier ::= edge [ edge_descriptor [ , edge_descriptor ] ] edge_descriptor1 ::= 01 | 10 | z_or_x zero_or_one | zero_or_one z_or_x zero_or_one ::= 0 | 1 z_or_x ::= x | X | z | Z timing_check_condition ::= scalar_timing_check_condition | ( scalar_timing_check_condition ) Assuming the next fix is correct than the brackets can be added when parsing the token expression therefore the removed rule is redundant. scalar_timing_check_condition ::= expression | ~ expression | expression == scalar_constant | expression === scalar_constant | expression != scalar_constant | expression !== scalar_constant The rules stroked out are redundant due to the fact that they all can be parsed by parsing the "expression token. The main intention might have been to use the syntactic category "primary" instead of "expression" in all the above rules in this case we wouldn't need to strike out the specified rules. scalar_constant ::= 1'b0 | 1'b1 | 1'B0 | 1'B1 | 'b0 | 'b1 | 'B0 | 'B1 | 1 | 0 A.8 Expressions A.8.1 Concatenations concatenation ::= { expression { , expression } } constant_concatenation ::= { constant_expression { , constant_expression } } constant_multiple_concatenation ::= { constant_expression constant_concatenation } module_path_concatenation ::= { module_path_expression { , module_path_expression } } module_path_multiple_concatenation ::= { constant_expression module_path_concatenation } multiple_concatenation ::= { constant_expression concatenation } net_concatenation ::= { net_concatenation_value { , net_concatenation_value } } net_concatenation_value ::= hierarchical_net_identifier | hierarchical_net_identifier [ expression ] { [ expression ] } | hierarchical_net_identifier [ expression ] { [ expression ] } [ range_expression ] | hierarchical_net_identifier [ range_expression ] | net_concatenation variable_concatenation ::= { variable_concatenation_value { , variable_concatenation_value } } variable_concatenation_value ::= hierarchical_variable_identifier | hierarchical_variable_identifier [ expression ] { [ expression ] } | hierarchical_variable_identifier [ expression ] { [ expression ] } [ range_expression ] | hierarchical_variable_identifier [ range_expression ] | variable_concatenation A.8.2 Function calls constant_function_call ::= function_identifier { attribute_instance } ( constant_expression { , constant_expression } ) function_call ::= hierarchical_function_identifier{ attribute_instance } ( expression { , expression } ) genvar_function_call ::= genvar_function_identifier { attribute_instance } ( constant_expression { , constant_expression } ) The "genvar_function_call" semantic category is never used. system_function_call ::= system_function_identifier [ ( expression { , expression } ) ] A.8.3 Expressions base_expression ::= expression inc_or_dec_expression ::= inc_or_dec_operator variable_lvalue_item | variable_lvalue_item inc_or_dec_operator Using the previous rules the following expressions are legal "foo(a1,a2,a3)++" and " i++ ++" conditional_expression ::= expression1 ? { attribute_instance } expression2 : expression3 constant_base_expression ::= constant_expression constant_expression ::= constant_primary | unary_operator { attribute_instance } constant_primary | constant_expression binary_operator { attribute_instance } constant_expression | constant_expression ? { attribute_instance } constant_expression : constant_expression | string constant_mintypmax_expression ::= constant_expression | constant_expression : constant_expression : constant_expression constant_param_expression ::= constant_expression | data_type constant_range_expression ::= constant_expression | msb_constant_expression : lsb_constant_expression | constant_base_expression +: width_constant_expression | constant_base_expression -: width_constant_expression All rules that parse the "constant_range_expression" token already parse the "constant_expression" token. dimension_constant_expression ::= constant_expression expression1 ::= expression expression2 ::= expression expression3 ::= expression expression ::= primary | unary_operator { attribute_instance } primary | { attribute_instance } inc_or_dec_expression | ( operator_assignment ) | expression binary_operator { attribute_instance } expression | conditional_expression | string The Attribute was removed from the" inc_or_dec_expression" syntactic category due to the fact that this is a built in conflict with in the language. For Example lets assume the following blocking assignment : lhs =op1 - (* attribute *) op2++; the attribute can refer to the minus ('-') binary operator or to the '++' auto-increment operator. My suggestion is to locate the attribute in-between the operand and the operator such as lhs = op1 (* auto_inc_attribute *) ++ * -- (* auto_dec_attribute *) op2; Using the following BNF: expression ::= | inc_or_dec_expression inc_or_dec_expression ::= inc_or_dec_operator { attribute_instance } variable_lvalue_item | variable_lvalue_item { attribute_instance } inc_or_dec_operator See more information under section 7.4. lsb_constant_expression ::= constant_expression mintypmax_expression ::= expression | expression : expression : expression module_path_conditional_expression ::= module_path_expression ? { attribute_instance } module_path_expression : module_path_expression module_path_expression ::= module_path_primary | unary_module_path_operator { attribute_instance } module_path_primary | module_path_expression binary_module_path_operator { attribute_instance } module_path_expression | module_path_conditional_expression module_path_mintypmax_expression ::= module_path_expression | module_path_expression : module_path_expression : module_path_expression msb_constant_expression ::= constant_expression range_expression ::= expression | msb_constant_expression : lsb_constant_expression | base_expression +: width_constant_expression | base_expression -: width_constant_expression All rules that parse the "range_expression" token already parse the "expression" token. width_constant_expression ::= constant_expression A.8.4 Primaries constant_primary ::= constant_concatenation | constant_function_call | ( constant_mintypmax_expression ) | constant_multiple_concatenation | genvar_identifier | number | parameter_identifier | specparam_identifier | ( time_literal ) | '0 | '1 | 'z | 'Z | 'x | 'X The rule constant_primary ::= time_literl is problematic here is it causes an ambiguousness when trying to parse and #1 ms(a,b,c) this can be interpreted as an unnamed and gate instance with a delay of 1 microsecond or an and gate named ms instance with a delay of 1 time unit. See more information under section 7.3. module_path_primary ::= number | identifier | module_path_concatenation | module_path_multiple_concatenation | function_call | system_function_call | constant_function_call | ( module_path_mintypmax_expression ) primary ::= number | hierarchical_identifier | hierarchical_identifier [ expression ] { [ expression ] } | hierarchical_identifier [ expression ]{ [ expression ] } [ range_expression ] | hierarchical_identifier [ range_expression ] | hierarchical_identifier { [ expression ] } [ [ range_expression ] ] This is a simpler way to write the four previous rules that were stroke out. | concatenation | multiple_concatenation | function_call | system_function_call | constant_function_call | ( mintypmax_expression ) | { expression { , expression } } | { expression { expression } } The concatenation operator ( {...} ) and replication operator ( {...{...} } ) are redundant due to the fact that they are already parsed using the "multiple_concatenation" and "concatenation" tokens. | simple_type_or_number ' ( expression ) | simple_type_or_number ' { expression { , expression } } | simple_type_or_number ' { expression { expression } } | ( time_literal ) | '0 | '1 | 'z | 'Z | 'x | 'X The rule primary ::= time_literl is problematic here is it causes an ambiguousness when trying to parse and #1 ms(a,b,c) this can be interpreted as an unnamed and gate instance with a delay of 1 microsecond or an and gate named ms instance with a delay of 1 time unit. See more information under section 7.3. time_literal ::= unsigned_number time_unit | fixed_point_number time_unit time_unit ::= s | ms | us | ns | ps | fs A.8.5 Expression left-side values net_lvalue ::= hierarchical_net_identifier | hierarchical_net_identifier [ constant_expression ] { [ constant_expression ] } | hierarchical_net_identifier [ constant_expression ] { [ constant_expression ] } [ constant_range_expression ] | hierarchical_net_identifier [ constant_range_expression ] | hierarchical_net_identifier { [ constant_expression ] } [ [ constant_range_expression ] ] This is a simpler way to write the four previous rules that were stroke out. | hierarchical_net_identifier ( [ constant_expression { , constant_expression } ] ) In what case can brackets appear in the left hand side of an assignment ? Is this legal "assign ident(exp1,exp2) = 1'b1;" ? The original intention might have been functions returning values by reference or functions returning some kind of pointer. | net_concatenation variable_lvalue ::= variable_lvalue_item [ inc_or_dec_operator ] | hierarchical_variable_identifier ( [ constant_expression { , constant_expression } ] ) In what case can brackets appear in the left hand side of an assignment ? Is this legal "ident(exp1,exp2) = 1'b1;" ? The original intention might have been functions returning values by reference or functions returning some kind of pointer. variable_lvalue_item ::= hierarchical_variable_identifier | hierarchical_variable_identifier [ expression ] { [ expression ] } | hierarchical_variable_identifier [ expression ] { [ expression ] } [ range_expression ] | hierarchical_variable_identifier [ range_expression ] | hierarchical_variable_identifier { [ expression ] } [ [ range_expression ] ] This is a simpler way to write the four previous rules that were stroke out. | variable_concatenation A.8.6 Operators unary_operator ::= + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~ binary_operator ::= + | - | * | / | % | == | != | === | !== | && | || | ** | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | << | >>> | <<< inc_or_dec_operator ::= ++ | -- unary_module_path_operator ::= ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~ binary_module_path_operator ::= == | != | && | || | & | | | ^ | ^~ | ~^ A.8.7 Numbers number ::= decimal_number | octal_number | binary_number | hex_number | real_number decimal_number ::= unsigned_number | [ size ] decimal_base unsigned_number | [ size ] decimal_base x_digit { _ } | [ size ] decimal_base z_digit { _ } binary_number ::= [ size ] binary_base binary_value octal_number ::= [ size ] octal_base octal_value hex_number ::= [ size ] hex_base hex_value sign ::= + | - size ::= non_zero_unsigned_number non_zero_unsigned_number1 ::= non_zero_decimal_digit { _ | decimal_digit} real_number1 ::= fixed_point_number | unsigned_number [ . unsigned_number ] exp [ sign ] unsigned_number fixed_point_number1 ::= unsigned_number . unsigned_number exp ::= e | E unsigned_number1 ::= decimal_digit { _ | decimal_digit } binary_value1 ::= binary_digit { _ | binary_digit } octal_value1 ::= octal_digit { _ | octal_digit } hex_value1 ::= hex_digit { _ | hex_digit } decimal_base1 ::= '[s|S]d | '[s|S]D binary_base1 ::= '[s|S]b | '[s|S]B octal_base1 ::= '[s|S]o | '[s|S]O hex_base1 ::= '[s|S]h | '[s|S]H non_zero_decimal_digit ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 decimal_digit ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 binary_digit ::= x_digit | z_digit | 0 | 1 octal_digit ::= x_digit | z_digit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 hex_digit ::= x_digit | z_digit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | f | A | B | C | D | E | F x_digit ::= x | X z_digit ::= z | Z | ? A.8.8 Strings string ::= " { Any_ASCII_Characters_except_new_line } " A.9 General A.9.1 Attributes attribute_instance ::= (* attr_spec { , attr_spec } *) attr_spec ::= attr_name = constant_expression | attr_name attr_name ::= identifier A.9.2 Comments comment ::= one_line_comment | block_comment one_line_comment ::= // comment_text \n block_comment ::= /* comment_text */ comment_text ::= { Any_ASCII_character } A.9.3 Identifiers arrayed_identifier ::= simple_arrayed_identifier | escaped_arrayed_identifier block_identifier ::= identifier cell_identifier ::= identifier config_identifier ::= identifier const_identifier ::= identifier enum_identifier ::= identifier escaped_arrayed_identifier ::= escaped_identifier [ range ] The square brackets should not be in bold text the square brackets ( [ ] ) punctuations are parsed in the rule parsing the "range" token. However I think that the range in optional therefore the square brackets should not be bold. escaped_hierarchical_identifier4 ::= escaped_hierarchical_branch { .simple_hierarchical_branch | .escaped_hierarchical_branch } escaped_identifier ::= \ {any_ASCII_character_except_white_space} white_space event_identifier ::= identifier function_identifier ::= identifier gate_instance_identifier ::= arrayed_identifier generate_block_identifier ::= identifier genvar_function_identifier ::= identifier8 genvar_identifier ::= identifier hierarchical_block_identifier ::= hierarchical_identifier hierarchical_event_identifier ::= hierarchical_identifier hierarchical_function_identifier ::= hierarchical_identifier hierarchical_identifier ::= simple_hierarchical_identifier | escaped_hierarchical_identifier hierarchical_net_identifier ::= hierarchical_identifier hierarchical_variable_identifier ::= hierarchical_identifier hierarchical_task_identifier ::= hierarchical_identifier identifier ::= simple_identifier | escaped_identifier interface_identifier ::= identifier inout_port_identifier ::= identifier input_port_identifier ::= identifier instance_identifier ::= identifier library_identifier ::= identifier memory_identifier ::= identifier modport_identifier ::= identifier module_identifier ::= identifier module_instance_identifier ::= arrayed_identifier net_identifier ::= identifier output_port_identifier ::= identifier parameter_identifier ::= identifier port_identifier ::= identifier real_identifier ::= identifier simple_arrayed_identifier ::= simple_identifier [ range ] The square brackets should not be in bold text the square brackets ( [ ] ) punctuations are parsed in the rule parsing the "range" token. However I think that the range in optional therefore the square brackets should not be bold. simple_hierarchical_identifier3 ::= simple_hierarchical_branch [ .escaped_identifier ] simple_identifier2 ::= [ a-zA-Z_ ] { [ a-zA-Z0-9_$ ] } specparam_identifier ::= identifier state_identifier ::= identifier system_function_identifier5 ::= $[ a-zA-Z0-9_$ ]{ [ a-zA-Z0-9_$ ] } system_task_identifier5 ::= $[ a-zA-Z0-9_$ ]{ [ a-zA-Z0-9_$ ] } task_or_function_identifier ::= task_identifier | function_identifier task_identifier ::= identifier terminal_identifier ::= identifier text_macro_identifier ::= simple_identifier topmodule_identifier ::= identifier type_declaration_identifier ::= type_identifier { packed_dimension } type_identifier ::= identifier udp_identifier ::= identifier udp_instance_identifier ::= arrayed_identifier variable_decl_assign_identifier ::= variable_identifier { unpacked_dimension } [ = constant_expression ] variable_declaration_identifier ::= variable_identifier { unpacked_dimension } variable_identifier ::= identifier A.9.4 Identifier branches simple_hierarchical_branch3 ::= simple_identifier { [ expression ] } [ { . simple_identifier { [expression] } } ] escaped_hierarchical_branch4 ::= escaped_identifier { [expression] } [ { . escaped_identifier { [expression] } } ] These changes are needed to enable expressions with in select indexes of hierarchical identifiers. According to the BNF the following example is illegal: typedef struct {logic field1,int field2} pair; module mymodule(...); parameter p1 = 127; pair mypair [p1:0] ; mypair[0].field1 = 1'b1; // this is legal due to the fact that the index '0' is an unsigned number mypair[p1].field1 = 1'b1; // this is illegal due to the fact that the index p1 is not an unsigned number mypair[0+1].field1 = 1'b1; // this is also illegal int cnt; always @* for (cnt =2;cnt < p1;cnt = cnt + 1) mypair[cnt].field1 = 1'b0; // this is also illegal endmodule See section 0 for more information. A.9.5 White space white_space ::= space | tab | newline | eof6 NOTES 1) Embedded spaces are illegal. 2) A simple_identifier and arrayed_reference shall start with an alpha or underscore (_) character, shall have at least one character, and shall not have any spaces. 3) The period (.) in simple_hierarchical_identifier and simple_hierarchical_branch shall not be preceded or followed by white_space. 4) The period in escaped_hierarchical_identifier and escaped_hierarchical_branch shall be preceded by white_space, but shall not be followed by white_space. 5) The $ character in a system_function_identifier or system_task_identifier shall not be followed by white_space. A system_function_identifier or system_task_identifier shall not be escaped. 6) End of file. 7) Must be a void function 8) Hierarchy is not allowed 6. Keywords - Annex B The keyword "transition" and "endtransition" are defined in Annex B however they are not used in the BNF nor are they mentioned in the rest of the Accellera publication. 7. Lingual features to be removed 7.1. Generic bondless with in interface body port declaration Use of generic interface bundles (see page 68 in the Accellera standard for definition) as ports of an interface will only be supported if declared as a "list of port declarations" (ANSI style port lists) with in the interface header. The use of generic interface bundles as interface ports will not be supported if they are declared in the body of the interface (V95 style). The following RTL will not be supported: interface myint1 (port1); interface port1; // this will not be supported and will yield with a syntax error endinterface : myint1 ... // the rest of the code is not a part of the limitation just comes to show the use of generic interface bundles with in an interface interface myint2(); logic clk; endinterface : myint2 module a(); myint2 i2; myint1 i1(.port1(i2)); son myson(i1); endmodule module son(myint1 myport); wire a; assign a = myport.port1.clk; endmodule However this RTL will still be supported // generic interface bundles as MODULE ports module myint1 (port1); interface port1; // this is O.K. endmodule or module myint1 (interface port1); endmodule // generic interface bundles as interface ports with in the list of port declarations in the // interface header interface myint1 (interface port1); endmodule : myint1 The main reason for changing the definition can be seen in the following RTL : interface a ( ... ); interface b ; interface c; interface d( ... ); interface e ; interface f ; endinterface endinterface endinterface It is very hard to match the endinteface's to the begging of the interface declaration - for example these two RTLs are legal. RTL 1 interface a ( b,c ); interface b ; interface c; interface d( e ); interface e ; interface f ; endinterface: f endinterface: d endinterface: a RTL 2 interface a ( b ); interface b ; interface c; interface d( e,f ); interface e ; interface f ; endinterface: d endinterface: c endinterface: a 7.2. Complex Expressions as delay values. The use of complex expression as delay values will be permuted only if the expression is with in braces (). Simple identifiers and numbers do not have to be wrapped with braces. The following RTL Examples will be considered illegal: out1 = #delay1+delay2 data; out2 = #delay++ data; out3 = #1+1 data; However the following will be supported: out1 = #(delay1+delay2) data; out2 = #(delay++) data; out2 = #delay(++ data); out3 = #2 data; out4 =#delay data; This limitation comes to solve an ambiguous definition of the System-Verilog definition for such statements: out2 = #delay++data; // the ++ can be associated with both the data and delay value 7.3. Removal of time literals from the expression definition. Time literals will not be supported as expressions. The following RTL samples will be considered illegal. time t1 = 1 ms; and #(1 ps) (out,in1,in2); It can be considered to support time literals as expression only if they are imbedded with in braces (). In this case the following example will be supported and #(1 ps) (out,in1,in2); However the use of time literals in time precision definition will still be supported: timeunit 1 ns; timeprecision 1fs; This limitation comes to solve an ambiguous definition of the System-Verilog definition for such statements: and #1 ps (out,in1,in2); // the word 'ps' can refer to the and gate instance name or to the delay time precision. out = #1 ps + data; // can be interpreted as out = #(1 ps) (+ data); or as #(1) (ps + data); 7.4. Attributes describing auto-increment and auto-decrement operators The auto-increment (++) and auto-decrement (--) operators will not be able to receive attributes the reason for this limitation is the ambiguity in the lingual definition for such an RTL; out = a - (* attribute *) b++; In this case the attribute can refer to the binary minus operator or to the auto-increment operator as one of the following: out = a - ( (* attribute *) b++) ; out = a - (* attribute *) b; b = b +1; Maybe it would be better to locate the attribute between the operand and the operator such as: out1 = a - b (* attribute *) ++; out2 = a - ++ (* attribute *) b; 8. Lingual features to be added 8.1. Empty port lists in function declarations and function calls Functions with out any ports will be supported including function calls with empty ports lists and function definitions with empty port lists. The following RTL examples will be supported. function foo(); // function definition ... endfunction ... foo() // function call The Suggested changes in the BNF (under section A.2.6 and A.8.2 and ) need to support such a feature are : function_declaration ::= function [ automatic ] [ signing ] [ range_or_type ] [ interface_identifier . ] function_identifier ; { function_item_declaration } { function_statement } endfunction [ : function_identifier ] | function [ automatic ] [ signing ] [ range_or_type ] [ interface_identifier . ] function_identifier ( [ function_port_list ] ) ; { block_item_declaration } { function_statement } endfunction [ : function_identifier ] function_prototype ::= function data_type ( [ list_of_function_proto_formals ] ) named_function_proto::= function data_type function_identifier ( [ list_of_function_proto_formals ] ) constant_function_call ::= function_identifier { attribute_instance } ( [ constant_expression { , constant_expression } ] ) function_call ::= hierarchical_function_identifier{ attribute_instance } ( [ expression { , expression } ] ) genvar_function_call ::= genvar_function_identifier { attribute_instance } ( [ constant_expression { , constant_expression } ] ) 8.2. Use of auto operators with in a for loop step The use of auto increment/decrement operators (++/--) and auto-assignment operators (+= , -= ...) will be permitted with in the third statement of the for loop header (the statement defining the loop step). The following RTL examples will be supported : for (counter = 0;counter < 100; counter++ ) ... for (counter = 0;counter < 100; counter += 1) ... The Suggested changes in the BNF (under section A.6.8 ) need to support such a feature are (the changes are already embedded in section 5): function_loop_statement ::= forever function_statement | repeat ( expression ) function_statement_or_null | while ( expression ) function_statement_or_null | for ( variable_decl_or_assignment ; expression ; for_variable_assignment ) function_statement_or_null | do function_statement while ( expression ) loop_statement ::= forever statement | repeat ( expression ) statement_or_null | while ( expression ) statement_or_null | for ( variable_decl_or_assignment ; expression ; for_variable_assignment ) statement_or_null | do statement while ( expression ) for_variable_assignment ::= operator_assignment | inc_or_dec_expression 8.3. parameter declaration with in the global name-space (under $ROOT) The declaration of parameters under the global name space will be permitted as show in the following RTL : parameter p1 = 1; module m1(...); ... The Suggested changes in the BNF (under section A.1.5 ) need to support such a feature are: module_root_item ::= { attribute_instance } module_instantiation | { attribute_instance } local_parameter_declaration | { attribute_instance } parameter_declaration ; | interface_declaration | module_common_item 8.4. default initialization of unpacked structs (and other data types) The System-Verilog 3.0 draft provides the ability to specify unpacked, structure literals. These structure literals must account for each element of the structure type. While this is functional, it is certainly not convenient. For large, unpacked structures, structure literals become intractable. To accommodate large unpacked structures, additional syntax is required. This syntax must allow coverage of a large number of fields with relatively few keystrokes, all without needing to detail each member field or memory layout. Before proceeding into syntactic suggestions, consider packed structures. To initialize all of the members of the following packed struct: typedef struct packed { logic a1; logic a2; ... logic aN; } ps_t; ps_t c,d; to a simple constant or expression, then only a simple assignment is required: c = '0; or d = {$bits(d){1'b1}}; Now consider unpacked structures such as: typedef struct { logic a1; logic a2; ... logic aN; } ups_t; ups_t uc,ud,ue; In order to assign one of these structs to a simple constant or expression much heavy lifting is required. 1) The literal must be completely aware of the structure type: uc = {0,0,...0}; 2) There are no means for programmatically simplifying the expression -$bits does not apply to unpacked structures and -There are no means for querying unpacked structure type information. So how can unpacked structures be assigned to a constant? 1) Casting uc = ups_t'('0); The downside to this is that the type must be known at all. This requires type parameters and type hard-coding in module and functions. 2) Enhanced literal syntax uc = {:'value}; Where `value would be assigned to each field of uc. This provides better control than simply casting a constant and has the extra benefit of being type neutral. Keyword suggestions include: all, each and default. Finally, consider a more realistic usage model: always @(posedge clk) if (reset) begin uc <= {each:'0}; ud <= ups_t'('0); end else if (set) begin uc <= {each:'1}; ud <= ups_t'('1); end else begin uc <= ue; ud <= ue; end In order for unpacked structures to be used more seamlessly, and potentially modularly, it is important to enable more convenient unpacked structure literals. Of the suggestions, casting and enhanced literal syntax, Intel prefers the enhanced syntax. In order to support such a change we suggest that the following rule should be added to the BNF (under sub-bullet A.8.4) primary ::= { keyword : constant_primary } keyword stand for one of the following - all, each or default. 8.5. hierarchical identifier selects with expressions as indexes The use of any expression with in the selectors of the hierarchical identifier will be permitted as shown in the following RTL: typedef struct {wire b1} s1; module m1(...); s1[1:0] mys1; reg r1,r2; assign mys1[r1 + 1 - r2] = 1'b1; The Suggested changes in the BNF (under section A.9.4 ) need to support such a feature are (the changes are already embedded in section 5): simple_hierarchical_branch3 ::= simple_identifier { [ expression ] } [ { . simple_identifier { [expression] } } ] escaped_hierarchical_branch4 ::= escaped_identifier { [expression] } [ { . escaped_identifier { [expression] } } ] 8.6. Use of a single direction declaration in modport declarations According to the BNF the following is not legal modport control (input a,b); Currently the only way to do this is re-declaring the port direction: modport control (input a, input b); It would be more convenient to use the same conventions used for modules port lists. The Suggested changes in the BNF (under section A.2.9 ) need to support such a feature are : modport_port ::= input [port_type] port_identifier | output [port_type] port_identifier | inout [port_type] port_identifier input_decleration | output_declaration // this is not 100% the same as output [port_type] | inout_declaration | interface_identifier . port_identifier | import_export task named_task_proto | import_export function named_function_proto | import_export task_or_function_identifier { , task_or_function_identifier } 09/10/2002 Dan Jacobi - Intel Corp. 1/1