ivl & vvp: Enabled 'string' as the return type in VPI functions.

This commit is contained in:
Maciej Suminski 2015-12-09 14:24:19 +01:00
parent 9886b8cb36
commit df6b24fd3a
13 changed files with 106 additions and 4 deletions

View File

@ -384,6 +384,11 @@ The function returns an integer.
The function returns a vector with the given width, and is signed or The function returns a vector with the given width, and is signed or
unsigned according to the flag. unsigned according to the flag.
.TP 8
.B vpiSysFuncString
The function returns a string. This is an Icarus-specific extension, not
available in the VPI standard.
.SH "COMMAND FILES" .SH "COMMAND FILES"
The command file allows the user to place source file names and The command file allows the user to place source file names and
certain command line switches into a text file instead of on a long certain command line switches into a text file instead of on a long

View File

@ -72,6 +72,10 @@ EXTERN_C_START
/********* Many-to-One ***********/ /********* Many-to-One ***********/
#define vpiMember 742 #define vpiMember 742
/* Icarus-specific function type to use string as the return type */
#define vpiStringFunc 10
#define vpiSysFuncString vpiSysFuncString
EXTERN_C_END EXTERN_C_END
#endif /* SV_VPI_USER_H */ #endif /* SV_VPI_USER_H */

View File

@ -204,6 +204,17 @@ int load_sys_func_table(const char*path)
continue; continue;
} }
if (strcmp(stype,"vpiSysFuncString") == 0) {
cell = new struct sfunc_return_type_cell;
cell->name = lex_strings.add(name);
cell->type = IVL_VT_STRING;
cell->wid = 0; // string is a dynamic length type
cell->signed_flag = false;
cell->next = sfunc_stack;
sfunc_stack = cell;
continue;
}
fprintf(stderr, "%s:%s: Unknown type: %s\n", fprintf(stderr, "%s:%s: Unknown type: %s\n",
path, name, stype); path, name, stype);
} }

View File

@ -513,3 +513,14 @@ void draw_vpi_rfunc_call(ivl_expr_t fnet)
draw_vpi_taskfunc_args(call_string, 0, fnet); draw_vpi_taskfunc_args(call_string, 0, fnet);
} }
void draw_vpi_sfunc_call(ivl_expr_t fnet)
{
char call_string[1024];
sprintf(call_string, " %%vpi_func/s %u %u \"%s\"",
ivl_file_table_index(ivl_expr_file(fnet)),
ivl_expr_lineno(fnet), ivl_expr_name(fnet));
draw_vpi_taskfunc_args(call_string, 0, fnet);
}

View File

@ -163,6 +163,12 @@ static void string_ex_pop(ivl_expr_t expr)
fprintf(vvp_out, " %%qpop/%s/str v%p_0;\n", fb, ivl_expr_signal(arg)); fprintf(vvp_out, " %%qpop/%s/str v%p_0;\n", fb, ivl_expr_signal(arg));
} }
static void draw_sfunc_string(ivl_expr_t expr)
{
assert(ivl_expr_value(expr) == IVL_VT_STRING);
draw_vpi_sfunc_call(expr);
}
void draw_eval_string(ivl_expr_t expr) void draw_eval_string(ivl_expr_t expr)
{ {
@ -195,7 +201,7 @@ void draw_eval_string(ivl_expr_t expr)
else if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_front")==0) else if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_front")==0)
string_ex_pop(expr); string_ex_pop(expr);
else else
fallback_eval(expr); draw_sfunc_string(expr);
break; break;
case IVL_EX_UFUNC: case IVL_EX_UFUNC:

View File

@ -133,6 +133,7 @@ extern void draw_vpi_task_call(ivl_statement_t net);
extern void draw_vpi_func_call(ivl_expr_t expr); extern void draw_vpi_func_call(ivl_expr_t expr);
extern void draw_vpi_rfunc_call(ivl_expr_t expr); extern void draw_vpi_rfunc_call(ivl_expr_t expr);
extern void draw_vpi_sfunc_call(ivl_expr_t expr);
extern void draw_class_in_scope(ivl_type_t classtype); extern void draw_class_in_scope(ivl_type_t classtype);

