Support nested l-value objects

This allows for syntax like a.b.c where a is a class with member
b, which is a class with member c, and so on. The handling is mostly
for the support of compound objects like classes.
This commit is contained in:
Stephen Williams 2013-11-22 19:54:42 -08:00
parent 37ac1ed474
commit fa8d35ae9c
14 changed files with 199 additions and 68 deletions

View File

@ -871,8 +871,10 @@ void NetAlloc::dump(ostream&o, unsigned ind) const
void NetAssign_::dump_lval(ostream&o) const void NetAssign_::dump_lval(ostream&o) const
{ {
if (sig_) { if (sig_) o << sig_->name();
o << sig_->name(); else if (nest_) nest_->dump_lval(o);
else o << "<?>";
if (! member_.nil()) { if (! member_.nil()) {
o << "." << member_; o << "." << member_;
} }
@ -882,9 +884,6 @@ void NetAssign_::dump_lval(ostream&o) const
if (base_) { if (base_) {
o << "[" << *base_ << " +: " << lwid_ << "]"; o << "[" << *base_ << " +: " << lwid_ << "]";
} }
} else {
o << "";
}
} }
void NetAssignBase::dump_lval(ostream&o) const void NetAssignBase::dump_lval(ostream&o) const

View File

@ -141,6 +141,7 @@ ivl_lpm_width
ivl_lval_idx ivl_lval_idx
ivl_lval_mux ivl_lval_mux
ivl_lval_nest
ivl_lval_part_off ivl_lval_part_off
ivl_lval_property_idx ivl_lval_property_idx
ivl_lval_sel_type ivl_lval_sel_type

View File

@ -1446,6 +1446,10 @@ extern const char*ivl_lpm_string(ivl_lpm_t net);
* *
* ivl_lval_mux (* obsolete *) * 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 * ivl_lval_sig
* If the l-value is a variable, this method returns the signal * If the l-value is a variable, this method returns the signal
* object that is the target of the assign. * 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 ivl_select_type_t ivl_lval_sel_type(ivl_lval_t net);
extern int ivl_lval_property_idx(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_signal_t ivl_lval_sig(ivl_lval_t net);
extern ivl_lval_t ivl_lval_nest(ivl_lval_t net);
/* NEXUS /* NEXUS

View File

@ -225,6 +225,7 @@ perm_string NetAssign_::name() const
NetNet* NetAssign_::sig() const NetNet* NetAssign_::sig() const
{ {
assert(sig_? nest_==0 : nest_!=0);
return sig_; return sig_;
} }

View File

@ -2594,6 +2594,7 @@ class NetAssign_ {
perm_string name() const; perm_string name() const;
NetNet* sig() const; NetNet* sig() const;
inline const NetAssign_* nest() const { return nest_; }
// Mark that the synthesizer has worked with this l-value, so // Mark that the synthesizer has worked with this l-value, so
// when it is released, the l-value signal should be turned // when it is released, the l-value signal should be turned

View File

@ -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) extern "C" const char* ivl_nature_name(ivl_nature_t net)
{ {
return net->name(); return net->name();
@ -2728,6 +2737,7 @@ extern "C" unsigned ivl_stmt_lwidth(ivl_statement_t net)
switch(cur->type_) { switch(cur->type_) {
case IVL_LVAL_REG: case IVL_LVAL_REG:
case IVL_LVAL_ARR: case IVL_LVAL_ARR:
case IVL_LVAL_LVAL:
sum += ivl_lval_width(cur); sum += ivl_lval_width(cur);
break; break;
default: default:

View File

@ -30,6 +30,7 @@
# include "netclass.h" # include "netclass.h"
# include <cstdlib> # include <cstdlib>
# include "ivl_alloc.h" # include "ivl_alloc.h"
# include "ivl_assert.h"
bool dll_target::process(const NetProcTop*net) bool dll_target::process(const NetProcTop*net)
{ {
@ -174,10 +175,23 @@ bool dll_target::make_single_lval_(const LineInfo*li, struct ivl_lval_s*cur, con
cur->width_ = asn->lwidth(); cur->width_ = asn->lwidth();
ivl_type_t nest_type = 0;
if (asn->sig()) { if (asn->sig()) {
cur->type_ = IVL_LVAL_REG; cur->type_ = IVL_LVAL_REG;
cur->n.sig = find_signal(des_, asn->sig()); cur->n.sig = find_signal(des_, asn->sig());
} else {
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; cur->idx = 0;
// If there is a word select expression, it is // If there is a word select expression, it is
// really an array index. Note that the word index // really an array index. Note that the word index
@ -194,15 +208,18 @@ bool dll_target::make_single_lval_(const LineInfo*li, struct ivl_lval_s*cur, con
cur->property_idx = -1; cur->property_idx = -1;
perm_string pname = asn->get_property(); perm_string pname = asn->get_property();
if (!pname.nil()) { if (!pname.nil()) {
const netclass_t*use_type = dynamic_cast<const netclass_t*> (cur->n.sig->net_type); const netclass_t*use_type;
cur->property_idx = use_type->property_idx_from_name(pname); switch (cur->type_) {
case IVL_LVAL_LVAL:
assert(nest_type);
use_type = dynamic_cast<const netclass_t*> (nest_type);
break;
default:
use_type = dynamic_cast<const netclass_t*> (cur->n.sig->net_type);
break;
} }
assert(use_type);
} else { cur->property_idx = use_type->property_idx_from_name(pname);
cerr << li->get_fileline() << ": internal error: "
<< "I don't know how to handle nested l-values "
<< "in ivl_target.h API." << endl;
flag = false;
} }
return flag; return flag;

View File

@ -454,7 +454,8 @@ struct ivl_lpm_s {
enum ivl_lval_type_t { enum ivl_lval_type_t {
IVL_LVAL_REG = 0, IVL_LVAL_REG = 0,
IVL_LVAL_ARR = 4 IVL_LVAL_ARR = 4,
IVL_LVAL_LVAL= 5 // Nested l-value
}; };
struct ivl_lval_s { struct ivl_lval_s {
@ -462,10 +463,11 @@ struct ivl_lval_s {
ivl_select_type_t sel_type :3; ivl_select_type_t sel_type :3;
ivl_expr_t idx; ivl_expr_t idx;
unsigned width_; unsigned width_;
unsigned type_ : 8; unsigned type_ : 8; /* values from ivl_lval_type_t */
int property_idx; int property_idx;
union { union {
ivl_signal_t sig; ivl_signal_t sig;
ivl_lval_t nest; // type_ == IVL_LVAL_LVAL
} n; } n;
}; };

View File

@ -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 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 * Test that a given expression is a valid delay expression, and
* print an error message if not. * print an error message if not.

View File

@ -76,8 +76,59 @@ static unsigned show_assign_lval_class(ivl_lval_t lval, unsigned ind)
return ivl_lval_width(lval); 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) 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); ivl_signal_t sig = ivl_lval_sig(lval);
assert(sig); assert(sig);
@ -254,6 +305,7 @@ void show_statement(ivl_statement_t net, unsigned ind)
{ {
unsigned idx; unsigned idx;
char opcode = 0; char opcode = 0;
unsigned lwid = 0;
const ivl_statement_type_t code = ivl_statement_type(net); const ivl_statement_type_t code = ivl_statement_type(net);
switch (code) { switch (code) {
@ -270,13 +322,14 @@ void show_statement(ivl_statement_t net, unsigned ind)
ivl_stmt_lwidth(net), opcode); ivl_stmt_lwidth(net), opcode);
for (idx = 0 ; idx < ivl_stmt_lvals(net) ; idx += 1) 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)) if (ivl_stmt_delay_expr(net))
show_expression(ivl_stmt_delay_expr(net), idx+4); show_expression(ivl_stmt_delay_expr(net), idx+4);
if (ivl_stmt_rval(net)) if (ivl_stmt_rval(net))
show_expression(ivl_stmt_rval(net), ind+4); show_expression(ivl_stmt_rval(net), ind+4);
fprintf(out, "%*sTotal l-value width is %u\n", ind+2, "", lwid);
break; break;
case IVL_ST_ASSIGN_NB: case IVL_ST_ASSIGN_NB:

View File

