Skip to content

Commit

Permalink
Add support for real/realtime arrays.
Browse files Browse the repository at this point in the history
Support arrays of realtime variable arrays and net arrays. This
involved a simple fix to the ivl core parser, proper support in
the code generator, and rework the runtime support in vvp.
  • Loading branch information
steveicarus committed Nov 2, 2008
1 parent 520d9b9 commit 6cac1d2
Show file tree
Hide file tree
Showing 14 changed files with 229 additions and 55 deletions.
8 changes: 7 additions & 1 deletion parse.y
Expand Up @@ -2978,7 +2978,13 @@ real_variable
{ perm_string name = lex_strings.make($1);
pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0);
if ($2 != 0) {
yyerror(@2, "sorry: real variables do not currently support arrays.");
index_component_t index;
if ($2->size() > 1) {
yyerror(@2, "sorry: only 1 dimensional arrays "
"are currently supported.");
}
index = $2->front();
pform_set_reg_idx(name, index.msb, index.lsb);
delete $2;
}
$$ = $1;
Expand Down
22 changes: 8 additions & 14 deletions tgt-vvp/eval_real.c
Expand Up @@ -354,23 +354,17 @@ static int draw_signal_real_real(ivl_expr_t exp)
{
ivl_signal_t sig = ivl_expr_signal(exp);
int res = allocate_word();
unsigned long word = 0;

if (ivl_signal_dimensions(sig) > 0) {
ivl_expr_t ix = ivl_expr_oper1(exp);
if (!number_is_immediate(ix, IMM_WID, 0)) {
/* XXXX Need to generate a %load/ar instruction. */
assert(0);
return res;
}

/* The index is constant, so we can return to direct
readout with the specific word selected. */
word = get_number_immediate(ix);
if (ivl_signal_dimensions(sig) == 0) {
fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, sig);
return res;
}

fprintf(vvp_out, " %%load/wr %d, v%p_%lu;\n", res, sig, word);

ivl_expr_t word_ex = ivl_expr_oper1(exp);
int word_ix = allocate_word();
draw_eval_expr_into_integer(word_ex, word_ix);
fprintf(vvp_out, " %%load/ar %d, v%p, %d;\n", res, sig, word_ix);
clr_word(word_ix);
return res;
}

Expand Down
20 changes: 17 additions & 3 deletions tgt-vvp/vvp_process.c
Expand Up @@ -497,16 +497,30 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
ivl_signal_t var;

res = draw_eval_real(ivl_stmt_rval(net));
clr_word(res);

assert(ivl_stmt_lvals(net) == 1);
lval = ivl_stmt_lval(net, 0);
var = ivl_lval_sig(lval);
assert(var != 0);

assert(ivl_signal_dimensions(var) == 0);
if (ivl_signal_dimensions(var) == 0) {
clr_word(res);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
return 0;
}

// For now, only support 1-dimensional arrays.
assert(ivl_signal_dimensions(var) == 1);

// Calculate the word index into an index register
ivl_expr_t word_ex = ivl_lval_idx(lval);
int word_ix = allocate_word();
draw_eval_expr_into_integer(word_ex, word_ix);
// Generate an assignment to write to the array.
fprintf(vvp_out, " %%set/ar v%p, %d, %d;\n", var, word_ix, res);

fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
clr_word(res);
clr_word(word_ix);

return 0;
}
Expand Down
108 changes: 80 additions & 28 deletions vvp/array.cc
Expand Up @@ -53,7 +53,28 @@ vvp_array_t array_find(const char*label)

