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);