From 102cbb67b46a83fc97e4c25855fc13fc5fc8874b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 16 May 2008 10:38:32 -0700 Subject: [PATCH 01/17] Rework variable arrays to not have vpi handles for every word. Save tons of space per memory word by not creating a vpi handle for each and every word of a variable array. (Net arrays still get a vpiHandle for every word.) The consequence of this is that all accesses to a variable array need to go through the indexing. This commit handles the most common places where this impacts, but there are still problems. --- tgt-vvp/draw_vpi.c | 3 + tgt-vvp/eval_expr.c | 45 ++++++++------ tgt-vvp/vvp_process.c | 6 +- tgt-vvp/vvp_scope.c | 6 ++ vvp/array.cc | 135 ++++++++++++++++++++++++++++++++---------- vvp/compile.h | 3 + vvp/parse.y | 3 + vvp/words.cc | 4 +- 8 files changed, 151 insertions(+), 54 deletions(-) diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 43821385f..d5fb20183 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -55,6 +55,9 @@ static int is_fixed_memory_word(ivl_expr_t net) if (ivl_signal_array_count(sig) == 1) return 1; + if (ivl_signal_type(sig) == IVL_SIT_REG) + return 0; + if (number_is_immediate(ivl_expr_oper1(net), 8*sizeof(unsigned))) return 1; diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index f7c5ed27d..00472dcb4 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -138,8 +138,22 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) case IVL_EX_SIGNAL: { ivl_signal_t sig = ivl_expr_signal(expr); + unsigned word = 0; if (ivl_signal_array_count(sig) > 1) { + + /* Detect the special case that this is a + variable array. In this case, the ix/getv + will not work, so do it the hard way. */ + if (ivl_signal_type(sig) == IVL_SIT_REG) { + struct vector_info rv; + rv = draw_eval_expr(expr, 0); + fprintf(vvp_out, " %%ix/get %u, %u, %u;\n", + ix, rv.base, rv.wid); + clr_vector(rv); + break; + } + ivl_expr_t ixe = ivl_expr_oper1(expr); if (number_is_immediate(ixe, 8*sizeof(unsigned long))) word = get_number_immediate(ixe); @@ -1896,26 +1910,21 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res, load/av instruction. */ if (ivl_signal_array_count(sig) > 1) { ivl_expr_t ix = ivl_expr_oper1(exp); - if (!number_is_immediate(ix, 8*sizeof(unsigned long))) { - draw_eval_expr_into_integer(ix, 3); - if (add_index < 0) { - fprintf(vvp_out, " %%load/av %u, v%p, %u;\n", - res.base, sig, swid); - } else { - assert(add_index == 0); - /* Add an immediate value to an array value. */ - fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate); - fprintf(vvp_out, " %%load/avp0 %u, v%p, %u;\n", - res.base, sig, swid); - } - pad_expr_in_place(exp, res, swid); - return; + draw_eval_expr_into_integer(ix, 3); + if (add_index < 0) { + fprintf(vvp_out, " %%load/av %u, v%p, %u;\n", + res.base, sig, swid); + } else { + assert(add_index == 0); + + /* Add an immediate value to an array value. */ + fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate); + fprintf(vvp_out, " %%load/avp0 %u, v%p, %u;\n", + res.base, sig, swid); } - - /* The index is constant, so we can return to direct - readout with the specific word selected. */ - word = get_number_immediate(ix); + pad_expr_in_place(exp, res, swid); + return; } diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 2af631538..1f2496ecf 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -151,8 +151,10 @@ static void set_to_lvariable(ivl_lval_t lval, directly to the word and save the index calculation. */ if (word_ix == 0) { if (use_word < ivl_signal_array_count(sig)) { - fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n", - sig, use_word, bit, wid); + fprintf(vvp_out, " %%ix/load 1, 0;\n"); + fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word); + fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", + sig, bit, wid); } else { fprintf(vvp_out, " ; %%set/v v%p_%lu, %u, %u " "OUT OF BOUNDS\n", sig, use_word, bit, wid); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 05944f639..7b92a343b 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -615,6 +615,12 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) /* Input is a .var. This device may be a non-zero pin because it may be an array of reg vectors. */ snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin); + + if (ivl_signal_array_count(sptr) > 1) { + fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n", + sptr, nptr_pin, sptr, nptr_pin); + } + return strdup(tmp); } diff --git a/vvp/array.cc b/vvp/array.cc index e57bbc375..a51521f7d 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -55,7 +55,9 @@ struct __vpiArray { unsigned array_count; struct __vpiDecConst first_addr; struct __vpiDecConst last_addr; - vpiHandle*words; + vpiHandle*nets; + vvp_vector4_t*vals; + unsigned vals_width; class vvp_fun_arrayport*ports_; }; @@ -205,7 +207,9 @@ static vpiHandle vpi_array_index(vpiHandle ref, int index) if (index < 0) return 0; - return obj->words[index]; + assert(obj->nets != 0); + + return obj->nets[index]; } # define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \ @@ -220,7 +224,9 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int) return 0; } - vpiHandle res = obj->array->words[obj->next]; + assert(obj->array->nets != 0); + + vpiHandle res = obj->array->nets[obj->next]; obj->next += 1; return res; } @@ -279,22 +285,61 @@ void array_set_word(vvp_array_t arr, if (address >= arr->array_count) return; + if (arr->vals) { + assert(arr->nets == 0); + if (part_off != 0) { + if (arr->vals[address].size() == 0) + arr->vals[address] = vvp_vector4_t(arr->vals_width, BIT4_X); + if ((part_off + val.size()) > arr->vals[address].size()) { + cerr << "part_off=" << part_off + << " val.size()=" << val.size() + << " arr->vals[address].size()=" << arr->vals[address].size() + << " arr->vals_width=" << arr->vals_width << endl; + assert(0); + } + arr->vals[address].set_vec(part_off, val); + } else { + arr->vals[address] = val; + } + array_word_change(arr, address); + return; + } + + assert(arr->nets != 0); + // Select the word of the array that we affect. - vpiHandle word = arr->words[address]; + vpiHandle word = arr->nets[address]; struct __vpiSignal*vsig = vpip_signal_from_handle(word); assert(vsig); vvp_net_ptr_t ptr (vsig->node, 0); vvp_send_vec4_pv(ptr, val, part_off, val.size(), vpip_size(vsig)); + array_word_change(arr, address); } vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) { + if (arr->vals) { + assert(arr->nets == 0); + + vvp_vector4_t tmp; + if (address < arr->array_count) + tmp = arr->vals[address]; + + if (tmp.size() == 0) + tmp = vvp_vector4_t(arr->vals_width, BIT4_X); + + return tmp; + } + + assert(arr->vals == 0); + assert(arr->nets != 0); + if (address >= arr->array_count) { // 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->words[0]; + vpiHandle word = arr->nets[0]; struct __vpiSignal*vsig = vpip_signal_from_handle(word); assert(vsig); vvp_fun_signal_vec*sig = dynamic_cast (vsig->node->fun); @@ -302,7 +347,7 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) return vvp_vector4_t(sig->size(), BIT4_X); } - vpiHandle word = arr->words[address]; + vpiHandle word = arr->nets[address]; struct __vpiSignal*vsig = vpip_signal_from_handle(word); assert(vsig); vvp_fun_signal_vec*sig = dynamic_cast (vsig->node->fun); @@ -332,7 +377,10 @@ static vpiHandle vpip_make_array(char*label, const char*name, vpip_make_dec_const(&obj->first_addr, first_addr); vpip_make_dec_const(&obj->last_addr, last_addr); - obj->words = (vpiHandle*)calloc(array_count, sizeof(vpiHandle)); + // Start off now knowing if we are nets or variables. + obj->nets = 0; + obj->vals = 0; + obj->vals_width = 0; // Initialize (clear) the read-ports list. obj->ports_ = 0; @@ -346,19 +394,29 @@ static vpiHandle vpip_make_array(char*label, const char*name, v.ptr = obj; sym_set_value(array_table, label, v); + /* Add this into the table of VPI objects. This is used for + contexts that try to look up VPI objects in + general. (i.e. arguments to vpi_task calls.) */ + compile_vpi_symbol(label, &(obj->base)); + + /* Blindly attach to the scope as an object. */ + vpip_attach_to_current_scope(&(obj->base)); + return &(obj->base); } void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word) { assert(addr < array->array_count); - array->words[addr] = word; + assert(array->nets); + array->nets[addr] = word; } void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word) { assert(addr < array->array_count); - array->words[addr] = word; + assert(array->nets); + array->nets[addr] = word; if (struct __vpiSignal*sig = vpip_signal_from_handle(word)) { vvp_net_t*net = sig->node; @@ -371,33 +429,16 @@ void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word) } } -static vpiHandle common_array_build(char*label, char*name, int last, int first) -{ - vpiHandle obj = vpip_make_array(label, name, first, last); - /* Add this into the table of VPI objects. This is used for - contexts that try to look up VPI objects in - general. (i.e. arguments to vpi_task calls.) */ - compile_vpi_symbol(label, obj); - /* Blindly attach to the scope as an object. */ - vpip_attach_to_current_scope(obj); - - return obj; -} - void compile_var_array(char*label, char*name, int last, int first, int msb, int lsb, char signed_flag) { - vpiHandle obj = common_array_build(label, name, last, first); + vpiHandle obj = vpip_make_array(label, name, first, last); struct __vpiArray*arr = ARRAY_HANDLE(obj); - vvp_array_t array = array_find(label); /* Make the words. */ - for (unsigned idx = 0 ; idx < arr->array_count ; idx += 1) { - char buf[64]; - snprintf(buf, sizeof buf, "%s_%u", label, idx); - compile_variablew(strdup(buf), array, idx, msb, lsb, signed_flag); - } + arr->vals = new vvp_vector4_t[arr->array_count]; + arr->vals_width = labs(msb-lsb) + 1; free(label); free(name); @@ -406,7 +447,7 @@ void compile_var_array(char*label, char*name, int last, int first, void compile_real_array(char*label, char*name, int last, int first, int msb, int lsb) { - vpiHandle obj = common_array_build(label, name, last, first); + vpiHandle obj = vpip_make_array(label, name, first, last); struct __vpiArray*arr = ARRAY_HANDLE(obj); vvp_array_t array = array_find(label); @@ -424,7 +465,10 @@ void compile_real_array(char*label, char*name, int last, int first, void compile_net_array(char*label, char*name, int last, int first) { - /* vpiHandle obj = */ common_array_build(label, name, last, first); + vpiHandle obj = vpip_make_array(label, name, first, last); + + struct __vpiArray*arr = ARRAY_HANDLE(obj); + arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle)); free(label); free(name); @@ -434,6 +478,7 @@ class vvp_fun_arrayport : public vvp_net_fun_t { public: explicit vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net); + explicit vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net, long addr); ~vvp_fun_arrayport(); void check_word_change(unsigned long addr); @@ -456,6 +501,12 @@ vvp_fun_arrayport::vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net) next_ = 0; } +vvp_fun_arrayport::vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net, long addr) +: arr_(mem), net_(net), addr_(addr) +{ + next_ = 0; +} + vvp_fun_arrayport::~vvp_fun_arrayport() { } @@ -521,6 +572,25 @@ void compile_array_port(char*label, char*array, char*addr) // The input_connect arranges for the array string to be free'ed. } +void compile_array_port(char*label, char*array, long addr) +{ + vvp_array_t mem = array_find(array); + assert(mem); + + vvp_net_t*ptr = new vvp_net_t; + vvp_fun_arrayport*fun = new vvp_fun_arrayport(mem, ptr, addr); + ptr->fun = fun; + + define_functor_symbol(label, ptr); + + // Other then the array itself, this kind of array port has no + // inputs. + array_attach_port(mem, fun); + + free(label); + free(array); +} + void compile_array_alias(char*label, char*name, char*src) { vvp_array_t mem = array_find(src); @@ -539,7 +609,8 @@ void compile_array_alias(char*label, char*name, char*src) vpip_make_dec_const(&obj->last_addr, mem->last_addr.value); // Share the words with the source array. - obj->words = mem->words; + obj->nets = mem->nets; + obj->vals = mem->vals; obj->ports_ = 0; diff --git a/vvp/compile.h b/vvp/compile.h index 89151af86..276af4ce1 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -295,7 +295,10 @@ extern void compile_net_array(char*label, char*name, int last, int first); extern void compile_array_alias(char*label, char*name, char*src); + /* Index is a net. */ extern void compile_array_port(char*label, char*name, char*addr); + /* Index is a constant address */ +extern void compile_array_port(char*label, char*name, long addr); extern void compile_memory(char *label, char *name, int lsb, int msb, unsigned idxs, long *idx); diff --git a/vvp/parse.y b/vvp/parse.y index 60eb9103e..8e577fd01 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -211,6 +211,9 @@ statement | T_LABEL K_ARRAY_PORT T_SYMBOL ',' T_SYMBOL ';' { compile_array_port($1, $3, $5); } + | T_LABEL K_ARRAY_PORT T_SYMBOL ',' T_NUMBER ';' + { compile_array_port($1, $3, $5); } + | T_LABEL K_ARRAY T_STRING ',' T_SYMBOL ';' { compile_array_alias($1, $3, $5); } diff --git a/vvp/words.cc b/vvp/words.cc index c3e1cfd19..b73574871 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -84,7 +84,7 @@ static void __compile_var(char*label, char*name, define_functor_symbol(label, node); vpiHandle obj = 0; - if (! local_flag) { + if (! local_flag && !array) { /* Make the vpiHandle for the reg. */ obj = (signed_flag > 1) ? vpip_make_int(name, msb, lsb, node) : @@ -102,7 +102,7 @@ static void __compile_var(char*label, char*name, // it is attached to the addressed array. if (array) { assert(!name); - array_attach_word(array, array_addr, obj); + if (obj) array_attach_word(array, array_addr, obj); } free(label); if (name) free(name); From 0cd946a7afd705e09ede67d1124c3f3b241a0446 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 16 May 2008 16:18:07 -0700 Subject: [PATCH 02/17] Remove a useless call to vpi_iterate. --- vpi/sys_readmem.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/vpi/sys_readmem.c b/vpi/sys_readmem.c index 5e2cc2b92..7c120772d 100644 --- a/vpi/sys_readmem.c +++ b/vpi/sys_readmem.c @@ -109,7 +109,6 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name) FILE*file; unsigned addr; s_vpi_value value; - vpiHandle words; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle item = vpi_scan(argv); @@ -283,11 +282,7 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name) } } - - words = vpi_iterate(vpiMemoryWord, mitem); - assert(words); - - item = vpi_scan(words); + item = vpi_handle_by_index(mitem,0); wwid = vpi_get(vpiSize, item); /* variable that will be uses by the lexer to pass values @@ -347,9 +342,6 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name) bailout: free(value.value.vector); - - if (item) - vpi_free_object(words); free(path); fclose(file); return 0; From e2ad59466ab20cf5360369c0bebd7e0ff4072b84 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 16 May 2008 16:20:22 -0700 Subject: [PATCH 03/17] 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 = { From 42913e46b8036345ee4cbecc9617438283212189 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 16 May 2008 16:33:04 -0700 Subject: [PATCH 04/17] Fix non-blocking assign to variable arrays. Non-blocking assignment with constant index was still trying to access the vpi handle directly. --- tgt-vvp/vvp_process.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 1f2496ecf..961346a83 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -237,16 +237,12 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, unsigned part_off = 0; ivl_expr_t word_ix = ivl_lval_idx(lval); - unsigned long use_word = 0; + const unsigned long use_word = 0; if (ivl_signal_array_count(sig) > 1) { assert(word_ix); - if (! number_is_immediate(word_ix, 8*sizeof(use_word))) { - assign_to_array_word(sig, word_ix, bit, delay, dexp, width); - return; - } - - use_word = get_number_immediate(word_ix); + assign_to_array_word(sig, word_ix, bit, delay, dexp, width); + return; } if (part_off_ex == 0) { From 6632e4c33ba47f801758b3b4166ddef6a9002932 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 16 May 2008 19:06:12 -0700 Subject: [PATCH 05/17] Allow ports to be declared before arrays. It is possible for the code generator to create .array/port objects before the .array object that the port refereces, so use the resolv_list to arrange for binding during cleanup. --- vvp/array.cc | 73 ++++++++++++++++++++++------------ vvp/array.h | 2 +- vvp/compile.cc | 104 ++++++++++++++++++++----------------------------- vvp/compile.h | 35 +++++++++++++++++ vvp/memory.cc | 2 +- vvp/memory.h | 2 +- 6 files changed, 129 insertions(+), 89 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index 3e9144e0e..c76e2db41 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -35,7 +35,7 @@ static symbol_table_t array_table =0; class vvp_fun_arrayport; static void array_attach_port(vvp_array_t, vvp_fun_arrayport*); -vvp_array_t array_find(char*label) +vvp_array_t array_find(const char*label) { if (array_table == 0) return 0; @@ -667,43 +667,66 @@ void array_word_change(vvp_array_t array, unsigned long addr) cur->check_word_change(addr); } -void compile_array_port(char*label, char*array, char*addr) +class array_port_resolv_list_t : public resolv_list_s { + + public: + explicit array_port_resolv_list_t(char*label) : resolv_list_s(label) { } + + vvp_net_t*ptr; + bool use_addr; + long addr; + bool resolve(bool mes); + + private: +}; + +bool array_port_resolv_list_t::resolve(bool mes) { - vvp_array_t mem = array_find(array); - assert(mem); + vvp_array_t mem = array_find(label()); + if (mem == 0) { + assert(mem || !mes); + return false; + } - vvp_net_t*ptr = new vvp_net_t; - vvp_fun_arrayport*fun = new vvp_fun_arrayport(mem, ptr); + vvp_fun_arrayport*fun; + if (use_addr) + fun = new vvp_fun_arrayport(mem, ptr, addr); + else + fun = new vvp_fun_arrayport(mem, ptr); ptr->fun = fun; - define_functor_symbol(label, ptr); - // Connect the port-0 input as the address. - input_connect(ptr, 0, addr); - array_attach_port(mem, fun); + return true; +} + +void compile_array_port(char*label, char*array, char*addr) +{ + array_port_resolv_list_t*resolv_mem + = new array_port_resolv_list_t(array); + + resolv_mem->ptr = new vvp_net_t; + resolv_mem->use_addr = false; + define_functor_symbol(label, resolv_mem->ptr); free(label); - free(array); - // The input_connect arranges for the array string to be free'ed. + // Connect the port-0 input as the address. + input_connect(resolv_mem->ptr, 0, addr); + + resolv_submit(resolv_mem); } void compile_array_port(char*label, char*array, long addr) { - vvp_array_t mem = array_find(array); - assert(mem); - - vvp_net_t*ptr = new vvp_net_t; - vvp_fun_arrayport*fun = new vvp_fun_arrayport(mem, ptr, addr); - ptr->fun = fun; - - define_functor_symbol(label, ptr); - - // Other then the array itself, this kind of array port has no - // inputs. - array_attach_port(mem, fun); + array_port_resolv_list_t*resolv_mem + = new array_port_resolv_list_t(array); + resolv_mem->ptr = new vvp_net_t; + resolv_mem->use_addr = true; + resolv_mem->addr = addr; + define_functor_symbol(label, resolv_mem->ptr); free(label); - free(array); + + resolv_submit(resolv_mem); } void compile_array_alias(char*label, char*name, char*src) diff --git a/vvp/array.h b/vvp/array.h index f7ad35f70..c081a4eb6 100644 --- a/vvp/array.h +++ b/vvp/array.h @@ -28,7 +28,7 @@ typedef struct __vpiArray* vvp_array_t; * This function tries to find the array (by label) in the global * table of all the arrays in the design. */ -extern vvp_array_t array_find(char*label); +extern vvp_array_t array_find(const char*label); extern vpiHandle array_index_iterate(int code, vpiHandle ref); extern void array_word_change(vvp_array_t array, unsigned long addr); diff --git a/vvp/compile.cc b/vvp/compile.cc index 5d6e819a8..fe9c82f82 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -321,13 +321,12 @@ vvp_net_t* vvp_net_lookup(const char*label) */ static struct resolv_list_s*resolv_list = 0; -struct resolv_list_s { - virtual ~resolv_list_s() { } - struct resolv_list_s*next; - virtual bool resolve(bool mes = false) = 0; -}; +resolv_list_s::~resolv_list_s() +{ + free(label_); +} -static void resolv_submit(struct resolv_list_s*cur) +void resolv_submit(struct resolv_list_s*cur) { if (cur->resolve()) { delete cur; @@ -346,8 +345,8 @@ static void resolv_submit(struct resolv_list_s*cur) * put net->port[port] into the fan-out list for that node. */ struct vvp_net_resolv_list_s: public resolv_list_s { - // node to locate - char*source; + + vvp_net_resolv_list_s(char*l) : resolv_list_s(l) { } // port to be driven by the located node. vvp_net_ptr_t port; virtual bool resolve(bool mes); @@ -355,20 +354,18 @@ struct vvp_net_resolv_list_s: public resolv_list_s { bool vvp_net_resolv_list_s::resolve(bool mes) { - vvp_net_t*tmp = vvp_net_lookup(source); + vvp_net_t*tmp = vvp_net_lookup(label()); if (tmp) { // Link the input port to the located output. vvp_net_t*net = port.ptr(); net->port[port.port()] = tmp->out; tmp->out = port; - - free(source); return true; } if (mes) - fprintf(stderr, "unresolved vvp_net reference: %s\n", source); + fprintf(stderr, "unresolved vvp_net reference: %s\n", label()); return false; } @@ -376,10 +373,8 @@ bool vvp_net_resolv_list_s::resolve(bool mes) inline static void postpone_functor_input(vvp_net_ptr_t port, char*lab) { - struct vvp_net_resolv_list_s*res = new struct vvp_net_resolv_list_s; - + struct vvp_net_resolv_list_s*res = new struct vvp_net_resolv_list_s(lab); res->port = port; - res->source = lab; resolv_submit(res); } @@ -390,24 +385,22 @@ void postpone_functor_input(vvp_net_ptr_t port, char*lab) */ struct functor_gen_resolv_list_s: public resolv_list_s { - char*source; + explicit functor_gen_resolv_list_s(char*txt) : resolv_list_s(txt) { } vvp_net_t**ref; virtual bool resolve(bool mes); }; bool functor_gen_resolv_list_s::resolve(bool mes) { - vvp_net_t*tmp = vvp_net_lookup(source); + vvp_net_t*tmp = vvp_net_lookup(label()); if (tmp) { *ref = tmp; - - free(source); return true; } if (mes) - fprintf(stderr, "unresolved functor reference: %s\n", source); + fprintf(stderr, "unresolved functor reference: %s\n", label()); return false; } @@ -415,10 +408,9 @@ bool functor_gen_resolv_list_s::resolve(bool mes) void functor_ref_lookup(vvp_net_t**ref, char*lab) { struct functor_gen_resolv_list_s*res = - new struct functor_gen_resolv_list_s; + new struct functor_gen_resolv_list_s(lab); res->ref = ref; - res->source = lab; resolv_submit(res); } @@ -428,27 +420,27 @@ void functor_ref_lookup(vvp_net_t**ref, char*lab) */ struct vpi_handle_resolv_list_s: public resolv_list_s { - vpiHandle *handle; - char *label; + explicit vpi_handle_resolv_list_s(char*label) : resolv_list_s(label) { } virtual bool resolve(bool mes); + vpiHandle *handle; }; bool vpi_handle_resolv_list_s::resolve(bool mes) { - symbol_value_t val = sym_get_value(sym_vpi, label); + symbol_value_t val = sym_get_value(sym_vpi, label()); if (!val.ptr) { // check for thread vector T unsigned base, wid; unsigned n = 0; char ss[32]; - if (2 <= sscanf(label, "T<%u,%u>%n", &base, &wid, &n) - && n == strlen(label)) { + if (2 <= sscanf(label(), "T<%u,%u>%n", &base, &wid, &n) + && n == strlen(label())) { val.ptr = vpip_make_vthr_vector(base, wid, false); - sym_set_value(sym_vpi, label, val); + sym_set_value(sym_vpi, label(), val); - } else if (3 <= sscanf(label, "T<%u,%u,%[su]>%n", &base, + } else if (3 <= sscanf(label(), "T<%u,%u,%[su]>%n", &base, &wid, ss, &n) - && n == strlen(label)) { + && n == strlen(label())) { bool signed_flag = false; for (char*fp = ss ; *fp ; fp += 1) switch (*fp) { @@ -463,13 +455,13 @@ bool vpi_handle_resolv_list_s::resolve(bool mes) } val.ptr = vpip_make_vthr_vector(base, wid, signed_flag); - sym_set_value(sym_vpi, label, val); + sym_set_value(sym_vpi, label(), val); - } else if (2 == sscanf(label, "W<%u,%[r]>%n", &base, ss, &n) - && n == strlen(label)) { + } else if (2 == sscanf(label(), "W<%u,%[r]>%n", &base, ss, &n) + && n == strlen(label())) { val.ptr = vpip_make_vthr_word(base, ss); - sym_set_value(sym_vpi, label, val); + sym_set_value(sym_vpi, label(), val); } } @@ -480,12 +472,11 @@ bool vpi_handle_resolv_list_s::resolve(bool mes) if (val.ptr) { *handle = (vpiHandle) val.ptr; - free(label); return true; } if (mes) - fprintf(stderr, "unresolved vpi name lookup: %s\n", label); + fprintf(stderr, "unresolved vpi name lookup: %s\n", label()); return false; } @@ -517,10 +508,9 @@ void compile_vpi_lookup(vpiHandle *handle, char*label) } struct vpi_handle_resolv_list_s*res - = new struct vpi_handle_resolv_list_s; + = new struct vpi_handle_resolv_list_s(label); res->handle = handle; - res->label = label; resolv_submit(res); } @@ -529,27 +519,24 @@ void compile_vpi_lookup(vpiHandle *handle, char*label) */ struct code_label_resolv_list_s: public resolv_list_s { + code_label_resolv_list_s(char*label) : resolv_list_s(label) { } struct vvp_code_s *code; - char *label; virtual bool resolve(bool mes); }; bool code_label_resolv_list_s::resolve(bool mes) { - symbol_value_t val = sym_get_value(sym_codespace, label); + symbol_value_t val = sym_get_value(sym_codespace, label()); if (val.num) { if (code->opcode == of_FORK) code->cptr2 = reinterpret_cast(val.ptr); else code->cptr = reinterpret_cast(val.ptr); - free(label); return true; } if (mes) - fprintf(stderr, - "unresolved code label: %s\n", - label); + fprintf(stderr, "unresolved code label: %s\n", label()); return false; } @@ -557,10 +544,9 @@ bool code_label_resolv_list_s::resolve(bool mes) void code_label_lookup(struct vvp_code_s *code, char *label) { struct code_label_resolv_list_s *res - = new struct code_label_resolv_list_s; + = new struct code_label_resolv_list_s(label); res->code = code; - res->label = label; resolv_submit(res); } @@ -569,21 +555,20 @@ void code_label_lookup(struct vvp_code_s *code, char *label) * Lookup memories. */ struct memory_resolv_list_s: public resolv_list_s { + memory_resolv_list_s(char*label) : resolv_list_s(label) { } struct vvp_code_s *code; - char *label; virtual bool resolve(bool mes); }; bool memory_resolv_list_s::resolve(bool mes) { - code->mem = memory_find(label); + code->mem = memory_find(label()); if (code->mem != 0) { - free(label); return true; } if (mes) - fprintf(stderr, "Memory unresolved: %s\n", label); + fprintf(stderr, "Memory unresolved: %s\n", label()); return false; } @@ -591,41 +576,38 @@ bool memory_resolv_list_s::resolve(bool mes) static void compile_mem_lookup(struct vvp_code_s *code, char *label) { struct memory_resolv_list_s *res - = new struct memory_resolv_list_s; + = new struct memory_resolv_list_s(label); res->code = code; - res->label = label; resolv_submit(res); } -struct array_resolv_list_s: public resolv_list_s { +struct code_array_resolv_list_s: public resolv_list_s { + code_array_resolv_list_s(char*label) : resolv_list_s(label) { } struct vvp_code_s *code; - char *label; virtual bool resolve(bool mes); }; -bool array_resolv_list_s::resolve(bool mes) +bool code_array_resolv_list_s::resolve(bool mes) { - code->array = array_find(label); + code->array = array_find(label()); if (code->array != 0) { - free(label); return true; } if (mes) - fprintf(stderr, "Array unresolved: %s\n", label); + fprintf(stderr, "Array unresolved: %s\n", label()); return false; } static void compile_array_lookup(struct vvp_code_s*code, char*label) { - struct array_resolv_list_s *res - = new struct array_resolv_list_s; + struct code_array_resolv_list_s *res + = new struct code_array_resolv_list_s(label); res->code = code; - res->label = label; resolv_submit(res); } diff --git a/vvp/compile.h b/vvp/compile.h index 276af4ce1..1e95e48f3 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -243,6 +243,41 @@ extern void compile_param_logic(char*label, char*name, char*value, extern void compile_param_real(char*label, char*name, char*value, long file_idx, long lineno); +/* + * The resolv_list_s is the base class for a symbol resolve + * action. Some function creates an instance of a resolv_list_s object + * that contains the data pertinent to that resolution request, and + * executes it with the resolv_submit function. If the operation can + * complete, then the resolv_submit deletes the object. Otherwise, it + * pushes it onto the resolv_list for later processing. + * + * Derived classes implement the resolve function to perform the + * actual binding or resolution that the instance requires. If the + * function succeeds, the resolve method returns true and the object + * can be deleted any time. + * + * The mes parameter of the resolve method tells the resolver that + * this call is its last chance. If it cannot complete the operation, + * it must print an error message and return false. + */ +class resolv_list_s { + + public: + explicit resolv_list_s(char*lab) : label_(lab) { } + virtual ~resolv_list_s(); + virtual bool resolve(bool mes = false) = 0; + + protected: + const char*label() const { return label_; } + + private: + friend void ::resolv_submit(struct resolv_list_s*cur); + friend void ::compile_cleanup(void); + + char*label_; + struct resolv_list_s*next; +}; + /* * This function schedules a lookup of an indexed label. The ref * points to the vvp_net_t that receives the result. The result may diff --git a/vvp/memory.cc b/vvp/memory.cc index 96f237eae..05f606aa9 100644 --- a/vvp/memory.cc +++ b/vvp/memory.cc @@ -62,7 +62,7 @@ struct vvp_memory_s static symbol_table_t memory_table = 0; -vvp_memory_t memory_find(char *label) +vvp_memory_t memory_find(const char *label) { if (memory_table == 0) return 0; diff --git a/vvp/memory.h b/vvp/memory.h index 3d3cf2e4e..85473ea30 100644 --- a/vvp/memory.h +++ b/vvp/memory.h @@ -152,7 +152,7 @@ class vvp_fun_memport : public vvp_net_fun_t { ** The memory_create function creates a new memory device with the given ** name. It is a fatal error to try to create a device that already exists. */ -vvp_memory_t memory_find(char *label); +vvp_memory_t memory_find(const char *label); vvp_memory_t memory_create(char *label); /* From 680d3c8a3ea7de608a120b6487b0195e971febc3 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 19 May 2008 11:18:04 -0700 Subject: [PATCH 06/17] Assign to variable array words using array indexing. The non-array set statements no longer work on array words. Handle the various cases properly. --- tgt-vvp/vvp_process.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 961346a83..af93740ce 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -99,7 +99,7 @@ static void set_to_lvariable(ivl_lval_t lval, if (ivl_lval_mux(lval)) part_off_ex = ivl_lval_mux(lval); - if (part_off_ex) { + if (part_off_ex && ivl_signal_dimensions(sig) == 0) { unsigned skip_set = transient_id++; /* There is a mux expression, so this must be a write to @@ -118,6 +118,39 @@ static void set_to_lvariable(ivl_lval_t lval, lookaside. */ save_signal_lookaside(bit, sig, use_word, 0); + } else if (part_off_ex && ivl_signal_dimensions(sig) > 0) { + + /* Here we have a part select write into an array word. */ + unsigned skip_set = transient_id++; + if (word_ix) { + draw_eval_expr_into_integer(word_ix, 3); + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); + } else { + fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word); + } + draw_eval_expr_into_integer(part_off_ex, 1); + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); + fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", + sig, bit, wid); + fprintf(vvp_out, "t_%u ;\n", skip_set); + + } else if ((part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) + && ivl_signal_dimensions(sig) > 0) { + + /* Here we have a part select write into an array word. */ + unsigned skip_set = transient_id++; + if (word_ix) { + draw_eval_expr_into_integer(word_ix, 3); + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); + } else { + fprintf(vvp_out, " %%ix/load 3, %lu;\n", use_word); + } + fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); + fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", + sig, bit, wid); + if (word_ix) /* Only need this label if word_ix is set. */ + fprintf(vvp_out, "t_%u ;\n", skip_set); + } else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) { /* There is no mux expression, but a constant part offset. Load that into index x0 and generate a @@ -145,7 +178,7 @@ static void set_to_lvariable(ivl_lval_t lval, lookaside. */ save_signal_lookaside(bit, sig, use_word, 0); - } else if (ivl_signal_array_count(sig) > 1) { + } else if (ivl_signal_dimensions(sig) > 0) { /* If the word index is a constant, then we can write directly to the word and save the index calculation. */ From 9a00829ee4f2904db2b464e4eb6643a895f2fb65 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 19 May 2008 11:31:40 -0700 Subject: [PATCH 07/17] Use ivl_signal_dimensions to detect that signal is an array. It is possible for an array to have 1 word in it, so using the array count to detect an array is incorrect. Use the ivl_signal_dimensions function, which is there exactly for that purpose. --- tgt-vvp/draw_vpi.c | 2 +- tgt-vvp/eval_expr.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index d5fb20183..f7508e71a 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -52,7 +52,7 @@ static int is_fixed_memory_word(ivl_expr_t net) sig = ivl_expr_signal(net); - if (ivl_signal_array_count(sig) == 1) + if (ivl_signal_dimensions(sig) == 0) return 1; if (ivl_signal_type(sig) == IVL_SIT_REG) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 00472dcb4..3ab82b3f4 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -140,7 +140,7 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) ivl_signal_t sig = ivl_expr_signal(expr); unsigned word = 0; - if (ivl_signal_array_count(sig) > 1) { + if (ivl_signal_dimensions(sig) > 0) { /* Detect the special case that this is a variable array. In this case, the ix/getv @@ -1908,7 +1908,7 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res, /* If this is an access to an array, handle that by emitting a load/av instruction. */ - if (ivl_signal_array_count(sig) > 1) { + if (ivl_signal_dimensions(sig) > 0) { ivl_expr_t ix = ivl_expr_oper1(exp); draw_eval_expr_into_integer(ix, 3); @@ -2043,7 +2043,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube, and we stay here. If it is not constant, then give up and do an array index in front of this part select. */ - if (ivl_signal_array_count(sig) > 1) { + if (ivl_signal_dimensions(sig) > 0) { ivl_expr_t ix = ivl_expr_oper1(sube); if (!number_is_immediate(ix, 8*sizeof(unsigned long))) From 07c8fce5308dc8e377dbd15a5ea554f15e90f2df Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 19 May 2008 11:44:03 -0700 Subject: [PATCH 08/17] Careful that select signal does not try to select reg words directly. --- tgt-vvp/eval_expr.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 3ab82b3f4..08080fe7e 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -2039,14 +2039,16 @@ static struct vector_info draw_select_signal(ivl_expr_t sube, unsigned use_word = 0; /* If this is an access to an array, try to get the index as a - constant. If it is, then this reduces to a signal access - and we stay here. If it is not constant, then give up and - do an array index in front of this part select. */ + constant. If it is (and the array is not a reg array then + this reduces to a signal access and we stay here. If it is + not constant, then give up and do an array index in front + of this part select. */ if (ivl_signal_dimensions(sig) > 0) { ivl_expr_t ix = ivl_expr_oper1(sube); - if (!number_is_immediate(ix, 8*sizeof(unsigned long))) + if (ivl_signal_type(sig)==IVL_SIT_REG + || !number_is_immediate(ix, 8*sizeof(unsigned long))) return draw_select_array(sube, bit_idx, bit_wid, wid); /* The index is constant, so we can return to direct From 96ec4b7ebac469d776f8e184d6685bb52980341c Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 19 May 2008 17:37:23 -0700 Subject: [PATCH 09/17] Fix array inputs to mux devices. The draw_input_from_net function was being used to access words of a var array, which doesn't work. Have the draw_input_from_net punt on that case, and by the way the mux inputs don't need to use that function, instead they should use the general draw_net_input function to get the input labels. --- tgt-vvp/draw_mux.c | 10 +++++++--- tgt-vvp/vvp_scope.c | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index 73cb075f6..019ef32b7 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -57,10 +57,14 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz) get_number_immediate(d_rise), net); } + const char* input[3]; + input[0] = draw_net_input(ivl_lpm_data(net,0)); + input[1] = draw_net_input(ivl_lpm_data(net,1)); + input[2] = draw_net_input(ivl_lpm_select(net)); fprintf(vvp_out, "L_%p%s .functor %s %u", net, dly, muxz, width); - fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_data(net,0))); - fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_data(net,1))); - fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_select(net))); + fprintf(vvp_out, ", %s", input[0]); + fprintf(vvp_out, ", %s", input[1]); + fprintf(vvp_out, ", %s", input[2]); fprintf(vvp_out, ", C4<>;\n"); } diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 7b92a343b..e3ff3e77c 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -994,6 +994,8 @@ const char*draw_input_from_net(ivl_nexus_t nex) ivl_signal_t sig = signal_of_nexus(nex, &word); if (sig == 0) return draw_net_input(nex); + if (ivl_signal_type(sig)==IVL_SIT_REG && ivl_signal_dimensions(sig)>0) + return draw_net_input(nex); snprintf(result, sizeof result, "v%p_%u", sig, word); return result; From 3189efacbca4ce65ba672bab7abe8a7b2bf8a7e1 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 19 May 2008 18:05:27 -0700 Subject: [PATCH 10/17] Fix memory word offset errors Fix handling writing to a word part select, Fix readmemb calculations for the word size. --- vpi/sys_readmem.c | 2 +- vvp/array.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vpi/sys_readmem.c b/vpi/sys_readmem.c index 7c120772d..a1a252f38 100644 --- a/vpi/sys_readmem.c +++ b/vpi/sys_readmem.c @@ -282,7 +282,7 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name) } } - item = vpi_handle_by_index(mitem,0); + item = vpi_handle_by_index(mitem,min_addr); wwid = vpi_get(vpiSize, item); /* variable that will be uses by the lexer to pass values diff --git a/vvp/array.cc b/vvp/array.cc index c76e2db41..683b0c7c3 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -401,7 +401,7 @@ void array_set_word(vvp_array_t arr, if (arr->vals) { assert(arr->nets == 0); - if (part_off != 0) { + if (part_off != 0 || val.size() != arr->vals_width) { if (arr->vals[address].size() == 0) arr->vals[address] = vvp_vector4_t(arr->vals_width, BIT4_X); if ((part_off + val.size()) > arr->vals[address].size()) { From 4c3d764a86c8cd74540d0b16f24b50d43e538f35 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 19 May 2008 19:04:42 -0700 Subject: [PATCH 11/17] Add support for array iterator scan. With the array vals_words method of getting compact vpiHandles to words of a var array, it becomes easy to support the array iterators. --- vvp/array.cc | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index 683b0c7c3..e644c8904 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -311,7 +311,8 @@ static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value) unsigned index = decode_array_word_pointer(obj, parent); - assert(0); + vpip_vec4_get_value(parent->vals[index], parent->vals_width, + false, value); } static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags) @@ -338,11 +339,18 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int) return 0; } - assert(obj->array->nets != 0); - - vpiHandle res = obj->array->nets[obj->next]; + unsigned use_index = obj->next; obj->next += 1; - return res; + + if (obj->array->nets) + return obj->array->nets[obj->next]; + + assert(obj->array->vals); + + if (obj->array->vals_words == 0) + array_make_vals_words(obj->array); + + return &(obj->array->vals_words[use_index].base); } static int array_iterator_free_object(vpiHandle ref) From d71a1cb9c103eb473f6a107086de12ed30ffc1dd Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 20 May 2008 11:51:17 -0700 Subject: [PATCH 12/17] Fix non-blocking assign to part select of memory word. Memory words may have part selects assigned, but the code messed up the testing for the validity of the part select base. This fixes do detect constant bases so that base validity tests are handled at compile time. --- tgt-vvp/vvp_process.c | 70 +++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index af93740ce..f104175e1 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -220,44 +220,70 @@ static void set_to_lvariable(ivl_lval_t lval, static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix, unsigned bit, unsigned delay, ivl_expr_t dexp, - unsigned width) + ivl_expr_t part_off_ex, unsigned width) { unsigned skip_assign = transient_id++; + unsigned part_off = 0; + if (part_off_ex == 0) { + part_off = 0; + } else if (number_is_immediate(part_off_ex, 64)) { + part_off = get_number_immediate(part_off_ex); + part_off_ex = 0; + } + if (dexp == 0) { /* Constant delay... */ - /* Calculate array word index into index register 3 */ - draw_eval_expr_into_integer(word_ix, 3); - /* Skip assignment if word expression is not defined. */ - fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); - + if (number_is_immediate(word_ix, 64)) { + fprintf(vvp_out, " %%ix/load 3, %lu; address\n", + get_number_immediate(word_ix)); + } else { + /* Calculate array word index into index register 3 */ + draw_eval_expr_into_integer(word_ix, 3); + /* Skip assignment if word expression is not defined. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + } /* Store expression width into index word 0 */ - fprintf(vvp_out, " %%ix/load 0, %u; // word width\n", width); - /* Store constant (0) word part select into index 1 */ - fprintf(vvp_out, " %%ix/load 1, 0;\n"); - + fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width); + if (part_off_ex) { + draw_eval_expr_into_integer(part_off_ex, 1); + /* If the index expression has XZ bits, skip the assign. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + } else { + /* Store word part select base into index 1 */ + fprintf(vvp_out, " %%ix/load 1, %u; part base\n", part_off); + } fprintf(vvp_out, " %%assign/av v%p, %u, %u;\n", lsig, delay, bit); - fprintf(vvp_out, "t_%u ;\n", skip_assign); } else { /* Calculated delay... */ int delay_index = allocate_word(); draw_eval_expr_into_integer(dexp, delay_index); - /* Calculate array word index into index register 3 */ - draw_eval_expr_into_integer(word_ix, 3); - /* Skip assignment if word expression is not defined. */ - fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); - + if (number_is_immediate(word_ix, 64)) { + fprintf(vvp_out, " %%ix/load 3, %lu; address\n", + get_number_immediate(word_ix)); + } else { + /* Calculate array word index into index register 3 */ + draw_eval_expr_into_integer(word_ix, 3); + /* Skip assignment if word expression is not defined. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + } /* Store expression width into index word 0 */ - fprintf(vvp_out, " %%ix/load 0, %u; // word width\n", width); - /* Store constant (0) word part select into index 1 */ - fprintf(vvp_out, " %%ix/load 1, 0;\n"); - + fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width); + if (part_off_ex) { + draw_eval_expr_into_integer(part_off_ex, 1); + /* If the index expression has XZ bits, skip the assign. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + } else { + /* Store word part select into index 1 */ + fprintf(vvp_out, " %%ix/load 1, %u; part off\n", part_off); + } fprintf(vvp_out, " %%assign/av/d v%p, %d, %u;\n", lsig, delay_index, bit); - fprintf(vvp_out, "t_%u ;\n", skip_assign); } + fprintf(vvp_out, "t_%u ;\n", skip_assign); + clear_expression_lookaside(); } @@ -274,7 +300,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, if (ivl_signal_array_count(sig) > 1) { assert(word_ix); - assign_to_array_word(sig, word_ix, bit, delay, dexp, width); + assign_to_array_word(sig, word_ix, bit, delay, dexp, part_off_ex, width); return; } From 2dcb1514a21ca31437f35b98ec7a532c784a6b2e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 20 May 2008 16:21:54 -0700 Subject: [PATCH 13/17] Add support for passing array words to system tasks. Array words don't have a vpiHandle with a label, so the %vpi_call needs a special syntac for arguments that reference array words. This syntax creates an array word reference that persists and can be used at a VPI object by system tasks. --- tgt-vvp/draw_vpi.c | 240 ++++++++++++++++++++------------------------- vvp/array.cc | 88 +++++++++++++++++ vvp/lexor.lex | 1 + vvp/parse.y | 64 ++++++------ vvp/vpi_priv.h | 2 + 5 files changed, 229 insertions(+), 166 deletions(-) diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index f7508e71a..b233e66f6 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -72,9 +72,14 @@ static void draw_vpi_taskfunc_args(const char*call_string, unsigned parm_count = tnet ? ivl_stmt_parm_count(tnet) : ivl_expr_parms(fnet); - struct vector_info *vec = 0x0; - unsigned int vecs= 0; - unsigned int veci= 0; + + struct args_info { + char*text; + int vec_flag; /* True if the vec must be released. */ + struct vector_info vec; + } *args = calloc(parm_count, sizeof(struct args_info)); + + char buffer[4096]; ivl_parameter_t par; @@ -92,17 +97,56 @@ static void draw_vpi_taskfunc_args(const char*call_string, with VPI handles of their own. Therefore, skip them in the process of evaluating expressions. */ case IVL_EX_NONE: + args[idx].text = strdup("\" \""); + continue; + case IVL_EX_ARRAY: - case IVL_EX_NUMBER: + snprintf(buffer, sizeof buffer, + "v%p", ivl_expr_signal(expr)); + args[idx].text = strdup(buffer); + continue; + + case IVL_EX_NUMBER: { + unsigned bit, wid = ivl_expr_width(expr); + const char*bits = ivl_expr_bits(expr); + char*dp; + + snprintf(buffer, sizeof buffer, + "%u'%sb", wid, ivl_expr_signed(expr)? "s" : ""); + dp = buffer + strlen(buffer); + for (bit = wid ; bit > 0 ; bit -= 1) + *dp++ = bits[bit-1]; + *dp++ = 0; + assert(dp - buffer <= sizeof buffer); + args[idx].text = strdup(buffer); + continue; + } + case IVL_EX_STRING: + if (( par = ivl_expr_parameter(expr) )) { + snprintf(buffer, sizeof buffer, "P_%p", par); + + } else { + snprintf(buffer, sizeof buffer, "\"%s\"", ivl_expr_string(expr)); + } + args[idx].text = strdup(buffer); + continue; + case IVL_EX_EVENT: + snprintf(buffer, sizeof buffer, "E_%p", ivl_expr_event(expr)); + args[idx].text = strdup(buffer); + continue; case IVL_EX_SCOPE: + snprintf(buffer, sizeof buffer, "S_%p", ivl_expr_scope(expr)); + args[idx].text = strdup(buffer); continue; case IVL_EX_SFUNC: - if (is_magic_sfunc(ivl_expr_name(expr))) + if (is_magic_sfunc(ivl_expr_name(expr))) { + snprintf(buffer, sizeof buffer, "%s", ivl_expr_name(expr)); + args[idx].text = strdup(buffer); continue; - + } break; case IVL_EX_SIGNAL: @@ -125,21 +169,47 @@ static void draw_vpi_taskfunc_args(const char*call_string, } else if (ivl_expr_signed(expr) != ivl_signal_signed(ivl_expr_signal(expr))) { break; - } else if (! is_fixed_memory_word(expr)){ - break; - } else { - /* Some array selects need to be evaluated. */ + } else if (is_fixed_memory_word(expr)) { + /* This is a word of a non-array, or a word + of a net array, so we can address the + word directly. */ + ivl_signal_t sig = ivl_expr_signal(expr); + unsigned use_word = 0; ivl_expr_t word_ex = ivl_expr_oper1(expr); - if (word_ex && !number_is_immediate(word_ex, - 8*sizeof(unsigned))) { - break; + if (word_ex) { + /* Some array select have been evaluated. */ + if (number_is_immediate(word_ex, 8*sizeof(unsigned))) { + use_word = get_number_immediate(word_ex); + word_ex = 0; + } } + if (word_ex) + break; + + assert(word_ex == 0); + snprintf(buffer, sizeof buffer, "v%p_%u", sig, use_word); + args[idx].text = strdup(buffer); continue; - } + } else { + /* What's left, this is the work of a var + array. Create the right code to handle + it. */ + ivl_signal_t sig = ivl_expr_signal(expr); + unsigned use_word = 0; + ivl_expr_t word_ex = ivl_expr_oper1(expr); + if (word_ex) { + /* Some array select have been evaluated. */ + if (number_is_immediate(word_ex, 8*sizeof(unsigned))) { + use_word = get_number_immediate(word_ex); + word_ex = 0; + } + } + if (word_ex) + break; - case IVL_EX_MEMORY: - if (!ivl_expr_oper1(expr)) { + snprintf(buffer, sizeof buffer, "&A", sig, use_word); + args[idx].text = strdup(buffer); continue; } @@ -149,143 +219,43 @@ static void draw_vpi_taskfunc_args(const char*call_string, break; } - vec = (struct vector_info *) - realloc(vec, (vecs+1)*sizeof(struct vector_info)); - switch (ivl_expr_value(expr)) { case IVL_VT_LOGIC: case IVL_VT_BOOL: - vec[vecs] = draw_eval_expr(expr, 0); + args[idx].vec_flag = 1; + args[idx].vec = draw_eval_expr(expr, 0); + snprintf(buffer, sizeof buffer, + "T<%u,%u,%s>", args[idx].vec.base, args[idx].vec.wid, + ivl_expr_signed(expr)? "s" : "u"); break; case IVL_VT_REAL: - vec[vecs].base = draw_eval_real(expr); - vec[vecs].wid = 0; + args[idx].vec_flag = 1; + args[idx].vec.base = draw_eval_real(expr); + args[idx].vec.wid = 0; + snprintf(buffer, sizeof buffer, + "W<%u,r>", args[idx].vec.base); break; default: assert(0); } - vecs++; + args[idx].text = strdup(buffer); } fprintf(vvp_out, "%s", call_string); for (idx = 0 ; idx < parm_count ; idx += 1) { - ivl_expr_t expr = tnet - ? ivl_stmt_parm(tnet, idx) - : ivl_expr_parm(fnet, idx); - switch (ivl_expr_type(expr)) { - case IVL_EX_NONE: - fprintf(vvp_out, ", \" \""); - continue; - - case IVL_EX_ARRAY: - fprintf(vvp_out, ", v%p", ivl_expr_signal(expr)); - continue; - - case IVL_EX_NUMBER: { - unsigned bit, wid = ivl_expr_width(expr); - const char*bits = ivl_expr_bits(expr); - - fprintf(vvp_out, ", %u'%sb", wid, - ivl_expr_signed(expr)? "s" : ""); - for (bit = wid ; bit > 0 ; bit -= 1) - fputc(bits[bit-1], vvp_out); - continue; - } - - case IVL_EX_SIGNAL: - /* If this is a part select, then the value was - calculated above. Otherwise, just pass the - signal. */ - if (ivl_expr_width(expr) != - ivl_signal_width(ivl_expr_signal(expr))) { - break; - - } else if (ivl_expr_signed(expr) != - ivl_signal_signed(ivl_expr_signal(expr))) { - break; - - } else if (! is_fixed_memory_word(expr)){ - break; - - } else { - ivl_signal_t sig = ivl_expr_signal(expr); - unsigned use_word = 0; - ivl_expr_t word_ex = ivl_expr_oper1(expr); - if (word_ex) { - /* Some array select have been evaluated. */ - if (!number_is_immediate(word_ex, - 8*sizeof(unsigned))) { - break; - } - use_word = get_number_immediate(word_ex); - } - fprintf(vvp_out, ", v%p_%u", sig, use_word); - continue; - } - assert(0); - continue; - - case IVL_EX_STRING: - if (( par = ivl_expr_parameter(expr) )) { - fprintf(vvp_out, ", P_%p", par); - - } else { - fprintf(vvp_out, ", \"%s\"", - ivl_expr_string(expr)); - } - continue; - - case IVL_EX_EVENT: - fprintf(vvp_out, ", E_%p", ivl_expr_event(expr)); - continue; - - case IVL_EX_SCOPE: - fprintf(vvp_out, ", S_%p", ivl_expr_scope(expr)); - continue; - - case IVL_EX_SFUNC: - if (is_magic_sfunc(ivl_expr_name(expr))) { - fprintf(vvp_out, ", %s", ivl_expr_name(expr)); - continue; - } - break; - - default: - break; + fprintf(vvp_out, ", %s", args[idx].text); + free(args[idx].text); + if (args[idx].vec_flag) { + if (args[idx].vec.wid > 0) + clr_vector(args[idx].vec); + else + clr_word(args[idx].vec.base); } - assert(veci < vecs); - - switch (ivl_expr_value(expr)) { - - case IVL_VT_LOGIC: - case IVL_VT_BOOL: - fprintf(vvp_out, ", T<%u,%u,%s>", vec[veci].base, - vec[veci].wid, ivl_expr_signed(expr)? "s" : "u"); - break; - - case IVL_VT_REAL: - fprintf(vvp_out, ", W<%u,r>", vec[veci].base); - break; - - default: - assert(0); - } - veci++; } - assert(veci == vecs); - - if (vecs) { - for (idx = 0; idx < vecs; idx++) { - if (vec[idx].wid > 0) - clr_vector(vec[idx]); - else if (vec[idx].wid == 0) - clr_word(vec[idx].base); - } - free(vec); - } + free(args); fprintf(vvp_out, ";\n"); } diff --git a/vvp/array.cc b/vvp/array.cc index e644c8904..8341c218c 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -77,6 +77,12 @@ struct __vpiArrayIndex { unsigned done; }; +struct __vpiArrayVthrA { + struct __vpiHandle base; + struct __vpiArray*array; + unsigned address; +}; + /* * 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 @@ -117,6 +123,10 @@ 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 int vpi_array_vthr_A_get(int code, vpiHandle); +static void vpi_array_vthr_A_get_value(vpiHandle, p_vpi_value); +static vpiHandle vpi_array_vthr_A_put_value(vpiHandle, p_vpi_value, int); + static const struct __vpirt vpip_arraymem_rt = { vpiMemory, vpi_array_get, @@ -167,12 +177,27 @@ static const struct __vpirt vpip_array_var_word_rt = { 0 }; +static const struct __vpirt vpip_array_vthr_A_rt = { + vpiMemoryWord, + &vpi_array_vthr_A_get, + 0, + &vpi_array_vthr_A_get_value, + &vpi_array_vthr_A_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) +# define ARRAY_VTHR_A_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemoryWord), \ + (struct __vpiArrayVthrA*)ref) + static void array_make_vals_words(struct __vpiArray*parent) { assert(parent->vals_words == 0); @@ -399,6 +424,53 @@ static int array_index_free_object(vpiHandle ref) return 1; } +static int vpi_array_vthr_A_get(int code, vpiHandle ref) +{ + struct __vpiArrayVthrA*obj = ARRAY_VTHR_A_HANDLE(ref); + struct __vpiArray*parent = obj->array; + + switch (code) { + case vpiLineNo: + return 0; // Not implemented for now! + + case vpiSize: + assert(parent->vals); + return parent->vals_width; + + default: + return 0; + } +} +static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value) +{ + struct __vpiArrayVthrA*obj = ARRAY_VTHR_A_HANDLE(ref); + struct __vpiArray*parent = obj->array; + + assert(parent); + assert(parent->vals); + assert(obj->address < parent->array_count); + + vpip_vec4_get_value(parent->vals[obj->address], + parent->vals_width, false, value); +} + +static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int) +{ + struct __vpiArrayVthrA*obj = ARRAY_VTHR_A_HANDLE(ref); + struct __vpiArray*parent = obj->array; + + unsigned index = obj->address; + + assert(parent); + assert(obj->address < parent->array_count); + + vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width); + array_set_word(parent, index, 0, val); + + return ref; +} + + void array_set_word(vvp_array_t arr, unsigned address, unsigned part_off, @@ -773,3 +845,19 @@ void compile_array_alias(char*label, char*name, char*src) free(name); free(src); } + +vpiHandle vpip_make_vthr_A(char*label, unsigned addr) +{ + struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) + malloc(sizeof (struct __vpiArrayVthrA)); + + obj->base.vpi_type = &vpip_array_vthr_A_rt; + + obj->array = array_find(label); + assert(obj->array); + + obj->address = addr; + assert(addr < obj->array->array_count); + + return &(obj->base); +} diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 46032abc5..fb0d919be 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -190,6 +190,7 @@ return T_NUMBER; } +"&A" { return K_A; } /* Handle some specialized constant/literals as symbols. */ diff --git a/vvp/parse.y b/vvp/parse.y index 8e577fd01..28e75b296 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -65,7 +65,7 @@ static struct __vpiModPath*modpath_dst = 0; vvp_delay_t*cdelay; }; -%token K_ALIAS K_ALIAS_S K_ALIAS_R +%token K_A K_ALIAS K_ALIAS_S K_ALIAS_R %token K_ARITH_ABS K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD %token K_ARITH_MOD_R %token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R @@ -766,38 +766,40 @@ argument_opt ; argument_list - : argument - { struct argv_s tmp; - argv_init(&tmp); - argv_add(&tmp, $1); - $$ = tmp; - } - | argument_list ',' argument - { struct argv_s tmp = $1; - argv_add(&tmp, $3); - $$ = tmp; - } - | T_SYMBOL - { struct argv_s tmp; - argv_init(&tmp); - argv_sym_add(&tmp, $1); - $$ = tmp; - } - | argument_list ',' T_SYMBOL - { struct argv_s tmp = $1; - argv_sym_add(&tmp, $3); - $$ = tmp; - } - ; + : argument + { struct argv_s tmp; + argv_init(&tmp); + argv_add(&tmp, $1); + $$ = tmp; + } + | argument_list ',' argument + { struct argv_s tmp = $1; + argv_add(&tmp, $3); + $$ = tmp; + } + | T_SYMBOL + { struct argv_s tmp; + argv_init(&tmp); + argv_sym_add(&tmp, $1); + $$ = tmp; + } + | argument_list ',' T_SYMBOL + { struct argv_s tmp = $1; + argv_sym_add(&tmp, $3); + $$ = tmp; + } + ; argument - : T_STRING - { $$ = vpip_make_string_const($1); } - | T_VECTOR - { $$ = vpip_make_binary_const($1.idx, $1.text); - free($1.text); - } - ; + : T_STRING + { $$ = vpip_make_string_const($1); } + | T_VECTOR + { $$ = vpip_make_binary_const($1.idx, $1.text); + free($1.text); + } + | K_A '<' T_SYMBOL ',' T_NUMBER '>' + { $$ = vpip_make_vthr_A($3, $5); } + ; /* functor operands can only be a list of symbols. */ diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 8c95673e0..8da38a0c4 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -433,6 +433,8 @@ vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag); vpiHandle vpip_make_vthr_word(unsigned base, const char*type); +vpiHandle vpip_make_vthr_A(char*symbol, unsigned index); + /* * This function is called before any compilation to load VPI * modules. This gives the modules a chance to announce their From 007056d671dd8b5d7eb01c17a726d2b1734ec2fe Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 20 May 2008 16:57:50 -0700 Subject: [PATCH 14/17] Remove last vestiges of the the .mem structures. Before the .array support, we had .mem nodes. These are long since removed because the arrays to all the jobs of the .mem nodes. --- vvp/Makefile.in | 4 +- vvp/codes.h | 3 - vvp/compile.cc | 131 ------------- vvp/compile.h | 8 - vvp/lexor.lex | 3 - vvp/memory.cc | 299 ----------------------------- vvp/memory.h | 180 ------------------ vvp/parse.y | 22 --- vvp/schedule.cc | 29 --- vvp/schedule.h | 6 - vvp/vpi_callback.cc | 4 - vvp/vpi_memory.cc | 449 -------------------------------------------- vvp/vpi_priv.h | 7 - vvp/vthread.cc | 73 ------- 14 files changed, 2 insertions(+), 1216 deletions(-) delete mode 100644 vvp/memory.cc delete mode 100644 vvp/memory.h delete mode 100644 vvp/vpi_memory.cc diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 65cab97f4..ac5cc9bd8 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -70,14 +70,14 @@ check: all V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \ vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_tasks.o vpi_time.o \ -vpi_memory.o vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.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 \ concat.o \ dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \ ufunc.o codes.o \ -vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o memory.o \ +vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o \ event.o logic.o delay.o words.o $V ifeq (@WIN32@,yes) diff --git a/vvp/codes.h b/vvp/codes.h index cb033f16f..0e93f72de 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -97,7 +97,6 @@ extern bool of_JOIN(vthread_t thr, vvp_code_t code); extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code); extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code); extern bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t code); -extern bool of_LOAD_MV(vthread_t thr, vvp_code_t code); extern bool of_LOAD_NX(vthread_t thr, vvp_code_t code); extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code); extern bool of_LOAD_VP0(vthread_t thr, vvp_code_t code); @@ -127,7 +126,6 @@ extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code); extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code); extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code); extern bool of_SET_AV(vthread_t thr, vvp_code_t code); -extern bool of_SET_MV(vthread_t thr, vvp_code_t code); extern bool of_SET_VEC(vthread_t thr, vvp_code_t code); extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code); extern bool of_SET_X0(vthread_t thr, vvp_code_t code); @@ -162,7 +160,6 @@ struct vvp_code_s { unsigned long number; vvp_net_t *net; vvp_code_t cptr; - vvp_memory_t mem; vvp_array_t array; struct __vpiHandle*handle; struct __vpiScope*scope; diff --git a/vvp/compile.cc b/vvp/compile.cc index fe9c82f82..d2e1c96d8 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -22,7 +22,6 @@ # include "logic.h" # include "resolv.h" # include "udp.h" -# include "memory.h" # include "symbols.h" # include "codes.h" # include "schedule.h" @@ -67,8 +66,6 @@ enum operand_e { OA_FUNC_PTR, /* The operand is a second functor pointer */ OA_FUNC_PTR2, - /* The operand is a pointer to a memory */ - OA_MEM_PTR, /* The operand is a VPI handle */ OA_VPI_PTR, }; @@ -90,7 +87,6 @@ const static struct opcode_table_s opcode_table[] = { { "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} }, { "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} }, - { "%assign/mv",of_ASSIGN_MV,3,{OA_MEM_PTR,OA_BIT1, OA_BIT2} }, { "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%assign/v0/d",of_ASSIGN_V0D,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, @@ -144,7 +140,6 @@ const static struct opcode_table_s opcode_table[] = { { "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} }, { "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} }, { "%load/avx.p",of_LOAD_AVX_P,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} }, - { "%load/mv",of_LOAD_MV,3, {OA_BIT1, OA_MEM_PTR, OA_BIT2} }, { "%load/nx",of_LOAD_NX,3, {OA_BIT1, OA_VPI_PTR, OA_BIT2} }, { "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} }, { "%load/vp0",of_LOAD_VP0,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} }, @@ -174,7 +169,6 @@ const static struct opcode_table_s opcode_table[] = { { "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} }, { "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} }, - { "%set/mv", of_SET_MV, 3, {OA_MEM_PTR, OA_BIT1, OA_BIT2} }, { "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, { "%set/wr", of_SET_WORDR,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} }, { "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, @@ -551,38 +545,6 @@ void code_label_lookup(struct vvp_code_s *code, char *label) resolv_submit(res); } -/* - * Lookup memories. - */ -struct memory_resolv_list_s: public resolv_list_s { - memory_resolv_list_s(char*label) : resolv_list_s(label) { } - struct vvp_code_s *code; - virtual bool resolve(bool mes); -}; - -bool memory_resolv_list_s::resolve(bool mes) -{ - code->mem = memory_find(label()); - if (code->mem != 0) { - return true; - } - - if (mes) - fprintf(stderr, "Memory unresolved: %s\n", label()); - - return false; -} - -static void compile_mem_lookup(struct vvp_code_s *code, char *label) -{ - struct memory_resolv_list_s *res - = new struct memory_resolv_list_s(label); - - res->code = code; - - resolv_submit(res); -} - struct code_array_resolv_list_s: public resolv_list_s { code_array_resolv_list_s(char*label) : resolv_list_s(label) { } struct vvp_code_s *code; @@ -1504,90 +1466,6 @@ char **compile_udp_table(char **table, char *row) return table; } -/* - * Take the detailed parse items from a .mem statement and generate - * the necessary internal structures. - * - *