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:
parent
3113392594
commit
102cbb67b4
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
135
vvp/array.cc
135
vvp/array.cc
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue