From e2ad59466ab20cf5360369c0bebd7e0ff4072b84 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 16 May 2008 16:20:22 -0700 Subject: [PATCH] Create handles to access words of an array, if needed. VPI code may need to access words of a variable array. If so, create a compact handle format that gains that access with minimal pain. --- vvp/array.cc | 123 ++++++++++++++++++++++++++++++++++++++++++++-- vvp/vpi_priv.h | 2 + vvp/vpi_signal.cc | 41 +++++++++------- 3 files changed, 145 insertions(+), 21 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index a51521f7d..3e9144e0e 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -55,9 +55,12 @@ struct __vpiArray { unsigned array_count; struct __vpiDecConst first_addr; struct __vpiDecConst last_addr; + // If this is a net array, nets lists the handles. vpiHandle*nets; - vvp_vector4_t*vals; - unsigned vals_width; + // If this is a var array, then these are used instead of nets. + vvp_vector4_t *vals; + unsigned vals_width; + struct __vpiArrayWord*vals_words; class vvp_fun_arrayport*ports_; }; @@ -74,6 +77,30 @@ struct __vpiArrayIndex { 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. + */ +struct __vpiArrayWord { + struct __vpiHandle base; + union { + struct __vpiArray*parent; + struct __vpiArrayWord*word0; + }; +}; + + static int vpi_array_get(int code, vpiHandle ref); static char*vpi_array_get_str(int code, vpiHandle ref); static vpiHandle vpi_array_get_handle(int code, vpiHandle ref); @@ -86,6 +113,10 @@ static int array_iterator_free_object(vpiHandle ref); static vpiHandle array_index_scan(vpiHandle ref, int); static int array_index_free_object(vpiHandle ref); +static int vpi_array_var_word_get(int code, vpiHandle); +static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value); +static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int); + static const struct __vpirt vpip_arraymem_rt = { vpiMemory, vpi_array_get, @@ -124,9 +155,49 @@ static const struct __vpirt vpip_array_index_rt = { array_index_free_object }; +static const struct __vpirt vpip_array_var_word_rt = { + vpiMemoryWord, + &vpi_array_var_word_get, + 0, + &vpi_array_var_word_get_value, + &vpi_array_var_word_put_value, + 0, + 0, + 0, + 0 +}; + # define ARRAY_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemory), \ (struct __vpiArray*)ref) +# define ARRAY_VAR_WORD(ref) (assert(ref->vpi_type->type_code==vpiMemoryWord), \ + (struct __vpiArrayWord*)ref) + +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].base.vpi_type = &vpip_array_var_word_rt; + 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_get(int code, vpiHandle ref) { struct __vpiArray*obj = ARRAY_HANDLE(ref); @@ -207,9 +278,52 @@ static vpiHandle vpi_array_index(vpiHandle ref, int index) if (index < 0) return 0; - assert(obj->nets != 0); + if (obj->nets != 0) { + return obj->nets[index]; + } - return obj->nets[index]; + if (obj->vals_words == 0) + array_make_vals_words(obj); + + return &(obj->vals_words[index].base); +} + +static int vpi_array_var_word_get(int code, vpiHandle ref) +{ + struct __vpiArrayWord*obj = ARRAY_VAR_WORD(ref); + struct __vpiArray*parent; + + decode_array_word_pointer(obj, parent); + + switch (code) { + case vpiSize: + return (int) parent->vals_width; + + default: + return 0; + } +} + +static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value) +{ + struct __vpiArrayWord*obj = ARRAY_VAR_WORD(ref); + struct __vpiArray*parent; + + unsigned index = decode_array_word_pointer(obj, parent); + + assert(0); +} + +static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags) +{ + struct __vpiArrayWord*obj = ARRAY_VAR_WORD(ref); + struct __vpiArray*parent; + + 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; } # define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \ @@ -381,6 +495,7 @@ static vpiHandle vpip_make_array(char*label, const char*name, obj->nets = 0; obj->vals = 0; obj->vals_width = 0; + obj->vals_words = 0; // Initialize (clear) the read-ports list. obj->ports_ = 0; diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index d515a0b62..8c95673e0 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -530,6 +530,8 @@ extern void vpip_oct_str_to_vec4(vvp_vector4_t&val, const char*str); extern void vpip_dec_str_to_vec4(vvp_vector4_t&val, const char*str, bool sign); extern void vpip_hex_str_to_vec4(vvp_vector4_t&val, const char*str); +extern vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid); + extern void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width, bool signed_flag, s_vpi_value*vp); diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 4d0b37971..7f09be83f 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -645,6 +645,27 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags) ? (rfp->msb - rfp->lsb + 1) : (rfp->lsb - rfp->msb + 1); + + vvp_vector4_t val = vec4_from_vpi_value(vp, wid); + + /* If this is a vpiForce, then instead of writing to the + signal input port, we write to the special "force" port. */ + int dest_port = 0; + if (flags == vpiForceFlag) + dest_port = 2; + + /* This is the destination that I'm going to poke into. Make + it from the vvp_net_t pointer, and assume a write to + port-0. This is the port where signals receive input. */ + vvp_net_ptr_t destination (rfp->node, dest_port); + + vvp_send_vec4(destination, val); + + return ref; +} + +vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid) +{ vvp_vector4_t val (wid, BIT4_0); switch (vp->format) { @@ -691,27 +712,13 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags) default: fprintf(stderr, "vvp internal error: put_value: " - "value type %u not implemented." - " Signal is %s in scope %s\n", - vp->format, vpi_get_str(vpiName, ref), rfp->scope->name); + "value type %u not implemented here.\n", + vp->format); assert(0); } - /* If this is a vpiForce, then instead of writing to the - signal input port, we write to the special "force" port. */ - int dest_port = 0; - if (flags == vpiForceFlag) - dest_port = 2; - - /* This is the destination that I'm going to poke into. Make - it from the vvp_net_t pointer, and assume a write to - port-0. This is the port where signals receive input. */ - vvp_net_ptr_t destination (rfp->node, dest_port); - - vvp_send_vec4(destination, val); - - return ref; + return val; } static const struct __vpirt vpip_reg_rt = {