Add support for real/realtime arrays.

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.
This commit is contained in:
Stephen Williams 2008-11-01 20:44:03 -07:00
parent 520d9b9dd0
commit 6cac1d2cab
14 changed files with 229 additions and 55 deletions

View File

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

View File

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

View File

@ -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;
}
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
// 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);
clr_word(res);
clr_word(word_ix);
return 0;
}

View File

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

View File

@ -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 */

View File

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

View File

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

View File

@ -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>
@ -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>
This instruction writes a real word to the specified VPI-like object.
The %set/wr 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>

View File

@ -369,6 +369,7 @@ struct __vpiRealVar {
extern struct __vpiScope* vpip_scope(__vpiRealVar*sig);
extern vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net);
extern struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj);
/*
* When a loaded VPI module announces a system task/function, one

View File

@ -28,11 +28,20 @@
#endif
# include <assert.h>
struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj)
{
assert(obj);
if (obj->vpi_type->type_code == vpiRealVar)
return (struct __vpiRealVar*)obj;
else
return 0;
}
static int real_var_get(int code, vpiHandle ref)
{
assert(ref->vpi_type->type_code == vpiRealVar);
struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref;
struct __vpiRealVar*rfp = vpip_realvar_from_handle(ref);
switch (code) {
case vpiArray:

View File

@ -2752,6 +2752,20 @@ bool of_JOIN(vthread_t thr, vvp_code_t cp)
return false;
}
/*
* %load/ar <bit>, <array-label>, <index>;
*/
bool of_LOAD_AR(vthread_t thr, vvp_code_t cp)
{
unsigned bit = cp->bit_idx[0];
unsigned idx = cp->bit_idx[1];
unsigned adr = thr->words[idx].w_int;
double word = array_get_word_r(cp->array, adr);
thr->words[bit].w_real = word;
return true;
}
/*
* %load/av <bit>, <array-label>, <wid> ;
*
@ -3936,6 +3950,24 @@ bool of_RELEASE_WR(vthread_t thr, vvp_code_t cp)
return true;
}
/*
* %set/av <label>, <index>, <bit>
*
* Write the real value in register <bit> to the array indexed by the
* integer value addressed bin index register <index>.
*/
bool of_SET_AR(vthread_t thr, vvp_code_t cp)
{
unsigned idx = cp->bit_idx[0];
unsigned bit = cp->bit_idx[1];
unsigned adr = thr->words[idx].w_int;
double value = thr->words[bit].w_real;
array_set_word(cp->array, adr, value);
return true;
}
/*
* This implements the "%set/av <label>, <bit>, <wid>" instruction. In
* this case, the <label> is an array label, and the <bit> and <wid>

View File

@ -1299,6 +1299,32 @@ bool vector4_to_value(const vvp_vector4_t&vec, double&val, bool signed_flag)
return flag;
}
vvp_realarray_t::vvp_realarray_t(unsigned wor)
: words_(wor)
{
array_ = new double[words_];
}
vvp_realarray_t::~vvp_realarray_t()
{
delete[]array_;
}
void vvp_realarray_t::set_word(unsigned word, double value)
{
if (word >= words_)
return;
array_[word] = value;
}
double vvp_realarray_t::get_word(unsigned word) const
{
if (word >= words_)
return 0.0;
else
return array_[word];
}
vvp_vector4array_t::vvp_vector4array_t(unsigned width__, unsigned words__)
: width_(width__), words_(words__)
{

View File

@ -467,6 +467,26 @@ extern bool vector4_to_value(const vvp_vector4_t&a, vvp_time64_t&val);
#endif
extern bool vector4_to_value(const vvp_vector4_t&a, double&val, bool is_signed);
/*
* The __vpiArray handle uses instances of this to keep an array of
* real valued variables.
*/
class vvp_realarray_t {
public:
vvp_realarray_t(unsigned words);
~vvp_realarray_t();
unsigned words() const { return words_; }
double get_word(unsigned idx) const;
void set_word(unsigned idx, double val);
private:
unsigned words_;
double*array_;
};
/*
* vvp_vector4array_t
*/

View File

@ -270,6 +270,8 @@ void compile_netw_real(char*label, char*array_label, unsigned long array_addr,
int msb, int lsb,
unsigned argc, struct symb_s*argv)
{
cerr << "XXXX compile_netw_real: label=" << label
<< ", array_label=" << array_label << endl;
__compile_real(label, 0, array_label, array_addr,
msb, lsb, false, argc, argv);
}