From c1164dcc333c366f3ebf92784be8b84c8f8431ac Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 14 Nov 2014 18:25:49 +0100 Subject: [PATCH] vvp: Initial work on support for dynamic arrays in VPI. Added array_common.[ch] to store shared code. --- vvp/Makefile.in | 2 +- vvp/array.cc | 612 +++++++++++++------------------------------- vvp/array_common.cc | 157 ++++++++++++ vvp/array_common.h | 100 ++++++++ vvp/vpi_darray.cc | 57 ++++- vvp/vpi_priv.h | 33 ++- vvp/vpi_signal.cc | 2 +- 7 files changed, 515 insertions(+), 448 deletions(-) create mode 100644 vvp/array_common.cc create mode 100644 vvp/array_common.h 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 c664fd647..6908c7a18 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" @@ -81,18 +82,20 @@ vvp_array_t array_find(const char*label) * 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; +struct __vpiArray : public __vpiArrayBase, public __vpiHandle { + int get_type_code(void) const { return vpiMemory; } + unsigned get_size() const { return array_count; } + int get_word_size() const; + int get_left_range() const { assert(nets == 0); return msb.get_value(); } + int get_right_range() const { assert(nets == 0); return lsb.get_value(); } + struct __vpiScope*get_scope() const { return scope; } + 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; @@ -103,33 +106,20 @@ struct __vpiArray : public __vpiHandle { // 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); +private: + unsigned array_count; + struct __vpiScope*scope; - 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; +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); }; struct __vpiArrayVthrA : public __vpiHandle { @@ -225,7 +215,7 @@ unsigned get_array_word_size(vvp_array_t array) { unsigned width; - assert(array->array_count > 0); + assert(array->get_size() > 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); @@ -250,65 +240,6 @@ 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. - */ - - -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; - - 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; - - union { - struct __vpiArray*parent; - struct __vpiArrayWord*word0; - }; -}; - -static void array_make_vals_words(struct __vpiArray*parent); - -static vpiHandle array_index_scan(vpiHandle ref, int); - -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); - -static void vpi_array_var_index_get_value(vpiHandle ref, p_vpi_value vp); - 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); @@ -319,11 +250,58 @@ 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); -inline __vpiArray::__vpiArray() -{ } -int __vpiArray::get_type_code(void) const -{ return vpiMemory; } +// This function return true if the underlying array words are real. +static bool vpi_array_is_real(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; + + 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->get_size() > 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; +} + +int __vpiArray::get_word_size() const +{ + assert(nets == 0); + + if (vals4) { + assert(vals == 0); + return (int) vals4->width(); + } else { + assert(vals4 == 0); + return 1; + } + + assert(false); + return 0; +} int __vpiArray::vpi_get(int code) { @@ -332,7 +310,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 +332,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 +350,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 +357,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 +367,32 @@ 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 = get_word_parent(obj); 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(); + return parent->get_left_range(); case vpiRightRange: - return parent->lsb.get_value(); + return parent->get_right_range(); 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,13 +404,13 @@ static int vpi_array_var_word_get(int code, vpiHandle ref) } } -static char*vpi_array_var_word_get_str(int code, vpiHandle ref) +// TODO make generic version of the following methods and move them to array_common +char* __vpiArrayWord::as_word_t::vpi_get_str(int code) { - struct __vpiArrayWord*obj = array_var_word_from_handle(ref); - struct __vpiArray*parent; - + struct __vpiArrayWord*obj = array_var_word_from_handle(this); assert(obj); - unsigned index = decode_array_word_pointer(obj, parent); + struct __vpiArray*parent = (__vpiArray*) get_word_parent(obj); + unsigned index = get_word_index(obj); if (code == vpiFile) { // Not implemented for now! return simple_set_rbuf_str(file_names[0]); @@ -641,52 +418,15 @@ static char*vpi_array_var_word_get_str(int code, vpiHandle ref) char sidx [64]; snprintf(sidx, 63, "%d", (int)index + parent->first_addr.get_value()); - return generic_get_str(code, parent->scope, parent->name, sidx); + return generic_get_str(code, parent->get_scope(), parent->name, sidx); } -// This function return true if the underlying array words are real. -static bool vpi_array_is_real(vvp_array_t arr) +void __vpiArrayWord::as_word_t::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; - - 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_var_word_get_value(vpiHandle ref, p_vpi_value vp) -{ - struct __vpiArrayWord*obj = array_var_word_from_handle(ref); - struct __vpiArray*parent; - + struct __vpiArrayWord*obj = array_var_word_from_handle(this); assert(obj); - unsigned index = decode_array_word_pointer(obj, parent); + struct __vpiArray*parent = (__vpiArray*) get_word_parent(obj); + unsigned index = get_word_index(obj); // Determine the appropriate format (The Verilog PLI Handbook 5.2.10) if(vp->format == vpiObjTypeVal) { @@ -737,26 +477,23 @@ 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) +vpiHandle __vpiArrayWord::as_word_t::vpi_put_value(p_vpi_value vp, int) { - struct __vpiArrayWord*obj = array_var_word_from_handle(ref); - struct __vpiArray*parent; - + struct __vpiArrayWord*obj = array_var_word_from_handle(this); assert(obj); - unsigned index = decode_array_word_pointer(obj, parent); + struct __vpiArray*parent = (__vpiArray*) get_word_parent(obj); + unsigned index = get_word_index(obj); vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width); array_set_word(parent, index, 0, val); - return ref; + return this; } -static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref) +vpiHandle __vpiArrayWord::as_word_t::vpi_handle(int code) { - 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); + struct __vpiArray*parent = (__vpiArray*) get_word_parent(obj); switch (code) { @@ -773,54 +510,62 @@ static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref) return parent; case vpiScope: - return parent->scope; + return parent->get_scope(); case vpiModule: - return vpip_module(parent->scope); + return vpip_module(parent->get_scope()); } return 0; } -static void vpi_array_var_index_get_value(vpiHandle ref, p_vpi_value vp) +void __vpiArrayWord::as_index_t::vpi_get_value(p_vpi_value vp) { - struct __vpiArrayWord*obj = array_var_index_from_handle(ref); - struct __vpiArray*parent; - + struct __vpiArrayWord*obj = array_var_index_from_handle(this); assert(obj); - unsigned index = decode_array_word_pointer(obj, parent); + unsigned index = get_word_index(obj); 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; -} +inline __vpiArrayVthrA::__vpiArrayVthrA() +{ } -static vpiHandle array_index_scan(vpiHandle ref, int) -{ - struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref); +int __vpiArrayVthrA::get_type_code(void) const +{ return vpiMemoryWord; } - if (obj->done == 0) { - obj->done = 1; - return obj->index; - } +int __vpiArrayVthrA::vpi_get(int code) +{ return vpi_array_vthr_A_get(code, this); } - vpi_free_object(ref); - return 0; -} +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 int vpi_array_vthr_A_get(int code, vpiHandle ref) { @@ -845,7 +590,7 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref) return (int)obj->get_address() + parent->first_addr.get_value(); 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: @@ -877,7 +622,7 @@ static char*vpi_array_vthr_A_get_str(int code, vpiHandle ref) 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); + return generic_get_str(code, parent->get_scope(), parent->name, sidx); } static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value vp) @@ -911,7 +656,7 @@ static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int) unsigned index = obj->get_address(); assert(parent); - assert(index < parent->array_count); + assert(index < parent->get_size()); if (vpi_array_is_real(parent)) { double val = real_from_vpi_value(vp); @@ -946,10 +691,10 @@ static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref) return parent; case vpiScope: - return parent->scope; + return parent->get_scope(); case vpiModule: - return vpip_module(parent->scope); + return vpip_module(parent->get_scope()); } return 0; @@ -977,7 +722,7 @@ static int vpi_array_vthr_APV_get(int code, vpiHandle ref) return (int)obj->word_sel; 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: @@ -1004,7 +749,7 @@ static char*vpi_array_vthr_APV_get_str(int code, vpiHandle ref) 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); + return generic_get_str(code, parent->get_scope(), parent->name, sidx); } static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp) @@ -1031,7 +776,7 @@ void array_set_word(vvp_array_t arr, unsigned part_off, vvp_vector4_t val) { - if (address >= arr->array_count) + if (address >= arr->get_size()) return; if (arr->vals4) { @@ -1134,10 +879,10 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) assert(arr->vals == 0); assert(arr->nets != 0); - if (address >= arr->array_count) { + if (address >= arr->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); + assert(arr->get_size() > 0); vpiHandle word = arr->nets[0]; assert(word); struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); @@ -1228,7 +973,7 @@ string array_get_word_str(vvp_array_t arr, unsigned address) 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) { @@ -1291,14 +1036,14 @@ void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word, { assert(array->msb.get_value() == msb); assert(array->lsb.get_value() == lsb); - assert(addr < array->array_count); + assert(addr < array->get_size()); assert(array->nets); array->nets[addr] = word; } void array_attach_word(vvp_array_t array, unsigned addr, vpiHandle word) { - assert(addr < array->array_count); + assert(addr < array->get_size()); assert(array->nets); array->nets[addr] = word; @@ -1343,16 +1088,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; @@ -1372,27 +1117,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; @@ -1405,11 +1150,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; @@ -1422,11 +1167,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; @@ -1439,11 +1184,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; @@ -1457,10 +1202,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; @@ -1540,7 +1285,7 @@ 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); else @@ -1646,7 +1391,7 @@ 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), context); @@ -1687,7 +1432,7 @@ void vvp_fun_arrayport_aa::check_word_change_(unsigned long addr, 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 { @@ -1704,7 +1449,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); @@ -1912,7 +1657,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*) get_word_parent(word); + unsigned addr = get_word_index(word); cbh = new array_word_value_callback(data); cbh->word_addr = addr; @@ -2145,7 +1891,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_common.cc b/vvp/array_common.cc new file mode 100644 index 000000000..cce82ecc5 --- /dev/null +++ b/vvp/array_common.cc @@ -0,0 +1,157 @@ +/* + * 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_iterate(int code) +{ + switch (code) { + case vpiMemoryWord: { + struct __vpiArrayIterator*res; + res = new __vpiArrayIterator; + res->array = this; + res->next = 0; + return res; + } + } + + return 0; +} + +// TODO template +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; + +// TODO ArrayBase::iterate(int)? + //if (array->nets) return array->nets[use_index]; + + //assert(array->vals4 || array->vals); + + if (array->vals_words == 0) array->make_vals_words(); + + 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; } + +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; // TODO ? see above comment + 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; } + +// TODO orson it should be a method +unsigned get_word_index(struct __vpiArrayWord*word) +{ + return word - word->word0; +} + +// TODO orson it should be a method +struct __vpiArrayBase*get_word_parent(struct __vpiArrayWord*word) +{ + struct __vpiArrayWord*word0 = word->word0; + return (word0 - 1)->parent; +} + +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..a38977849 --- /dev/null +++ b/vvp/array_common.h @@ -0,0 +1,100 @@ +/* + * 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; } + + virtual 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; + }; +}; + +unsigned get_word_index(struct __vpiArrayWord*word); +struct __vpiArrayBase*get_word_parent(struct __vpiArrayWord*word); + +struct __vpiArrayWord*array_var_word_from_handle(vpiHandle ref); +struct __vpiArrayWord*array_var_index_from_handle(vpiHandle ref); + +vpiHandle array_index_iterate(int code, vpiHandle ref); + +#endif /* ARRAY_COMMON_H */ diff --git a/vvp/vpi_darray.cc b/vvp/vpi_darray.cc index 95046ecee..3f3694e4c 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,31 +40,67 @@ __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(); +} + +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) +{ + // TODO orson + return NULL; +} + +vpiHandle __vpiDarrayVar::vpi_handle(int code) +{ + // TODO orson + //switch (code) { + //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; diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 07ce78a71..3fb08a1a1 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -35,6 +35,7 @@ class class_type; +typedef struct __vpiArray* vvp_array_t; /* * This header file contains the internal definitions that the vvp @@ -514,8 +515,10 @@ class __vpiBaseVar : public __vpiHandle { inline vvp_net_t* get_net() const { return net_; } - private: + protected: struct __vpiScope* scope_; + + private: const char*name_; vvp_net_t*net_; }; @@ -532,13 +535,37 @@ 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 int get_word_size() const = 0; + virtual int get_left_range() const = 0; + virtual int get_right_range() const = 0; + virtual struct __vpiScope*get_scope() const = 0; + + virtual vpiHandle vpi_iterate(int code); + virtual void make_vals_words(); + + struct __vpiArrayWord*vals_words; +}; + +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; + int get_word_size() const { return 0; } // TODO + int get_left_range() const { return 0; } + int get_right_range() const { return 0; } + struct __vpiScope*get_scope() const { return scope_; } + 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); }; 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;