diff --git a/elab_sig.cc b/elab_sig.cc index 889819563..7c73c718d 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -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; + } } diff --git a/parse.y b/parse.y index b3a1a3377..abe7af828 100644 --- a/parse.y +++ b/parse.y @@ -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*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*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*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*range_stub - = new svector(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*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*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*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, $2, + IVL_VT_NO_TYPE, $2, $3, $4, @1.text, @1.first_line); $$ = tmp;