View File

@ -841,6 +841,7 @@ instructions. The formats are:
%vpi_call/i <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>... ;
%vpi_func/s <file-index> <lineno> <name>, <args>... ;
The <file-index> is an index into the string table. The indexed string The <file-index> is an index into the string table. The indexed string
is the source code file name where this call appears. The <lineno> is is the source code file name where this call appears. The <lineno> is

View File

@ -234,6 +234,7 @@ static char* strdupnew(char const *str)
"%vpi_call/i" { return K_vpi_call_i; } "%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; }
"%vpi_func/s" { return K_vpi_func_s; }
"%file_line" { return K_file_line; } "%file_line" { return K_file_line; }
/* Handle the specialized variable access functions. */ /* Handle the specialized variable access functions. */

View File

@ -1213,6 +1213,7 @@ stack when the call returns.
* %vpi_func <file> <line> <name> [, ...] {<vec4> <real> <str>} * %vpi_func <file> <line> <name> [, ...] {<vec4> <real> <str>}
* %vpi_func/r <file> <line> <name> [, ...] {<vec4> <real> <str>} * %vpi_func/r <file> <line> <name> [, ...] {<vec4> <real> <str>}
* %vpi_func/s <file> <line> <name> [, ...] {<vec4> <real> <str>}
This instruction is similar to %vpi_call, except that it is for This instruction is similar to %vpi_call, except that it is for
calling system functions. The difference here is the return value from calling system functions. The difference here is the return value from

View File

