diff --git a/design_dump.cc b/design_dump.cc index 3086f1b4b..2a9219f34 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -871,19 +871,18 @@ void NetAlloc::dump(ostream&o, unsigned ind) const void NetAssign_::dump_lval(ostream&o) const { - if (sig_) { - o << sig_->name(); - if (! member_.nil()) { - o << "." << member_; - } - if (word_) { - o << "[word=" << *word_ << "]"; - } - if (base_) { - o << "[" << *base_ << " +: " << lwid_ << "]"; - } - } else { - o << ""; + if (sig_) o << sig_->name(); + else if (nest_) nest_->dump_lval(o); + else o << ""; + + if (! member_.nil()) { + o << "." << member_; + } + if (word_) { + o << "[word=" << *word_ << "]"; + } + if (base_) { + o << "[" << *base_ << " +: " << lwid_ << "]"; } } diff --git a/ivl.def b/ivl.def index 4dc4f3edf..a49849ba7 100644 --- a/ivl.def +++ b/ivl.def @@ -141,6 +141,7 @@ ivl_lpm_width ivl_lval_idx ivl_lval_mux +ivl_lval_nest ivl_lval_part_off ivl_lval_property_idx ivl_lval_sel_type diff --git a/ivl_target.h b/ivl_target.h index fc5a67679..cf5b9b3aa 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1446,6 +1446,10 @@ extern const char*ivl_lpm_string(ivl_lpm_t net); * * ivl_lval_mux (* obsolete *) * + * ivl_lval_nest + * If the l-value is an object more complex than a variable, then + * this returns the nested l-value (and ivl_lval_sig==0). + * * ivl_lval_sig * If the l-value is a variable, this method returns the signal * object that is the target of the assign. @@ -1493,6 +1497,7 @@ extern ivl_expr_t ivl_lval_part_off(ivl_lval_t net); extern ivl_select_type_t ivl_lval_sel_type(ivl_lval_t net); extern int ivl_lval_property_idx(ivl_lval_t net); extern ivl_signal_t ivl_lval_sig(ivl_lval_t net); +extern ivl_lval_t ivl_lval_nest(ivl_lval_t net); /* NEXUS diff --git a/net_assign.cc b/net_assign.cc index a47e9b1f7..2efd91d27 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -225,6 +225,7 @@ perm_string NetAssign_::name() const NetNet* NetAssign_::sig() const { + assert(sig_? nest_==0 : nest_!=0); return sig_; } diff --git a/netlist.h b/netlist.h index d3f31dd1d..78cbb6a5c 100644 --- a/netlist.h +++ b/netlist.h @@ -2594,6 +2594,7 @@ class NetAssign_ { perm_string name() const; NetNet* sig() const; + inline const NetAssign_* nest() const { return nest_; } // Mark that the synthesizer has worked with this l-value, so // when it is released, the l-value signal should be turned diff --git a/t-dll-api.cc b/t-dll-api.cc index 7597878aa..a4189d6d1 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1625,6 +1625,15 @@ extern "C" ivl_signal_t ivl_lval_sig(ivl_lval_t net) } } +extern "C" ivl_lval_t ivl_lval_nest(ivl_lval_t net) +{ + assert(net); + if (net->type_ == IVL_LVAL_LVAL) + return net->n.nest; + + return 0; +} + extern "C" const char* ivl_nature_name(ivl_nature_t net) { return net->name(); @@ -2728,6 +2737,7 @@ extern "C" unsigned ivl_stmt_lwidth(ivl_statement_t net) switch(cur->type_) { case IVL_LVAL_REG: case IVL_LVAL_ARR: + case IVL_LVAL_LVAL: sum += ivl_lval_width(cur); break; default: diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 1225a25f2..87b49ed5c 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -30,6 +30,7 @@ # include "netclass.h" # include # include "ivl_alloc.h" +# include "ivl_assert.h" bool dll_target::process(const NetProcTop*net) { @@ -174,35 +175,51 @@ bool dll_target::make_single_lval_(const LineInfo*li, struct ivl_lval_s*cur, con cur->width_ = asn->lwidth(); + ivl_type_t nest_type = 0; + if (asn->sig()) { cur->type_ = IVL_LVAL_REG; cur->n.sig = find_signal(des_, asn->sig()); - cur->idx = 0; - // If there is a word select expression, it is - // really an array index. Note that the word index - // expression is already converted to canonical - // form by elaboration. - if (asn->word()) { - assert(expr_ == 0); - asn->word()->expr_scan(this); - cur->type_ = IVL_LVAL_ARR; - cur->idx = expr_; - expr_ = 0; - } - - cur->property_idx = -1; - perm_string pname = asn->get_property(); - if (!pname.nil()) { - const netclass_t*use_type = dynamic_cast (cur->n.sig->net_type); - cur->property_idx = use_type->property_idx_from_name(pname); - } - } else { - cerr << li->get_fileline() << ": internal error: " - << "I don't know how to handle nested l-values " - << "in ivl_target.h API." << endl; - flag = false; + const NetAssign_*asn_nest = asn->nest(); + ivl_assert(*li, asn_nest); + nest_type = asn_nest->net_type(); + struct ivl_lval_s*cur_nest = new struct ivl_lval_s; + make_single_lval_(li, cur_nest, asn_nest); + + cur->type_ = IVL_LVAL_LVAL; + cur->n.nest = cur_nest; + } + + cur->idx = 0; + // If there is a word select expression, it is + // really an array index. Note that the word index + // expression is already converted to canonical + // form by elaboration. + if (asn->word()) { + assert(expr_ == 0); + asn->word()->expr_scan(this); + cur->type_ = IVL_LVAL_ARR; + cur->idx = expr_; + expr_ = 0; + } + + cur->property_idx = -1; + perm_string pname = asn->get_property(); + if (!pname.nil()) { + const netclass_t*use_type; + switch (cur->type_) { + case IVL_LVAL_LVAL: + assert(nest_type); + use_type = dynamic_cast (nest_type); + break; + default: + use_type = dynamic_cast (cur->n.sig->net_type); + break; + } + assert(use_type); + cur->property_idx = use_type->property_idx_from_name(pname); } return flag; diff --git a/t-dll.h b/t-dll.h index 6bc2a9450..f357ab384 100644 --- a/t-dll.h +++ b/t-dll.h @@ -454,7 +454,8 @@ struct ivl_lpm_s { enum ivl_lval_type_t { IVL_LVAL_REG = 0, - IVL_LVAL_ARR = 4 + IVL_LVAL_ARR = 4, + IVL_LVAL_LVAL= 5 // Nested l-value }; struct ivl_lval_s { @@ -462,10 +463,11 @@ struct ivl_lval_s { ivl_select_type_t sel_type :3; ivl_expr_t idx; unsigned width_; - unsigned type_ : 8; + unsigned type_ : 8; /* values from ivl_lval_type_t */ int property_idx; union { ivl_signal_t sig; + ivl_lval_t nest; // type_ == IVL_LVAL_LVAL } n; }; diff --git a/tgt-stub/priv.h b/tgt-stub/priv.h index 9a2a48663..38fb5c08a 100644 --- a/tgt-stub/priv.h +++ b/tgt-stub/priv.h @@ -43,6 +43,8 @@ extern ivl_variable_type_t type_of_nexus(ivl_nexus_t nex); extern ivl_discipline_t discipline_of_nexus(ivl_nexus_t nex); +extern unsigned width_of_type(ivl_type_t net); + /* * Test that a given expression is a valid delay expression, and * print an error message if not. diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index 347cd120a..0d95f771a 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -76,8 +76,59 @@ static unsigned show_assign_lval_class(ivl_lval_t lval, unsigned ind) return ivl_lval_width(lval); } +unsigned width_of_type(ivl_type_t net) +{ + switch (ivl_type_packed_dimensions(net)) { + case 0: + return 1; + case 1: { + int msb = ivl_type_packed_msb(net,0); + int lsb = ivl_type_packed_lsb(net,0); + if (msb > lsb) + return msb-lsb+1; + else + return lsb-msb+1; + } + default: + return 0; + } +} + +static ivl_type_t show_assign_lval_nest(ivl_lval_t lval, unsigned ind) +{ + ivl_type_t sub_type; + + if (ivl_lval_nest(lval)) { + fprintf(out, "%*s{nested lval property=%d}\n", ind, "", + ivl_lval_property_idx(lval)); + sub_type = show_assign_lval_nest(ivl_lval_nest(lval), ind+4); + + } else { + assert(ivl_lval_sig(lval)); + ivl_signal_t sig = ivl_lval_sig(lval); + fprintf(out, "%*s{name=%s property=%d, signal width=%u l-value width=%u}\n", + ind, "", + ivl_signal_name(sig), + ivl_lval_property_idx(lval), + ivl_signal_width(sig), + ivl_lval_width(lval)); + + sub_type = ivl_signal_net_type(sig); + } + + assert(ivl_type_base(sub_type) == IVL_VT_CLASS); + ivl_type_t lval_type = ivl_type_prop_type(sub_type, ivl_lval_property_idx(lval)); + return lval_type; +} + static unsigned show_assign_lval(ivl_lval_t lval, unsigned ind) { + ivl_lval_t lval_nest = ivl_lval_nest(lval); + if (lval_nest) { + ivl_type_t net_type = show_assign_lval_nest(lval, ind); + return width_of_type(net_type); + } + ivl_signal_t sig = ivl_lval_sig(lval); assert(sig); @@ -254,6 +305,7 @@ void show_statement(ivl_statement_t net, unsigned ind) { unsigned idx; char opcode = 0; + unsigned lwid = 0; const ivl_statement_type_t code = ivl_statement_type(net); switch (code) { @@ -270,13 +322,14 @@ void show_statement(ivl_statement_t net, unsigned ind) ivl_stmt_lwidth(net), opcode); for (idx = 0 ; idx < ivl_stmt_lvals(net) ; idx += 1) - show_assign_lval(ivl_stmt_lval(net, idx), ind+4); + lwid += show_assign_lval(ivl_stmt_lval(net, idx), ind+4); if (ivl_stmt_delay_expr(net)) show_expression(ivl_stmt_delay_expr(net), idx+4); if (ivl_stmt_rval(net)) show_expression(ivl_stmt_rval(net), ind+4); + fprintf(out, "%*sTotal l-value width is %u\n", ind+2, "", lwid); break; case IVL_ST_ASSIGN_NB: diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index c890648f0..4201778aa 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -318,6 +318,38 @@ static void put_vec_to_lval(ivl_statement_t net, struct vec_slice_info*slices, } } +static ivl_type_t draw_lval_expr(ivl_lval_t lval) +{ + ivl_lval_t lval_nest = ivl_lval_nest(lval); + ivl_signal_t lval_sig = ivl_lval_sig(lval); + ivl_type_t sub_type; + + if (lval_nest) { + sub_type = draw_lval_expr(lval_nest); + } else { + assert(lval_sig); + sub_type = ivl_signal_net_type(lval_sig); + assert(ivl_type_base(sub_type) == IVL_VT_CLASS); + fprintf(vvp_out, " %%load/obj v%p_0;\n", lval_sig); + } + + assert(ivl_type_base(sub_type) == IVL_VT_CLASS); + fprintf(vvp_out, " %%prop/obj %d;\n", ivl_lval_property_idx(lval)); + fprintf(vvp_out, " %%pop/obj 1, 1;\n"); + return ivl_type_prop_type(sub_type, ivl_lval_property_idx(lval)); +} + +static void set_vec_to_lval_slice_nest(ivl_lval_t lval, unsigned bit, unsigned wid) +{ + ivl_lval_t lval_nest = ivl_lval_nest(lval); + ivl_type_t ltype = draw_lval_expr(lval_nest); + assert(ivl_type_base(ltype) == IVL_VT_CLASS); + + fprintf(vvp_out, " %%store/prop/v %d, %u, %u;\n", + ivl_lval_property_idx(lval), bit, wid); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); +} + static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid) { ivl_signal_t sig = ivl_lval_sig(lval); @@ -330,6 +362,13 @@ static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid) ivl_expr_t word_ix = ivl_lval_idx(lval); unsigned long use_word = 0; + /* If the l-value is nested, then it is something like a class + with a chain of member names, so handle that elsewhere. */ + if (ivl_lval_nest(lval)) { + set_vec_to_lval_slice_nest(lval, bit, wid); + return; + } + if (part_off_ex == 0) { part_off = 0; } else if (number_is_immediate(part_off_ex, IMM_WID, 0) && @@ -953,7 +992,7 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in bool property %s\n", prop_idx, val.base, val.wid, ivl_type_prop_name(sig_type, prop_idx)); - fprintf(vvp_out, " %%pop/obj 1;\n"); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); clr_vector(val); } else if (ivl_type_base(prop_type) == IVL_VT_LOGIC) { @@ -967,7 +1006,7 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in logic property %s\n", prop_idx, val.base, val.wid, ivl_type_prop_name(sig_type, prop_idx)); - fprintf(vvp_out, " %%pop/obj 1;\n"); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); clr_vector(val); } else if (ivl_type_base(prop_type) == IVL_VT_REAL) { @@ -978,7 +1017,7 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) draw_eval_real(rval); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%store/prop/r %d;\n", prop_idx); - fprintf(vvp_out, " %%pop/obj 1;\n"); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_STRING) { @@ -988,7 +1027,7 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) draw_eval_string(rval); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%store/prop/str %d;\n", prop_idx); - fprintf(vvp_out, " %%pop/obj 1;\n"); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_DARRAY) { @@ -998,7 +1037,7 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); draw_eval_object(rval); fprintf(vvp_out, " %%store/prop/obj %d;\n", prop_idx); - fprintf(vvp_out, " %%pop/obj 1;\n"); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_CLASS) { @@ -1006,7 +1045,7 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); draw_eval_object(rval); fprintf(vvp_out, " %%store/prop/obj %d;\n", prop_idx); - fprintf(vvp_out, " %%pop/obj 1;\n"); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else { fprintf(vvp_out, " ; ERROR: ivl_type_base(prop_type) = %d\n", diff --git a/vvp/compile.cc b/vvp/compile.cc index a19264495..f79b5b883 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -209,7 +209,7 @@ static const struct opcode_table_s opcode_table[] = { { "%or", of_OR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%or/r", of_ORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%pad", of_PAD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, - { "%pop/obj", of_POP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, + { "%pop/obj", of_POP_OBJ, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%pop/real",of_POP_REAL,1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%pop/str", of_POP_STR, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%pow", of_POW, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index b7bcc2dc2..27aa2b6ec 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -646,16 +646,6 @@ the object handle stack. See also %store/obj. - -* %load/prop/v , , - -This instruction loads from a class object property into the specified -thread register bit. The is the number of the property and the - is the location where the loaded value goes. - -The handle for the class object is found on the top of the object -stack, and the stack is NOT popped. - * %load/real The %load/real instruction reads a real value from the vpi-like object @@ -874,14 +864,18 @@ or sign extending a vector. * %pop/str * %pop/real -* %pop/obj +* %pop/obj , -Pop this many items from the string/real/object stack. This is the +Pop items from the string/real/object stack. This is the opposite of the %pushX/str opcode which pushes a string to the stack. The %pop/str is not normally needed because the %store/str includes an implicit pop, but sometimes it is necessary to pop explicitly. +The is the number of top positions on the stack to keep, +beforing starting to pop. This allows for popping positions other then +the top of the stack. + * %pow , , * %pow/s , , @@ -902,9 +896,10 @@ the result. * %prop/r * %prop/str -Write the vector (/v) or real value (/r) or string (/str) into -property number of the class object on the top of the object -stack. +Read a vector (/v) or real value (/r) or string (/str) or object from +the property number of the class object on the stop of the +object stack. Push the resulting value to the appropriate stack. The +object that is the source is NOT popped from from object stack. The class object stack is NOT popped. diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 53f7530b9..4f355d509 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -187,12 +187,16 @@ struct vthread_s { obj = stack_obj_[stack_obj_size_]; stack_obj_[stack_obj_size_].reset(0); } - inline void pop_object(unsigned cnt) + inline void pop_object(unsigned cnt, unsigned skip =0) { - assert(cnt <= stack_obj_size_); - for (size_t idx = stack_obj_size_-cnt ; idx < stack_obj_size_ ; idx += 1) + assert((cnt+skip) <= stack_obj_size_); + for (size_t idx = stack_obj_size_-skip-cnt ; idx < stack_obj_size_-skip ; idx += 1) stack_obj_[idx].reset(0); stack_obj_size_ -= cnt; + for (size_t idx = stack_obj_size_-skip ; idx < stack_obj_size_ ; idx += 1) + stack_obj_[idx] = stack_obj_[idx+skip]; + for (size_t idx = stack_obj_size_ ; idx < stack_obj_size_+skip ; idx += 1) + stack_obj_[idx].reset(0); } inline void push_object(const vvp_object_t&obj) { @@ -4502,12 +4506,14 @@ bool of_NOR(vthread_t thr, vvp_code_t cp) } /* - * %pop/obj + * %pop/obj , */ bool of_POP_OBJ(vthread_t thr, vvp_code_t cp) { - unsigned cnt = cp->number; - thr->pop_object(cnt); + unsigned cnt = cp->bit_idx[0]; + unsigned skip = cp->bit_idx[1]; + + thr->pop_object(cnt, skip); return true; }