diff --git a/elaborate.cc b/elaborate.cc index 332c976eb..f2927719e 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3381,29 +3381,6 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const verinum(1)); } while (0); - /* If this is an always block and we have no or zero delay then - * a runtime infinite loop will happen. If we possible have some - * delay then print a warning that an infinite loop is possible. - */ - if (type() == PProcess::PR_ALWAYS) { - DelayType dly_type = top->statement()->delay_type(); - - if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) { - cerr << get_fileline() << ": error: always statement" - << " does not have any delay." << endl; - cerr << get_fileline() << ": : A runtime infinite" - << " loop will occur." << endl; - des->errors += 1; - return false; - - } else if (dly_type == POSSIBLE_DELAY && warn_inf_loop) { - cerr << get_fileline() << ": warning: always statement" - << " may not have any delay." << endl; - cerr << get_fileline() << ": : A runtime infinite" - << " loop may be possible." << endl; - } - } - return true; } @@ -3871,6 +3848,37 @@ class later_defparams : public elaborator_work_item_t { } }; +bool Design::check_always_delay() const +{ + bool result_flag = true; + + for (const NetProcTop*pr = procs_ ; pr ; pr = pr->next_) { + /* If this is an always block and we have no or zero delay then + * a runtime infinite loop will happen. If we possible have some + * delay then print a warning that an infinite loop is possible. + */ + if (pr->type() == NetProcTop::KALWAYS) { + DelayType dly_type = pr->statement()->delay_type(); + + if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) { + cerr << pr->get_fileline() << ": error: always" + << " statement does not have any delay." << endl; + cerr << pr->get_fileline() << ": : A runtime" + << " infinite loop will occur." << endl; + result_flag = false; + + } else if (dly_type == POSSIBLE_DELAY && warn_inf_loop) { + cerr << pr->get_fileline() << ": warning: always" + << " statement may not have any delay." << endl; + cerr << pr->get_fileline() << ": : A runtime" + << " infinite loop may be possible." << endl; + } + } + } + + return result_flag; +} + /* * This function is the root of all elaboration. The input is the list * of root module names. The function locates the Module definitions @@ -3906,7 +3914,7 @@ Design* elaborate(listroots) // Get the module definition for this root instance. Module *rmod = (*mod).second; - // Make the root scope. This makes a NetScoep object and + // Make the root scope. This makes a NetScope object and // pushes it into the list of root scopes in the Design. NetScope*scope = des->make_root_scope(*root); @@ -3919,7 +3927,7 @@ Design* elaborate(listroots) des->set_precision(rmod->time_precision); - // Save this scope, along with its defintion, in the + // Save this scope, along with its definition, in the // "root_elems" list for later passes. struct root_elem *r = new struct root_elem; r->mod = rmod; @@ -3997,8 +4005,14 @@ Design* elaborate(listroots) rc &= rmod->elaborate(des, scope); } - if (rc == false) { + delete des; + return 0; + } + + // Now that everything is fully elaborated verify that we do + // not have an always block with no delay (an infinite loop). + if (des->check_always_delay() == false) { delete des; des = 0; } diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index 1624f172a..492b07a13 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -1588,6 +1588,12 @@ static int load_next_input() if(depend_file) fprintf(depend_file, "%s\n", istack->path); + /* This works around an issue in flex yyrestart() where it + * uses yyin to create a new buffer when one does not exist. + * I would have assumed that it would use the file argument. + * The problem is that we have deleted the buffer and freed + * yyin (isp->file) above. */ + yyin = 0; yyrestart(istack->file); return 1; } diff --git a/netlist.cc b/netlist.cc index 51cf898f6..fe09e0a7e 100644 --- a/netlist.cc +++ b/netlist.cc @@ -2575,6 +2575,7 @@ DelayType NetBlock::delay_type() const for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) { DelayType dt = cur->delay_type(); if (dt > result) result = dt; + if (dt == DEFINITE_DELAY) break; } return result; @@ -2609,7 +2610,9 @@ DelayType NetCondit::delay_type() const if (else_) { result = combine_delays(if_->delay_type(), else_->delay_type()); } else { - result = if_->delay_type(); + /* Because of the indeterminate conditional value the + * best we can have for this case is a possible delay. */ + result = combine_delays(if_->delay_type(), NO_DELAY); } return result; diff --git a/netlist.h b/netlist.h index 141c3d909..b962b9e3c 100644 --- a/netlist.h +++ b/netlist.h @@ -3715,6 +3715,7 @@ class Design { // PROCESSES void add_process(NetProcTop*); void delete_process(NetProcTop*); + bool check_always_delay() const; // Iterate over the design... void dump(ostream&) const; diff --git a/netmisc.cc b/netmisc.cc index e6e6e5659..7f82fd129 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -245,16 +245,16 @@ bool eval_as_double(double&value, NetExpr*expr) } /* - * At the parser level, a name component it a name with a collection + * At the parser level, a name component is a name with a collection * of expressions. For example foo[N] is the name "foo" and the index * expression "N". This function takes as input the name component and - * returns the path component name. It will evaulate the index + * returns the path component name. It will evaluate the index * expression if it is present. */ hname_t eval_path_component(Design*des, NetScope*scope, const name_component_t&comp) { - // No index exression, so the path component is an undecorated + // No index expression, so the path component is an undecorated // name, for example "foo". if (comp.index.empty()) return hname_t(comp.name); @@ -284,7 +284,7 @@ hname_t eval_path_component(Design*des, NetScope*scope, } // Darn, the expression doesn't evaluate to a constant. That's - // and error to be reported. And make up a fake index value to + // an error to be reported. And make up a fake index value to // return to the caller. cerr << index.msb->get_fileline() << ": error: " << "Scope index expression is not constant: " 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/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index a9931423e..df53648e3 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -1670,22 +1670,31 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid) vvp_errors += 1; } + /* Detect the special case that the entire number fits in an + immediate. In this case we generate a single %movi + instruction. */ if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID,0)) { unsigned long val = get_number_immediate(exp); fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid); return res; } + /* Use %movi as much as possible to build the value into the + destination. Use the %mov to handle the remaining general + bits. */ idx = 0; + unsigned long val = 0; + unsigned val_bits = 0; + unsigned val_addr = res.base; while (idx < nwid) { - unsigned cnt; - char src = '?'; + char src = 0; switch (bits[idx]) { case '0': - src = '0'; + val_bits += 1; break; case '1': - src = '1'; + val |= 1UL << val_bits; + val_bits += 1; break; case 'x': src = '2'; @@ -1695,14 +1704,29 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid) break; } - for (cnt = 1 ; idx+cnt < nwid ; cnt += 1) - if (bits[idx+cnt] != bits[idx]) - break; + if (val_bits >= IMM_WID + || (val_bits>0 && src != 0) + || (val_bits>0 && idx+1==nwid)) { + fprintf(vvp_out, " %%movi %u, %lu, %u;\n", + val_addr, val, val_bits); + val_addr += val_bits; + val_bits = 0; + val = 0; + } - fprintf(vvp_out, " %%mov %u, %c, %u;\n", - res.base+idx, src, cnt); + if (src != 0) { + assert(val_bits == 0); + unsigned cnt; + for (cnt = 1 ; idx+cnt < nwid ; cnt += 1) + if (bits[idx+cnt] != bits[idx]) + break; - idx += cnt; + fprintf(vvp_out, " %%mov %u, %c, %u;\n", val_addr, src, cnt); + val_addr += cnt; + idx += cnt-1; + } + + idx += 1; } /* Pad the number up to the expression width. */ diff --git a/vpi/sys_clog2.c b/vpi/sys_clog2.c index 043e44fd0..9d30f60a5 100644 --- a/vpi/sys_clog2.c +++ b/vpi/sys_clog2.c @@ -63,7 +63,7 @@ static PLI_INT32 sys_clog2_compiletf(PLI_BYTE8 *name) vpi_printf("%s $clog2 takes at most one argument.\n", msg); vpi_printf("%*s Found %u extra argument%s.\n", - strlen(msg), " ", argc, argc == 1 ? "" : "s"); + (int) strlen(msg), " ", argc, argc == 1 ? "" : "s"); vpi_control(vpiFinish, 1); } diff --git a/vvp/array.cc b/vvp/array.cc index 29de4f15d..41fa517aa 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -75,6 +75,7 @@ struct __vpiArray { class vvp_fun_arrayport*ports_; struct __vpiCallback *vpi_callbacks; + bool signed_flag; }; struct __vpiArrayIterator { @@ -452,7 +453,8 @@ static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value) unsigned index = decode_array_word_pointer(obj, parent); unsigned width = parent->vals->width(); - vpip_vec4_get_value(parent->vals->get_word(index), width, false, value); + vpip_vec4_get_value(parent->vals->get_word(index), width, + parent->signed_flag, value); } static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags) @@ -635,7 +637,7 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value) unsigned index = obj->get_address(); vvp_vector4_t tmp = array_get_word(parent, index); - vpip_vec4_get_value(tmp, parent->vals_width, false, value); + vpip_vec4_get_value(tmp, parent->vals_width, parent->signed_flag, value); } static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int) @@ -756,11 +758,14 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) } static vpiHandle vpip_make_array(char*label, const char*name, - int first_addr, int last_addr) + int first_addr, int last_addr, + bool signed_flag) { struct __vpiArray*obj = (struct __vpiArray*) malloc(sizeof(struct __vpiArray)); + obj->signed_flag = signed_flag; + // Assume increasing addresses. assert(last_addr >= first_addr); unsigned array_count = last_addr+1-first_addr; @@ -833,7 +838,8 @@ void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word) void compile_var_array(char*label, char*name, int last, int first, int msb, int lsb, char signed_flag) { - vpiHandle obj = vpip_make_array(label, name, first, last); + vpiHandle obj = vpip_make_array(label, name, first, last, + signed_flag != 0); struct __vpiArray*arr = ARRAY_HANDLE(obj); @@ -853,7 +859,7 @@ void compile_var_array(char*label, char*name, int last, int first, void compile_real_array(char*label, char*name, int last, int first, int msb, int lsb) { - vpiHandle obj = vpip_make_array(label, name, first, last); + vpiHandle obj = vpip_make_array(label, name, first, last, true); struct __vpiArray*arr = ARRAY_HANDLE(obj); vvp_array_t array = array_find(label); @@ -874,7 +880,7 @@ void compile_real_array(char*label, char*name, int last, int first, void compile_net_array(char*label, char*name, int last, int first) { - vpiHandle obj = vpip_make_array(label, name, first, last); + vpiHandle obj = vpip_make_array(label, name, first, last, false); struct __vpiArray*arr = ARRAY_HANDLE(obj); arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle)); @@ -981,7 +987,8 @@ void array_word_change(vvp_array_t array, unsigned long addr) if (cur->cb_data.value) vpip_vec4_get_value(array->vals->get_word(addr), array->vals_width, - false, cur->cb_data.value); + array->signed_flag, + cur->cb_data.value); callback_execute(cur); prev = cur; @@ -1170,6 +1177,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)); diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 86d8ed5dd..65425ff84 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1626,7 +1626,10 @@ static unsigned long* divide_bits(unsigned long*ap, unsigned long*bp, unsigned w unsigned cur_ptr = cur-1; unsigned long cur_res; if (ap[cur_ptr+btop] >= bp[btop]) { - cur_res = ap[cur_ptr+btop] / bp[btop]; + unsigned long high = 0; + if (cur_ptr+btop+1 < words) + high = ap[cur_ptr+btop+1]; + cur_res = divide2words(ap[cur_ptr+btop], bp[btop], high); } else if (cur_ptr+btop+1 >= words) { continue; @@ -1749,6 +1752,9 @@ bool of_DIV_S(vthread_t thr, vvp_code_t cp) assert(adra >= 4); + // Get the values, left in right, in binary form. If there is + // a problem with either (caused by an X or Z bit) then we + // know right away that the entire result is X. unsigned long*ap = vector_to_array(thr, adra, wid); if (ap == 0) { vvp_vector4_t tmp(wid, BIT4_X); @@ -1764,6 +1770,7 @@ bool of_DIV_S(vthread_t thr, vvp_code_t cp) return true; } + // Sign extend the bits in the array to fill out the array. unsigned long sign_mask = 0; if (unsigned long sign_bits = (words*CPU_WORD_BITS) - wid) { sign_mask = -1UL << (CPU_WORD_BITS-sign_bits); @@ -1773,6 +1780,7 @@ bool of_DIV_S(vthread_t thr, vvp_code_t cp) bp[words-1] |= sign_mask; } + // If the value fits in a single word, then use the native divide. if (wid <= CPU_WORD_BITS) { if (bp[0] == 0) { vvp_vector4_t tmp(wid, BIT4_X); diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index a9d9df79c..f921e014c 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -2144,22 +2144,19 @@ void vvp_net_fun_t::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&) assert(0); } -void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t, const vvp_vector4_t&bits, +void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t, const vvp_vector4_t&bit, unsigned base, unsigned wid, unsigned vwid) { cerr << "internal error: " << typeid(*this).name() << ": " - << "recv_vec4_pv(" << bits << ", " << base + << "recv_vec4_pv(" << bit << ", " << base << ", " << wid << ", " << vwid << ") not implemented" << endl; assert(0); } -void vvp_net_fun_t::recv_vec8_pv(vvp_net_ptr_t, const vvp_vector8_t&bits, +void vvp_net_fun_t::recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit, unsigned base, unsigned wid, unsigned vwid) { - cerr << "internal error: " << typeid(*this).name() << ": " - << "recv_vec8_pv(" << bits << ", " << base - << ", " << wid << ", " << vwid << ") not implemented" << endl; - assert(0); + recv_vec4_pv(port, reduce4(bit), base, wid, vwid); } void vvp_net_fun_t::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 1297564e8..b9b3bfb6c 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -859,8 +859,9 @@ struct vvp_net_t { * port. The value is a vvp_vector4_t. * * Most nodes do not care about the specific strengths of bits, so the - * default behavior for recv_vec8 is to reduce the operand to a - * vvp_vector4_t and pass it on to the recv_vec4 method. + * default behavior for recv_vec8 and recv_vec8_pv is to reduce the + * operand to a vvp_vector4_t and pass it on to the recv_vec4 or + * recv_vec4_pv method. */ class vvp_net_fun_t {