@ -100,7 +100,7 @@ static struct __vpiModPath*modpath_dst = 0;
%token K_VAR_QUEUE %token K_VAR_QUEUE
%token K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U %token K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U
%token K_vpi_call K_vpi_call_w K_vpi_call_i %token K_vpi_call K_vpi_call_w K_vpi_call_i
%token K_vpi_func K_vpi_func_r %token K_vpi_func K_vpi_func_r K_vpi_func_s
%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 K_file_line %token K_vpi_module K_vpi_time_precision K_file_names K_file_line
%token K_PORT_INPUT K_PORT_OUTPUT K_PORT_INOUT K_PORT_MIXED K_PORT_NODIR %token K_PORT_INPUT K_PORT_OUTPUT K_PORT_INOUT K_PORT_MIXED K_PORT_NODIR
@ -663,6 +663,10 @@ statement
{ compile_vpi_func_call($1, $5, -vpiRealVal, 0, $3, $4, { compile_vpi_func_call($1, $5, -vpiRealVal, 0, $3, $4,
$6.argc, $6.argv, $8, $9, $10); } $6.argc, $6.argv, $8, $9, $10); }
| label_opt K_vpi_func_s T_NUMBER T_NUMBER T_STRING
argument_opt '{' T_NUMBER T_NUMBER T_NUMBER '}' ';'
{ compile_vpi_func_call($1, $5, -vpiStringVal, 0, $3, $4,
$6.argc, $6.argv, $8, $9, $10); }
/* Scope statements come in two forms. There are the scope /* Scope statements come in two forms. There are the scope
declaration and the scope recall. The declarations create the declaration and the scope recall. The declarations create the

View File

@ -211,6 +211,51 @@ vpiHandle sysfunc_real::vpi_put_value(p_vpi_value vp, int)
return 0; return 0;
} }
struct sysfunc_string : public __vpiSysTaskCall {
inline sysfunc_string() { }
int get_type_code(void) const { return vpiSysFuncCall; }
int vpi_get(int code);
char* vpi_get_str(int code) { return systask_get_str(code, this); }
vpiHandle vpi_put_value(p_vpi_value val, int flags);
vpiHandle vpi_handle(int code) { return systask_handle(code, this); }
vpiHandle vpi_iterate(int code) { return systask_iter(code, this); }
std::string return_value_;
};
int sysfunc_string::vpi_get(int code)
{
switch (code) {
case vpiSize:
return return_value_.size();
case vpiLineNo:
return lineno;
case vpiUserDefn:
return defn->is_user_defn;
default:
return vpiUndefined;
}
}
vpiHandle sysfunc_string::vpi_put_value(p_vpi_value vp, int)
{
put_value = true;
switch (vp->format) {
case vpiStringVal:
return_value_ = std::string(vp->value.str);
break;
default:
fprintf(stderr, "Unsupported format %d.\n", (int)vp->format);
assert(0);
}
return 0;
}
class sysfunc_vec4 : public __vpiSysTaskCall { class sysfunc_vec4 : public __vpiSysTaskCall {
public: public:
explicit inline sysfunc_vec4(unsigned wid): return_value_(wid, BIT4_X) { } explicit inline sysfunc_vec4(unsigned wid): return_value_(wid, BIT4_X) { }
@ -845,6 +890,9 @@ vpiHandle vpip_build_vpi_call(const char*name, int val_code, unsigned return_wid
} else if (val_code == -vpiVectorVal) { } else if (val_code == -vpiVectorVal) {
obj = new sysfunc_vec4(return_width); obj = new sysfunc_vec4(return_width);
} else if (val_code == -vpiStringVal) {
obj = new sysfunc_string;
} else if (val_code == 0 && fnet == 0) { } else if (val_code == 0 && fnet == 0) {
obj = new sysfunc_no; obj = new sysfunc_no;
@ -957,11 +1005,14 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref)
if (vpip_cur_task->string_stack > 0) if (vpip_cur_task->string_stack > 0)
vthread_pop_str(thr, vpip_cur_task->string_stack); vthread_pop_str(thr, vpip_cur_task->string_stack);
/* If the function has a real value, then push the value /* If the function returns a value, then push the value
to the thread stack. */ to the appropriate thread stack. */
if (sysfunc_real*func_real = dynamic_cast<sysfunc_real*>(ref)) { if (sysfunc_real*func_real = dynamic_cast<sysfunc_real*>(ref)) {
vthread_push_real(thr, func_real->return_value_); vthread_push_real(thr, func_real->return_value_);
} }
if (sysfunc_string*func_string = dynamic_cast<sysfunc_string*>(ref)) {
vthread_push_str(thr, func_string->return_value_);
}
if (sysfunc_vec4*func_vec4 = dynamic_cast<sysfunc_vec4*>(ref)) { if (sysfunc_vec4*func_vec4 = dynamic_cast<sysfunc_vec4*>(ref)) {
vthread_push_vec4(thr, func_vec4->return_value()); vthread_push_vec4(thr, func_vec4->return_value());
} }

View File

@ -328,6 +328,11 @@ void vthread_push_real(struct vthread_s*thr, double val)
thr->push_real(val); thr->push_real(val);
} }
void vthread_push_str(struct vthread_s*thr, const string&val)
{
thr->push_str(val);
}
void vthread_pop_vec4(struct vthread_s*thr, unsigned depth) void vthread_pop_vec4(struct vthread_s*thr, unsigned depth)
{ {
thr->pop_vec4(depth); thr->pop_vec4(depth);

View File

@ -113,6 +113,7 @@ extern vvp_context_item_t vthread_get_rd_context_item(unsigned context_idx);
* Access value stacks from thread space. * Access value stacks from thread space.
*/ */
extern void vthread_push_vec4(struct vthread_s*thr, const vvp_vector4_t&val); extern void vthread_push_vec4(struct vthread_s*thr, const vvp_vector4_t&val);
extern void vthread_push_str(struct vthread_s*thr, const std::string&val);
extern void vthread_push_real(struct vthread_s*thr, double val); extern void vthread_push_real(struct vthread_s*thr, double val);
extern void vthread_pop_vec4(struct vthread_s*thr, unsigned count); extern void vthread_pop_vec4(struct vthread_s*thr, unsigned count);