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
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

View File

@ -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 */

View File

@ -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);
}

View File

@ -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);
}

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));
}
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:

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_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);

View File

@ -841,6 +841,7 @@ instructions. The formats are:
%vpi_call/i <file-index> <lineno> <name>, <args>... ;
%vpi_func <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
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_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. */

View File

@ -1213,6 +1213,7 @@ stack when the call returns.
* %vpi_func <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
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_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

View File

@ -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<sysfunc_real*>(ref)) {
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)) {
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);
}
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);

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.
*/
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);