/*
* The vpiArray object holds an array of vpi objects that themselves
* represent the words of the array. The vpi_array_t is a pointer to this.
* represent the words of the array. The vpi_array_t is a pointer to
* a struct __vpiArray.
*
* The details of the implementation depends on what this is an array
* of. The easiest case is if this is an array of nets.
*
* - Array of Nets:
* If this represents an array of nets, then the nets member points to
* an array of vpiHandle objects. Each vpiHandle is a word. This is
* done because typically each word of a net array is simultaneously
* driven and accessed by other means, so there is no advantage to
* compacting the array in any other way.
*
* - Array of vector4 words.
* In this case, the nets pointer is nil, and the vals4 member points
* to a vvl_vector4array_t object that is a compact representation of
* an array of vvp_vector4_t vectors.
*
* - Array of real variables
* The valsr member points to a vvp_realarray_t objects that has an
* array of double variables. This is very much line the way the
* vector4 array works.
*/
struct __vpiArray {
__vpiArray() { }
Expand All @@ -70,7 +91,8 @@ struct __vpiArray {
// If this is a net array, nets lists the handles.
vpiHandle*nets;
// If this is a var array, then these are used instead of nets.
vvp_vector4array_t *vals;
vvp_vector4array_t *vals4;
vvp_realarray_t *valsr;
struct __vpiArrayWord*vals_words;

class vvp_fun_arrayport*ports_;
Expand Down Expand Up @@ -127,7 +149,7 @@ struct __vpiArrayVthrA {
/* Get the array word size. This has only been checked for reg arrays. */
unsigned get_array_word_size(vvp_array_t array)
{
assert(array->vals);
assert(array->vals4);
return array->vals_width;
}

Expand Down Expand Up @@ -424,7 +446,7 @@ static int vpi_array_var_word_get(int code, vpiHandle ref)

switch (code) {
case vpiSize:
return (int) parent->vals->width();
return (int) parent->vals4->width();

case vpiLeftRange:
return parent->msb.value;
Expand Down Expand Up @@ -461,9 +483,9 @@ static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)

assert(obj);
unsigned index = decode_array_word_pointer(obj, parent);
unsigned width = parent->vals->width();
unsigned width = parent->vals4->width();

vpip_vec4_get_value(parent->vals->get_word(index), width,
vpip_vec4_get_value(parent->vals4->get_word(index), width,
parent->signed_flag, value);
}

Expand Down Expand Up @@ -539,7 +561,7 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int)
if (obj->array->nets)
return obj->array->nets[obj->next];

assert(obj->array->vals);
assert(obj->array->vals4);

if (obj->array->vals_words == 0)
array_make_vals_words(obj->array);
Expand Down Expand Up @@ -702,10 +724,10 @@ void array_set_word(vvp_array_t arr,
if (address >= arr->array_count)
return;

if (arr->vals) {
if (arr->vals4) {
assert(arr->nets == 0);
if (part_off != 0 || val.size() != arr->vals_width) {
vvp_vector4_t tmp = arr->vals->get_word(address);
vvp_vector4_t tmp = arr->vals4->get_word(address);
if ((part_off + val.size()) > tmp.size()) {
cerr << "part_off=" << part_off
<< " val.size()=" << val.size()
Expand All @@ -714,9 +736,9 @@ void array_set_word(vvp_array_t arr,
assert(0);
}
tmp.set_vec(part_off, val);
arr->vals->set_word(address, tmp);
arr->vals4->set_word(address, tmp);
} else {
arr->vals->set_word(address, val);
arr->vals4->set_word(address, val);
}
array_word_change(arr, address);
return;
Expand All @@ -734,15 +756,22 @@ void array_set_word(vvp_array_t arr,
array_word_change(arr, address);
}

void array_set_word(vvp_array_t arr, unsigned address, double val)
{
assert(arr->valsr!= 0);
assert(arr->nets == 0);

arr->valsr->set_word(address, val);
}

vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
{
if (arr->vals) {
if (arr->vals4) {
assert(arr->nets == 0);

return arr->vals->get_word(address);
return arr->vals4->get_word(address);
}

assert(arr->vals == 0);
assert(arr->vals4 == 0);
assert(arr->nets != 0);

if (address >= arr->array_count) {
Expand All @@ -767,6 +796,26 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
return val;
}

double array_get_word_r(vvp_array_t arr, unsigned address)
{
if (arr->valsr) {
assert(arr->vals4 == 0);
assert(arr->nets == 0);
return arr->valsr->get_word(address);
}

assert(arr->nets);
vpiHandle word = arr->nets[address];
struct __vpiRealVar*vsig = vpip_realvar_from_handle(word);
assert(vsig);
vvp_fun_signal_real*sig = dynamic_cast<vvp_fun_signal_real*> (vsig->net->fun);
assert(sig);

double val = sig->real_value();
return val;

}

static vpiHandle vpip_make_array(char*label, const char*name,
int first_addr, int last_addr,
bool signed_flag)
Expand All @@ -792,7 +841,8 @@ static vpiHandle vpip_make_array(char*label, const char*name,

// Start off now knowing if we are nets or variables.
obj->nets = 0;
obj->vals = 0;
obj->vals4 = 0;
obj->valsr = 0;
obj->vals_width = 0;
vpip_make_dec_const(&obj->msb, 0);
vpip_make_dec_const(&obj->lsb, 0);
Expand Down Expand Up @@ -869,11 +919,11 @@ void compile_var_array(char*label, char*name, int last, int first,
/* Make the words. */
arr->vals_width = labs(msb-lsb) + 1;
if (vpip_peek_current_scope()->is_automatic) {
arr->vals = new vvp_vector4array_aa(arr->vals_width,
arr->array_count);
arr->vals4 = new vvp_vector4array_aa(arr->vals_width,
arr->array_count);
} else {
arr->vals = new vvp_vector4array_sa(arr->vals_width,
arr->array_count);
arr->vals4 = new vvp_vector4array_sa(arr->vals_width,
arr->array_count);
}
vpip_make_dec_const(&arr->msb, msb);
vpip_make_dec_const(&arr->lsb, lsb);
Expand All @@ -891,14 +941,16 @@ void compile_real_array(char*label, char*name, int last, int first,
vpiHandle obj = vpip_make_array(label, name, first, last, true);

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_varw_real(strdup(buf), array, idx, msb, lsb);
}
arr->valsr = new vvp_realarray_t(arr->array_count);
arr->vals_width = 1;

/* Do these even make sense for real arrays? These are the
part select of a vector, but the real value is not
vectorable. */
vpip_make_dec_const(&arr->msb, msb);
vpip_make_dec_const(&arr->lsb, lsb);

count_real_arrays += 1;
count_real_array_words += arr->array_count;
Expand Down Expand Up @@ -1146,7 +1198,7 @@ void array_word_change(vvp_array_t array, unsigned long addr)

if (cur->cb_data.cb_rtn != 0) {
if (cur->cb_data.value)
vpip_vec4_get_value(array->vals->get_word(addr),
vpip_vec4_get_value(array->vals4->get_word(addr),
array->vals_width,
array->signed_flag,
cur->cb_data.value);
Expand Down Expand Up @@ -1282,7 +1334,7 @@ void compile_array_alias(char*label, char*name, char*src)

// Share the words with the source array.
obj->nets = mem->nets;
obj->vals = mem->vals;
obj->vals4 = mem->vals4;

obj->ports_ = 0;

Expand Down
9 changes: 5 additions & 4 deletions vvp/array.h
Expand Up @@ -39,12 +39,13 @@ extern void array_attach_word(vvp_array_t array, unsigned long addr,
extern void array_alias_word(vvp_array_t array, unsigned long addr,
vpiHandle word);

extern void array_set_word(vvp_array_t arr,
unsigned idx,
unsigned off,
vvp_vector4_t val);
extern void array_set_word(vvp_array_t arr, unsigned idx,
unsigned off, vvp_vector4_t val);
extern void array_set_word(vvp_array_t arr, unsigned idx,
double val);

extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned address);
extern double array_get_word_r(vvp_array_t array, unsigned address);

/* VPI hooks */

Expand Down
2 changes: 2 additions & 0 deletions vvp/codes.h
Expand Up @@ -107,6 +107,7 @@ extern bool of_JMP0(vthread_t thr, vvp_code_t code);
extern bool of_JMP0XZ(vthread_t thr, vvp_code_t code);
extern bool of_JMP1(vthread_t thr, vvp_code_t code);
extern bool of_JOIN(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AR(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AVP0_S(vthread_t thr, vvp_code_t code);
Expand Down Expand Up @@ -138,6 +139,7 @@ extern bool of_POW_WR(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
extern bool of_SET_AR(vthread_t thr, vvp_code_t code);
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);
Expand Down
3 changes: 2 additions & 1 deletion vvp/compile.cc
Expand Up @@ -150,6 +150,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%jmp/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%jmp/1", of_JMP1, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%load/ar",of_LOAD_AR,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/avp0/s",of_LOAD_AVP0_S,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
Expand Down Expand Up @@ -181,11 +182,11 @@ const static struct opcode_table_s opcode_table[] = {
{ "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
{ "%set/ar", of_SET_AR, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%set/wr", of_SET_WORDR,2,{OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
// { "%set/x0/x",of_SET_X0_X,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%shiftl/i0", of_SHIFTL_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
{ "%shiftr/i0", of_SHIFTR_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
{ "%shiftr/s/i0", of_SHIFTR_S_I0,2,{OA_BIT1,OA_NUMBER, OA_NONE} },
Expand Down
20 changes: 17 additions & 3 deletions vvp/opcodes.txt
Expand Up @@ -512,9 +512,14 @@ The <wid> is, line the %load/v, the result width. But unlike the
(%load/vp0/s) to the desired width.

* %load/wr <bit>, <vpi-label>
* %load/ar <bit>, <array-label>, <index>

This instruction reads a real value from the vpi-like object to a word
register.
The %load/wr instruction reads a real value from the vpi-like object
to a word register <bit>.

The %load/ar instruction reads a real value from an array. The <index>
is the index register that contains the canonical word address into
the array.

* %load/x1p <bit>, <functor-label>, <wid>

Expand Down Expand Up @@ -708,8 +713,17 @@ The address (in canonical form) is precalculated and loaded into index
register 3. This is the address of the word within the array.

* %set/wr <vpi-label>, <bit>
* %set/ar <array-label>, <index>, <bit>

The %set/wr instruction writes a real word to the specified VPI-like
object.

This instruction writes a real word to the specified VPI-like object.
The %set/ar instruction writes a real work to the specified array
word. The <array-label> addresses the array, and the <index> is the
name of the index register to address into the word. The index
register must contain an integer value that is the canonical address
of the array word. The <bit> is the index register that contains the
real value word to write.

* %set/x0 <var-label>, <bit>, <wid>

Expand Down

0 comments on commit 6cac1d2

Please sign in to comment.