@ -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) static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid)
{ {
ivl_signal_t sig = ivl_lval_sig(lval); 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); ivl_expr_t word_ix = ivl_lval_idx(lval);
unsigned long use_word = 0; 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) { if (part_off_ex == 0) {
part_off = 0; part_off = 0;
} else if (number_is_immediate(part_off_ex, IMM_WID, 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", fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in bool property %s\n",
prop_idx, val.base, val.wid, prop_idx, val.base, val.wid,
ivl_type_prop_name(sig_type, prop_idx)); 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); clr_vector(val);
} else if (ivl_type_base(prop_type) == IVL_VT_LOGIC) { } 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", fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in logic property %s\n",
prop_idx, val.base, val.wid, prop_idx, val.base, val.wid,
ivl_type_prop_name(sig_type, prop_idx)); 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); clr_vector(val);
} else if (ivl_type_base(prop_type) == IVL_VT_REAL) { } 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); draw_eval_real(rval);
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
fprintf(vvp_out, " %%store/prop/r %d;\n", prop_idx); 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) { } 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); draw_eval_string(rval);
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
fprintf(vvp_out, " %%store/prop/str %d;\n", prop_idx); 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) { } 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); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
draw_eval_object(rval); draw_eval_object(rval);
fprintf(vvp_out, " %%store/prop/obj %d;\n", prop_idx); 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) { } 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); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
draw_eval_object(rval); draw_eval_object(rval);
fprintf(vvp_out, " %%store/prop/obj %d;\n", prop_idx); 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 { } else {
fprintf(vvp_out, " ; ERROR: ivl_type_base(prop_type) = %d\n", fprintf(vvp_out, " ; ERROR: ivl_type_base(prop_type) = %d\n",

View File

@ -209,7 +209,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%or", of_OR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%or", of_OR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%or/r", of_ORR, 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} }, { "%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/real",of_POP_REAL,1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%pop/str", of_POP_STR, 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} }, { "%pow", of_POW, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },

View File

@ -646,16 +646,6 @@ the object handle stack.
See also %store/obj. See also %store/obj.
* %load/prop/v <pid>, <bit>, <wid>
This instruction loads from a class object property into the specified
thread register bit. The <pid> is the number of the property and the
<bit> 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 <vpi-label> * %load/real <vpi-label>
The %load/real instruction reads a real value from the vpi-like object The %load/real instruction reads a real value from the vpi-like object
@ -874,14 +864,18 @@ or sign extending a vector.
* %pop/str <num> * %pop/str <num>
* %pop/real <num> * %pop/real <num>
* %pop/obj <num> * %pop/obj <num>, <skip>
Pop this many items from the string/real/object stack. This is the Pop <num> items from the string/real/object stack. This is the
opposite of the %pushX/str opcode which pushes a string to 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 stack. The %pop/str is not normally needed because the %store/str
includes an implicit pop, but sometimes it is necessary to pop includes an implicit pop, but sometimes it is necessary to pop
explicitly. explicitly.
The <skip> 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 <bit-l>, <bit-r>, <wid> * %pow <bit-l>, <bit-r>, <wid>
* %pow/s <bit-l>, <bit-r>, <wid> * %pow/s <bit-l>, <bit-r>, <wid>
@ -902,9 +896,10 @@ the result.
* %prop/r <pid> * %prop/r <pid>
* %prop/str <pid> * %prop/str <pid>
Write the vector (/v) or real value (/r) or string (/str) into Read a vector (/v) or real value (/r) or string (/str) or object from
property number <pid> of the class object on the top of the object the property number <pid> of the class object on the stop of the
stack. 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. The class object stack is NOT popped.

View File

@ -187,12 +187,16 @@ struct vthread_s {
obj = stack_obj_[stack_obj_size_]; obj = stack_obj_[stack_obj_size_];
stack_obj_[stack_obj_size_].reset(0); 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_); assert((cnt+skip) <= stack_obj_size_);
for (size_t idx = stack_obj_size_-cnt ; idx < stack_obj_size_ ; idx += 1) for (size_t idx = stack_obj_size_-skip-cnt ; idx < stack_obj_size_-skip ; idx += 1)
stack_obj_[idx].reset(0); stack_obj_[idx].reset(0);
stack_obj_size_ -= cnt; 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) 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 <number> * %pop/obj <num>, <skip>
*/ */
bool of_POP_OBJ(vthread_t thr, vvp_code_t cp) bool of_POP_OBJ(vthread_t thr, vvp_code_t cp)
{ {
unsigned cnt = cp->number; unsigned cnt = cp->bit_idx[0];
thr->pop_object(cnt); unsigned skip = cp->bit_idx[1];
thr->pop_object(cnt, skip);
return true; return true;
} }