Allow class properties to be arrayed.

This adds the runtime support for class properties that are classes
to be arrayed. Add a means to define the dimensions of a property
in the vvp format, and add functions for setting/extracting elements
of a property.
This commit is contained in:
Stephen Williams 2014-09-13 21:12:39 -07:00
parent ea4b000be6
commit 98799ff7fa
17 changed files with 188 additions and 59 deletions

View File

@ -203,6 +203,21 @@ ostream& ivl_type_s::debug_dump(ostream&o) const
return o;
}
ostream& netclass_t::debug_dump(ostream&fd) const
{
fd << "class " << name_ << "{";
for (size_t idx = 0 ; idx < property_table_.size() ; idx += 1) {
if (idx != 0) fd << "; ";
if (property_table_[idx].type)
property_table_[idx].type->debug_dump(fd);
else
fd << "NO_TYPE";
fd << " " << property_table_[idx].name;
}
fd << "}";
return fd;
}
ostream& netdarray_t::debug_dump(ostream&o) const
{
o << "dynamic array of " << *element_type();

View File

@ -107,6 +107,7 @@ class netclass_t : public ivl_type_s {
void emit_scope(struct target_t*tgt) const;
bool emit_defs(struct target_t*tgt) const;
std::ostream& debug_dump(std::ostream&fd) const;
void dump_scope(ostream&fd) const;
private:

View File

@ -65,3 +65,8 @@ vector<netrange_t> netparray_t::slice_dimensions() const
netuarray_t::~netuarray_t()
{
}
vector<netrange_t> netuarray_t::slice_dimensions() const
{
return static_dimensions();
}

View File

@ -84,6 +84,10 @@ class netuarray_t : public netsarray_t {
explicit netuarray_t(const std::vector<netrange_t>&packed,
ivl_type_t etype);
~netuarray_t();
public:
// Virtual methods from the ivl_type_s type...
std::vector<netrange_t> slice_dimensions() const;
};
inline netuarray_t::netuarray_t(const std::vector<netrange_t>&pd,

View File

@ -70,6 +70,8 @@ class netarray_t : public ivl_type_s {
public:
// Some virtual methods have a common implementation for arrays.
// The base_type() for arrays is the base_Typeof the element.
ivl_variable_type_t base_type() const;
public:

View File

@ -49,6 +49,7 @@ static void show_prop_type_vector(ivl_type_t ptype)
static void show_prop_type(ivl_type_t ptype)
{
ivl_variable_type_t data_type = ivl_type_base(ptype);
unsigned packed_dimensions = ivl_type_packed_dimensions(ptype);
switch (data_type) {
case IVL_VT_REAL:
@ -64,6 +65,15 @@ static void show_prop_type(ivl_type_t ptype)
case IVL_VT_DARRAY:
case IVL_VT_CLASS:
fprintf(vvp_out, "\"o\"");
if (packed_dimensions > 0) {
unsigned idx;
fprintf(vvp_out, " ");
for (idx = 0 ; idx < packed_dimensions ; idx += 1) {
fprintf(vvp_out, "[%d:%d]",
ivl_type_packed_msb(ptype,idx),
ivl_type_packed_lsb(ptype,idx));
}
}
break;
default:
fprintf(vvp_out, "\"<ERROR-no-type>\"");

View File

@ -172,9 +172,22 @@ static int eval_object_property(ivl_expr_t expr)
ivl_signal_t sig = ivl_expr_signal(expr);
unsigned pidx = ivl_expr_property_idx(expr);
int idx = 0;
ivl_expr_t idx_expr = 0;
/* If there is an array index expression, then this is an
array'ed property, and we need to calculate the index for
the expression. */
if ( (idx_expr = ivl_expr_oper1(expr)) ) {
idx = allocate_word();
draw_eval_expr_into_integer(idx_expr, idx);
}
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
fprintf(vvp_out, " %%prop/obj %u;\n", pidx);
fprintf(vvp_out, " %%prop/obj %u, %d; eval_object_property\n", pidx, idx);
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
if (idx != 0) clr_word(idx);
return 0;
}

View File

@ -334,7 +334,11 @@ static ivl_type_t draw_lval_expr(ivl_lval_t lval)
}
assert(ivl_type_base(sub_type) == IVL_VT_CLASS);
fprintf(vvp_out, " %%prop/obj %d;\n", ivl_lval_property_idx(lval));
if (ivl_lval_idx(lval)) {
fprintf(vvp_out, " ; XXXX Don't know how to handle ivl_lval_idx values here.\n");
}
fprintf(vvp_out, " %%prop/obj %d, 0; draw_lval_expr\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));
}
@ -1063,22 +1067,33 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net)
} else if (ivl_type_base(prop_type) == IVL_VT_DARRAY) {
int idx = 0;
/* The property is a darray, and there is no mux
expression to the assignment is of an entire
array object. */
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, " %%store/prop/obj %d, %d; IVL_VT_DARRAY\n", prop_idx, idx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
} else if (ivl_type_base(prop_type) == IVL_VT_CLASS) {
int idx = 0;
ivl_expr_t idx_expr;
if ( (idx_expr = ivl_lval_idx(lval)) ) {
idx = allocate_word();
}
/* The property is a class object. */
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
draw_eval_object(rval);
fprintf(vvp_out, " %%store/prop/obj %d;\n", prop_idx);
if (idx_expr) draw_eval_expr_into_integer(idx_expr, idx);
fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_CLASS\n", prop_idx, idx);
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
if (idx_expr) clr_word(idx);
} else {
fprintf(vvp_out, " ; ERROR: ivl_type_base(prop_type) = %d\n",
ivl_type_base(prop_type));

View File

@ -56,8 +56,8 @@ class class_property_t {
virtual void set_string(char*buf, const std::string&val);
virtual string get_string(char*buf);
virtual void set_object(char*buf, const vvp_object_t&val);
virtual void get_object(char*buf, vvp_object_t&val);
virtual void set_object(char*buf, const vvp_object_t&val, uint64_t element);
virtual void get_object(char*buf, vvp_object_t&val, uint64_t element);
// Implement polymorphic shallow copy.
virtual void copy(char*buf, char*src) = 0;
@ -110,12 +110,12 @@ string class_property_t::get_string(char*)
return "";
}
void class_property_t::set_object(char*, const vvp_object_t&)
void class_property_t::set_object(char*, const vvp_object_t&, uint64_t)
{
assert(0);
}
void class_property_t::get_object(char*, vvp_object_t&)
void class_property_t::get_object(char*, vvp_object_t&, uint64_t)
{
assert(0);
}
@ -234,24 +234,23 @@ class property_string : public class_property_t {
class property_object : public class_property_t {
public:
inline explicit property_object(void) { }
inline explicit property_object(uint64_t as): array_size_(as==0? 1 : as) { }
~property_object() { }
size_t instance_size() const { return sizeof(vvp_object_t); }
size_t instance_size() const { return array_size_ * sizeof(vvp_object_t); }
public:
void construct(char*buf) const
{ /* vvp_object_t*tmp = */ new (buf+offset_) vvp_object_t; }
void construct(char*buf) const;
void destruct(char*buf) const
{ vvp_object_t*tmp = reinterpret_cast<vvp_object_t*> (buf+offset_);
tmp->~vvp_object_t();
}
void destruct(char*buf) const;
void set_object(char*buf, const vvp_object_t&);
void get_object(char*buf, vvp_object_t&);
void set_object(char*buf, const vvp_object_t&, uint64_t);
void get_object(char*buf, vvp_object_t&, uint64_t);
void copy(char*dst, char*src);
private:
size_t array_size_;
};
template <class T> void property_atom<T>::set_vec4(char*buf, const vvp_vector4_t&val)
@ -360,23 +359,39 @@ void property_string::copy(char*dst, char*src)
*dst_obj = *src_obj;
}
void property_object::set_object(char*buf, const vvp_object_t&val)
void property_object::construct(char*buf) const
{
vvp_object_t*tmp = reinterpret_cast<vvp_object_t*>(buf+offset_);
*tmp = val;
for (size_t idx = 0 ; idx < array_size_ ; idx += 1)
new (buf+offset_ + idx*sizeof(vvp_object_t)) vvp_object_t;
}
void property_object::get_object(char*buf, vvp_object_t&val)
void property_object::destruct(char*buf) const
{
vvp_object_t*tmp = reinterpret_cast<vvp_object_t*> (buf+offset_);
for (size_t idx = 0 ; idx < array_size_ ; idx += 1)
(tmp+idx)->~vvp_object_t();
}
void property_object::set_object(char*buf, const vvp_object_t&val, uint64_t idx)
{
assert(idx < array_size_);
vvp_object_t*tmp = reinterpret_cast<vvp_object_t*>(buf+offset_);
val = *tmp;
tmp[idx] = val;
}
void property_object::get_object(char*buf, vvp_object_t&val, uint64_t idx)
{
assert(idx < array_size_);
vvp_object_t*tmp = reinterpret_cast<vvp_object_t*>(buf+offset_);
val = tmp[idx];
}
void property_object::copy(char*dst, char*src)
{
vvp_object_t*dst_obj = reinterpret_cast<vvp_object_t*>(dst);
vvp_object_t*src_obj = reinterpret_cast<vvp_object_t*>(src);
*dst_obj = *src_obj;
for (size_t idx = 0 ; idx < array_size_ ; idx += 1)
dst_obj[idx] = src_obj[idx];
}
/* **** */
@ -393,7 +408,7 @@ class_type::~class_type()
delete properties_[idx].type;
}
void class_type::set_property(size_t idx, const string&name, const string&type)
void class_type::set_property(size_t idx, const string&name, const string&type, uint64_t array_size)
{
assert(idx < properties_.size());
properties_[idx].name = name;
@ -419,7 +434,7 @@ void class_type::set_property(size_t idx, const string&name, const string&type)
else if (type == "S")
properties_[idx].type = new property_string;
else if (type == "o")
properties_[idx].type = new property_object;
properties_[idx].type = new property_object(array_size);
else if (type[0] == 'b') {
size_t wid = strtoul(type.c_str()+1, 0, 0);
properties_[idx].type = new property_bit(wid);
@ -529,18 +544,19 @@ string class_type::get_string(class_type::inst_t obj, size_t pid) const
}
void class_type::set_object(class_type::inst_t obj, size_t pid,
const vvp_object_t&val) const
const vvp_object_t&val, size_t idx) const
{
char*buf = reinterpret_cast<char*> (obj);
assert(pid < properties_.size());
properties_[pid].type->set_object(buf, val);
properties_[pid].type->set_object(buf, val, idx);
}
void class_type::get_object(class_type::inst_t obj, size_t pid, vvp_object_t&val) const
void class_type::get_object(class_type::inst_t obj, size_t pid,
vvp_object_t&val, size_t idx) const
{
char*buf = reinterpret_cast<char*> (obj);
assert(pid < properties_.size());
properties_[pid].type->get_object(buf, val);
properties_[pid].type->get_object(buf, val, idx);
}
void class_type::copy_property(class_type::inst_t dst, size_t pid, class_type::inst_t src) const
@ -569,10 +585,10 @@ void compile_class_start(char*lab, char*nam, unsigned ntype)
delete[]nam;
}
void compile_class_property(unsigned idx, char*nam, char*typ)
void compile_class_property(unsigned idx, char*nam, char*typ, uint64_t array_size)
{
assert(compile_class);
compile_class->set_property(idx, nam, typ);
compile_class->set_property(idx, nam, typ, array_size);
delete[]nam;
delete[]typ;
}

View File

@ -49,7 +49,7 @@ class class_type : public __vpiHandle {
// Set the details about the property. This is used during
// parse of the .vvp file to fill in the details of the
// property for the class definition.
void set_property(size_t idx, const std::string&name, const std::string&type);
void set_property(size_t idx, const std::string&name, const std::string&type, uint64_t array_size);
// This method is called after all the properties are
// defined. This calculates information about the definition.
@ -66,8 +66,8 @@ class class_type : public __vpiHandle {
double get_real(inst_t inst, size_t pid) const;
void set_string(inst_t inst, size_t pid, const std::string&val) const;
std::string get_string(inst_t inst, size_t pid) const;
void set_object(inst_t inst, size_t pid, const vvp_object_t&val) const;
void get_object(inst_t inst, size_t pid, vvp_object_t&val) const;
void set_object(inst_t inst, size_t pid, const vvp_object_t&val, size_t idx) const;
void get_object(inst_t inst, size_t pid, vvp_object_t&val, size_t idx) const;
void copy_property(inst_t dst, size_t idx, inst_t src) const;

View File

@ -216,7 +216,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%pow", of_POW, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pow/s", of_POW_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pow/wr", of_POW_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%prop/obj",of_PROP_OBJ,1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%prop/obj",of_PROP_OBJ,2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%prop/r", of_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%prop/str",of_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%prop/v", of_PROP_V, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
@ -248,7 +248,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%store/dar/str",of_STORE_DAR_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%store/obj", of_STORE_OBJ, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%store/obja", of_STORE_OBJA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
{ "%store/prop/obj",of_STORE_PROP_OBJ,1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%store/prop/obj",of_STORE_PROP_OBJ,2, {OA_NUMBER, OA_BIT1, OA_NONE} },
{ "%store/prop/r", of_STORE_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%store/prop/str",of_STORE_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%store/prop/v", of_STORE_PROP_V, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },

View File

@ -552,7 +552,7 @@ extern void compile_island_tranvp(char*island, char*ba, char*bb,
extern void delete_udp_symbols(void);
extern void compile_class_start(char*lab, char*nam, unsigned nprop);
extern void compile_class_property(unsigned idx, char*nam, char*typ);
extern void compile_class_property(unsigned idx, char*nam, char*typ, uint64_t array_size);
extern void compile_class_done(void);
#endif /* IVL_compile_H */

View File

@ -892,7 +892,7 @@ This opcode raises the left operand by the right operand, and pushes
the result.
* %prop/v <pid>, <base>, <wid>
* %prop/obj <pid>
* %prop/obj <pid>, <idx>
* %prop/r <pid>
* %prop/str <pid>
@ -901,6 +901,11 @@ the property number <pid> of the class object on the top of the
object stack. Push the resulting value to the appropriate stack. The
class object that is the source is NOT popped from the object stack.
The <idx> is the address of an index variable that selects the word of
an arrayed property. If the <idx> value is 0, then use index value
zero instead of reading index register zero. Use this form for
non-arrayed properties.
* %pushi/real <mant>, <exp>
This opcode loads an immediate value, floating point, into the real
@ -1048,18 +1053,21 @@ variable given by the label.
See also %load/obj.
* %store/prop/obj <index>
* %store/prop/r <index>
* %store/prop/str <index>
* %store/prop/v <index>, <bit>, <wid>
* %store/prop/obj <pid>, <idx>
* %store/prop/r <pid>
* %store/prop/str <pid>
* %store/prop/v <pid>, <bit>, <wid>
The %store/prop/r pops a real value from the real stack and stores it
into the the property number <index> of a cobject in the top of the
into the the property number <pid> of a cobject in the top of the
object stack. The cobject is NOT popped.
The %store/prop/obj pops an object from the top of the object stack,
then writes it to the property number <index> of the cobject now on
top of the object stack. The cobject is NOT popped.
then writes it to the property number <pid> of the cobject now on
top of the object stack. The cobject is NOT popped. The <idx> argument
is the index register to select an element. If the property is an
array, this selects the element. If <idx> is 0, then use the value 0
instead of index register zero. Use 0 for non-array properties.
* %store/real <var-label>
* %store/reala <var-label>, <index>

View File

@ -115,6 +115,7 @@ static struct __vpiModPath*modpath_dst = 0;
%type <flag> local_flag
%type <vpi_enum> port_type
%type <numb> signed_t_number
%type <numb> dimension dimensions dimensions_opt
%type <symb> symbol symbol_opt
%type <symbv> symbols symbols_net
%type <numbv> numbers
@ -898,8 +899,32 @@ class_properties
;
class_property
: T_NUMBER ':' T_STRING ',' T_STRING
{ compile_class_property($1, $3, $5); }
: T_NUMBER ':' T_STRING ',' T_STRING dimensions_opt
{ compile_class_property($1, $3, $5, $6); }
;
/*
* The syntax for dimensions allows the code generator to give the
* accurate dimensions for for the property, but for now we are only
* interested in the total number of elements. So reduce the ranges
* to a simple number, and scale the number.
*/
dimensions_opt
: dimensions
{ $$ = $1; }
| { $$ = 0; }
;
dimensions
: dimensions dimension
{ $$ = $1 * $2; }
| dimension
{ $$ = $1; }
;
dimension
: '[' T_NUMBER ':' T_NUMBER ']'
{ $$ = ($2 > $4? $2 - $4 : $4 - $2) + 1; }
;
/* Enumeration types */

View File

@ -94,6 +94,8 @@ using namespace std;
* to reap the child immediately.
*/
const size_t THR_MAX_WORDS = 16;
struct vthread_s {
vthread_s();
@ -106,7 +108,7 @@ struct vthread_s {
union {
int64_t w_int;
uint64_t w_uint;
} words[16];
} words[THR_MAX_WORDS];
private:
vector<double> stack_real_;
@ -4657,19 +4659,25 @@ bool of_POW_WR(vthread_t thr, vvp_code_t)
}
/*
* %prop/obj <pid>
* %prop/obj <pid>, <idx>
*
* Load an object value from the cobject and push it onto the object stack.
*/
bool of_PROP_OBJ(vthread_t thr, vvp_code_t cp)
{
unsigned pid = cp->number;
unsigned idx = cp->bit_idx[0];
if (idx != 0) {
assert(idx < THR_MAX_WORDS);
idx = thr->words[idx].w_uint;
}
vvp_object_t&obj = thr->peek_object();
vvp_cobject*cobj = obj.peek<vvp_cobject>();
vvp_object_t val;
cobj->get_object(pid, val);
cobj->get_object(pid, val, idx);
thr->push_object(val);
@ -5479,7 +5487,7 @@ bool of_STORE_OBJA(vthread_t thr, vvp_code_t cp)
/*
* %store/prop/obj <id>
* %store/prop/obj <pid>, <idx>
*
* Pop an object value from the object stack, and store the value into
* the property of the object references by the top of the stack. Do NOT
@ -5488,6 +5496,13 @@ bool of_STORE_OBJA(vthread_t thr, vvp_code_t cp)
bool of_STORE_PROP_OBJ(vthread_t thr, vvp_code_t cp)
{
size_t pid = cp->number;
unsigned idx = cp->bit_idx[0];
if (idx != 0) {
assert(idx < THR_MAX_WORDS);
idx = thr->words[idx].w_uint;
}
vvp_object_t val;
thr->pop_object(val);
@ -5495,7 +5510,7 @@ bool of_STORE_PROP_OBJ(vthread_t thr, vvp_code_t cp)
vvp_cobject*cobj = obj.peek<vvp_cobject>();
assert(cobj);
cobj->set_object(pid, val);
cobj->set_object(pid, val, idx);
return true;
}

View File

@ -65,14 +65,14 @@ string vvp_cobject::get_string(size_t pid)
return defn_->get_string(properties_, pid);
}
void vvp_cobject::set_object(size_t pid, const vvp_object_t&val)
void vvp_cobject::set_object(size_t pid, const vvp_object_t&val, size_t idx)
{
defn_->set_object(properties_, pid, val);
defn_->set_object(properties_, pid, val, idx);
}
void vvp_cobject::get_object(size_t pid, vvp_object_t&val)
void vvp_cobject::get_object(size_t pid, vvp_object_t&val, size_t idx)
{
return defn_->get_object(properties_, pid, val);
return defn_->get_object(properties_, pid, val, idx);
}
void vvp_cobject::shallow_copy(const vvp_object*obj)

View File

@ -41,8 +41,8 @@ class vvp_cobject : public vvp_object {
void set_string(size_t pid, const std::string&val);
std::string get_string(size_t pid);
void set_object(size_t pid, const vvp_object_t&val);
void get_object(size_t pid, vvp_object_t&val);
void set_object(size_t pid, const vvp_object_t&val, size_t idx);
void get_object(size_t pid, vvp_object_t&val, size_t idx);
void shallow_copy(const vvp_object*that);