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:
|
instructions. The formats are:
|
||||||
|
|
||||||
%vpi_call <file-index> <lineno> <name>, <args>... ;
|
%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 <file-index> <lineno> <name>, <args>... ;
|
||||||
%vpi_func/r <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
|
The <args>... is a comma (",") separated list of arguments. These are
|
||||||
made available to the VPI code as vpi handles.
|
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
|
||||||
|
|
||||||
The &A<> argument is a reference to the word of a variable array. The
|
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,
|
void compile_vpi_call(char*label, char*name,
|
||||||
|
bool func_as_task_err, bool func_as_task_warn,
|
||||||
long file_idx, long lineno,
|
long file_idx, long lineno,
|
||||||
unsigned argc, vpiHandle*argv)
|
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
|
/* Create a vpiHandle that bundles the call information, and
|
||||||
store that handle in the instruction. */
|
store that handle in the instruction. */
|
||||||
code->handle = vpip_build_vpi_call(name, 0, 0, 0, argc, argv,
|
code->handle = vpip_build_vpi_call(name, 0, 0, 0,
|
||||||
file_idx, lineno);
|
func_as_task_err, func_as_task_warn,
|
||||||
|
argc, argv, file_idx, lineno);
|
||||||
if (code->handle == 0)
|
if (code->handle == 0)
|
||||||
compile_errors += 1;
|
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
|
/* Create a vpiHandle that bundles the call information, and
|
||||||
store that handle in the instruction. */
|
store that handle in the instruction. */
|
||||||
code->handle = vpip_build_vpi_call(name, vbit, vwid, 0, argc, argv,
|
code->handle = vpip_build_vpi_call(name, vbit, vwid, 0, true, false,
|
||||||
file_idx, lineno);
|
argc, argv, file_idx, lineno);
|
||||||
if (code->handle == 0)
|
if (code->handle == 0)
|
||||||
compile_errors += 1;
|
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_disable(char*label, struct symb_s symb);
|
||||||
|
|
||||||
extern void compile_vpi_call(char*label, char*name,
|
extern void compile_vpi_call(char*label, char*name,
|
||||||
|
bool func_as_task_err, bool func_as_task_warn,
|
||||||
long file_idx, long lineno,
|
long file_idx, long lineno,
|
||||||
unsigned argc, vpiHandle*argv);
|
unsigned argc, vpiHandle*argv);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,8 @@ static char* strdupnew(char const *str)
|
||||||
exceptional parameter requirements) are listed first. */
|
exceptional parameter requirements) are listed first. */
|
||||||
|
|
||||||
"%vpi_call" { return K_vpi_call; }
|
"%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" { return K_vpi_func; }
|
||||||
"%vpi_func/r" { return K_vpi_func_r; }
|
"%vpi_func/r" { return K_vpi_func_r; }
|
||||||
"%disable" { return K_disable; }
|
"%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_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_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_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_disable K_fork
|
||||||
%token K_ivl_version K_ivl_delay_selection
|
%token K_ivl_version K_ivl_delay_selection
|
||||||
%token K_vpi_module K_vpi_time_precision K_file_names
|
%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
|
statement is a variant of %vpi_call that includes a thread vector
|
||||||
after the name, and is used for function calls. */
|
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 ';'
|
| 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 ','
|
| label_opt K_vpi_func T_NUMBER T_NUMBER T_STRING ','
|
||||||
T_NUMBER ',' T_NUMBER argument_opt ';'
|
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;
|
vvp_net_t*ptr = new vvp_net_t;
|
||||||
|
|
||||||
vpiHandle sys = vpip_build_vpi_call(name, 0, width_code, ptr,
|
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);
|
assert(sys);
|
||||||
|
|
||||||
/* Create and connect the functor to the label. */
|
/* Create and connect the functor to the label. */
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,7 @@ static void cmd_call(unsigned argc, char*argv[])
|
||||||
when we finish. */
|
when we finish. */
|
||||||
if (errors == 0) {
|
if (errors == 0) {
|
||||||
vpiHandle call_handle = vpip_build_vpi_call(argv[0], 0, 0, 0,
|
vpiHandle call_handle = vpip_build_vpi_call(argv[0], 0, 0, 0,
|
||||||
|
true, false,
|
||||||
vpi_argc, vpi_argv,
|
vpi_argc, vpi_argv,
|
||||||
1, 0);
|
1, 0);
|
||||||
if (call_handle == 0)
|
if (call_handle == 0)
|
||||||
|
|
@ -532,4 +533,3 @@ void stop_handler(int rc)
|
||||||
|
|
||||||
vpi_mcd_printf(1,"** Continue **\n");
|
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,
|
extern vpiHandle vpip_build_vpi_call(const char*name,
|
||||||
unsigned vbit, int vwid,
|
unsigned vbit, int vwid,
|
||||||
class vvp_net_t*fnet,
|
class vvp_net_t*fnet,
|
||||||
|
bool func_as_task_err,
|
||||||
|
bool func_as_task_warn,
|
||||||
unsigned argc,
|
unsigned argc,
|
||||||
vpiHandle*argv,
|
vpiHandle*argv,
|
||||||
long file_idx,
|
long file_idx,
|
||||||
|
|
|
||||||
|
|
@ -458,6 +458,13 @@ static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int)
|
||||||
return 0;
|
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 = {
|
static const struct __vpirt vpip_sysfunc_rt = {
|
||||||
vpiSysFuncCall,
|
vpiSysFuncCall,
|
||||||
|
|
@ -499,6 +506,16 @@ static const struct __vpirt vpip_sysfunc_rnet_rt = {
|
||||||
systask_iter
|
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. **** */
|
/* **** Manipulate the internal data structures. **** */
|
||||||
|
|
||||||
static struct __vpiUserSystf**def_table = 0;
|
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.
|
* information so that we can print the file name.
|
||||||
*/
|
*/
|
||||||
enum vpi_call_error_type {VPI_CALL_NO_DEF, VPI_CALL_TASK_AS_FUNC,
|
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 {
|
typedef struct vpi_call_error {
|
||||||
vpi_call_error_type type;
|
vpi_call_error_type type;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
@ -662,23 +679,34 @@ void print_vpi_call_errors()
|
||||||
fprintf(stderr, "%s:%d: Error: System task/function %s() is "
|
fprintf(stderr, "%s:%d: Error: System task/function %s() is "
|
||||||
"not defined by any module.\n",
|
"not defined by any module.\n",
|
||||||
file_names[vpi_call_error_lst[idx].file_idx],
|
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);
|
vpi_call_error_lst[idx].name);
|
||||||
break;
|
break;
|
||||||
case VPI_CALL_TASK_AS_FUNC:
|
case VPI_CALL_TASK_AS_FUNC:
|
||||||
fprintf(stderr, "%s:%d: Error: %s() is a system task, it "
|
fprintf(stderr, "%s:%d: Error: %s() is a system task, it "
|
||||||
"cannot be called as a function.\n",
|
"cannot be called as a function.\n",
|
||||||
file_names[vpi_call_error_lst[idx].file_idx],
|
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);
|
vpi_call_error_lst[idx].name);
|
||||||
break;
|
break;
|
||||||
case VPI_CALL_FUNC_AS_TASK:
|
case VPI_CALL_FUNC_AS_TASK:
|
||||||
fprintf(stderr, "%s:%d: Error: %s() is a system function, it "
|
fprintf(stderr, "%s:%d: Error: %s() is a system function, it "
|
||||||
"cannot be called as a task.\n",
|
"cannot be called as a task.\n",
|
||||||
file_names[vpi_call_error_lst[idx].file_idx],
|
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);
|
vpi_call_error_lst[idx].name);
|
||||||
break;
|
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);
|
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,
|
vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
||||||
class vvp_net_t*fnet,
|
class vvp_net_t*fnet,
|
||||||
|
bool func_as_task_err, bool func_as_task_warn,
|
||||||
unsigned argc, vpiHandle*argv,
|
unsigned argc, vpiHandle*argv,
|
||||||
long file_idx, long lineno)
|
long file_idx, long lineno)
|
||||||
{
|
{
|
||||||
|
assert(!(func_as_task_err && func_as_task_warn));
|
||||||
|
|
||||||
struct __vpiUserSystf*defn = vpip_find_systf(name);
|
struct __vpiUserSystf*defn = vpip_find_systf(name);
|
||||||
if (defn == 0) {
|
if (defn == 0) {
|
||||||
add_vpi_call_error(VPI_CALL_NO_DEF, name, file_idx, lineno);
|
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:
|
case vpiSysFunc:
|
||||||
if (vwid == 0 && fnet == 0) {
|
if (vwid == 0 && fnet == 0) {
|
||||||
add_vpi_call_error(VPI_CALL_FUNC_AS_TASK, name, file_idx,
|
if (func_as_task_err) {
|
||||||
lineno);
|
add_vpi_call_error(VPI_CALL_FUNC_AS_TASK,
|
||||||
|
name, file_idx, lineno);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (func_as_task_warn) {
|
||||||
|
add_vpi_call_error(VPI_CALL_FUNC_AS_TASK_WARN,
|
||||||
|
name, file_idx, lineno);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "Unsupported call type %d.\n",
|
fprintf(stderr, "Unsupported vpi_call type %d.\n",
|
||||||
(int)defn->info.type);
|
(int)defn->info.type);
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
@ -752,6 +788,9 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
|
||||||
} else if (vwid > 0) {
|
} else if (vwid > 0) {
|
||||||
obj->base.vpi_type = &vpip_sysfunc_rt;
|
obj->base.vpi_type = &vpip_sysfunc_rt;
|
||||||
|
|
||||||
|
} else if (vwid == 0 && fnet == 0) {
|
||||||
|
obj->base.vpi_type = &vpip_sysfunc_no_rt;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue