diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 1c2271116..fa27d34f3 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -29,6 +29,13 @@ #define snprintf _snprintf #endif +struct args_info { + char*text; + int vec_flag; /* True if the vec must be released. */ + struct vector_info vec; + struct args_info *child; /* Arguments can be nested. */ +}; + static const char* magic_sfuncs[] = { "$time", "$stime", @@ -68,6 +75,153 @@ static int is_fixed_memory_word(ivl_expr_t net) return 0; } +static int get_vpi_taskfunc_signal_arg(struct args_info *result, + ivl_expr_t expr) +{ + char buffer[4096]; + + switch (ivl_expr_type(expr)) { + case IVL_EX_SIGNAL: + /* If the signal node is narrower then the signal itself, + then this is a part select so I'm going to need to + evaluate the expression. + + Also, if the signedness of the expression is different + from the signedness of the signal. This could be + caused by a $signed or $unsigned system function. + + If I don't need to do any evaluating, then skip it as + I'll be passing the handle to the signal itself. */ + if (ivl_expr_width(expr) != + ivl_signal_width(ivl_expr_signal(expr))) { + /* This should never happen since we have IVL_EX_SELECT. */ + return 0; + + } else if (ivl_expr_signed(expr) != + ivl_signal_signed(ivl_expr_signal(expr))) { + return 0; + } else if (is_fixed_memory_word(expr)) { + /* This is a word of a non-array, or a word of a net + array, so we can address the word directly. */ + ivl_signal_t sig = ivl_expr_signal(expr); + unsigned use_word = 0; + ivl_expr_t word_ex = ivl_expr_oper1(expr); + if (word_ex) { + /* Some array select have been evaluated. */ + if (number_is_immediate(word_ex, + 8*sizeof(unsigned), 0)) { + use_word = get_number_immediate(word_ex); + word_ex = 0; + } + } + if (word_ex) return 0; + + assert(word_ex == 0); + snprintf(buffer, sizeof buffer, "v%p_%u", sig, use_word); + result->text = strdup(buffer); + return 1; + + } else { + /* What's left, this is the work of a var array. + Create the right code to handle it. */ + ivl_signal_t sig = ivl_expr_signal(expr); + unsigned use_word = 0; + ivl_expr_t word_ex = ivl_expr_oper1(expr); + if (word_ex) { + /* Some array select have been evaluated. */ + if (number_is_immediate(word_ex, + 8*sizeof(unsigned), 0)) { + use_word = get_number_immediate(word_ex); + word_ex = 0; + } + } + if (word_ex && (ivl_expr_type(word_ex)==IVL_EX_SIGNAL || + ivl_expr_type(word_ex)==IVL_EX_SELECT)) { + /* Special case: the index is a signal/select. */ + result->child = calloc(1, sizeof(struct args_info)); + if (get_vpi_taskfunc_signal_arg(result->child, + word_ex)) { + snprintf(buffer, sizeof buffer, "&A", + sig, result->child->text); + free(result->child->text); + } else { + free(result->child); + result->child = NULL; + return 0; + } + } else if (word_ex) { + /* Fallback case: evaluate expression. */ + struct vector_info av; + av = draw_eval_expr(word_ex, STUFF_OK_XZ); + snprintf(buffer, sizeof buffer, "&A", + sig, av.base, av.wid); + result->vec = av; + result->vec_flag = 1; + } else { + snprintf(buffer, sizeof buffer, "&A", + sig, use_word); + } + result->text = strdup(buffer); + return 1; + } + + case IVL_EX_SELECT: { + ivl_expr_t vexpr = ivl_expr_oper1(expr); + assert(vexpr); + + /* This code is only for signals or selects. */ + if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL && + ivl_expr_type(vexpr) != IVL_EX_SELECT) return 0; + + /* The signal is part of an array. */ + /* Add &APV<> code here when it is finished. */ + if (ivl_expr_oper1(vexpr)) return 0; + + ivl_expr_t bexpr = ivl_expr_oper2(expr); + assert(bexpr); + + /* This is a constant bit/part select. */ + if (number_is_immediate(bexpr, 64, 1)) { + snprintf(buffer, sizeof buffer, "&PV", + ivl_expr_signal(vexpr), + get_number_immediate(bexpr), + ivl_expr_width(expr)); + /* This is an indexed bit/part select. */ + } else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL || + ivl_expr_type(bexpr) == IVL_EX_SELECT) { + /* Special case: the base is a signal/select. */ + result->child = calloc(1, sizeof(struct args_info)); + if (get_vpi_taskfunc_signal_arg(result->child, bexpr)) { + snprintf(buffer, sizeof buffer, "&PV", + ivl_expr_signal(vexpr), + result->child->text, + ivl_expr_width(expr)); + free(result->child->text); + } else { + free(result->child); + result->child = NULL; + return 0; + } + } else { + /* Fallback case: evaluate the expression. */ + struct vector_info rv; + rv = draw_eval_expr(bexpr, STUFF_OK_XZ); + snprintf(buffer, sizeof buffer, "&PV", + ivl_expr_signal(vexpr), + rv.base, rv.wid, + ivl_expr_width(expr)); + result->vec = rv; + result->vec_flag = 1; + } + result->text = strdup(buffer); + return 1; + } + + default: + return 0; + } +} + static void draw_vpi_taskfunc_args(const char*call_string, ivl_statement_t tnet, ivl_expr_t fnet) @@ -77,11 +231,7 @@ static void draw_vpi_taskfunc_args(const char*call_string, ? ivl_stmt_parm_count(tnet) : ivl_expr_parms(fnet); - struct args_info { - char*text; - int vec_flag; /* True if the vec must be released. */ - struct vector_info vec; - } *args = calloc(parm_count, sizeof(struct args_info)); + struct args_info *args = calloc(parm_count, sizeof(struct args_info)); char buffer[4096]; @@ -154,121 +304,9 @@ static void draw_vpi_taskfunc_args(const char*call_string, break; case IVL_EX_SIGNAL: - /* If the signal node is narrower then the signal - itself, then this is a part select so I'm going - to need to evaluate the expression. - - Also, if the signedness of the expression is - different from the signedness of the - signal. This could be caused by a $signed or - $unsigned system function. - - If I don't need to do any evaluating, then skip - it as I'll be passing the handle to the signal - itself. */ - if (ivl_expr_width(expr) != - ivl_signal_width(ivl_expr_signal(expr))) { - break; - - } else if (ivl_expr_signed(expr) != - ivl_signal_signed(ivl_expr_signal(expr))) { - break; - } else if (is_fixed_memory_word(expr)) { - /* This is a word of a non-array, or a word - of a net array, so we can address the - word directly. */ - ivl_signal_t sig = ivl_expr_signal(expr); - unsigned use_word = 0; - ivl_expr_t word_ex = ivl_expr_oper1(expr); - if (word_ex) { - /* Some array select have been evaluated. */ - if (number_is_immediate(word_ex, 8*sizeof(unsigned), 0)) { - use_word = get_number_immediate(word_ex); - word_ex = 0; - } - } - if (word_ex) - break; - - assert(word_ex == 0); - snprintf(buffer, sizeof buffer, "v%p_%u", sig, use_word); - args[idx].text = strdup(buffer); - continue; - - } else { - /* What's left, this is the work of a var - array. Create the right code to handle - it. */ - ivl_signal_t sig = ivl_expr_signal(expr); - unsigned use_word = 0; - ivl_expr_t word_ex = ivl_expr_oper1(expr); - if (word_ex) { - /* Some array select have been evaluated. */ - if (number_is_immediate(word_ex, 8*sizeof(unsigned), 0)) { - use_word = get_number_immediate(word_ex); - word_ex = 0; - } - } - if (word_ex && ivl_expr_type(word_ex)==IVL_EX_SIGNAL) { - /* Special case: the index is a signal. */ - snprintf(buffer, sizeof buffer, - "&A", sig, - ivl_expr_signal(word_ex)); - } else if (word_ex) { - /* Fallback case: evaluate expression. */ - struct vector_info av; - av = draw_eval_expr(word_ex, STUFF_OK_XZ); - snprintf(buffer, sizeof buffer, - "&A", sig, av.base, av.wid); - args[idx].vec = av; - args[idx].vec_flag = 1; - } else { - snprintf(buffer, sizeof buffer, - "&A", sig, use_word); - } - args[idx].text = strdup(buffer); - continue; - } - - case IVL_EX_SELECT: { - ivl_expr_t vexpr = ivl_expr_oper1(expr); - assert(vexpr); - - /* This code is only for signals. */ - if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL) break; - - /* The signal is part of an array. */ - /* Add &APV<> code here when it is finished. */ - if (ivl_expr_oper1(vexpr)) break; - - ivl_expr_t bexpr = ivl_expr_oper2(expr); - assert(bexpr); - - /* This is a constant bit/part select. */ - if (number_is_immediate(bexpr, 64, 1)) { - snprintf(buffer, sizeof buffer, "&PV", - ivl_expr_signal(vexpr), - get_number_immediate(bexpr), - ivl_expr_width(expr)); - /* This is an indexed bit/part select. */ - } else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL) { - /* Sepcial case: the base is a signal. */ - snprintf(buffer, sizeof buffer, "&PV", - ivl_expr_signal(vexpr), - ivl_expr_signal(bexpr), - ivl_expr_width(expr)); - } else { - /* Fallback case: evaluate the expression. */ - struct vector_info rv; - rv = draw_eval_expr(bexpr, STUFF_OK_XZ); - snprintf(buffer, sizeof buffer, "&PV", - ivl_expr_signal(vexpr), - rv.base, rv.wid, - ivl_expr_width(expr)); - } - args[idx].text = strdup(buffer); - continue; - } + case IVL_EX_SELECT: + if (get_vpi_taskfunc_signal_arg(&args[idx], expr)) continue; + else break; /* Everything else will need to be evaluated and passed as a constant to the vpi task. */ @@ -301,14 +339,22 @@ static void draw_vpi_taskfunc_args(const char*call_string, fprintf(vvp_out, "%s", call_string); for (idx = 0 ; idx < parm_count ; idx += 1) { - fprintf(vvp_out, ", %s", args[idx].text); free(args[idx].text); - if (args[idx].vec_flag) { - if (args[idx].vec.wid > 0) - clr_vector(args[idx].vec); - else - clr_word(args[idx].vec.base); + struct args_info*ptr; + /* Clear the nested children vectors. */ + for (ptr = &args[idx]; ptr != NULL; ptr = ptr->child) { + if (ptr->vec_flag) { + if (ptr->vec.wid > 0) clr_vector(ptr->vec); + else clr_word(ptr->vec.base); + } + } + /* Free the nested children. */ + ptr = args[idx].child; + while (ptr != NULL) { + struct args_info*tptr = ptr; + ptr = ptr->child; + free(tptr); } } diff --git a/vvp/array.cc b/vvp/array.cc index 29de4f15d..2916cf678 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -1170,6 +1170,23 @@ vpiHandle vpip_make_vthr_A(char*label, char*symbol) return &(obj->base); } +vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle) +{ + struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) + malloc(sizeof (struct __vpiArrayVthrA)); + + obj->base.vpi_type = &vpip_array_vthr_A_rt; + + obj->array = array_find(label); + assert(obj->array); + free(label); + + obj->address_handle = handle; + obj->address = 0; + obj->wid = 0; + + return &(obj->base); +} void compile_array_cleanup(void) { diff --git a/vvp/parse.y b/vvp/parse.y index 07c22abe6..ec1da8a36 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -105,7 +105,7 @@ static struct __vpiModPath*modpath_dst = 0; %type udp_table %type argument_opt argument_list -%type argument +%type argument symbol_access %type delay delay_opt %% @@ -831,21 +831,29 @@ argument { $$ = vpip_make_binary_const($1.idx, $1.text); free($1.text); } - | K_A '<' T_SYMBOL ',' T_NUMBER '>' + | symbol_access + { $$ = $1; } + ; + +symbol_access + : K_A '<' T_SYMBOL ',' T_NUMBER '>' { $$ = vpip_make_vthr_A($3, $5); } | K_A '<' T_SYMBOL ',' T_NUMBER T_NUMBER '>' { $$ = vpip_make_vthr_A($3, $5, $6); } | K_A '<' T_SYMBOL ',' T_SYMBOL '>' { $$ = vpip_make_vthr_A($3, $5); } + | K_A '<' T_SYMBOL ',' symbol_access '>' + { $$ = vpip_make_vthr_A($3, $5); } | K_PV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER '>' { $$ = vpip_make_PV($3, $5, $7); } | K_PV '<' T_SYMBOL ',' '-' T_NUMBER ',' T_NUMBER '>' { $$ = vpip_make_PV($3, -$6, $8); } | K_PV '<' T_SYMBOL ',' T_SYMBOL ',' T_NUMBER '>' { $$ = vpip_make_PV($3, $5, $7); } + | K_PV '<' T_SYMBOL ',' symbol_access ',' T_NUMBER '>' + { $$ = vpip_make_PV($3, $5, $7); } | K_PV '<' T_SYMBOL ',' T_NUMBER T_NUMBER ',' T_NUMBER '>' { $$ = vpip_make_PV($3, $5, $6, $8); } - ; /* functor operands can only be a list of symbols. */ symbols diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 49d38ed5d..0c03e13ea 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -239,6 +239,7 @@ struct __vpiPV { }; extern vpiHandle vpip_make_PV(char*name, int base, int width); extern vpiHandle vpip_make_PV(char*name, char*symbol, int width); +extern vpiHandle vpip_make_PV(char*name, vpiHandle handle, int width); extern vpiHandle vpip_make_PV(char*name, int tbase, int twid, int width); extern struct __vpiPV* vpip_PV_from_handle(vpiHandle obj); @@ -456,9 +457,10 @@ vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag); vpiHandle vpip_make_vthr_word(unsigned base, const char*type); -vpiHandle vpip_make_vthr_A(char*symbol, unsigned index); +vpiHandle vpip_make_vthr_A(char*label, unsigned index); vpiHandle vpip_make_vthr_A(char*label, char*symbol); -vpiHandle vpip_make_vthr_A(char*symbol, unsigned tbase, unsigned twid); +vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid); +vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle); /* * This function is called before any compilation to load VPI diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index cea4c9882..f5ab5be93 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -1171,6 +1171,21 @@ vpiHandle vpip_make_PV(char*var, char*symbol, int width) return &obj->base; } +vpiHandle vpip_make_PV(char*var, vpiHandle handle, int width) +{ + struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV)); + obj->base.vpi_type = &vpip_PV_rt; + obj->parent = vvp_lookup_handle(var); + obj->sbase = handle; + obj->tbase = 0; + obj->twid = 0; + obj->width = (unsigned) width; + obj->net = 0; + functor_ref_lookup(&obj->net, var); + + return &obj->base; +} + vpiHandle vpip_make_PV(char*var, int tbase, int twid, int width) { struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV));