diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index bf7d986be..edc967d11 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -384,6 +384,11 @@ The function returns an integer. The function returns a vector with the given width, and is signed or 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" 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 diff --git a/sv_vpi_user.h b/sv_vpi_user.h index 1282e0ee2..8e6d21aae 100644 --- a/sv_vpi_user.h +++ b/sv_vpi_user.h @@ -72,6 +72,10 @@ EXTERN_C_START /********* Many-to-One ***********/ #define vpiMember 742 +/* Icarus-specific function type to use string as the return type */ +#define vpiStringFunc 10 +#define vpiSysFuncString vpiSysFuncString + EXTERN_C_END #endif /* SV_VPI_USER_H */ diff --git a/sys_funcs.cc b/sys_funcs.cc index 3e2b26a51..bb1ccd8bc 100644 --- a/sys_funcs.cc +++ b/sys_funcs.cc @@ -204,6 +204,17 @@ int load_sys_func_table(const char*path) 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", path, name, stype); } diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 3587815eb..5239661a3 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -513,3 +513,14 @@ void draw_vpi_rfunc_call(ivl_expr_t 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); +} diff --git a/tgt-vvp/eval_string.c b/tgt-vvp/eval_string.c index 92d702058..8cdb26338 100644 --- a/tgt-vvp/eval_string.c +++ b/tgt-vvp/eval_string.c @@ -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)); } +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) { @@ -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) string_ex_pop(expr); else - fallback_eval(expr); + draw_sfunc_string(expr); break; case IVL_EX_UFUNC: diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 5255058cc..f4271620c 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -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_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); diff --git a/vvp/README.txt b/vvp/README.txt index f74cf2fa6..7f717bb91 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -841,6 +841,7 @@ instructions. The formats are: %vpi_call/i , ... ; %vpi_func , ... ; %vpi_func/r , ... ; + %vpi_func/s , ... ; The is an index into the string table. The indexed string is the source code file name where this call appears. The is diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 2b2a81f0d..f442f16ec 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -234,6 +234,7 @@ static char* strdupnew(char const *str) "%vpi_call/i" { return K_vpi_call_i; } "%vpi_func" { return K_vpi_func; } "%vpi_func/r" { return K_vpi_func_r; } +"%vpi_func/s" { return K_vpi_func_s; } "%file_line" { return K_file_line; } /* Handle the specialized variable access functions. */ diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index d5adfa4a4..43eca604f 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -1213,6 +1213,7 @@ stack when the call returns. * %vpi_func [, ...] { } * %vpi_func/r [, ...] { } +* %vpi_func/s [, ...] { } This instruction is similar to %vpi_call, except that it is for calling system functions. The difference here is the return value from diff --git a/vvp/parse.y b/vvp/parse.y index d54dac6c3..22da1cf18 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -100,7 +100,7 @@ static struct __vpiModPath*modpath_dst = 0; %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_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_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 @@ -663,6 +663,10 @@ statement { compile_vpi_func_call($1, $5, -vpiRealVal, 0, $3, $4, $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 declaration and the scope recall. The declarations create the diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index 4f35903c7..94df6f573 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -211,6 +211,51 @@ vpiHandle sysfunc_real::vpi_put_value(p_vpi_value vp, int) 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 { public: 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) { obj = new sysfunc_vec4(return_width); + } else if (val_code == -vpiStringVal) { + obj = new sysfunc_string; + } else if (val_code == 0 && fnet == 0) { 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) vthread_pop_str(thr, vpip_cur_task->string_stack); - /* If the function has a real value, then push the value - to the thread stack. */ + /* If the function returns a value, then push the value + to the appropriate thread stack. */ if (sysfunc_real*func_real = dynamic_cast(ref)) { vthread_push_real(thr, func_real->return_value_); } + if (sysfunc_string*func_string = dynamic_cast(ref)) { + vthread_push_str(thr, func_string->return_value_); + } if (sysfunc_vec4*func_vec4 = dynamic_cast(ref)) { vthread_push_vec4(thr, func_vec4->return_value()); } diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 032bce64c..0b1abe3f3 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -328,6 +328,11 @@ void vthread_push_real(struct vthread_s*thr, double 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) { thr->pop_vec4(depth); diff --git a/vvp/vthread.h b/vvp/vthread.h index 7e9af3031..4df387128 100644 --- a/vvp/vthread.h +++ b/vvp/vthread.h @@ -113,6 +113,7 @@ extern vvp_context_item_t vthread_get_rd_context_item(unsigned context_idx); * Access value stacks from thread space. */ 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_pop_vec4(struct vthread_s*thr, unsigned count);