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(); perm_string pname = (*ports_)[idx]->basename();
NetNet*tmp = scope->find_signal(pname); NetNet*tmp = scope->find_signal(pname);
ports[idx] = 0;
if (tmp == 0) { if (tmp == 0) {
cerr << get_fileline() << ": internal error: function " cerr << get_fileline() << ": internal error: function "
<< scope_path(scope) << " is missing port " << scope_path(scope) << " is missing port "
@ -600,9 +602,27 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
scope->dump(cerr); scope->dump(cerr);
cerr << get_fileline() << ": Continuing..." << endl; cerr << get_fileline() << ": Continuing..." << endl;
des->errors += 1; 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; 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 /* A function_item_list borrows the task_port_item run to match
declaration) or an input declaration. There are no output or declarations of ports. We check later to make sure there are no
inout ports. */ output or inout ports actually used. */
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. */
function_item_list function_item_list
: function_item : function_item
{ $$ = $1; } { $$ = $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 /* 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. */ type. In any case, the gate has a set of connections to ports. */
gate_instance gate_instance
@ -1865,7 +1805,7 @@ module_item
FILE_NAME(current_task, @1); FILE_NAME(current_task, @1);
} }
'(' task_port_decl_list ')' ';' '(' task_port_decl_list ')' ';'
task_item_list_opt block_item_decls_opt
statement_or_null statement_or_null
K_endtask K_endtask
{ current_task->set_ports($5); { current_task->set_ports($5);
@ -1895,6 +1835,23 @@ module_item
delete[]$3; 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 /* A generate region can contain further module items. Actually, it
is supposed to be limited to certain kinds of module items, but is supposed to be limited to certain kinds of module items, but
the semantic tests will check that for us. */ the semantic tests will check that for us. */
@ -3312,7 +3269,7 @@ task_port_item
: K_input signed_opt range_opt list_of_identifiers ';' : K_input signed_opt range_opt list_of_identifiers ';'
{ svector<PWire*>*tmp { svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT, = pform_make_task_ports(NetNet::PINPUT,
IVL_VT_LOGIC, $2, IVL_VT_NO_TYPE, $2,
$3, $4, $3, $4,
@1.text, @1.first_line); @1.text, @1.first_line);
$$ = tmp; $$ = tmp;