diff --git a/parse.y b/parse.y index f2845750d6..e3a592fa65 100644 --- a/parse.y +++ b/parse.y @@ -135,17 +135,17 @@ static list*attributes_in_context = 0; static const struct str_pair_t pull_strength = { IVL_DR_PULL, IVL_DR_PULL }; static const struct str_pair_t str_strength = { IVL_DR_STRONG, IVL_DR_STRONG }; -static list >* make_port_list(char*id, PExpr*expr) +static list* make_port_list(char*id, list*udims, PExpr*expr) { - list >*tmp = new list >; - tmp->push_back(make_pair(lex_strings.make(id), expr)); + list*tmp = new list; + tmp->push_back(pform_port_t(lex_strings.make(id), udims, expr)); delete[]id; return tmp; } -static list >* make_port_list(list >*tmp, - char*id, PExpr*expr) +static list* make_port_list(list*tmp, + char*id, list*udims, PExpr*expr) { - tmp->push_back(make_pair(lex_strings.make(id), expr)); + tmp->push_back(pform_port_t(lex_strings.make(id), udims, expr)); delete[]id; return tmp; } @@ -374,7 +374,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector char*text; list*perm_strings; - list >*port_list; + list*port_list; vector* tf_ports; @@ -582,7 +582,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type register_variable net_variable event_variable endlabel_opt class_declaration_endlabel_opt %type register_variable_list net_variable_list event_variable_list %type list_of_identifiers loop_variables -%type list_of_port_identifiers +%type list_of_port_identifiers list_of_variable_port_identifiers %type net_decl_assign net_decl_assigns @@ -642,7 +642,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type variable_dimension %type dimensions_opt dimensions -%type net_type var_type net_type_opt +%type net_type net_type_opt %type gatetype switchtype %type port_direction port_direction_opt %type bit_logic bit_logic_opt @@ -4057,14 +4057,21 @@ list_of_identifiers ; list_of_port_identifiers - : IDENTIFIER - { $$ = make_port_list($1, 0); } - | IDENTIFIER '=' expression - { $$ = make_port_list($1, $3); } - | list_of_port_identifiers ',' IDENTIFIER - { $$ = make_port_list($1, $3, 0); } - | list_of_port_identifiers ',' IDENTIFIER '=' expression - { $$ = make_port_list($1, $3, $5); } + : IDENTIFIER dimensions_opt + { $$ = make_port_list($1, $2, 0); } + | list_of_port_identifiers ',' IDENTIFIER dimensions_opt + { $$ = make_port_list($1, $3, $4, 0); } + ; + +list_of_variable_port_identifiers + : IDENTIFIER dimensions_opt + { $$ = make_port_list($1, $2, 0); } + | IDENTIFIER dimensions_opt '=' expression + { $$ = make_port_list($1, $2, $4); } + | list_of_variable_port_identifiers ',' IDENTIFIER dimensions_opt + { $$ = make_port_list($1, $3, $4, 0); } + | list_of_variable_port_identifiers ',' IDENTIFIER dimensions_opt '=' expression + { $$ = make_port_list($1, $3, $4, $6); } ; @@ -4652,58 +4659,102 @@ module_item delete $4; } - | attribute_list_opt port_direction unsigned_signed_opt dimensions_opt delay3_opt list_of_identifiers ';' - { pform_set_port_type(@2, $6, $4, $3, $2, $1); } - /* The next two rules handle Verilog 2001 statements of the form: + /* The next two rules handle port declarations that include a net type, e.g. input wire signed [h:l] ; This creates the wire and sets the port type all at once. */ - | attribute_list_opt port_direction net_type unsigned_signed_opt dimensions_opt list_of_identifiers ';' - { pform_makewire(@2, $5, $4, $6, $3, $2, IVL_VT_NO_TYPE, $1, SR_BOTH); } + | attribute_list_opt port_direction net_type data_type_or_implicit list_of_port_identifiers ';' + { pform_module_define_port(@2, $5, $2, $3, $4, $1); } - | attribute_list_opt K_output var_type unsigned_signed_opt dimensions_opt list_of_port_identifiers ';' - { list >::const_iterator pp; - list*tmp = new list; - for (pp = $6->begin(); pp != $6->end(); ++ pp ) { - tmp->push_back((*pp).first); + | attribute_list_opt port_direction K_wreal list_of_port_identifiers ';' + { real_type_t*real_type = new real_type_t(real_type_t::REAL); + pform_module_define_port(@2, $4, $2, NetNet::WIRE, real_type, $1); + } + + /* The next three rules handle port declarations that include a variable + type, e.g. + output reg signed [h:l] ; + and also handle incomplete port declarations, e.g. + input signed [h:l] ; + */ + | attribute_list_opt K_inout data_type_or_implicit list_of_port_identifiers ';' + { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3)) { + if (dtype->implicit_flag) + use_type = NetNet::NONE; } - pform_makewire(@2, $5, $4, tmp, $3, NetNet::POUTPUT, - IVL_VT_NO_TYPE, $1, SR_BOTH); - for (pp = $6->begin(); pp != $6->end(); ++ pp ) { - if ((*pp).second) { - pform_make_var_init(@2, (*pp).first, (*pp).second); - } + if (use_type == NetNet::NONE) + pform_set_port_type(@2, $4, NetNet::PINOUT, $3, $1); + else + pform_module_define_port(@2, $4, NetNet::PINOUT, use_type, $3, $1); + } + + | attribute_list_opt K_input data_type_or_implicit list_of_port_identifiers ';' + { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3)) { + if (dtype->implicit_flag) + use_type = NetNet::NONE; } - delete $6; + if (use_type == NetNet::NONE) + pform_set_port_type(@2, $4, NetNet::PINPUT, $3, $1); + else + pform_module_define_port(@2, $4, NetNet::PINPUT, use_type, $3, $1); } - | attribute_list_opt port_direction K_wreal list_of_identifiers ';' - { pform_makewire(@2, 0, true, $4, NetNet::WIRE, $2, - IVL_VT_REAL, $1, SR_BOTH); + | attribute_list_opt K_output data_type_or_implicit list_of_variable_port_identifiers ';' + { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3)) { + if (dtype->implicit_flag) + use_type = NetNet::NONE; + else if (dtype->reg_flag) + use_type = NetNet::REG; + else + use_type = NetNet::IMPLICIT_REG; + + // The SystemVerilog types that can show up as + // output ports are implicitly (on the inside) + // variables because "reg" is not valid syntax + // here. + } else if (dynamic_cast ($3)) { + use_type = NetNet::IMPLICIT_REG; + } else if (dynamic_cast ($3)) { + use_type = NetNet::IMPLICIT_REG; + } else if (enum_type_t*etype = dynamic_cast ($3)) { + if(etype->base_type == IVL_VT_LOGIC) + use_type = NetNet::IMPLICIT_REG; + } + if (use_type == NetNet::NONE) + pform_set_port_type(@2, $4, NetNet::POUTPUT, $3, $1); + else + pform_module_define_port(@2, $4, NetNet::POUTPUT, use_type, $3, $1); } - /* var_type declaration (reg variables) cannot be input or output, - because the port declaration implies an external driver, which - cannot be attached to a reg. These rules catch that error early. */ + | attribute_list_opt port_direction net_type data_type_or_implicit error ';' + { yyerror(@2, "error: Invalid variable list in port declaration."); + if ($1) delete $1; + if ($4) delete $4; + yyerrok; + } - | attribute_list_opt K_input var_type unsigned_signed_opt dimensions_opt list_of_identifiers ';' - { pform_makewire(@2, $5, $4, $6, $3, NetNet::PINPUT, - IVL_VT_NO_TYPE, $1); - yyerror(@3, "error: reg variables cannot be inputs."); + | attribute_list_opt K_inout data_type_or_implicit error ';' + { yyerror(@2, "error: Invalid variable list in port declaration."); + if ($1) delete $1; + if ($3) delete $3; + yyerrok; } - | attribute_list_opt K_inout var_type unsigned_signed_opt dimensions_opt list_of_identifiers ';' - { pform_makewire(@2, $5, $4, $6, $3, NetNet::PINOUT, - IVL_VT_NO_TYPE, $1); - yyerror(@3, "error: reg variables cannot be inouts."); + | attribute_list_opt K_input data_type_or_implicit error ';' + { yyerror(@2, "error: Invalid variable list in port declaration."); + if ($1) delete $1; + if ($3) delete $3; + yyerrok; } - | attribute_list_opt port_direction unsigned_signed_opt dimensions_opt delay3_opt error ';' + | attribute_list_opt K_output data_type_or_implicit error ';' { yyerror(@2, "error: Invalid variable list in port declaration."); if ($1) delete $1; - if ($4) delete $4; - if ($5) delete $5; + if ($3) delete $3; yyerrok; } @@ -5103,10 +5154,6 @@ net_type | K_uwire { $$ = NetNet::UNRESOLVED_WIRE; } ; -var_type - : K_reg { $$ = NetNet::REG; } - ; - param_type : bit_logic_opt unsigned_signed_opt dimensions_opt { param_active_range = $3; diff --git a/pform.cc b/pform.cc index 44bb8ae44c..8ed8c8dae4 100644 --- a/pform.cc +++ b/pform.cc @@ -1944,6 +1944,7 @@ static void pform_set_net_range(perm_string name, VLerror("error: name is not a valid net."); return; } + // If this is not implicit ("implicit" meaning we don't // know what the type is yet) then set the type now. if (net_type != NetNet::IMPLICIT && net_type != NetNet::NONE) { @@ -2349,7 +2350,8 @@ void pform_module_define_port(const struct vlltype&li, NetNet::PortType port_kind, NetNet::Type type, data_type_t*vtype, - list*attr) + list*attr, + bool keep_attr) { struct_type_t*struct_type = 0; ivl_variable_type_t data_type = IVL_VT_NO_TYPE; @@ -2438,10 +2440,37 @@ void pform_module_define_port(const struct vlltype&li, cur->set_unpacked_idx(*urange); } - pform_bind_attributes(cur->attributes, attr); + pform_bind_attributes(cur->attributes, attr, keep_attr); pform_put_wire_in_scope(name, cur); } +void pform_module_define_port(const struct vlltype&li, + list*ports, + NetNet::PortType port_kind, + NetNet::Type type, + data_type_t*vtype, + list*attr) +{ + for (list::iterator cur = ports->begin() + ; cur != ports->end() ; ++ cur ) { + + data_type_t*use_type = vtype; + if (cur->udims) + use_type = new uarray_type_t(vtype, cur->udims); + + pform_module_define_port(li, cur->name, port_kind, type, use_type, + attr, true); + if (cur->udims) + delete use_type; + + if (cur->expr) + pform_make_var_init(li, cur->name, cur->expr); + } + + delete ports; + delete attr; +} + /* * This function makes a single signal (a wire, a reg, etc) as * requested by the parser. The name is unscoped, so I attach the @@ -3246,24 +3275,53 @@ static void pform_set_port_type(perm_string name, NetNet::PortType pt, } void pform_set_port_type(const struct vlltype&li, - list*names, - list*range, - bool signed_flag, + list*ports, NetNet::PortType pt, + data_type_t*dt, list*attr) { assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); - for (list::iterator cur = names->begin() - ; cur != names->end() ; ++ cur ) { - perm_string txt = *cur; - pform_set_port_type(txt, pt, li.text, li.first_line); - pform_set_net_range(txt, NetNet::NONE, range, signed_flag, IVL_VT_NO_TYPE, - SR_PORT, attr); + list*range = 0; + bool signed_flag = false; + if (vector_type_t*vt = dynamic_cast (dt)) { + assert(vt->implicit_flag); + range = vt->pdims.get(); + signed_flag = vt->signed_flag; + } else { + assert(dt == 0); + } + + bool have_init_expr = false; + for (list::iterator cur = ports->begin() + ; cur != ports->end() ; ++ cur ) { + + pform_set_port_type(cur->name, pt, li.text, li.first_line); + pform_set_net_range(cur->name, NetNet::NONE, range, signed_flag, + IVL_VT_NO_TYPE, SR_PORT, attr); + if (cur->udims) { + cerr << li.text << ":" << li.first_line << ": warning: " + << "Array dimensions in incomplete port declarations " + << "are currently ignored." << endl; + cerr << li.text << ":" << li.first_line << ": : " + << "The dimensions specified in the net or variable " + << "declaration will be used." << endl; + delete cur->udims; + } + if (cur->expr) { + have_init_expr = true; + delete cur->expr; + } + } + if (have_init_expr) { + cerr << li.text << ":" << li.first_line << ": error: " + << "Incomplete port declarations cannot be initialized." + << endl; + error_count += 1; } - delete names; - delete range; + delete ports; + delete dt; delete attr; } diff --git a/pform.h b/pform.h index 673273b6ed..e6e2db539b 100644 --- a/pform.h +++ b/pform.h @@ -168,14 +168,21 @@ extern void pform_startmodule(const struct vlltype&loc, const char*name, extern void pform_check_timeunit_prec(); extern void pform_module_set_ports(vector*); -/* This function is used to support the port definition in a - port_definition_list. In this case, we have everything needed to - define the port, all in one place. */ +/* These functions are used when we have a complete port definition, either + in an ansi style or non-ansi style declaration. In this case, we have + everything needed to define the port, all in one place. */ extern void pform_module_define_port(const struct vlltype&li, perm_string name, NetNet::PortType, NetNet::Type type, data_type_t*vtype, + list*attr, + bool keep_attr =false); +extern void pform_module_define_port(const struct vlltype&li, + list*ports, + NetNet::PortType, + NetNet::Type type, + data_type_t*vtype, list*attr); extern Module::port_t* pform_module_port_reference(perm_string name, @@ -364,14 +371,14 @@ extern void pform_makewire(const struct vlltype&li, extern void pform_make_var_init(const struct vlltype&li, perm_string name, PExpr*expr); - /* Look up the names of the wires, and set the port type, - i.e. input, output or inout. If the wire does not exist, create - it. The second form takes a single name. */ +/* This function is used when we have an incomplete port definition in + a non-ansi style declaration. Look up the names of the wires, and set + the port type, i.e. input, output or inout, and, if specified, the + range and signedness. If the wire does not exist, create it. */ extern void pform_set_port_type(const struct vlltype&li, - list*names, - list*range, - bool signed_flag, + list*ports, NetNet::PortType, + data_type_t*dt, list*attr); extern void pform_set_reg_idx(perm_string name, diff --git a/pform_types.h b/pform_types.h index 149ae9f277..22dab4b465 100644 --- a/pform_types.h +++ b/pform_types.h @@ -1,7 +1,7 @@ #ifndef IVL_pform_types_H #define IVL_pform_types_H /* - * Copyright (c) 2007-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2016 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 @@ -72,6 +72,21 @@ typedef named named_pexpr_t; */ typedef std::pair pform_range_t; +/* + * The pform_port_t holds the name and optional unpacked dimensions + * and initialization expression for a single port in a list of port + * declarations. + */ +struct pform_port_t { + pform_port_t(perm_string n, list*ud, PExpr*e) + : name(n), udims(ud), expr(e) { } + ~pform_port_t() { } + + perm_string name; + list*udims; + PExpr*expr; +}; + /* * Semantic NOTES: * - The SEL_BIT is a single expression. This might me a bit select