Rework variable arrays to not have vpi handles for every word.

Save tons of space per memory word by not creating a vpi handle for
each and every word of a variable array. (Net arrays still get a
vpiHandle for every word.) The consequence of this is that all
accesses to a variable array need to go through the indexing.

This commit handles the most common places where this impacts, but
there are still problems.
This commit is contained in:
Stephen Williams 2008-05-16 10:38:32 -07:00
parent 3113392594
commit 102cbb67b4
8 changed files with 151 additions and 54 deletions

View File

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

View File

@ -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;
}

View File

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

View File

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

View File

@ -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<vvp_fun_signal_vec*> (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<vvp_fun_signal_vec*> (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;

View File

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

View File

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

View File

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