User defined functions can have ANSI-style ports

Update the rules for parsing user function definitions to allow
Verilog-2001 ANSI style port declarations. In the process, also
unify with the user task port declaration so that the types don't
diverge. The rules are the same for both, with the extra constraint
that function ports must all be input. This latter rule is checked
later, during elaboration, so that the task/function pform code
can be shared, and better error messages can be generated.
This commit is contained in:
Stephen Williams 2008-04-18 21:33:03 -07:00
parent 54918cf5b9
commit bdab7698d2
2 changed files with 49 additions and 72 deletions

View File

@ -593,6 +593,8 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
perm_string pname = (*ports_)[idx]->basename();
NetNet*tmp = scope->find_signal(pname);
ports[idx] = 0;
if (tmp == 0) {
cerr << get_fileline() << ": internal error: function "
<< scope_path(scope) << " is missing port "
@ -600,9 +602,27 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
scope->dump(cerr);
cerr << get_fileline() << ": Continuing..." << endl;
des->errors += 1;
continue;
}
if (tmp->port_type() == NetNet::NOT_A_PORT) {
cerr << get_fileline() << ": internal error: function "
<< scope_path(scope) << " port " << pname
<< " is a port but is not a port?" << endl;
des->errors += 1;
scope->dump(cerr);
continue;
}
ports[idx] = tmp;
if (tmp->port_type() != NetNet::PINPUT) {
cerr << tmp->get_fileline() << ": error: function "
<< scope_path(scope) << " port " << pname
<< " is not an input port." << endl;
cerr << tmp->get_fileline() << ": : Function arguments "
<< "must be input ports." << endl;
des->errors += 1;
}
}

101
parse.y
View File

@ -1097,76 +1097,9 @@ expr_primary
}
;
/* A function_item is either a block item (i.e. a reg or integer
declaration) or an input declaration. There are no output or
inout ports. */
function_item
: K_input signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_NO_TYPE, $2,
$3, $4,
@1.text, @1.first_line);
$$ = tmp;
}
| K_output signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_NO_TYPE, $2,
$3, $4,
@1.text, @1.first_line);
$$ = tmp;
yyerror(@1, "Functions may not have output ports.");
}
| K_inout signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_NO_TYPE, $2,
$3, $4,
@1.text, @1.first_line);
$$ = tmp;
yyerror(@1, "Functions may not have inout ports.");
}
/* When the port is an integer, infer a signed vector of the integer
shape. Generate a range to make it work. */
| K_input K_integer list_of_identifiers ';'
{ svector<PExpr*>*range_stub
= new svector<PExpr*>(2);
PExpr*re;
re = new PENumber(new verinum(integer_width-1,
integer_width));
(*range_stub)[0] = re;
re = new PENumber(new verinum((uint64_t)0, integer_width));
(*range_stub)[1] = re;
svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_LOGIC, true,
range_stub, $3,
@1.text, @1.first_line);
$$ = tmp;
}
/* Ports can be real. */
| K_input K_real list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_REAL, false,
0, $3,
@1.text, @1.first_line);
$$ = tmp;
}
| block_item_decl
{ $$ = 0; }
;
/* A function_item_list only lists the input/output/inout
declarations. The integer and reg declarations are handled in
place, so are not listed. The list builder needs to account for
the possibility that the various parts may be NULL. */
/* A function_item_list borrows the task_port_item run to match
declarations of ports. We check later to make sure there are no
output or inout ports actually used. */
function_item_list
: function_item
{ $$ = $1; }
@ -1184,6 +1117,13 @@ function_item_list
}
;
function_item
: task_port_item
{ $$ = $1; }
| block_item_decl
{ $$ = 0; }
;
/* A gate_instance is a module instantiation or a built in part
type. In any case, the gate has a set of connections to ports. */
gate_instance
@ -1865,7 +1805,7 @@ module_item
FILE_NAME(current_task, @1);
}
'(' task_port_decl_list ')' ';'
task_item_list_opt
block_item_decls_opt
statement_or_null
K_endtask
{ current_task->set_ports($5);
@ -1895,6 +1835,23 @@ module_item
delete[]$3;
}
| K_function function_range_or_type_opt IDENTIFIER
{ assert(current_function == 0);
current_function = pform_push_function_scope($3);
FILE_NAME(current_function, @1);
}
'(' task_port_decl_list ')' ';'
block_item_decls_opt
statement
K_endfunction
{ current_function->set_ports($6);
current_function->set_statement($10);
current_function->set_return($2);
pform_pop_scope();
current_function = 0;
delete[]$3;
}
/* A generate region can contain further module items. Actually, it
is supposed to be limited to certain kinds of module items, but
the semantic tests will check that for us. */
@ -3312,7 +3269,7 @@ task_port_item
: K_input signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT,
IVL_VT_LOGIC, $2,
IVL_VT_NO_TYPE, $2,
$3, $4,
@1.text, @1.first_line);
$$ = tmp;