Add run time support for calling system functions as task.
This patch adds two new opcodes and the infrastructure needed to call system functions as tasks. The normal %vpi_call will generate an error if a system function is called as a task. %vpi_call/w will generate a warning and will ignore any value returned by the function. %vpi_call/i will ignore the system function return value and will not print a message. Adding this is a feature request and is supported in SystemVerilog. Next I need to add flags to control this depending on the compiler generation and possibly other flags. I may leave the cast to void (%vpi_call/i) functionality unimplemented for now.
This commit is contained in:
parent
3d63f664c8
commit
3f6aff47c9
|
|
@ -799,6 +799,8 @@ Threads call vpi tasks with the %vpi_call or %vpi_func
|
|||
instructions. The formats are:
|
||||
|
||||
%vpi_call <file-index> <lineno> <name>, <args>... ;
|
||||
%vpi_call/w <file-index> <lineno> <name>, <args>... ;
|
||||
%vpi_call/i <file-index> <lineno> <name>, <args>... ;
|
||||
%vpi_func <file-index> <lineno> <name>, <args>... ;
|
||||
%vpi_func/r <file-index> <lineno> <name>, <args>... ;
|
||||
|
||||
|
|
@ -813,6 +815,12 @@ looked up and compared with the registered system tasks/functions.
|
|||
The <args>... is a comma (",") separated list of arguments. These are
|
||||
made available to the VPI code as vpi handles.
|
||||
|
||||
The plain %vpi_call will fail with an error message if a system function
|
||||
is called as a task. The /w suffix version will display a warning message
|
||||
if a system function is called as a task and will ignore any value that
|
||||
the function tries to return. The /i suffix version silently ignores any
|
||||
value returned by a system function called as a task.
|
||||
|
||||
* The &A<> argument
|
||||
|
||||
The &A<> argument is a reference to the word of a variable array. The
|
||||
|
|
|
|||
|
|
@ -1679,6 +1679,7 @@ void compile_fork(char*label, struct symb_s dest, struct symb_s scope)
|
|||
}
|
||||
|
||||
void compile_vpi_call(char*label, char*name,
|
||||
bool func_as_task_err, bool func_as_task_warn,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv)
|
||||
{
|
||||
|
|
@ -1691,8 +1692,9 @@ void compile_vpi_call(char*label, char*name,
|
|||
|
||||
/* Create a vpiHandle that bundles the call information, and
|
||||
store that handle in the instruction. */
|
||||
code->handle = vpip_build_vpi_call(name, 0, 0, 0, argc, argv,
|
||||
file_idx, lineno);
|
||||
code->handle = vpip_build_vpi_call(name, 0, 0, 0,
|
||||
func_as_task_err, func_as_task_warn,
|
||||
argc, argv, file_idx, lineno);
|
||||
if (code->handle == 0)
|
||||
compile_errors += 1;
|
||||
|
||||
|
|
@ -1714,8 +1716,8 @@ void compile_vpi_func_call(char*label, char*name,
|
|||
|
||||
/* Create a vpiHandle that bundles the call information, and
|
||||
store that handle in the instruction. */
|
||||
code->handle = vpip_build_vpi_call(name, vbit, vwid, 0, argc, argv,
|
||||
file_idx, lineno);
|
||||
code->handle = vpip_build_vpi_call(name, vbit, vwid, 0, true, false,
|
||||
argc, argv, file_idx, lineno);
|
||||
if (code->handle == 0)
|
||||
compile_errors += 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -395,6 +395,7 @@ extern void compile_code(char*label, char*mnem, comp_operands_t opa);
|
|||
extern void compile_disable(char*label, struct symb_s symb);
|
||||
|
||||
extern void compile_vpi_call(char*label, char*name,
|
||||
bool func_as_task_err, bool func_as_task_warn,
|
||||
long file_idx, long lineno,
|
||||
unsigned argc, vpiHandle*argv);
|
||||
|
||||
|
|
|
|||
|
|
@ -198,6 +198,8 @@ static char* strdupnew(char const *str)
|
|||
exceptional parameter requirements) are listed first. */
|
||||
|
||||
"%vpi_call" { return K_vpi_call; }
|
||||
"%vpi_call/w" { return K_vpi_call_w; }
|
||||
"%vpi_call/i" { return K_vpi_call_i; }
|
||||
"%vpi_func" { return K_vpi_func; }
|
||||
"%vpi_func/r" { return K_vpi_func_r; }
|
||||
"%disable" { return K_disable; }
|
||||
|
|
|
|||
19
vvp/parse.y
19
vvp/parse.y
|
|
@ -84,7 +84,8 @@ static struct __vpiModPath*modpath_dst = 0;
|
|||
%token K_RESOLV K_SCOPE K_SFUNC K_SFUNC_E K_SHIFTL K_SHIFTR K_SHIFTRS
|
||||
%token K_THREAD K_TIMESCALE K_TRAN K_TRANIF0 K_TRANIF1 K_TRANVP
|
||||
%token K_UFUNC K_UFUNC_E K_UDP K_UDP_C K_UDP_S
|
||||
%token K_VAR K_VAR_S K_VAR_I K_VAR_R K_vpi_call K_vpi_func K_vpi_func_r
|
||||
%token K_VAR K_VAR_S K_VAR_I K_VAR_R K_vpi_call K_vpi_call_w K_vpi_call_i
|
||||
%token K_vpi_func K_vpi_func_r
|
||||
%token K_disable K_fork
|
||||
%token K_ivl_version K_ivl_delay_selection
|
||||
%token K_vpi_module K_vpi_time_precision K_file_names
|
||||
|
|
@ -540,8 +541,22 @@ statement
|
|||
statement is a variant of %vpi_call that includes a thread vector
|
||||
after the name, and is used for function calls. */
|
||||
|
||||
/* This version does not allow a function to be called as a task. */
|
||||
| label_opt K_vpi_call T_NUMBER T_NUMBER T_STRING argument_opt ';'
|
||||
{ compile_vpi_call($1, $5, $3, $4, $6.argc, $6.argv); }
|
||||
{ compile_vpi_call($1, $5, true, false, $3, $4,
|
||||
$6.argc, $6.argv); }
|
||||
|
||||
/* This version allows a function to be called as a task, but prints a
|
||||
* warning message. */
|
||||
| label_opt K_vpi_call_w T_NUMBER T_NUMBER T_STRING argument_opt ';'
|
||||
{ compile_vpi_call($1, $5, false, true, $3, $4,
|
||||
$6.argc, $6.argv); }
|
||||
|
||||
/* This version allows a function to be called as a task and does not
|
||||
* print a message. */
|
||||
| label_opt K_vpi_call_i T_NUMBER T_NUMBER T_STRING argument_opt ';'
|
||||
{ compile_vpi_call($1, $5, false, false, $3, $4,
|
||||
$6.argc, $6.argv); }
|
||||
|
||||
| label_opt K_vpi_func T_NUMBER T_NUMBER T_STRING ','
|
||||
T_NUMBER ',' T_NUMBER argument_opt ';'
|
||||
|
|
|
|||
|
|
@ -158,7 +158,8 @@ void compile_sfunc(char*label, char*name, char*format_string,
|
|||
vvp_net_t*ptr = new vvp_net_t;
|
||||
|
||||
vpiHandle sys = vpip_build_vpi_call(name, 0, width_code, ptr,
|
||||
argc, vpi_argv, file_idx, lineno);
|
||||
true, false, argc, vpi_argv,
|
||||
file_idx, lineno);
|
||||
assert(sys);
|
||||
|
||||
/* Create and connect the functor to the label. */
|
||||
|
|
|
|||
|
|
@ -170,8 +170,9 @@ static void cmd_call(unsigned argc, char*argv[])
|
|||
when we finish. */
|
||||
if (errors == 0) {
|
||||
vpiHandle call_handle = vpip_build_vpi_call(argv[0], 0, 0, 0,
|
||||
vpi_argc, vpi_argv,
|
||||
1, 0);
|
||||
true, false,
|
||||
vpi_argc, vpi_argv,
|
||||
1, 0);
|
||||
if (call_handle == 0)
|
||||
goto out;
|
||||
|
||||
|
|
@ -532,4 +533,3 @@ void stop_handler(int rc)
|
|||
|
||||
vpi_mcd_printf(1,"** Continue **\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -541,6 +541,8 @@ extern unsigned vpip_module_path_cnt;
|
|||
extern vpiHandle vpip_build_vpi_call(const char*name,
|
||||
unsigned vbit, int vwid,
|
||||
class vvp_net_t*fnet,
|
||||
bool func_as_task_err,
|
||||
bool func_as_task_warn,
|
||||
unsigned argc,
|
||||
vpiHandle*argv,
|
||||
long file_idx,
|
||||
|
|
|
|||
|
|
@ -458,6 +458,13 @@ static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static vpiHandle sysfunc_put_no_value(vpiHandle ref, p_vpi_value, int)
|
||||
{
|
||||
assert(ref->vpi_type->type_code == vpiSysFuncCall);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct __vpirt vpip_sysfunc_rt = {
|
||||
vpiSysFuncCall,
|
||||
|
|
@ -499,6 +506,16 @@ static const struct __vpirt vpip_sysfunc_rnet_rt = {
|
|||
systask_iter
|
||||
};
|
||||
|
||||
static const struct __vpirt vpip_sysfunc_no_rt = {
|
||||
vpiSysFuncCall,
|
||||
sysfunc_get,
|
||||
systask_get_str,
|
||||
0,
|
||||
sysfunc_put_no_value,
|
||||
systask_handle,
|
||||
systask_iter
|
||||
};
|
||||
|
||||
/* **** Manipulate the internal data structures. **** */
|
||||
|
||||
static struct __vpiUserSystf**def_table = 0;
|
||||
|
|
@ -629,7 +646,7 @@ void vpip_make_systf_system_defined(vpiHandle ref)
|
|||
* information so that we can print the file name.
|
||||
*/
|
||||
enum vpi_call_error_type {VPI_CALL_NO_DEF, VPI_CALL_TASK_AS_FUNC,
|
||||
VPI_CALL_FUNC_AS_TASK};
|
||||
VPI_CALL_FUNC_AS_TASK, VPI_CALL_FUNC_AS_TASK_WARN};
|
||||
typedef struct vpi_call_error {
|
||||
vpi_call_error_type type;
|
||||
char *name;
|
||||
|
|
@ -662,23 +679,34 @@ void print_vpi_call_errors()
|
|||
fprintf(stderr, "%s:%d: Error: System task/function %s() is "
|
||||
"not defined by any module.\n",
|
||||
file_names[vpi_call_error_lst[idx].file_idx],
|
||||
vpi_call_error_lst[idx].lineno,
|
||||
(int)vpi_call_error_lst[idx].lineno,
|
||||
vpi_call_error_lst[idx].name);
|
||||
break;
|
||||
case VPI_CALL_TASK_AS_FUNC:
|
||||
fprintf(stderr, "%s:%d: Error: %s() is a system task, it "
|
||||
"cannot be called as a function.\n",
|
||||
file_names[vpi_call_error_lst[idx].file_idx],
|
||||
vpi_call_error_lst[idx].lineno,
|
||||
(int)vpi_call_error_lst[idx].lineno,
|
||||
vpi_call_error_lst[idx].name);
|
||||
break;
|
||||
case VPI_CALL_FUNC_AS_TASK:
|
||||
fprintf(stderr, "%s:%d: Error: %s() is a system function, it "
|
||||
"cannot be called as a task.\n",
|
||||
file_names[vpi_call_error_lst[idx].file_idx],
|
||||
vpi_call_error_lst[idx].lineno,
|
||||
(int)vpi_call_error_lst[idx].lineno,
|
||||
vpi_call_error_lst[idx].name);
|
||||
break;
|
||||
case VPI_CALL_FUNC_AS_TASK_WARN:
|
||||
fprintf(stderr, "%s:%d: Warning: Calling system function "
|
||||
"%s() as a task.\n",
|
||||
file_names[vpi_call_error_lst[idx].file_idx],
|
||||
(int)vpi_call_error_lst[idx].lineno,
|
||||
vpi_call_error_lst[idx].name);
|
||||
fprintf(stderr, "%s:%d: The functions return "
|
||||
"value will be ignored.\n",
|
||||
file_names[vpi_call_error_lst[idx].file_idx],
|
||||
(int)vpi_call_error_lst[idx].lineno);
|
||||
break;
|
||||
}
|
||||
free(vpi_call_error_lst[idx].name);
|
||||
}
|
||||
|
|
@ -699,9 +727,12 @@ void print_vpi_call_errors()
|
|||
*/
|
||||
vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
||||
class vvp_net_t*fnet,
|
||||
bool func_as_task_err, bool func_as_task_warn,
|
||||
unsigned argc, vpiHandle*argv,
|
||||
long file_idx, long lineno)
|
||||
{
|
||||
assert(!(func_as_task_err && func_as_task_warn));
|
||||
|
||||
struct __vpiUserSystf*defn = vpip_find_systf(name);
|
||||
if (defn == 0) {
|
||||
add_vpi_call_error(VPI_CALL_NO_DEF, name, file_idx, lineno);
|
||||
|
|
@ -720,14 +751,19 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
|||
|
||||
case vpiSysFunc:
|
||||
if (vwid == 0 && fnet == 0) {
|
||||
add_vpi_call_error(VPI_CALL_FUNC_AS_TASK, name, file_idx,
|
||||
lineno);
|
||||
return 0;
|
||||
if (func_as_task_err) {
|
||||
add_vpi_call_error(VPI_CALL_FUNC_AS_TASK,
|
||||
name, file_idx, lineno);
|
||||
return 0;
|
||||
} else if (func_as_task_warn) {
|
||||
add_vpi_call_error(VPI_CALL_FUNC_AS_TASK_WARN,
|
||||
name, file_idx, lineno);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unsupported call type %d.\n",
|
||||
fprintf(stderr, "Unsupported vpi_call type %d.\n",
|
||||
(int)defn->info.type);
|
||||
assert(0);
|
||||
}
|
||||
|
|
@ -752,6 +788,9 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
|||
} else if (vwid > 0) {
|
||||
obj->base.vpi_type = &vpip_sysfunc_rt;
|
||||
|
||||
} else if (vwid == 0 && fnet == 0) {
|
||||
obj->base.vpi_type = &vpip_sysfunc_no_rt;
|
||||
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue