From 6cac1d2cab693687f071d34809ce1edfb7c9b368 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 1 Nov 2008 20:44:03 -0700 Subject: [PATCH] Add support for real/realtime arrays. Support arrays of realtime variable arrays and net arrays. This involved a simple fix to the ivl core parser, proper support in the code generator, and rework the runtime support in vvp. --- parse.y | 8 +++- tgt-vvp/eval_real.c | 22 ++++----- tgt-vvp/vvp_process.c | 20 ++++++-- vvp/array.cc | 108 +++++++++++++++++++++++++++++++----------- vvp/array.h | 9 ++-- vvp/codes.h | 2 + vvp/compile.cc | 3 +- vvp/opcodes.txt | 20 ++++++-- vvp/vpi_priv.h | 1 + vvp/vpi_real.cc | 11 ++++- vvp/vthread.cc | 32 +++++++++++++ vvp/vvp_net.cc | 26 ++++++++++ vvp/vvp_net.h | 20 ++++++++ vvp/words.cc | 2 + 14 files changed, 229 insertions(+), 55 deletions(-) diff --git a/parse.y b/parse.y index a860fdcce..ee84a9c8e 100644 --- a/parse.y +++ b/parse.y @@ -2978,7 +2978,13 @@ real_variable { perm_string name = lex_strings.make($1); pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); if ($2 != 0) { - yyerror(@2, "sorry: real variables do not currently support arrays."); + index_component_t index; + if ($2->size() > 1) { + yyerror(@2, "sorry: only 1 dimensional arrays " + "are currently supported."); + } + index = $2->front(); + pform_set_reg_idx(name, index.msb, index.lsb); delete $2; } $$ = $1; diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index de9ce577e..f2b577ba1 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -354,23 +354,17 @@ static int draw_signal_real_real(ivl_expr_t exp) { ivl_signal_t sig = ivl_expr_signal(exp); int res = allocate_word(); - unsigned long word = 0; - if (ivl_signal_dimensions(sig) > 0) { - ivl_expr_t ix = ivl_expr_oper1(exp); - if (!number_is_immediate(ix, IMM_WID, 0)) { - /* XXXX Need to generate a %load/ar instruction. */ - assert(0); - return res; - } - - /* The index is constant, so we can return to direct - readout with the specific word selected. */ - word = get_number_immediate(ix); + if (ivl_signal_dimensions(sig) == 0) { + fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, sig); + return res; } - fprintf(vvp_out, " %%load/wr %d, v%p_%lu;\n", res, sig, word); - + ivl_expr_t word_ex = ivl_expr_oper1(exp); + int word_ix = allocate_word(); + draw_eval_expr_into_integer(word_ex, word_ix); + fprintf(vvp_out, " %%load/ar %d, v%p, %d;\n", res, sig, word_ix); + clr_word(word_ix); return res; } diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 1d643454f..eacf35547 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -497,16 +497,30 @@ static int show_stmt_assign_sig_real(ivl_statement_t net) ivl_signal_t var; res = draw_eval_real(ivl_stmt_rval(net)); - clr_word(res); assert(ivl_stmt_lvals(net) == 1); lval = ivl_stmt_lval(net, 0); var = ivl_lval_sig(lval); assert(var != 0); - assert(ivl_signal_dimensions(var) == 0); + if (ivl_signal_dimensions(var) == 0) { + clr_word(res); + fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res); + return 0; + } - fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res); + // For now, only support 1-dimensional arrays. + assert(ivl_signal_dimensions(var) == 1); + + // Calculate the word index into an index register + ivl_expr_t word_ex = ivl_lval_idx(lval); + int word_ix = allocate_word(); + draw_eval_expr_into_integer(word_ex, word_ix); + // Generate an assignment to write to the array. + fprintf(vvp_out, " %%set/ar v%p, %d, %d;\n", var, word_ix, res); + + clr_word(res); + clr_word(word_ix); return 0; } diff --git a/vvp/array.cc b/vvp/array.cc index defaddffb..0cd51b5ff 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -53,7 +53,28 @@ vvp_array_t array_find(const char*label) /* * The vpiArray object holds an array of vpi objects that themselves -* represent the words of the array. The vpi_array_t is a pointer to this. +* represent the words of the array. The vpi_array_t is a pointer to +* a struct __vpiArray. +* +* The details of the implementation depends on what this is an array +* of. The easiest case is if this is an array of nets. +* +* - Array of Nets: +* If this represents an array of nets, then the nets member points to +* an array of vpiHandle objects. Each vpiHandle is a word. This is +* done because typically each word of a net array is simultaneously +* driven and accessed by other means, so there is no advantage to +* compacting the array in any other way. +* +* - Array of vector4 words. +* In this case, the nets pointer is nil, and the vals4 member points +* to a vvl_vector4array_t object that is a compact representation of +* an array of vvp_vector4_t vectors. +* +* - Array of real variables +* The valsr member points to a vvp_realarray_t objects that has an +* array of double variables. This is very much line the way the +* vector4 array works. */ struct __vpiArray { __vpiArray() { } @@ -70,7 +91,8 @@ struct __vpiArray { // If this is a net array, nets lists the handles. vpiHandle*nets; // If this is a var array, then these are used instead of nets. - vvp_vector4array_t *vals; + vvp_vector4array_t *vals4; + vvp_realarray_t *valsr; struct __vpiArrayWord*vals_words; class vvp_fun_arrayport*ports_; @@ -127,7 +149,7 @@ struct __vpiArrayVthrA { /* Get the array word size. This has only been checked for reg arrays. */ unsigned get_array_word_size(vvp_array_t array) { - assert(array->vals); + assert(array->vals4); return array->vals_width; } @@ -424,7 +446,7 @@ static int vpi_array_var_word_get(int code, vpiHandle ref) switch (code) { case vpiSize: - return (int) parent->vals->width(); + return (int) parent->vals4->width(); case vpiLeftRange: return parent->msb.value; @@ -461,9 +483,9 @@ static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value) assert(obj); unsigned index = decode_array_word_pointer(obj, parent); - unsigned width = parent->vals->width(); + unsigned width = parent->vals4->width(); - vpip_vec4_get_value(parent->vals->get_word(index), width, + vpip_vec4_get_value(parent->vals4->get_word(index), width, parent->signed_flag, value); } @@ -539,7 +561,7 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int) if (obj->array->nets) return obj->array->nets[obj->next]; - assert(obj->array->vals); + assert(obj->array->vals4); if (obj->array->vals_words == 0) array_make_vals_words(obj->array); @@ -702,10 +724,10 @@ void array_set_word(vvp_array_t arr, if (address >= arr->array_count) return; - if (arr->vals) { + if (arr->vals4) { assert(arr->nets == 0); if (part_off != 0 || val.size() != arr->vals_width) { - vvp_vector4_t tmp = arr->vals->get_word(address); + vvp_vector4_t tmp = arr->vals4->get_word(address); if ((part_off + val.size()) > tmp.size()) { cerr << "part_off=" << part_off << " val.size()=" << val.size() @@ -714,9 +736,9 @@ void array_set_word(vvp_array_t arr, assert(0); } tmp.set_vec(part_off, val); - arr->vals->set_word(address, tmp); + arr->vals4->set_word(address, tmp); } else { - arr->vals->set_word(address, val); + arr->vals4->set_word(address, val); } array_word_change(arr, address); return; @@ -734,15 +756,22 @@ void array_set_word(vvp_array_t arr, array_word_change(arr, address); } +void array_set_word(vvp_array_t arr, unsigned address, double val) +{ + assert(arr->valsr!= 0); + assert(arr->nets == 0); + + arr->valsr->set_word(address, val); +} + vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) { - if (arr->vals) { + if (arr->vals4) { assert(arr->nets == 0); - - return arr->vals->get_word(address); + return arr->vals4->get_word(address); } - assert(arr->vals == 0); + assert(arr->vals4 == 0); assert(arr->nets != 0); if (address >= arr->array_count) { @@ -767,6 +796,26 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) return val; } +double array_get_word_r(vvp_array_t arr, unsigned address) +{ + if (arr->valsr) { + assert(arr->vals4 == 0); + assert(arr->nets == 0); + return arr->valsr->get_word(address); + } + + assert(arr->nets); + vpiHandle word = arr->nets[address]; + struct __vpiRealVar*vsig = vpip_realvar_from_handle(word); + assert(vsig); + vvp_fun_signal_real*sig = dynamic_cast (vsig->net->fun); + assert(sig); + + double val = sig->real_value(); + return val; + +} + static vpiHandle vpip_make_array(char*label, const char*name, int first_addr, int last_addr, bool signed_flag) @@ -792,7 +841,8 @@ static vpiHandle vpip_make_array(char*label, const char*name, // Start off now knowing if we are nets or variables. obj->nets = 0; - obj->vals = 0; + obj->vals4 = 0; + obj->valsr = 0; obj->vals_width = 0; vpip_make_dec_const(&obj->msb, 0); vpip_make_dec_const(&obj->lsb, 0); @@ -869,11 +919,11 @@ void compile_var_array(char*label, char*name, int last, int first, /* Make the words. */ arr->vals_width = labs(msb-lsb) + 1; if (vpip_peek_current_scope()->is_automatic) { - arr->vals = new vvp_vector4array_aa(arr->vals_width, - arr->array_count); + arr->vals4 = new vvp_vector4array_aa(arr->vals_width, + arr->array_count); } else { - arr->vals = new vvp_vector4array_sa(arr->vals_width, - arr->array_count); + arr->vals4 = new vvp_vector4array_sa(arr->vals_width, + arr->array_count); } vpip_make_dec_const(&arr->msb, msb); vpip_make_dec_const(&arr->lsb, lsb); @@ -891,14 +941,16 @@ void compile_real_array(char*label, char*name, int last, int first, vpiHandle obj = vpip_make_array(label, name, first, last, true); 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_varw_real(strdup(buf), array, idx, msb, lsb); - } + arr->valsr = new vvp_realarray_t(arr->array_count); + arr->vals_width = 1; + + /* Do these even make sense for real arrays? These are the + part select of a vector, but the real value is not + vectorable. */ + vpip_make_dec_const(&arr->msb, msb); + vpip_make_dec_const(&arr->lsb, lsb); count_real_arrays += 1; count_real_array_words += arr->array_count; @@ -1146,7 +1198,7 @@ void array_word_change(vvp_array_t array, unsigned long addr) if (cur->cb_data.cb_rtn != 0) { if (cur->cb_data.value) - vpip_vec4_get_value(array->vals->get_word(addr), + vpip_vec4_get_value(array->vals4->get_word(addr), array->vals_width, array->signed_flag, cur->cb_data.value); @@ -1282,7 +1334,7 @@ void compile_array_alias(char*label, char*name, char*src) // Share the words with the source array. obj->nets = mem->nets; - obj->vals = mem->vals; + obj->vals4 = mem->vals4; obj->ports_ = 0; diff --git a/vvp/array.h b/vvp/array.h index 7bac81088..167fc9387 100644 --- a/vvp/array.h +++ b/vvp/array.h @@ -39,12 +39,13 @@ extern void array_attach_word(vvp_array_t array, unsigned long addr, extern void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word); -extern void array_set_word(vvp_array_t arr, - unsigned idx, - unsigned off, - vvp_vector4_t val); +extern void array_set_word(vvp_array_t arr, unsigned idx, + unsigned off, vvp_vector4_t val); +extern void array_set_word(vvp_array_t arr, unsigned idx, + double val); extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned address); +extern double array_get_word_r(vvp_array_t array, unsigned address); /* VPI hooks */ diff --git a/vvp/codes.h b/vvp/codes.h index 769b3a915..0e634a95b 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -107,6 +107,7 @@ extern bool of_JMP0(vthread_t thr, vvp_code_t code); extern bool of_JMP0XZ(vthread_t thr, vvp_code_t code); extern bool of_JMP1(vthread_t thr, vvp_code_t code); extern bool of_JOIN(vthread_t thr, vvp_code_t code); +extern bool of_LOAD_AR(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_AVP0_S(vthread_t thr, vvp_code_t code); @@ -138,6 +139,7 @@ extern bool of_POW_WR(vthread_t thr, vvp_code_t code); 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_AR(vthread_t thr, vvp_code_t code); extern bool of_SET_AV(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); diff --git a/vvp/compile.cc b/vvp/compile.cc index 023b23e2e..75a84311e 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -150,6 +150,7 @@ const static struct opcode_table_s opcode_table[] = { { "%jmp/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} }, { "%jmp/1", of_JMP1, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} }, { "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} }, + { "%load/ar",of_LOAD_AR,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} }, { "%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/avp0/s",of_LOAD_AVP0_S,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} }, @@ -181,11 +182,11 @@ const static struct opcode_table_s opcode_table[] = { { "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%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/ar", of_SET_AR, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} }, { "%set/av", of_SET_AV, 3, {OA_ARR_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_FUNC_PTR, OA_BIT1, OA_NONE} }, { "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, -// { "%set/x0/x",of_SET_X0_X,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, { "%shiftl/i0", of_SHIFTL_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} }, { "%shiftr/i0", of_SHIFTR_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} }, { "%shiftr/s/i0", of_SHIFTR_S_I0,2,{OA_BIT1,OA_NUMBER, OA_NONE} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 1cf47d03c..c9419c405 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -512,9 +512,14 @@ The is, line the %load/v, the result width. But unlike the (%load/vp0/s) to the desired width. * %load/wr , +* %load/ar , , -This instruction reads a real value from the vpi-like object to a word -register. +The %load/wr instruction reads a real value from the vpi-like object +to a word register . + +The %load/ar instruction reads a real value from an array. The +is the index register that contains the canonical word address into +the array. * %load/x1p , , @@ -708,8 +713,17 @@ The address (in canonical form) is precalculated and loaded into index register 3. This is the address of the word within the array. * %set/wr , +* %set/ar , , -This instruction writes a real word to the specified VPI-like object. +The %set/wr instruction writes a real word to the specified VPI-like +object. + +The %set/ar instruction writes a real work to the specified array +word. The addresses the array, and the is the +name of the index register to address into the word. The index +register must contain an integer value that is the canonical address +of the array word. The is the index register that contains the +real value word to write. * %set/x0 , , diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 6b053ad72..a9ffd0369 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -369,6 +369,7 @@ struct __vpiRealVar { extern struct __vpiScope* vpip_scope(__vpiRealVar*sig); extern vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net); +extern struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj); /* * When a loaded VPI module announces a system task/function, one diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index f80e472b6..a0c83d466 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -28,11 +28,20 @@ #endif # include +struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj) +{ + assert(obj); + if (obj->vpi_type->type_code == vpiRealVar) + return (struct __vpiRealVar*)obj; + else + return 0; +} + static int real_var_get(int code, vpiHandle ref) { assert(ref->vpi_type->type_code == vpiRealVar); - struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; + struct __vpiRealVar*rfp = vpip_realvar_from_handle(ref); switch (code) { case vpiArray: diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 65a5a4250..b8e6871f3 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2752,6 +2752,20 @@ bool of_JOIN(vthread_t thr, vvp_code_t cp) return false; } +/* + * %load/ar , , ; +*/ +bool of_LOAD_AR(vthread_t thr, vvp_code_t cp) +{ + unsigned bit = cp->bit_idx[0]; + unsigned idx = cp->bit_idx[1]; + unsigned adr = thr->words[idx].w_int; + + double word = array_get_word_r(cp->array, adr); + thr->words[bit].w_real = word; + return true; +} + /* * %load/av , , ; * @@ -3936,6 +3950,24 @@ bool of_RELEASE_WR(vthread_t thr, vvp_code_t cp) return true; } +/* + * %set/av