diff --git a/PExpr.cc b/PExpr.cc index 4c7f303f6..7e0e3693f 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -146,6 +146,15 @@ PECastSize::~PECastSize() { } +PECastType::PECastType(data_type_t*t, PExpr*b) +: target_(t), base_(b) +{ +} + +PECastType::~PECastType() +{ +} + PEBComp::PEBComp(char op, PExpr*l, PExpr*r) : PEBinary(op, l, r) { diff --git a/PExpr.h b/PExpr.h index 44c4008a5..004c619a7 100644 --- a/PExpr.h +++ b/PExpr.h @@ -986,6 +986,28 @@ class PECastSize : public PExpr { PExpr* base_; }; +/* + * Support the SystemVerilog cast to a different type. + */ +class PECastType : public PExpr { + + public: + explicit PECastType(data_type_t*target, PExpr*base); + ~PECastType(); + + void dump(ostream &out) const; + + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + unsigned expr_wid, unsigned flags) const; + + virtual unsigned test_width(Design*des, NetScope*scope, + width_mode_t&mode); + + private: + data_type_t* target_; + PExpr* base_; +}; + /* * This class is used for error recovery. All methods do nothing and return * null or default values. diff --git a/elab_expr.cc b/elab_expr.cc index c64582df4..fb07e07da 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -36,6 +36,7 @@ # include "netmisc.h" # include "netdarray.h" # include "netstruct.h" +# include "netscalar.h" # include "util.h" # include "ivl_assert.h" @@ -2431,6 +2432,87 @@ NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope, return sel; } +unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&wid) +{ + ivl_type_t t = target_->elaborate_type(des, scope); + base_->test_width(des, scope, wid); + + if(const netdarray_t*use_darray = dynamic_cast (t)) { + expr_type_ = use_darray->element_base_type(); + expr_width_ = use_darray->element_width(); + } + + else if(const netstring_t*use_string = dynamic_cast (t)) { + expr_type_ = use_string->base_type(); + expr_width_ = 8; + } + + else { + expr_type_ = t->base_type(); + expr_width_ = t->packed_width(); + } + + signed_flag_= t->get_signed(); + min_width_ = expr_width_; + return expr_width_; +} + +NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope, + unsigned, unsigned) const +{ + NetExpr*expr = base_->elaborate_expr(des, scope, base_->expr_width(), NO_FLAGS); + + if(dynamic_cast(target_)) { + return cast_to_real(expr); + } + + if(const atom2_type_t*atom = dynamic_cast(target_)) { + if(base_->expr_width() > expr_width_) { + cerr << get_fileline() << ": cast type is not wide enough to store the result." << endl; + ivl_assert(*this, 0); + } + + if(base_->has_sign() != atom->signed_flag) { + cerr << get_fileline() << ": cast type and subject differ in signedness." << endl; + ivl_assert(*this, 0); + } + + // That is how you both resize & cast to integers + return new NetECast('2', expr, expr_width_, expr->has_sign()); + } + + if(const vector_type_t*vec = dynamic_cast(target_)) { + switch(vec->base_type) { + case IVL_VT_BOOL: + return cast_to_int2(expr, expr_width_); + + case IVL_VT_LOGIC: + return cast_to_int4(expr, expr_width_); + + default: + break; /* Suppress warnings */ + } + } + + else if(dynamic_cast(target_)) { + if(base_->expr_type() == IVL_VT_STRING) + return expr; // no conversion + + if((base_->expr_type() != IVL_VT_BOOL) && + (base_->expr_type() != IVL_VT_LOGIC)) { + cerr << get_fileline() << ": cannot be casted to string." << endl; + ivl_assert(*this, false); + } + + return expr; + } + + cerr << get_fileline() << ": sorry: I don't know how to cast expression." << endl; + ivl_assert(*this, false); + + return expr; +} + unsigned PEConcat::test_width(Design*des, NetScope*scope, width_mode_t&) { expr_width_ = 0; @@ -4942,6 +5024,18 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, return res; } + if (net->sig()->data_type() == IVL_VT_STRING) { + // Special case: This is a select of a string. + // This should be interpreted as a byte select. + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Bit select of a string becomes NetESelect." << endl; + } + NetESelect*res = new NetESelect(net, mux, 8); + res->set_line(*net); + return res; + } + // Non-constant bit select? punt and make a subsignal // device to mux the bit in the net. This is a fairly // complicated task because we need to generate diff --git a/parse.y b/parse.y index b2f1a815a..a69b43c1a 100644 --- a/parse.y +++ b/parse.y @@ -3543,6 +3543,18 @@ expr_primary } } + | data_type '\'' '(' expression ')' + { PExpr*base = $4; + if (gn_system_verilog()) { + PECastType*tmp = new PECastType($1, base); + FILE_NAME(tmp, @1); + $$ = tmp; + } else { + yyerror(@1, "error: Type cast requires SystemVerilog."); + $$ = base; + } + } + /* Aggregate literals are primaries. */ | assignment_pattern diff --git a/pform.cc b/pform.cc index ecb81b721..48b136755 100644 --- a/pform.cc +++ b/pform.cc @@ -2239,7 +2239,7 @@ void pform_make_reginit(const struct vlltype&li, PEIdent*lval = new PEIdent(name); FILE_NAME(lval, li); - PAssign*ass = new PAssign(lval, expr, true); + PAssign*ass = new PAssign(lval, expr, generation_flag < GN_VER2001); FILE_NAME(ass, li); PProcess*top = new PProcess(IVL_PR_INITIAL, ass); FILE_NAME(top, li); diff --git a/pform_dump.cc b/pform_dump.cc index 981fbecd2..4cbd994ec 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -323,6 +323,14 @@ void PECastSize::dump(ostream &out) const out << ")"; } +void PECastType::dump(ostream &out) const +{ + target_->pform_dump(out, 0); + out << "'("; + base_->dump(out); + out << ")"; +} + void PEEvent::dump(ostream&out) const { switch (type_) { diff --git a/sys_funcs.cc b/sys_funcs.cc index 8e13ddede..3e2b26a51 100644 --- a/sys_funcs.cc +++ b/sys_funcs.cc @@ -193,6 +193,17 @@ int load_sys_func_table(const char*path) continue; } + if (strcmp(stype,"vpiSysFuncVoid") == 0) { + cell = new struct sfunc_return_type_cell; + cell->name = lex_strings.add(name); + cell->type = IVL_VT_VOID; + cell->wid = 0; + 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/stmt_assign.c b/tgt-vvp/stmt_assign.c index 761d967a1..c7607920a 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -593,6 +593,14 @@ static int show_stmt_assign_vector(ivl_statement_t net) fprintf(vvp_out, " %%cvt/vr %u, %u;\n", res.base, res.wid); + } else if (ivl_expr_value(rval) == IVL_VT_STRING) { + /* Special case: vector to string casting */ + ivl_lval_t lval = ivl_stmt_lval(net, 0); + fprintf(vvp_out, " %%vpi_call %u %u \"$ivl_string_method$to_vec\", v%p_0, v%p_0 {0 0};\n", + ivl_file_table_index(ivl_stmt_file(net)), ivl_stmt_lineno(net), + ivl_expr_signal(rval), ivl_lval_sig(lval)); + return 0; + } else { res = draw_eval_expr(rval, 0); } diff --git a/vpi/system.sft b/vpi/system.sft index 2e65eade3..f3048198f 100644 --- a/vpi/system.sft +++ b/vpi/system.sft @@ -22,4 +22,5 @@ $simparam vpiSysFuncReal $simparam$str vpiSysFuncSized 1024 unsigned $table_model vpiSysFuncReal -$ivl_string_method$len vpiSysFuncInt +$ivl_string_method$len vpiSysFuncInt +$ivl_string_method$to_vec vpiSysFuncVoid diff --git a/vpi/v2009_string.c b/vpi/v2009_string.c index bb7bed623..29dd3691d 100644 --- a/vpi/v2009_string.c +++ b/vpi/v2009_string.c @@ -19,6 +19,9 @@ # include "sys_priv.h" # include +# include +# include +# include static PLI_INT32 one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) { @@ -75,6 +78,120 @@ static PLI_INT32 len_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } + +static PLI_INT32 to_vec_compiletf(ICARUS_VPI_CONST PLI_BYTE8*user_data) +{ + (void) user_data; /* Parameter is not used. */ + + vpiHandle systf_handle, arg_iterator, arg_handle; + PLI_INT32 arg_type[2]; + + /* obtain a handle to the system task instance */ + systf_handle = vpi_handle(vpiSysTfCall, NULL); + if (systf_handle == NULL) { + vpi_printf("ERROR: $ivl_string_method$to_vec failed to obtain systf handle\n"); + vpi_control(vpiFinish,0); /* abort simulation */ + return 0; + } + + /* obtain handles to system task arguments */ + arg_iterator = vpi_iterate(vpiArgument, systf_handle); + if (arg_iterator == NULL) { + vpi_printf("ERROR: $ivl_string_method$to_vec requires 2 arguments\n"); + vpi_control(vpiFinish, 0); + return 0; + } + + /* check the type of object in system task arguments */ + arg_handle = vpi_scan(arg_iterator); + for(int i = 0; i < 2; ++i) { + arg_type[i] = vpi_get(vpiType, arg_handle); + arg_handle = vpi_scan(arg_iterator); + } + + if (arg_handle != NULL) { /* are there more arguments? */ + vpi_printf("ERROR: $ivl_string_method$to_vec can only have 2 arguments\n"); + vpi_free_object(arg_iterator); + vpi_control(vpiFinish, 0); + return 0; + } + + if ((arg_type[0] != vpiStringVar) || + (arg_type[1] != vpiNet && arg_type[1] != vpiReg)) { + vpi_printf("ERROR: $ivl_string_method$to_vec value arguments must be a string and a net or reg\n"); + vpi_free_object(arg_iterator); + vpi_control(vpiFinish, 0); + return 0; + } + + return 0; +} + +static PLI_INT32 to_vec_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + (void)name; /* Parameter is not used. */ + + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv, str, vec; + s_vpi_value str_val; + s_vpi_vecval*vec_val; + + /* Fetch arguments */ + argv = vpi_iterate(vpiArgument, callh); + assert(argv); + str = vpi_scan(argv); + assert(str); + vec = vpi_scan(argv); + assert(vec); + vpi_free_object(argv); + + int str_size = vpi_get(vpiSize, str); + int vec_size = vpi_get(vpiSize, vec); + if(str_size <= 0) { + vpi_printf("ERROR: Cannot cast empty string"); + vpi_control(vpiFinish, 0); + return 0; + } + + if(vec_size != str_size * 8) { + vpi_printf("ERROR: String and vector size do not match"); + vpi_control(vpiFinish, 0); + return 0; + } + + str_val.format = vpiStringVal; + vpi_get_value(str, &str_val); + assert(str_val.value.str); + + /* Conversion part */ + int vec_number = ceil((double)str_size / sizeof(PLI_INT32)); + vec_val = calloc(vec_number, sizeof(s_vpi_vecval)); + PLI_BYTE8*str_ptr = &str_val.value.str[str_size - 1]; + + /* We have to reverse the order of string, no memcpy here */ + for(int i = 0; i < vec_number; ++i) { + int copy_size = str_size > (int)sizeof(PLI_INT32) ? + (int)sizeof(PLI_INT32) : str_size; + + /* Clear the part responsible for X & Z values */ + memset(&vec_val[i].bval, 0x00, sizeof(PLI_INT32)); + PLI_BYTE8*dest = (PLI_BYTE8*)&vec_val[i].aval; + + for(int j = 0; j < copy_size; ++j) + *dest++ = *str_ptr--; + + str_size -= copy_size; + } + + str_val.format = vpiVectorVal; + str_val.value.vector = vec_val; + vpi_put_value(vec, &str_val, 0, vpiNoDelay); + + free(vec_val); + + return 0; +} + void v2009_string_register(void) { s_vpi_systf_data tf_data; @@ -89,4 +206,14 @@ void v2009_string_register(void) tf_data.user_data = "$ivl_string_method$len"; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysTask; + tf_data.sysfunctype = 0; + tf_data.tfname = "$ivl_string_method$to_vec"; + tf_data.calltf = to_vec_calltf; + tf_data.compiletf = to_vec_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$ivl_string_method$to_vec"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); } diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 16a0ecbc2..35750f69d 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -71,7 +71,7 @@ V = vpi_modules.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_darray.o \ vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \ vpip_to_dec.o vpip_format.o vvp_vpi.o -O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \ +O = main.o parse.o parse_misc.o lexor.o arith.o array_common.o array.o bufif.o compile.o \ concat.o dff.o class_type.o enum_type.o extend.o file_line.o npmos.o part.o \ permaheap.o reduce.o resolv.o \ sfunc.o stop.o \ diff --git a/vvp/array.cc b/vvp/array.cc index 396b7effe..84dcce59d 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +# include "array_common.h" # include "array.h" # include "symbols.h" # include "schedule.h" @@ -56,86 +57,8 @@ vvp_array_t array_find(const char*label) return v; } -/* -* The vpiArray object holds an array of vpi objects that themselves -* represent the words of the array. The vpi_array_t is a pointer to -* a struct __vpiArray. -* -* The details of the implementation depends on what this is an array -* of. The easiest case is if this is an array of nets. -* -* - Array of Nets: -* If this represents an array of nets, then the nets member points to -* an array of vpiHandle objects. Each vpiHandle is a word. This is -* done because typically each word of a net array is simultaneously -* driven and accessed by other means, so there is no advantage to -* compacting the array in any other way. -* -* - Array of vector4 words. -* In this case, the nets pointer is nil, and the vals4 member points -* to a vvl_vector4array_t object that is a compact representation of -* an array of vvp_vector4_t vectors. -* -* - Array of real variables -* The vals member points to a dynamic array objects that has an -* array of double variables. This is very much like the way the -* vector4 array works. -*/ -struct __vpiArray : public __vpiHandle { - __vpiArray(); - int get_type_code(void) const; - int vpi_get(int code); - char* vpi_get_str(int code); - vpiHandle vpi_handle(int code); - vpiHandle vpi_iterate(int code); - vpiHandle vpi_index(int idx); - - struct __vpiScope*scope; - const char*name; /* Permanently allocated string */ - unsigned array_count; - __vpiDecConst first_addr; - __vpiDecConst last_addr; - __vpiDecConst msb; - __vpiDecConst lsb; - unsigned vals_width; - // If this is a net array, nets lists the handles. - vpiHandle*nets; - // If this is a var array, then these are used instead of nets. - vvp_vector4array_t*vals4; - vvp_darray *vals; - struct __vpiArrayWord*vals_words; - - vvp_fun_arrayport*ports_; - struct __vpiCallback *vpi_callbacks; - bool signed_flag; - bool swap_addr; -}; - -struct __vpiArrayIterator : public __vpiHandle { - __vpiArrayIterator(); - int get_type_code(void) const; - vpiHandle vpi_index(int idx); - free_object_fun_t free_object_fun(void); - - struct __vpiArray*array; - unsigned next; -}; - -struct __vpiArrayIndex : public __vpiHandle { - __vpiArrayIndex(); - int get_type_code(void) const; - vpiHandle vpi_iterate(int code); - vpiHandle vpi_index(int idx); - free_object_fun_t free_object_fun(void); - - __vpiDecConst *index; - unsigned done; -}; - struct __vpiArrayVthrA : public __vpiHandle { - - __vpiArrayVthrA(); - int get_type_code(void) const; + int get_type_code(void) const { return vpiMemoryWord; } int vpi_get(int code); char* vpi_get_str(int code); void vpi_get_value(p_vpi_value val); @@ -208,8 +131,7 @@ struct __vpiArrayVthrA : public __vpiHandle { struct __vpiArrayVthrAPV : public __vpiHandle { - __vpiArrayVthrAPV(); - int get_type_code(void) const; + int get_type_code(void) const { return vpiMemoryWord; } int vpi_get(int code); char* vpi_get_str(int code); void vpi_get_value(p_vpi_value val); @@ -220,27 +142,6 @@ struct __vpiArrayVthrAPV : public __vpiHandle { unsigned part_wid; }; -/* Get the array word size. */ -unsigned get_array_word_size(vvp_array_t array) -{ - unsigned width; - - assert(array->array_count > 0); - /* For a net array we need to get the width from the first element. */ - if (array->nets) { - assert(array->vals4 == 0 && array->vals == 0); - struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(array->nets[0]); - assert(vsig); - width = vpip_size(vsig); - /* For a variable array we can get the width from vals_width. */ - } else { - assert(array->vals4 || array->vals); - width = array->vals_width; - } - - return width; -} - bool is_net_array(vpiHandle obj) { struct __vpiArray*rfp = dynamic_cast<__vpiArray*> (obj); @@ -250,80 +151,155 @@ bool is_net_array(vpiHandle obj) return false; } -/* - * The vpiArrayWord is magic. It is used as the handle to return when - * vpi code tries to index or scan an array of variable words. The - * array word handle contains no actual data. It is just a hook for - * the vpi methods and to point to the parent. - * - * How the point to the parent works is tricky. The vpiArrayWord - * objects for an array are themselves allocated as an array. All the - * ArrayWord objects in the array have a word0 that points to the base - * of the array. Thus, the position into the array (and the index into - * the memory) is calculated by subtracting word0 from the ArrayWord - * pointer. - * - * To then get to the parent, use word0[-1].parent. - * - * The vpiArrayWord is also used as a handle for the index (vpiIndex) - * for the word. To make that work, return the pointer to the as_index - * member instead of the as_word member. The result is a different set - * of vpi functions is bound to the same structure. All the details - * for the word also apply when treating this as an index. - */ +// This function return true if the underlying array words are real. +static bool vpi_array_is_real(const vvp_array_t arr) +{ + // Check to see if this is a variable/register array. + if (arr->vals4 != 0) // A bit based variable/register array. + return false; + if (dynamic_cast (arr->vals)) + return true; -struct __vpiArrayWord { - struct as_word_t : public __vpiHandle { - as_word_t(); - int get_type_code(void) const; - int vpi_get(int code); - char*vpi_get_str(int code); - void vpi_get_value(p_vpi_value val); - vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code); - } as_word; + if (arr->vals != 0) + return false; - struct as_index_t : public __vpiHandle { - as_index_t(); - int get_type_code(void) const; - void vpi_get_value(p_vpi_value val); - } as_index; + // This must be a net array so look at element 0 to find the type. + assert(arr->nets != 0); + assert(arr->get_size() > 0); + struct __vpiRealVar*rsig = dynamic_cast<__vpiRealVar*>(arr->nets[0]); + if (rsig) { + return true; + } - union { - struct __vpiArray*parent; - struct __vpiArrayWord*word0; - }; -}; + return false; +} -static void array_make_vals_words(struct __vpiArray*parent); +static bool vpi_array_is_string(const vvp_array_t arr) +{ + // Check to see if this is a variable/register array. + if (arr->vals4 != 0) // A bit based variable/register array. + return false; -static vpiHandle array_index_scan(vpiHandle ref, int); + if (dynamic_cast (arr->vals)) + return true; -static int vpi_array_var_word_get(int code, vpiHandle); -static char*vpi_array_var_word_get_str(int code, vpiHandle); -static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value vp); -static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, - int); -static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref); + return false; +} -static void vpi_array_var_index_get_value(vpiHandle ref, p_vpi_value vp); +int __vpiArray::get_word_size() const +{ + unsigned width; -static int vpi_array_vthr_A_get(int code, vpiHandle); -static char*vpi_array_vthr_A_get_str(int code, vpiHandle); -static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value vp); -static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int); -static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref); + assert(get_size() > 0); + /* For a net array we need to get the width from the first element. */ + if (nets) { + assert(vals4 == 0 && vals == 0); + struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(nets[0]); + assert(vsig); + width = vpip_size(vsig); + /* For a variable array we can get the width from vals_width. */ + } else { + assert(vals4 || vals); + width = vals_width; + } -static int vpi_array_vthr_APV_get(int code, vpiHandle); -static char*vpi_array_vthr_APV_get_str(int code, vpiHandle); -static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp); + return width; +} -inline __vpiArray::__vpiArray() -{ } +char*__vpiArray::get_word_str(struct __vpiArrayWord*word, int code) +{ + unsigned index = word->get_index(); -int __vpiArray::get_type_code(void) const -{ return vpiMemory; } + if (code == vpiFile) { // Not implemented for now! + return simple_set_rbuf_str(file_names[0]); + } + + char sidx [64]; + snprintf(sidx, 63, "%d", (int)index + first_addr.get_value()); + return generic_get_str(code, get_scope(), name, sidx); +} + +void __vpiArray::get_word_value(struct __vpiArrayWord*word, p_vpi_value vp) +{ + unsigned index = word->get_index(); + + // Determine the appropriate format (The Verilog PLI Handbook 5.2.10) + if(vp->format == vpiObjTypeVal) { + if(vpi_array_is_real(this)) + vp->format = vpiRealVal; + else if(vpi_array_is_string(this)) + vp->format = vpiStringVal; + else + vp->format = vpiIntVal; + } + + if(vals4) { + vpip_vec4_get_value(vals4->get_word(index), + vals4->width(), signed_flag, vp); + } else if(vals) { + switch(vp->format) { + case vpiBinStrVal: + case vpiOctStrVal: + case vpiDecStrVal: + case vpiHexStrVal: + case vpiScalarVal: + case vpiIntVal: + { + vvp_vector4_t v; + vals->get_word(index, v); + vpip_vec4_get_value(v, vals_width, signed_flag, vp); + } + break; + + case vpiVectorVal: + { + vvp_vector4_t v; + vals->get_word(index, v); + vpip_vec2_get_value(v, vals_width, signed_flag, vp); + } + break; + + case vpiRealVal: + { + double d; + vals->get_word(index, d); + vpip_real_get_value(d, vp); + } + break; + + case vpiStringVal: + { + string s; + vals->get_word(index, s); + vpip_string_get_value(s, vp); + } + break; + + default: + fprintf(stderr, "vpi sorry: format is not implemented\n"); + assert(false); + } + } +} + +void __vpiArray::put_word_value(struct __vpiArrayWord*word, p_vpi_value vp, int) +{ + unsigned index = word->get_index(); + vvp_vector4_t val = vec4_from_vpi_value(vp, vals_width); + set_word(index, 0, val); +} + +vpiHandle __vpiArray::get_iter_index(struct __vpiArrayIterator*, int idx) +{ + if (nets) return nets[idx]; + + assert(vals4 || vals); + + if (vals_words == 0) make_vals_words(); + + return &(vals_words[idx].as_word); +} int __vpiArray::vpi_get(int code) { @@ -332,7 +308,7 @@ int __vpiArray::vpi_get(int code) return 0; // Not implemented for now! case vpiSize: - return (int) array_count; + return get_size(); case vpiAutomatic: return (int) scope->is_automatic; @@ -354,14 +330,13 @@ char* __vpiArray::vpi_get_str(int code) vpiHandle __vpiArray::vpi_handle(int code) { switch (code) { + case vpiLeftRange: + if (swap_addr) return &last_addr; + else return &first_addr; - case vpiLeftRange: - if (swap_addr) return &last_addr; - else return &first_addr; - - case vpiRightRange: - if (swap_addr) return &first_addr; - else return &last_addr; + case vpiRightRange: + if (swap_addr) return &first_addr; + else return &last_addr; case vpiScope: return scope; @@ -373,23 +348,6 @@ vpiHandle __vpiArray::vpi_handle(int code) return 0; } -vpiHandle __vpiArray::vpi_iterate(int code) -{ - switch (code) { - - case vpiMemoryWord: { - struct __vpiArrayIterator*res; - res = new __vpiArrayIterator; - res->array = this; - res->next = 0; - return res; - } - - } - - return 0; -} - /* * VPI code passes indices that are not yet converted to canonical * form, so this index function does it here. @@ -397,7 +355,7 @@ vpiHandle __vpiArray::vpi_iterate(int code) vpiHandle __vpiArray::vpi_index(int index) { index -= first_addr.get_value(); - if (index >= (long)array_count) + if (index >= (long) get_size()) return 0; if (index < 0) return 0; @@ -407,215 +365,39 @@ vpiHandle __vpiArray::vpi_index(int index) } if (vals_words == 0) - array_make_vals_words(this); + make_vals_words(); return &(vals_words[index].as_word); } - -inline __vpiArrayIterator::__vpiArrayIterator() -{ } - -int __vpiArrayIterator::get_type_code(void) const -{ return vpiIterator; } - -vpiHandle __vpiArrayIterator::vpi_index(int) -{ - if (next >= array->array_count) { - vpi_free_object(this); - return 0; - } - - unsigned use_index = next; - next += 1; - - if (array->nets) return array->nets[use_index]; - - assert(array->vals4 || array->vals); - - if (array->vals_words == 0) array_make_vals_words(array); - - return &(array->vals_words[use_index].as_word); -} - - -static int array_iterator_free_object(vpiHandle ref) -{ - struct __vpiArrayIterator*obj = dynamic_cast<__vpiArrayIterator*>(ref); - delete obj; - return 1; -} - -__vpiHandle::free_object_fun_t __vpiArrayIterator::free_object_fun(void) -{ return &array_iterator_free_object; } - -inline __vpiArrayIndex::__vpiArrayIndex() -{ } - -int __vpiArrayIndex::get_type_code(void) const -{ return vpiIterator; } - -vpiHandle __vpiArrayIndex::vpi_iterate(int code) -{ return array_index_iterate(code, this); } - -vpiHandle __vpiArrayIndex::vpi_index(int idx) -{ return array_index_scan(this, idx); } - -static int array_index_free_object(vpiHandle ref) -{ - struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref); - delete obj; - return 1; -} - -__vpiHandle::free_object_fun_t __vpiArrayIndex::free_object_fun(void) -{ return &array_index_free_object; } - -inline __vpiArrayWord::as_word_t::as_word_t() -{ } - -int __vpiArrayWord::as_word_t::get_type_code(void) const -{ return vpiMemoryWord; } - int __vpiArrayWord::as_word_t::vpi_get(int code) -{ return vpi_array_var_word_get(code, this); } - -char* __vpiArrayWord::as_word_t::vpi_get_str(int code) -{ return vpi_array_var_word_get_str(code, this); } - -void __vpiArrayWord::as_word_t::vpi_get_value(p_vpi_value val) -{ vpi_array_var_word_get_value(this, val); } - -vpiHandle __vpiArrayWord::as_word_t::vpi_put_value(p_vpi_value val, int flags) -{ return vpi_array_var_word_put_value(this, val, flags); } - -vpiHandle __vpiArrayWord::as_word_t::vpi_handle(int code) -{ return vpi_array_var_word_get_handle(code, this); } - -inline __vpiArrayWord::as_index_t::as_index_t() -{ } - -int __vpiArrayWord::as_index_t::get_type_code(void) const -{ return vpiIndex; } - -void __vpiArrayWord::as_index_t::vpi_get_value(p_vpi_value val) -{ vpi_array_var_index_get_value(this, val); } - -inline __vpiArrayVthrA::__vpiArrayVthrA() -{ } - -int __vpiArrayVthrA::get_type_code(void) const -{ return vpiMemoryWord; } - -int __vpiArrayVthrA::vpi_get(int code) -{ return vpi_array_vthr_A_get(code, this); } - -char* __vpiArrayVthrA::vpi_get_str(int code) -{ return vpi_array_vthr_A_get_str(code, this); } - -void __vpiArrayVthrA::vpi_get_value(p_vpi_value val) -{ vpi_array_vthr_A_get_value(this, val); } - -vpiHandle __vpiArrayVthrA::vpi_put_value(p_vpi_value val, int flags) -{ return vpi_array_vthr_A_put_value(this, val, flags); } - -vpiHandle __vpiArrayVthrA::vpi_handle(int code) -{ return vpi_array_vthr_A_get_handle(code, this); } - - -inline __vpiArrayVthrAPV::__vpiArrayVthrAPV() -{ } - -int __vpiArrayVthrAPV::get_type_code(void) const -{ return vpiMemoryWord; } - -int __vpiArrayVthrAPV::vpi_get(int code) -{ return vpi_array_vthr_APV_get(code, this); } - -char* __vpiArrayVthrAPV::vpi_get_str(int code) -{ return vpi_array_vthr_APV_get_str(code, this); } - -void __vpiArrayVthrAPV::vpi_get_value(p_vpi_value val) -{ vpi_array_vthr_APV_get_value(this, val); } - -static struct __vpiArrayWord* array_var_word_from_handle(vpiHandle ref) { - if (ref == 0) - return 0; - __vpiArrayWord::as_word_t*ptr = dynamic_cast<__vpiArrayWord::as_word_t*> (ref); - if (ptr == 0) - return 0; - - return (struct __vpiArrayWord*) ref; -} - -static struct __vpiArrayWord* array_var_index_from_handle(vpiHandle ref) -{ - if (ref == 0) - return 0; - __vpiArrayWord::as_index_t*ptr = dynamic_cast<__vpiArrayWord::as_index_t*> (ref); - if (ptr == 0) - return 0; - - assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_index_t)); - assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_word_t)); - return (struct __vpiArrayWord*) (ref-1); -} - -static void array_make_vals_words(struct __vpiArray*parent) -{ - assert(parent->vals_words == 0); - parent->vals_words = new struct __vpiArrayWord[parent->array_count + 1]; - - // Make word[-1] point to the parent. - parent->vals_words->parent = parent; - // Now point to word-0 - parent->vals_words += 1; - - struct __vpiArrayWord*words = parent->vals_words; - for (unsigned idx = 0 ; idx < parent->array_count ; idx += 1) { - words[idx].word0 = words; - } -} - -static unsigned decode_array_word_pointer(struct __vpiArrayWord*word, - struct __vpiArray*&parent) -{ - struct __vpiArrayWord*word0 = word->word0; - parent = (word0 - 1) -> parent; - return word - word0; -} - -static int vpi_array_var_word_get(int code, vpiHandle ref) -{ - struct __vpiArrayWord*obj = array_var_word_from_handle(ref); - struct __vpiArray*parent; - + struct __vpiArrayWord*obj = array_var_word_from_handle(this); assert(obj); - decode_array_word_pointer(obj, parent); - assert(parent->nets == 0); + struct __vpiArrayBase*parent = obj->get_parent(); + t_vpi_value val; switch (code) { case vpiLineNo: return 0; // Not implemented for now! case vpiSize: - if (parent->vals4) { - assert(parent->vals == 0); - return (int) parent->vals4->width(); - } else { - assert(parent->vals4 == 0); - return 1; - } + return parent->get_word_size(); case vpiLeftRange: - return parent->msb.get_value(); + val.format = vpiIntVal; + parent->get_left_range()->vpi_get_value(&val); + assert(val.format == vpiIntVal); + return val.value.integer; case vpiRightRange: - return parent->lsb.get_value(); + val.format = vpiIntVal; + parent->get_right_range()->vpi_get_value(&val); + assert(val.format == vpiIntVal); + return val.value.integer; case vpiAutomatic: - return (int) parent->scope->is_automatic; + return (int) parent->get_scope()->is_automatic; #if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX) case _vpiFromThr: @@ -627,145 +409,27 @@ static int vpi_array_var_word_get(int code, vpiHandle ref) } } -static char*vpi_array_var_word_get_str(int code, vpiHandle ref) + +int __vpiArrayVthrA::vpi_get(int code) { - struct __vpiArrayWord*obj = array_var_word_from_handle(ref); - struct __vpiArray*parent; - - assert(obj); - unsigned index = decode_array_word_pointer(obj, parent); - - if (code == vpiFile) { // Not implemented for now! - return simple_set_rbuf_str(file_names[0]); - } - - char sidx [64]; - snprintf(sidx, 63, "%d", (int)index + parent->first_addr.get_value()); - return generic_get_str(code, parent->scope, parent->name, sidx); -} - -static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value vp) -{ - struct __vpiArrayWord*obj = array_var_word_from_handle(ref); - struct __vpiArray*parent; - - assert(obj); - unsigned index = decode_array_word_pointer(obj, parent); - unsigned width = parent->vals4->width(); - - vpip_vec4_get_value(parent->vals4->get_word(index), width, - parent->signed_flag, vp); -} - -static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int) -{ - struct __vpiArrayWord*obj = array_var_word_from_handle(ref); - struct __vpiArray*parent; - - assert(obj); - unsigned index = decode_array_word_pointer(obj, parent); - - vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width); - array_set_word(parent, index, 0, val); - return ref; -} - -static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref) -{ - struct __vpiArrayWord*obj = array_var_word_from_handle(ref); - struct __vpiArray*parent; - - assert(obj); - decode_array_word_pointer(obj, parent); - - switch (code) { - - case vpiIndex: - return &(obj->as_index); - - case vpiLeftRange: - return &parent->msb; - - case vpiRightRange: - return &parent->lsb; - - case vpiParent: - return parent; - - case vpiScope: - return parent->scope; - - case vpiModule: - return vpip_module(parent->scope); - } - - return 0; -} - -static void vpi_array_var_index_get_value(vpiHandle ref, p_vpi_value vp) -{ - struct __vpiArrayWord*obj = array_var_index_from_handle(ref); - struct __vpiArray*parent; - - assert(obj); - unsigned index = decode_array_word_pointer(obj, parent); - - assert(vp->format == vpiIntVal); - vp->value.integer = index; -} - -vpiHandle array_index_iterate(int code, vpiHandle ref) -{ - __vpiDecConst *obj = dynamic_cast<__vpiDecConst*>(ref); - assert(obj); - - if (code == vpiIndex) { - struct __vpiArrayIndex*res; - res = new __vpiArrayIndex; - res->index = obj; - res->done = 0; - return res; - } - return 0; -} - -static vpiHandle array_index_scan(vpiHandle ref, int) -{ - struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref); - - if (obj->done == 0) { - obj->done = 1; - return obj->index; - } - - vpi_free_object(ref); - return 0; -} - -static int vpi_array_vthr_A_get(int code, vpiHandle ref) -{ - struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); - assert(obj); - struct __vpiArray*parent = obj->array; - switch (code) { case vpiLineNo: return 0; // Not implemented for now! case vpiSize: - return get_array_word_size(parent); + return array->get_word_size(); case vpiLeftRange: - return parent->msb.get_value(); + return array->msb.get_value(); case vpiRightRange: - return parent->lsb.get_value(); + return array->lsb.get_value(); case vpiIndex: - return (int)obj->get_address() + parent->first_addr.get_value(); + return (int)get_address() + array->first_addr.get_value(); case vpiAutomatic: - return (int) parent->scope->is_automatic; + return (int) array->get_scope()->is_automatic; #if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX) case _vpiFromThr: @@ -778,162 +442,108 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref) // This assumes that the compiler is squashing all the // constant expressions down to a single value. case vpiConstantSelect: - return obj->address_handle == 0 && obj->wid == 0; + return address_handle == 0 && wid == 0; default: return 0; } } -static char*vpi_array_vthr_A_get_str(int code, vpiHandle ref) +char* __vpiArrayVthrA::vpi_get_str(int code) { - struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); - assert(obj); - struct __vpiArray*parent = obj->array; - if (code == vpiFile) { // Not implemented for now! return simple_set_rbuf_str(file_names[0]); } char sidx [64]; - snprintf(sidx, 63, "%d", (int)obj->get_address() + parent->first_addr.get_value()); - return generic_get_str(code, parent->scope, parent->name, sidx); + snprintf(sidx, 63, "%d", (int)get_address() + array->first_addr.get_value()); + return generic_get_str(code, array->get_scope(), array->name, sidx); } -// This function return true if the underlying array words are real. -static bool vpi_array_is_real(vvp_array_t arr) +void __vpiArrayVthrA::vpi_get_value(p_vpi_value vp) { - // Check to see if this is a variable/register array. - if (arr->vals4 != 0) // A bit based variable/register array. - return false; + assert(array); - if (dynamic_cast (arr->vals)) - return true; - - if (arr->vals != 0) - return false; - - // This must be a net array so look at element 0 to find the type. - assert(arr->nets != 0); - assert(arr->array_count > 0); - struct __vpiRealVar*rsig = dynamic_cast<__vpiRealVar*>(arr->nets[0]); - if (rsig) { - return true; - } - - return false; -} - -static bool vpi_array_is_string(vvp_array_t arr) -{ - // Check to see if this is a variable/register array. - if (arr->vals4 != 0) // A bit based variable/register array. - return false; - - if (dynamic_cast (arr->vals)) - return true; - - return false; -} - -static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value vp) -{ - struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); - assert(obj); - struct __vpiArray*parent = obj->array; - - assert(parent); - - unsigned index = obj->get_address(); - if (vpi_array_is_real(parent)) { - double tmp = array_get_word_r(parent, index); + unsigned index = get_address(); + if (vpi_array_is_real(array)) { + double tmp = array->get_word_r(index); vpip_real_get_value(tmp, vp); - } else if (vpi_array_is_string(parent)) { - string tmp = array_get_word_str(parent, index); + } else if (vpi_array_is_string(array)) { + string tmp = array->get_word_str(index); vpip_string_get_value(tmp, vp); } else { - vvp_vector4_t tmp = array_get_word(parent, index); - unsigned width = get_array_word_size(parent); - vpip_vec4_get_value(tmp, width, parent->signed_flag, vp); + vvp_vector4_t tmp = array->get_word(index); + unsigned width = array->get_word_size(); + vpip_vec4_get_value(tmp, width, array->signed_flag, vp); } } -static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int) +vpiHandle __vpiArrayVthrA::vpi_put_value(p_vpi_value vp, int) { - struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); - assert(obj); - struct __vpiArray*parent = obj->array; + unsigned index = get_address(); - unsigned index = obj->get_address(); + assert(array); + assert(index < array->get_size()); - assert(parent); - assert(index < parent->array_count); - - if (vpi_array_is_real(parent)) { + if (vpi_array_is_real(array)) { double val = real_from_vpi_value(vp); - array_set_word(parent, index, val); + array->set_word(index, val); } else { - unsigned width = get_array_word_size(parent); + unsigned width = array->get_word_size(); vvp_vector4_t val = vec4_from_vpi_value(vp, width); - array_set_word(parent, index, 0, val); + array->set_word(index, 0, val); } - return ref; + return this; } -static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref) +vpiHandle __vpiArrayVthrA::vpi_handle(int code) { - struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); - assert(obj); - struct __vpiArray*parent = obj->array; - switch (code) { - case vpiIndex: break; // Not implemented! case vpiLeftRange: - return &parent->msb; + return &array->msb; case vpiRightRange: - return &parent->lsb; + return &array->lsb; case vpiParent: - return parent; + case vpiArray: + return array; case vpiScope: - return parent->scope; + return array->get_scope(); case vpiModule: - return vpip_module(parent->scope); + return vpip_module(array->get_scope()); } return 0; } -static int vpi_array_vthr_APV_get(int code, vpiHandle ref) -{ - struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref); - struct __vpiArray*parent = obj->array; +int __vpiArrayVthrAPV::vpi_get(int code) +{ switch (code) { case vpiLineNo: return 0; // Not implemented for now! case vpiSize: - return obj->part_wid; + return part_wid; case vpiLeftRange: - return parent->msb.get_value(); + return array->msb.get_value(); case vpiRightRange: - return parent->lsb.get_value(); + return array->lsb.get_value(); case vpiIndex: - return (int)obj->word_sel; + return (int)word_sel; case vpiAutomatic: - return (int) parent->scope->is_automatic; + return (int) array->get_scope()->is_automatic; #if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX) case _vpiFromThr: @@ -948,153 +558,142 @@ static int vpi_array_vthr_APV_get(int code, vpiHandle ref) } } -static char*vpi_array_vthr_APV_get_str(int code, vpiHandle ref) +char* __vpiArrayVthrAPV::vpi_get_str(int code) { - struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref); - assert(obj); - struct __vpiArray*parent = obj->array; - if (code == vpiFile) { // Not implemented for now! return simple_set_rbuf_str(file_names[0]); } char sidx [64]; - snprintf(sidx, 63, "%u", obj->word_sel + parent->first_addr.get_value()); - return generic_get_str(code, parent->scope, parent->name, sidx); + snprintf(sidx, 63, "%u", word_sel + array->first_addr.get_value()); + return generic_get_str(code, array->get_scope(), array->name, sidx); } -static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp) +void __vpiArrayVthrAPV::vpi_get_value(p_vpi_value vp) { - struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref); - assert(obj); - struct __vpiArray*parent = obj->array; + assert(array); - assert(parent); - - unsigned index = obj->word_sel; - if (vpi_array_is_real(parent)) { - double tmp = array_get_word_r(parent, index); + unsigned index = word_sel; + if (vpi_array_is_real(array)) { + double tmp = array->get_word_r(index); vpip_real_get_value(tmp, vp); } else { - vvp_vector4_t tmp = array_get_word(parent, index); - tmp = tmp.subvalue(obj->part_bit, obj->part_wid); - vpip_vec4_get_value(tmp, obj->part_wid, parent->signed_flag, vp); + vvp_vector4_t tmp = array->get_word(index); + tmp = tmp.subvalue(part_bit, part_wid); + vpip_vec4_get_value(tmp, part_wid, array->signed_flag, vp); } } -void array_set_word(vvp_array_t arr, - unsigned address, - unsigned part_off, - vvp_vector4_t val) +void __vpiArray::set_word(unsigned address, unsigned part_off, vvp_vector4_t val) { - if (address >= arr->array_count) + if (address >= get_size()) return; - if (arr->vals4) { - assert(arr->nets == 0); - if (part_off != 0 || val.size() != arr->vals_width) { - vvp_vector4_t tmp = arr->vals4->get_word(address); + if (vals4) { + assert(nets == 0); + if (part_off != 0 || val.size() != vals_width) { + vvp_vector4_t tmp = vals4->get_word(address); if ((part_off + val.size()) > tmp.size()) { cerr << "part_off=" << part_off << " val.size()=" << val.size() - << " arr->vals[address].size()=" << tmp.size() - << " arr->vals_width=" << arr->vals_width << endl; + << " vals[address].size()=" << tmp.size() + << " vals_width=" << vals_width << endl; assert(0); } tmp.set_vec(part_off, val); - arr->vals4->set_word(address, tmp); + vals4->set_word(address, tmp); } else { - arr->vals4->set_word(address, val); + vals4->set_word(address, val); } - array_word_change(arr, address); + word_change(address); return; } - if (arr->vals) { - assert(arr->nets == 0); + if (vals) { + assert(nets == 0); // FIXME: For now, assume no part select of word? assert(part_off==0); - assert(val.size() == arr->vals_width); - arr->vals->set_word(address, val); - array_word_change(arr, address); + assert(val.size() == vals_width); + vals->set_word(address, val); + word_change(address); return; } - assert(arr->nets != 0); + assert(nets != 0); // Select the word of the array that we affect. - vpiHandle word = arr->nets[address]; + vpiHandle word = nets[address]; struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); assert(vsig); vsig->node->send_vec4_pv(val, part_off, val.size(), vpip_size(vsig), 0); - array_word_change(arr, address); + word_change(address); } -void array_set_word(vvp_array_t arr, unsigned address, double val) +void __vpiArray::set_word(unsigned address, double val) { - assert(arr->vals != 0); - assert(arr->nets == 0); + assert(vals != 0); + assert(nets == 0); - if (address >= arr->vals->get_size()) + if (address >= vals->get_size()) return; - arr->vals->set_word(address, val); - array_word_change(arr, address); + vals->set_word(address, val); + word_change(address); } -void array_set_word(vvp_array_t arr, unsigned address, const string&val) +void __vpiArray::set_word(unsigned address, const string&val) { - assert(arr->vals != 0); - assert(arr->nets == 0); + assert(vals != 0); + assert(nets == 0); - if (address >= arr->vals->get_size()) + if (address >= vals->get_size()) return; - arr->vals->set_word(address, val); - array_word_change(arr, address); + vals->set_word(address, val); + word_change(address); } -void array_set_word(vvp_array_t arr, unsigned address, const vvp_object_t&val) +void __vpiArray::set_word(unsigned address, const vvp_object_t&val) { - assert(arr->vals != 0); - assert(arr->nets == 0); + assert(vals != 0); + assert(nets == 0); - if (address >= arr->vals->get_size()) + if (address >= vals->get_size()) return; - arr->vals->set_word(address, val); - array_word_change(arr, address); + vals->set_word(address, val); + word_change(address); } -vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) +vvp_vector4_t __vpiArray::get_word(unsigned address) { - if (arr->vals4) { - assert(arr->nets == 0); - assert(arr->vals == 0); - return arr->vals4->get_word(address); + if (vals4) { + assert(nets == 0); + assert(vals == 0); + return vals4->get_word(address); } - if (arr->vals) { - assert(arr->nets == 0); - assert(arr->vals4== 0); - if (address >= arr->vals->get_size()) - return vvp_vector4_t(arr->vals_width, BIT4_X); + if (vals) { + assert(nets == 0); + assert(vals4== 0); + if (address >= vals->get_size()) + return vvp_vector4_t(vals_width, BIT4_X); vvp_vector4_t val; - arr->vals->get_word(address, val); + vals->get_word(address, val); return val; } - assert(arr->vals4 == 0); - assert(arr->vals == 0); - assert(arr->nets != 0); + assert(vals4 == 0); + assert(vals == 0); + assert(nets != 0); - if (address >= arr->array_count) { + if (address >= get_size()) { // Reading outside the array. Return X's but get the // width by looking at a word that we know is present. - assert(arr->array_count > 0); - vpiHandle word = arr->nets[0]; + assert(get_size() > 0); + vpiHandle word = nets[0]; assert(word); struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); assert(vsig); @@ -1103,7 +702,7 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) return vvp_vector4_t(sig->value_size(), BIT4_X); } - vpiHandle word = arr->nets[address]; + vpiHandle word = nets[address]; struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); assert(vsig); vvp_signal_value*sig = dynamic_cast (vsig->node->fil); @@ -1114,23 +713,23 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) return val; } -double array_get_word_r(vvp_array_t arr, unsigned address) +double __vpiArray::get_word_r(unsigned address) { - if (arr->vals) { - assert(arr->vals4 == 0); - assert(arr->nets == 0); + if (vals) { + assert(vals4 == 0); + assert(nets == 0); // In this context, address out of bounds returns 0.0 // instead of an error. - if (address >= arr->vals->get_size()) + if (address >= vals->get_size()) return 0.0; double val; - arr->vals->get_word(address, val); + vals->get_word(address, val); return val; } - assert(arr->nets); - vpiHandle word = arr->nets[address]; + assert(nets); + vpiHandle word = nets[address]; struct __vpiRealVar*vsig = dynamic_cast<__vpiRealVar*>(word); assert(vsig); vvp_signal_value*sig = dynamic_cast (vsig->net->fil); @@ -1138,53 +737,52 @@ double array_get_word_r(vvp_array_t arr, unsigned address) double val = sig->real_value(); return val; - } -void array_get_word_obj(vvp_array_t arr, unsigned address, vvp_object_t&val) +void __vpiArray::get_word_obj(unsigned address, vvp_object_t&val) { - if (arr->vals) { - assert(arr->vals4 == 0); - assert(arr->nets == 0); + if (vals) { + assert(vals4 == 0); + assert(nets == 0); // In this context, address out of bounds returns 0.0 // instead of an error. - if (address >= arr->vals->get_size()) { + if (address >= vals->get_size()) { val = vvp_object_t(); return; } - arr->vals->get_word(address, val); + vals->get_word(address, val); return; } - assert(arr->nets); + assert(nets); // Arrays of string nets not implemented! assert(0); return; } -string array_get_word_str(vvp_array_t arr, unsigned address) +string __vpiArray::get_word_str(unsigned address) { - if (arr->vals) { - assert(arr->vals4 == 0); - assert(arr->nets == 0); + if (vals) { + assert(vals4 == 0); + assert(nets == 0); // In this context, address out of bounds returns 0.0 // instead of an error. - if (address >= arr->vals->get_size()) + if (address >= vals->get_size()) return ""; string val; - arr->vals->get_word(address, val); + vals->get_word(address, val); return val; } - assert(arr->nets); + assert(nets); // Arrays of string nets not implemented! assert(0); return ""; } -static vpiHandle vpip_make_array(char*label, const char*name, +vpiHandle vpip_make_array(char*label, const char*name, int first_addr, int last_addr, bool signed_flag) { @@ -1242,33 +840,32 @@ static vpiHandle vpip_make_array(char*label, const char*name, return obj; } -void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word, - int msb, int lsb) +void __vpiArray::alias_word(unsigned long addr, vpiHandle word, int msb_, int lsb_) { - assert(array->msb.get_value() == msb); - assert(array->lsb.get_value() == lsb); - assert(addr < array->array_count); - assert(array->nets); - array->nets[addr] = word; + assert(msb.get_value() == msb_); + assert(lsb.get_value() == lsb_); + assert(addr < get_size()); + assert(nets); + nets[addr] = word; } -void array_attach_word(vvp_array_t array, unsigned addr, vpiHandle word) +void __vpiArray::attach_word(unsigned addr, vpiHandle word) { - assert(addr < array->array_count); - assert(array->nets); - array->nets[addr] = word; + assert(addr < get_size()); + assert(nets); + nets[addr] = word; if (struct __vpiSignal*sig = dynamic_cast<__vpiSignal*>(word)) { vvp_net_t*net = sig->node; assert(net); vvp_vpi_callback*fun = dynamic_cast(net->fil); assert(fun); - fun->attach_as_word(array, addr); + fun->attach_as_word(this, addr); sig->is_netarray = 1; - sig->within.parent = array; - sig->id.index = new __vpiDecConst(addr + array->first_addr.get_value()); + sig->within.parent = this; + sig->id.index = new __vpiDecConst(addr + first_addr.get_value()); // Now we know the data type, update the array signed_flag. - array->signed_flag = sig->signed_flag; + signed_flag = sig->signed_flag; return; } @@ -1277,12 +874,12 @@ void array_attach_word(vvp_array_t array, unsigned addr, vpiHandle word) assert(net); vvp_vpi_callback*fun = dynamic_cast(net->fil); assert(fun); - fun->attach_as_word(array, addr); + fun->attach_as_word(this, addr); sig->is_netarray = 1; - sig->within.parent = array; - sig->id.index = new __vpiDecConst(addr + array->first_addr.get_value()); + sig->within.parent = this; + sig->id.index = new __vpiDecConst(addr + first_addr.get_value()); // Now we know the data type, update the array signed_flag. - array->signed_flag = true; + signed_flag = true; return; } } @@ -1299,16 +896,16 @@ void compile_var_array(char*label, char*name, int last, int first, arr->vals_width = labs(msb-lsb) + 1; if (vpip_peek_current_scope()->is_automatic) { arr->vals4 = new vvp_vector4array_aa(arr->vals_width, - arr->array_count); + arr->get_size()); } else { arr->vals4 = new vvp_vector4array_sa(arr->vals_width, - arr->array_count); + arr->get_size()); } arr->msb.set_value(msb); arr->lsb.set_value(lsb); count_var_arrays += 1; - count_var_array_words += arr->array_count; + count_var_array_words += arr->get_size(); free(label); delete[] name; @@ -1328,27 +925,27 @@ void compile_var2_array(char*label, char*name, int last, int first, assert(! arr->nets); if (lsb == 0 && msb == 7 && signed_flag) { - arr->vals = new vvp_darray_atom(arr->array_count); + arr->vals = new vvp_darray_atom(arr->get_size()); } else if (lsb == 0 && msb == 7 && !signed_flag) { - arr->vals = new vvp_darray_atom(arr->array_count); + arr->vals = new vvp_darray_atom(arr->get_size()); } else if (lsb == 0 && msb == 15 && signed_flag) { - arr->vals = new vvp_darray_atom(arr->array_count); + arr->vals = new vvp_darray_atom(arr->get_size()); } else if (lsb == 0 && msb == 15 && !signed_flag) { - arr->vals = new vvp_darray_atom(arr->array_count); + arr->vals = new vvp_darray_atom(arr->get_size()); } else if (lsb == 0 && msb == 31 && signed_flag) { - arr->vals = new vvp_darray_atom(arr->array_count); + arr->vals = new vvp_darray_atom(arr->get_size()); } else if (lsb == 0 && msb == 31 && !signed_flag) { - arr->vals = new vvp_darray_atom(arr->array_count); + arr->vals = new vvp_darray_atom(arr->get_size()); } else if (lsb == 0 && msb == 63 && signed_flag) { - arr->vals = new vvp_darray_atom(arr->array_count); + arr->vals = new vvp_darray_atom(arr->get_size()); } else if (lsb == 0 && msb == 63 && !signed_flag) { - arr->vals = new vvp_darray_atom(arr->array_count); + arr->vals = new vvp_darray_atom(arr->get_size()); } else { // For now, only support the atom sizes. assert(0); } count_var_arrays += 1; - count_var_array_words += arr->array_count; + count_var_array_words += arr->get_size(); free(label); delete[] name; @@ -1361,11 +958,11 @@ void compile_real_array(char*label, char*name, int last, int first) struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); /* Make the words. */ - arr->vals = new vvp_darray_real(arr->array_count); + arr->vals = new vvp_darray_real(arr->get_size()); arr->vals_width = 1; count_real_arrays += 1; - count_real_array_words += arr->array_count; + count_real_array_words += arr->get_size(); free(label); delete[] name; @@ -1378,11 +975,11 @@ void compile_string_array(char*label, char*name, int last, int first) struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); /* Make the words. */ - arr->vals = new vvp_darray_string(arr->array_count); + arr->vals = new vvp_darray_string(arr->get_size()); arr->vals_width = 1; count_real_arrays += 1; - count_real_array_words += arr->array_count; + count_real_array_words += arr->get_size(); free(label); delete[] name; @@ -1395,11 +992,11 @@ void compile_object_array(char*label, char*name, int last, int first) struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); /* Make the words. */ - arr->vals = new vvp_darray_object(arr->array_count); + arr->vals = new vvp_darray_object(arr->get_size()); arr->vals_width = 1; count_real_arrays += 1; - count_real_array_words += arr->array_count; + count_real_array_words += arr->get_size(); free(label); delete[] name; @@ -1413,10 +1010,10 @@ void compile_net_array(char*label, char*name, int last, int first) vpiHandle obj = vpip_make_array(label, name, first, last, false); struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); - arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle)); + arr->nets = (vpiHandle*)calloc(arr->get_size(), sizeof(vpiHandle)); count_net_arrays += 1; - count_net_array_words += arr->array_count; + count_net_array_words += arr->get_size(); free(label); delete[] name; @@ -1437,7 +1034,7 @@ class vvp_fun_arrayport : public vvp_net_fun_t { unsigned long addr_; friend void array_attach_port(vvp_array_t, vvp_fun_arrayport*); - friend void array_word_change(vvp_array_t, unsigned long); + friend void __vpiArray::word_change(unsigned long); vvp_fun_arrayport*next_; }; @@ -1496,11 +1093,11 @@ void vvp_fun_arrayport_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit case 0: // Address input addr_valid_flag = vector4_to_value(bit, addr_); if (! addr_valid_flag) - addr_ = arr_->array_count; + addr_ = arr_->get_size(); if (vpi_array_is_real(arr_)) - port.ptr()->send_real(array_get_word_r(arr_, addr_), 0); + port.ptr()->send_real(arr_->get_word_r(addr_), 0); else - port.ptr()->send_vec4(array_get_word(arr_,addr_), 0); + port.ptr()->send_vec4(arr_->get_word(addr_), 0); break; @@ -1515,9 +1112,9 @@ void vvp_fun_arrayport_sa::check_word_change(unsigned long addr) if (addr != addr_) return; if (vpi_array_is_real(arr_)) { - net_->send_real(array_get_word_r(arr_, addr_), 0); + net_->send_real(arr_->get_word_r(addr_), 0); } else { - net_->send_vec4(array_get_word(arr_, addr_), 0); + net_->send_vec4(arr_->get_word(addr_), 0); } } @@ -1602,12 +1199,12 @@ void vvp_fun_arrayport_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit case 0: // Address input addr_valid_flag = vector4_to_value(bit, *addr); - if (! addr_valid_flag) *addr = arr_->array_count; + if (! addr_valid_flag) *addr = arr_->get_size(); if (vpi_array_is_real(arr_)) { - port.ptr()->send_real(array_get_word_r(arr_, *addr), + port.ptr()->send_real(arr_->get_word_r(*addr), context); } else { - port.ptr()->send_vec4(array_get_word(arr_, *addr), + port.ptr()->send_vec4(arr_->get_word(*addr), context); } break; @@ -1635,15 +1232,15 @@ void vvp_fun_arrayport_aa::check_word_change_(unsigned long addr, return; if (vpi_array_is_real(arr_)) { - net_->send_real(array_get_word_r(arr_, addr), context); + net_->send_real(arr_->get_word_r(addr), context); } else { - net_->send_vec4(array_get_word(arr_, addr), context); + net_->send_vec4(arr_->get_word(addr), context); } } void vvp_fun_arrayport_aa::check_word_change(unsigned long addr) { - if (arr_->scope->is_automatic) { + if (arr_->get_scope()->is_automatic) { assert(vthread_get_wt_context()); check_word_change_(addr, vthread_get_wt_context()); } else { @@ -1660,7 +1257,7 @@ static void array_attach_port(vvp_array_t array, vvp_fun_arrayport*fun) assert(fun->next_ == 0); fun->next_ = array->ports_; array->ports_ = fun; - if (!array->scope->is_automatic) { + if (!array->get_scope()->is_automatic) { /* propagate initial values for variable arrays */ if (array->vals4) { vvp_vector4_t tmp(array->vals_width, BIT4_X); @@ -1682,13 +1279,13 @@ class array_word_value_callback : public value_callback { long word_addr; }; -void array_word_change(vvp_array_t array, unsigned long addr) +void __vpiArray::word_change(unsigned long addr) { - for (vvp_fun_arrayport*cur = array->ports_; cur; cur = cur->next_) + for (vvp_fun_arrayport*cur = ports_; cur; cur = cur->next_) cur->check_word_change(addr); // Run callbacks attached to the array itself. - struct __vpiCallback *next = array->vpi_callbacks; + struct __vpiCallback *next = vpi_callbacks; struct __vpiCallback *prev = 0; while (next) { @@ -1704,21 +1301,21 @@ void array_word_change(vvp_array_t array, unsigned long addr) // For whole array callbacks we need to set the index. if (cur->word_addr == -1) { cur->cb_data.index = (PLI_INT32) ((int)addr + - array->first_addr.get_value()); + first_addr.get_value()); } if (cur->cb_data.cb_rtn != 0) { if (cur->test_value_callback_ready()) { if (cur->cb_data.value) { - if (vpi_array_is_real(array)) { + if (vpi_array_is_real(this)) { double val = 0.0; - if (addr < array->vals->get_size()) - array->vals->get_word(addr, val); + if (addr < vals->get_size()) + vals->get_word(addr, val); vpip_real_get_value(val, cur->cb_data.value); } else { - vpip_vec4_get_value(array->vals4->get_word(addr), - array->vals_width, - array->signed_flag, + vpip_vec4_get_value(vals4->get_word(addr), + vals_width, + signed_flag, cur->cb_data.value); } } @@ -1730,7 +1327,7 @@ void array_word_change(vvp_array_t array, unsigned long addr) } else if (prev == 0) { - array->vpi_callbacks = next; + vpi_callbacks = next; cur->next = 0; delete cur; @@ -1868,7 +1465,8 @@ value_callback*vpip_array_word_change(p_cb_data data) struct __vpiArray*parent = 0; array_word_value_callback*cbh = 0; if (struct __vpiArrayWord*word = array_var_word_from_handle(data->obj)) { - unsigned addr = decode_array_word_pointer(word, parent); + parent = (__vpiArray*) word->get_parent(); + unsigned addr = word->get_index(); cbh = new array_word_value_callback(data); cbh->word_addr = addr; @@ -2101,7 +1699,7 @@ void memory_delete(vpiHandle item) delete arr->vals; if (arr->nets) { - for (unsigned idx = 0; idx < arr->array_count; idx += 1) { + for (unsigned idx = 0; idx < arr->get_size(); idx += 1) { if (struct __vpiSignal*sig = dynamic_cast<__vpiSignal*>(arr->nets[idx])) { // Delete the individual words? diff --git a/vvp/array.h b/vvp/array.h index d1766ed15..7b62f7cc0 100644 --- a/vvp/array.h +++ b/vvp/array.h @@ -30,31 +30,8 @@ class value_callback; * table of all the arrays in the design. */ extern vvp_array_t array_find(const char*label); -extern unsigned get_array_word_size(vvp_array_t array); -extern vpiHandle array_index_iterate(int code, vpiHandle ref); - -extern void array_word_change(vvp_array_t array, unsigned long addr); - -extern void array_attach_word(vvp_array_t array, unsigned addr, vpiHandle word); -extern void array_alias_word(vvp_array_t array, unsigned long addr, - vpiHandle word, int msb, int lsb); - -extern void array_set_word(vvp_array_t arr, unsigned idx, - unsigned off, vvp_vector4_t val); -extern void array_set_word(vvp_array_t arr, unsigned idx, - double val); -extern void array_set_word(vvp_array_t arr, unsigned idx, - const std::string&val); -extern void array_set_word(vvp_array_t arr, unsigned idx, - const vvp_object_t&val); - -extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned address); -extern double array_get_word_r(vvp_array_t array, unsigned address); -extern void array_get_word_obj(vvp_array_t array, unsigned address, vvp_object_t&val); -extern std::string array_get_word_str(vvp_array_t array, unsigned address); /* VPI hooks */ - extern value_callback* vpip_array_word_change(p_cb_data data); extern value_callback* vpip_array_change(p_cb_data data); diff --git a/vvp/array_common.cc b/vvp/array_common.cc new file mode 100644 index 000000000..59d928df9 --- /dev/null +++ b/vvp/array_common.cc @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2014 CERN + * @author Maciej Suminski + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "array_common.h" + +vpiHandle __vpiArrayBase::vpi_array_base_iterate(int code) +{ + switch (code) { + case vpiReg: + case vpiMemoryWord: { + struct __vpiArrayIterator*res; + res = new __vpiArrayIterator; + res->array = this; + res->next = 0; + return res; + } + } + + return 0; +} + +void __vpiArrayBase::make_vals_words() +{ + assert(vals_words == 0); + vals_words = new struct __vpiArrayWord[get_size() + 1]; + + // Make word[-1] point to the parent. + vals_words->parent = this; + // Now point to word-0 + vals_words += 1; + + struct __vpiArrayWord*words = vals_words; + for (unsigned idx = 0 ; idx < get_size() ; idx += 1) { + words[idx].word0 = words; + } +} + +vpiHandle __vpiArrayIterator::vpi_index(int) +{ + if (next >= array->get_size()) { + vpi_free_object(this); + return 0; + } + + unsigned use_index = next; + next += 1; + + return array->get_iter_index(this, use_index); +} + +static int array_iterator_free_object(vpiHandle ref) +{ + struct __vpiArrayIterator*obj = dynamic_cast<__vpiArrayIterator*>(ref); + delete obj; + return 1; +} + +__vpiHandle::free_object_fun_t __vpiArrayIterator::free_object_fun(void) +{ return &array_iterator_free_object; } + +vpiHandle __vpiArrayIndex::vpi_iterate(int code) +{ + // TODO originally, __vpiArrayIndex is casted to __vpiDecConst and assigned + // to res->index - seems like a bug to me + + if (code == vpiIndex) { + struct __vpiArrayIndex*res; + res = new __vpiArrayIndex; + res->index = index; // see the comment above + res->done = 0; + return res; + } + return 0; +} + +vpiHandle __vpiArrayIndex::vpi_index(int) +{ + if (done == 0) { + done = 1; + return index; + } + + vpi_free_object(this); + return 0; +} + +static int array_index_free_object(vpiHandle ref) +{ + struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref); + delete obj; + return 1; +} + +__vpiHandle::free_object_fun_t __vpiArrayIndex::free_object_fun(void) +{ return &array_index_free_object; } + +char* __vpiArrayWord::as_word_t::vpi_get_str(int code) +{ + struct __vpiArrayWord*obj = array_var_word_from_handle(this); + assert(obj); + struct __vpiArrayBase*parent = obj->get_parent(); + return parent->get_word_str(obj, code); +} + +void __vpiArrayWord::as_word_t::vpi_get_value(p_vpi_value vp) +{ + struct __vpiArrayWord*obj = array_var_word_from_handle(this); + assert(obj); + struct __vpiArrayBase*parent = obj->get_parent(); + return parent->get_word_value(obj, vp); +} + +vpiHandle __vpiArrayWord::as_word_t::vpi_put_value(p_vpi_value vp, int flags) +{ + struct __vpiArrayWord*obj = array_var_word_from_handle(this); + assert(obj); + struct __vpiArrayBase*parent = obj->get_parent(); + parent->put_word_value(obj, vp, flags); + return this; +} + +vpiHandle __vpiArrayWord::as_word_t::vpi_handle(int code) +{ + struct __vpiArrayWord*obj = array_var_word_from_handle(this); + assert(obj); + struct __vpiArrayBase*parent = obj->get_parent(); + + switch (code) { + + case vpiIndex: + return &(obj->as_index); + + case vpiLeftRange: + return parent->get_left_range(); + + case vpiRightRange: + return parent->get_right_range(); + + case vpiParent: + return dynamic_cast(parent); + + case vpiScope: + return parent->get_scope(); + + case vpiModule: + return vpip_module(parent->get_scope()); + } + + return 0; +} + +void __vpiArrayWord::as_index_t::vpi_get_value(p_vpi_value vp) +{ + struct __vpiArrayWord*obj = array_var_index_from_handle(this); + assert(obj); + unsigned index = obj->get_index(); + + assert(vp->format == vpiIntVal); + vp->value.integer = index; +} + +struct __vpiArrayWord*array_var_word_from_handle(vpiHandle ref) +{ + if (ref == 0) + return 0; + __vpiArrayWord::as_word_t*ptr = dynamic_cast<__vpiArrayWord::as_word_t*> (ref); + if (ptr == 0) + return 0; + + return (struct __vpiArrayWord*) ref; +} + +struct __vpiArrayWord* array_var_index_from_handle(vpiHandle ref) +{ + if (ref == 0) + return 0; + __vpiArrayWord::as_index_t*ptr = dynamic_cast<__vpiArrayWord::as_index_t*> (ref); + if (ptr == 0) + return 0; + + assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_index_t)); + assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_word_t)); + return (struct __vpiArrayWord*) (ref-1); +} + diff --git a/vvp/array_common.h b/vvp/array_common.h new file mode 100644 index 000000000..8b4d8c334 --- /dev/null +++ b/vvp/array_common.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2014 CERN + * @author Maciej Suminski + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ARRAY_COMMON_H +#define ARRAY_COMMON_H + +#include "vpi_priv.h" + +struct __vpiArrayIterator : public __vpiHandle { + int get_type_code(void) const + { return vpiIterator; } + + vpiHandle vpi_index(int idx); + free_object_fun_t free_object_fun(void); + + struct __vpiArrayBase*array; + unsigned next; +}; + +struct __vpiArrayIndex : public __vpiHandle { + int get_type_code(void) const + { return vpiIterator; } + + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); + free_object_fun_t free_object_fun(void); + + __vpiDecConst *index; + unsigned done; +}; + +/* + * The vpiArrayWord is magic. It is used as the handle to return when + * vpi code tries to index or scan an array of variable words. The + * array word handle contains no actual data. It is just a hook for + * the vpi methods and to point to the parent. + * + * How the point to the parent works is tricky. The vpiArrayWord + * objects for an array are themselves allocated as an array. All the + * ArrayWord objects in the array have a word0 that points to the base + * of the array. Thus, the position into the array (and the index into + * the memory) is calculated by subtracting word0 from the ArrayWord + * pointer. + * + * To then get to the parent, use word0[-1].parent. + * + * The vpiArrayWord is also used as a handle for the index (vpiIndex) + * for the word. To make that work, return the pointer to the as_index + * member instead of the as_word member. The result is a different set + * of vpi functions is bound to the same structure. All the details + * for the word also apply when treating this as an index. + */ +struct __vpiArrayWord { + struct as_word_t : public __vpiHandle { + int get_type_code(void) const { return vpiMemoryWord; } + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value vp); + vpiHandle vpi_put_value(p_vpi_value vp, int flags); + vpiHandle vpi_handle(int code); + } as_word; + + struct as_index_t : public __vpiHandle { + int get_type_code(void) const { return vpiIndex; } + void vpi_get_value(p_vpi_value val); + } as_index; + + union { + struct __vpiArrayBase*parent; + struct __vpiArrayWord*word0; + }; + + inline unsigned get_index() const { return this - word0; } + inline struct __vpiArrayBase*get_parent() const { return (word0 - 1)->parent; } +}; + +struct __vpiArrayWord*array_var_word_from_handle(vpiHandle ref); +struct __vpiArrayWord*array_var_index_from_handle(vpiHandle ref); + +#endif /* ARRAY_COMMON_H */ diff --git a/vvp/event.cc b/vvp/event.cc index 47b3d143a..d95ce975c 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -137,7 +137,7 @@ evctl_array::evctl_array(vvp_array_t memory, unsigned index, void evctl_array::run_run() { - array_set_word(mem_, idx_, off_, value_); + mem_->set_word(idx_, off_, value_); } void schedule_evctl(vvp_array_t memory, unsigned index, @@ -163,7 +163,7 @@ evctl_array_r::evctl_array_r(vvp_array_t memory, unsigned index, void evctl_array_r::run_run() { - array_set_word(mem_, idx_, value_); + mem_->set_word(idx_, value_); } void schedule_evctl(vvp_array_t memory, unsigned index, diff --git a/vvp/schedule.cc b/vvp/schedule.cc index 4a62bf4de..c6bb71030 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -306,7 +306,7 @@ struct assign_array_word_s : public event_s { void assign_array_word_s::run_run(void) { count_assign_events += 1; - array_set_word(mem, adr, off, val); + mem->set_word(adr, off, val); } static const size_t ARRAY_W_CHUNK_COUNT = 8192 / sizeof(struct assign_array_word_s); @@ -396,7 +396,7 @@ struct assign_array_r_word_s : public event_s { void assign_array_r_word_s::run_run(void) { count_assign_events += 1; - array_set_word(mem, adr, val); + mem->set_word(adr, val); } static const size_t ARRAY_R_W_CHUNK_COUNT = 8192 / sizeof(struct assign_array_r_word_s); static slab_t array_r_w_heap; diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index cf12f0850..2d2574564 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -688,7 +688,7 @@ void vvp_vpi_callback::clear_all_callbacks() */ void vvp_vpi_callback::run_vpi_callbacks() { - if (array_) array_word_change(array_, array_word_); + if (array_) array_->word_change(array_word_); value_callback *next = vpi_callbacks_; value_callback *prev = 0; diff --git a/vvp/vpi_darray.cc b/vvp/vpi_darray.cc index 95046ecee..2f6104f71 100644 --- a/vvp/vpi_darray.cc +++ b/vvp/vpi_darray.cc @@ -22,6 +22,7 @@ # include "vpi_priv.h" # include "vvp_net_sig.h" # include "vvp_darray.h" +# include "array_common.h" # include "schedule.h" #ifdef CHECK_WITH_VALGRIND # include "vvp_cleanup.h" @@ -39,42 +40,255 @@ __vpiDarrayVar::__vpiDarrayVar(__vpiScope*sc, const char*na, vvp_net_t*ne) { } -int __vpiDarrayVar::get_type_code(void) const -{ return vpiArrayVar; } - - -int __vpiDarrayVar::vpi_get(int code) +unsigned __vpiDarrayVar::get_size() const { vvp_fun_signal_object*fun = dynamic_cast (get_net()->fun); - assert(fun); + if(!fun) + return 0; + vvp_object_t val = fun->get_object(); vvp_darray*aval = val.peek(); + if(!aval) + return 0; + + return aval->get_size(); +} + +vpiHandle __vpiDarrayVar::get_left_range() +{ + left_range_.set_value(0); + return &left_range_; +} + +vpiHandle __vpiDarrayVar::get_right_range() +{ + right_range_.set_value(get_size() - 1); + return &right_range_; +} + +int __vpiDarrayVar::get_word_size() const +{ + vvp_vector4_t new_vec; + vvp_darray*aobj = get_vvp_darray(); + aobj->get_word(0, new_vec); + return new_vec.size(); +} + +char*__vpiDarrayVar::get_word_str(struct __vpiArrayWord*word, int code) +{ + unsigned index = word->get_index(); + + if (code == vpiFile) { // Not implemented for now! + return simple_set_rbuf_str(file_names[0]); + } + + char sidx [64]; + snprintf(sidx, 63, "%d", (int)index); + return generic_get_str(code, scope_, name_, sidx); +} + +void __vpiDarrayVar::get_word_value(struct __vpiArrayWord*word, p_vpi_value vp) +{ + unsigned index = word->get_index(); + vvp_darray*aobj = get_vvp_darray(); + + if(vp->format == vpiObjTypeVal) { + if(dynamic_cast(aobj)) + vp->format = vpiRealVal; + else if(dynamic_cast(aobj)) + vp->format = vpiStringVal; + else + vp->format = vpiVectorVal; + } + + switch(vp->format) { + case vpiBinStrVal: + case vpiOctStrVal: + case vpiDecStrVal: + case vpiHexStrVal: + case vpiScalarVal: + case vpiIntVal: + { + vvp_vector4_t v; + aobj->get_word(index, v); // width == 1? + vpip_vec4_get_value(v, 1, false, vp); // TODO sign? + } + break; + + case vpiVectorVal: // TODO vpip_vec2_ or vpip_vec4_? + { + vvp_vector4_t v; + aobj->get_word(index, v); + vpip_vec2_get_value(v, v.size(), false, vp); // TODO sign? + } + break; + + case vpiRealVal: + { + double d; + aobj->get_word(index, d); + vpip_real_get_value(d, vp); + } + break; + + case vpiStringVal: + { + string s; + aobj->get_word(index, s); + vpip_string_get_value(s, vp); + } + break; + + default: + fprintf(stderr, "vpi sorry: format is not implemented\n"); + assert(false); + } +} + +void __vpiDarrayVar::put_word_value(struct __vpiArrayWord*word, p_vpi_value vp, int) +{ + unsigned index = word->get_index(); + vvp_darray*aobj = get_vvp_darray(); + + switch(vp->format) { + case vpiScalarVal: + { + vvp_vector4_t vec(1, vp->value.scalar); + aobj->set_word(index, vec); + } + break; + + case vpiIntVal: + { + vvp_vector4_t vec; + vec.setarray(0, 8 * sizeof(vp->value.integer), (unsigned long*)(&vp->value.integer)); + aobj->set_word(index, vec); + } + break; + + case vpiVectorVal: // 2 vs 4 state logic? + { + int new_bit; + int size = get_word_size(); + PLI_INT32 a = 0, b = 0; + vvp_vector4_t new_vec(size); + p_vpi_vecval vec = vp->value.vector; + vec--; // it will be increased in the first loop iteration + + for(int i = 0; i < size; ++i) { + if(i % (8 * sizeof(vec->aval)) == 0) { + ++vec; + a = vec->aval; + b = vec->bval; + } + + // convert to vvp_bit4_t + new_bit = ((b & 1) << 2) | (a & 1); + new_vec.set_bit(i, (vvp_bit4_t) new_bit); + + a >>= 1; + b >>= 1; + } + aobj->set_word(index, new_vec); + } + break; + + case vpiRealVal: + aobj->set_word(index, vp->value.real); + break; + + case vpiStringVal: + aobj->set_word(index, std::string(vp->value.str)); + break; + + default: + fprintf(stderr, "vpi sorry: format is not implemented"); + assert(false); + } +} + +vpiHandle __vpiDarrayVar::get_iter_index(struct __vpiArrayIterator*, int idx) +{ + if (vals_words == 0) make_vals_words(); + + return &(vals_words[idx].as_word); +} + +int __vpiDarrayVar::vpi_get(int code) +{ switch (code) { case vpiArrayType: return vpiDynamicArray; case vpiSize: - if (aval == 0) - return 0; - else - return aval->get_size(); + return get_size(); default: return 0; } } +char* __vpiDarrayVar::vpi_get_str(int code) +{ + if (code == vpiFile) { // Not implemented for now! + return simple_set_rbuf_str(file_names[0]); + } + + return generic_get_str(code, scope_, name_, NULL); +} + +vpiHandle __vpiDarrayVar::vpi_handle(int code) +{ + switch (code) { + case vpiLeftRange: + return get_left_range(); + + case vpiRightRange: + return get_right_range(); + + case vpiScope: + return scope_; + + case vpiModule: + return vpip_module(scope_); + } + + return 0; +} + +vpiHandle __vpiDarrayVar::vpi_index(int index) +{ + if (index >= (long) get_size()) + return 0; + if (index < 0) + return 0; + + if (vals_words == 0) + make_vals_words(); + + return &(vals_words[index].as_word); +} + void __vpiDarrayVar::vpi_get_value(p_vpi_value val) { val->format = vpiSuppressVal; } +vvp_darray*__vpiDarrayVar::get_vvp_darray() const +{ + vvp_fun_signal_object*fun = dynamic_cast (get_net()->fun); + assert(fun); + vvp_object_t obj = fun->get_object(); + + return obj.peek(); +} + vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net) { struct __vpiScope*scope = vpip_peek_current_scope(); const char*use_name = name ? vpip_name_string(name) : 0; - class __vpiDarrayVar*obj = new __vpiDarrayVar(scope, use_name, net); + __vpiDarrayVar*obj = new __vpiDarrayVar(scope, use_name, net); return obj; } diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 07ce78a71..f83e09b30 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -35,6 +35,10 @@ class class_type; +class vvp_darray; +class vvp_fun_arrayport; + +typedef struct __vpiArray* vvp_array_t; /* * This header file contains the internal definitions that the vvp @@ -514,9 +518,11 @@ class __vpiBaseVar : public __vpiHandle { inline vvp_net_t* get_net() const { return net_; } - private: + protected: struct __vpiScope* scope_; const char*name_; + + private: vvp_net_t*net_; }; @@ -532,14 +538,145 @@ class __vpiStringVar : public __vpiBaseVar { extern vpiHandle vpip_make_string_var(const char*name, vvp_net_t*net); -class __vpiDarrayVar : public __vpiBaseVar { +struct __vpiArrayBase { + __vpiArrayBase() : vals_words(NULL) {} + virtual unsigned get_size(void) const = 0; + virtual vpiHandle get_left_range() = 0; + virtual vpiHandle get_right_range() = 0; + virtual struct __vpiScope*get_scope() const = 0; + + virtual int get_word_size() const = 0; + virtual char*get_word_str(struct __vpiArrayWord*word, int code) = 0; + virtual void get_word_value(struct __vpiArrayWord*word, p_vpi_value vp) = 0; + virtual void put_word_value(struct __vpiArrayWord*word, p_vpi_value vp, + int flags) = 0; + virtual vpiHandle get_iter_index(struct __vpiArrayIterator*iter, int idx) = 0; + + // vpi_iterate is already defined by vpiHandle, so to avoid problems with + // classes inheriting from vpiHandle and vpiArrayBase just share the common + // code in the following function + vpiHandle vpi_array_base_iterate(int code); + + virtual void make_vals_words(); + + struct __vpiArrayWord*vals_words; +}; + +/* +* The vpiArray object holds an array of vpi objects that themselves +* represent the words of the array. The vpi_array_t is a pointer to +* a struct __vpiArray. +* +* The details of the implementation depends on what this is an array +* of. The easiest case is if this is an array of nets. +* +* - Array of Nets: +* If this represents an array of nets, then the nets member points to +* an array of vpiHandle objects. Each vpiHandle is a word. This is +* done because typically each word of a net array is simultaneously +* driven and accessed by other means, so there is no advantage to +* compacting the array in any other way. +* +* - Array of vector4 words. +* In this case, the nets pointer is nil, and the vals4 member points +* to a vvl_vector4array_t object that is a compact representation of +* an array of vvp_vector4_t vectors. +* +* - Array of real variables +* The vals member points to a dynamic array objects that has an +* array of double variables. This is very much like the way the +* vector4 array works. +*/ +struct __vpiArray : public __vpiArrayBase, public __vpiHandle { + int get_type_code(void) const { return vpiMemory; } + unsigned get_size() const { return array_count; } + vpiHandle get_left_range() { assert(nets == 0); return &msb; } + vpiHandle get_right_range() { assert(nets == 0); return &lsb; } + struct __vpiScope*get_scope() const { return scope; } + + int get_word_size() const; + char*get_word_str(struct __vpiArrayWord*word, int code); + void get_word_value(struct __vpiArrayWord*word, p_vpi_value vp); + void put_word_value(struct __vpiArrayWord*word, p_vpi_value vp, int flags); + + vpiHandle get_iter_index(struct __vpiArrayIterator*iter, int idx); + + int vpi_get(int code); + char* vpi_get_str(int code); + vpiHandle vpi_handle(int code); + inline vpiHandle vpi_iterate(int code) { return vpi_array_base_iterate(code); } + vpiHandle vpi_index(int idx); + + void set_word(unsigned idx, unsigned off, vvp_vector4_t val); + void set_word(unsigned idx, double val); + void set_word(unsigned idx, const std::string&val); + void set_word(unsigned idx, const vvp_object_t&val); + + vvp_vector4_t get_word(unsigned address); + double get_word_r(unsigned address); + void get_word_obj(unsigned address, vvp_object_t&val); + std::string get_word_str(unsigned address); + + void alias_word(unsigned long addr, vpiHandle word, int msb, int lsb); + void attach_word(unsigned addr, vpiHandle word); + void word_change(unsigned long addr); + + const char*name; /* Permanently allocated string */ + __vpiDecConst first_addr; + __vpiDecConst last_addr; + __vpiDecConst msb; + __vpiDecConst lsb; + unsigned vals_width; + // If this is a net array, nets lists the handles. + vpiHandle*nets; + // If this is a var array, then these are used instead of nets. + vvp_vector4array_t*vals4; + vvp_darray *vals; + + vvp_fun_arrayport*ports_; + struct __vpiCallback *vpi_callbacks; + bool signed_flag; + bool swap_addr; + +private: + unsigned array_count; + struct __vpiScope*scope; + +friend vpiHandle vpip_make_array(char*label, const char*name, + int first_addr, int last_addr, + bool signed_flag); +friend void compile_array_alias(char*label, char*name, char*src); +}; + +class __vpiDarrayVar : public __vpiBaseVar, public __vpiArrayBase { public: __vpiDarrayVar(__vpiScope*scope, const char*name, vvp_net_t*net); - int get_type_code(void) const; + int get_type_code() const { return vpiArrayVar; } + unsigned get_size() const; + vpiHandle get_left_range(); + vpiHandle get_right_range(); + struct __vpiScope*get_scope() const { return scope_; } + + int get_word_size() const; + char*get_word_str(struct __vpiArrayWord*word, int code); + void get_word_value(struct __vpiArrayWord*word, p_vpi_value vp); + void put_word_value(struct __vpiArrayWord*word, p_vpi_value vp, int flags); + + vpiHandle get_iter_index(struct __vpiArrayIterator*iter, int idx); + inline vpiHandle vpi_iterate(int code) { return vpi_array_base_iterate(code); } + int vpi_get(int code); + char* vpi_get_str(int code); + vpiHandle vpi_handle(int code); + vpiHandle vpi_index(int index); + void vpi_get_value(p_vpi_value val); + + protected: + vvp_darray*get_vvp_darray() const; + __vpiDecConst left_range_, right_range_; }; extern vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net); diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index a71fdd262..5cb6de055 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -654,7 +654,7 @@ static vpiHandle signal_iterate(int code, vpiHandle ref) assert(rfp); if (code == vpiIndex) { - return rfp->is_netarray? array_index_iterate(code, rfp->id.index) : 0; + return rfp->is_netarray ? rfp->id.index->vpi_iterate(code) : 0; } return 0; diff --git a/vvp/vthread.cc b/vvp/vthread.cc index db0111773..32a0d8a29 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1020,7 +1020,7 @@ bool of_ASSIGN_AV(vthread_t thr, vvp_code_t cp) if (adr < 0) return true; - long vwidth = get_array_word_size(cp->array); + long vwidth = cp->array->get_word_size(); // We fell off the MSB end. if (off >= vwidth) return true; // Trim the bits after the MSB @@ -1059,7 +1059,7 @@ bool of_ASSIGN_AVD(vthread_t thr, vvp_code_t cp) if (adr < 0) return true; - long vwidth = get_array_word_size(cp->array); + long vwidth = cp->array->get_word_size(); // We fell off the MSB end. if (off >= vwidth) return true; // Trim the bits after the MSB @@ -1091,7 +1091,7 @@ bool of_ASSIGN_AVE(vthread_t thr, vvp_code_t cp) if (adr < 0) return true; - long vwidth = get_array_word_size(cp->array); + long vwidth = cp->array->get_word_size(); // We fell off the MSB end. if (off >= vwidth) return true; // Trim the bits after the MSB @@ -3262,7 +3262,7 @@ bool of_LOAD_AR(vthread_t thr, vvp_code_t cp) if (thr_get_bit(thr, 4) == BIT4_1) { word = 0.0; } else { - word = array_get_word_r(cp->array, adr); + word = cp->array->get_word_r(adr); } thr->push_real(word); @@ -3294,7 +3294,7 @@ bool of_LOAD_AV(vthread_t thr, vvp_code_t cp) return true; } - vvp_vector4_t word = array_get_word(cp->array, adr); + vvp_vector4_t word = cp->array->get_word(adr); if (word.size() > wid) word.resize(wid); @@ -3451,7 +3451,7 @@ bool of_LOAD_AVP0(vthread_t thr, vvp_code_t cp) /* We need a vector this wide to make the math work correctly. * Copy the base bits into the vector, but keep the width. */ vvp_vector4_t sig_value(wid, BIT4_0); - sig_value.copy_bits(array_get_word(cp->array, adr)); + sig_value.copy_bits(cp->array->get_word(adr)); load_vp0_common(thr, cp, sig_value); return true; @@ -3471,7 +3471,7 @@ bool of_LOAD_AVP0_S(vthread_t thr, vvp_code_t cp) return true; } - vvp_vector4_t tmp (array_get_word(cp->array, adr)); + vvp_vector4_t tmp (cp->array->get_word(adr)); /* We need a vector this wide to make the math work correctly. * Copy the base bits into the vector, but keep the width. */ @@ -3505,7 +3505,7 @@ bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t cp) long use_index = thr->words[index].w_int; - vvp_vector4_t word = array_get_word(cp->array, adr); + vvp_vector4_t word = cp->array->get_word(adr); if ((use_index >= (long)word.size()) || (use_index < 0)) { thr_put_bit(thr, bit, BIT4_X); @@ -3543,7 +3543,7 @@ bool of_LOAD_OBJA(vthread_t thr, vvp_code_t cp) if (thr_get_bit(thr, 4) == BIT4_1) { ; // Return nil } else { - array_get_word_obj(cp->array, adr, word); + cp->array->get_word_obj(adr, word); } thr->push_object(word); @@ -3591,7 +3591,7 @@ bool of_LOAD_STRA(vthread_t thr, vvp_code_t cp) if (thr_get_bit(thr, 4) == BIT4_1) { word = ""; } else { - word = array_get_word_str(cp->array, adr); + word = cp->array->get_word_str(adr); } thr->push_str(word); @@ -5051,7 +5051,7 @@ bool of_SET_AV(vthread_t thr, vvp_code_t cp) /* Make a vector of the desired width. */ vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid); - array_set_word(cp->array, adr, off, value); + cp->array->set_word(adr, off, value); return true; } @@ -5482,7 +5482,7 @@ bool of_STORE_OBJA(vthread_t thr, vvp_code_t cp) vvp_object_t val; thr->pop_object(val); - array_set_word(cp->array, adr, val); + cp->array->set_word(adr, val); return true; } @@ -5653,7 +5653,7 @@ bool of_STORE_REALA(vthread_t thr, vvp_code_t cp) unsigned adr = thr->words[idx].w_int; double val = thr->pop_real(); - array_set_word(cp->array, adr, val); + cp->array->set_word(adr, val); return true; } @@ -5678,7 +5678,7 @@ bool of_STORE_STRA(vthread_t thr, vvp_code_t cp) unsigned adr = thr->words[idx].w_int; string val = thr->pop_str(); - array_set_word(cp->array, adr, val); + cp->array->set_word(adr, val); return true; } @@ -5861,7 +5861,7 @@ bool of_TEST_NUL_A(vthread_t thr, vvp_code_t cp) return true; } - array_get_word_obj(cp->array, adr, word); + cp->array->get_word_obj(adr, word); if (word.test_nil()) thr_put_bit(thr, 4, BIT4_1); else diff --git a/vvp/words.cc b/vvp/words.cc index a09e880d1..e7480bd05 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -59,7 +59,7 @@ static void __compile_var_real(char*label, char*name, } if (array) { assert(!name); - array_attach_word(array, array_addr, obj); + array->attach_word(array_addr, obj); } free(label); delete[] name; @@ -365,7 +365,7 @@ static void do_compile_net(vvp_net_t*node, vvp_array_t array, define_functor_symbol(my_label, node); if (array) - array_attach_word(array, array_addr, obj); + array->attach_word(array_addr, obj); else if (obj) vpip_attach_to_scope(scope,obj); @@ -495,7 +495,7 @@ static void __compile_real_net2(vvp_net_t*node, vvp_array_t array, define_functor_symbol(my_label, node); if (array) - array_attach_word(array, array_addr, obj); + array->attach_word(array_addr, obj); else if (obj) vpip_attach_to_scope(scope, obj); @@ -583,7 +583,7 @@ void compile_aliasw(char*label, char*array_label, unsigned long array_addr, vpiHandle obj = vvp_lookup_handle(argv[0].text); assert(obj); - array_alias_word(array, array_addr, obj, msb, lsb); + array->alias_word(array_addr, obj, msb, lsb); free(label); free(array_label);