Create handles to access words of an array, if needed.

VPI code may need to access words of a variable array. If so, create
a compact handle format that gains that access with minimal pain.
This commit is contained in:
Stephen Williams 2008-05-16 16:20:22 -07:00
parent 0cd946a7af
commit e2ad59466a
3 changed files with 145 additions and 21 deletions

View File

@ -55,9 +55,12 @@ struct __vpiArray {
unsigned array_count;
struct __vpiDecConst first_addr;
struct __vpiDecConst last_addr;
// If this is a net array, nets lists the handles.
vpiHandle*nets;
vvp_vector4_t*vals;
unsigned vals_width;
// If this is a var array, then these are used instead of nets.
vvp_vector4_t *vals;
unsigned vals_width;
struct __vpiArrayWord*vals_words;
class vvp_fun_arrayport*ports_;
};
@ -74,6 +77,30 @@ struct __vpiArrayIndex {
unsigned done;
};
/*
* The vpiArrayWord is magic. It is used as the handle to return when
* vpi code tries to index or scan an array of variable words. The
* array word handle contains no actual data. It is just a hook for
* the vpi methods and to point to the parent.
*
* How the point to the parent works is tricky. The vpiArrayWord
* objects for an array are themselves allocated as an array. All the
* ArrayWord objects in the array have a word0 that points to the base
* of the array. Thus, the position into the array (and the index into
* the memory) is calculated by subtracting word0 from the ArrayWord
* pointer.
*
* To then get to the parent, use word0[-1].parent.
*/
struct __vpiArrayWord {
struct __vpiHandle base;
union {
struct __vpiArray*parent;
struct __vpiArrayWord*word0;
};
};
static int vpi_array_get(int code, vpiHandle ref);
static char*vpi_array_get_str(int code, vpiHandle ref);
static vpiHandle vpi_array_get_handle(int code, vpiHandle ref);
@ -86,6 +113,10 @@ static int array_iterator_free_object(vpiHandle ref);
static vpiHandle array_index_scan(vpiHandle ref, int);
static int array_index_free_object(vpiHandle ref);
static int vpi_array_var_word_get(int code, vpiHandle);
static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value);
static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int);
static const struct __vpirt vpip_arraymem_rt = {
vpiMemory,
vpi_array_get,
@ -124,9 +155,49 @@ static const struct __vpirt vpip_array_index_rt = {
array_index_free_object
};
static const struct __vpirt vpip_array_var_word_rt = {
vpiMemoryWord,
&vpi_array_var_word_get,
0,
&vpi_array_var_word_get_value,
&vpi_array_var_word_put_value,
0,
0,
0,
0
};
# define ARRAY_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemory), \
(struct __vpiArray*)ref)
# define ARRAY_VAR_WORD(ref) (assert(ref->vpi_type->type_code==vpiMemoryWord), \
(struct __vpiArrayWord*)ref)
static void array_make_vals_words(struct __vpiArray*parent)
{
assert(parent->vals_words == 0);
parent->vals_words = new struct __vpiArrayWord[parent->array_count + 1];
// Make word[-1] point to the parent.
parent->vals_words->parent = parent;
// Now point to word-0
parent->vals_words += 1;
struct __vpiArrayWord*words = parent->vals_words;
for (unsigned idx = 0 ; idx < parent->array_count ; idx += 1) {
words[idx].base.vpi_type = &vpip_array_var_word_rt;
words[idx].word0 = words;
}
}
static unsigned decode_array_word_pointer(struct __vpiArrayWord*word,
struct __vpiArray*&parent)
{
struct __vpiArrayWord*word0 = word->word0;
parent = (word0 - 1) -> parent;
return word - word0;
}
static int vpi_array_get(int code, vpiHandle ref)
{
struct __vpiArray*obj = ARRAY_HANDLE(ref);
@ -207,9 +278,52 @@ static vpiHandle vpi_array_index(vpiHandle ref, int index)
if (index < 0)
return 0;
assert(obj->nets != 0);
if (obj->nets != 0) {
return obj->nets[index];
}
return obj->nets[index];
if (obj->vals_words == 0)
array_make_vals_words(obj);
return &(obj->vals_words[index].base);
}
static int vpi_array_var_word_get(int code, vpiHandle ref)
{
struct __vpiArrayWord*obj = ARRAY_VAR_WORD(ref);
struct __vpiArray*parent;
decode_array_word_pointer(obj, parent);
switch (code) {
case vpiSize:
return (int) parent->vals_width;
default:
return 0;
}
}
static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
{
struct __vpiArrayWord*obj = ARRAY_VAR_WORD(ref);
struct __vpiArray*parent;
unsigned index = decode_array_word_pointer(obj, parent);
assert(0);
}
static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags)
{
struct __vpiArrayWord*obj = ARRAY_VAR_WORD(ref);
struct __vpiArray*parent;
unsigned index = decode_array_word_pointer(obj, parent);
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
array_set_word(parent, index, 0, val);
return ref;
}
# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \
@ -381,6 +495,7 @@ static vpiHandle vpip_make_array(char*label, const char*name,
obj->nets = 0;
obj->vals = 0;
obj->vals_width = 0;
obj->vals_words = 0;
// Initialize (clear) the read-ports list.
obj->ports_ = 0;

View File

@ -530,6 +530,8 @@ extern void vpip_oct_str_to_vec4(vvp_vector4_t&val, const char*str);
extern void vpip_dec_str_to_vec4(vvp_vector4_t&val, const char*str, bool sign);
extern void vpip_hex_str_to_vec4(vvp_vector4_t&val, const char*str);
extern vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid);
extern void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width,
bool signed_flag, s_vpi_value*vp);

View File

@ -645,6 +645,27 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
? (rfp->msb - rfp->lsb + 1)
: (rfp->lsb - rfp->msb + 1);
vvp_vector4_t val = vec4_from_vpi_value(vp, wid);
/* If this is a vpiForce, then instead of writing to the
signal input port, we write to the special "force" port. */
int dest_port = 0;
if (flags == vpiForceFlag)
dest_port = 2;
/* This is the destination that I'm going to poke into. Make
it from the vvp_net_t pointer, and assume a write to
port-0. This is the port where signals receive input. */
vvp_net_ptr_t destination (rfp->node, dest_port);
vvp_send_vec4(destination, val);
return ref;
}
vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid)
{
vvp_vector4_t val (wid, BIT4_0);
switch (vp->format) {
@ -691,27 +712,13 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
default:
fprintf(stderr, "vvp internal error: put_value: "
"value type %u not implemented."
" Signal is %s in scope %s\n",
vp->format, vpi_get_str(vpiName, ref), rfp->scope->name);
"value type %u not implemented here.\n",
vp->format);
assert(0);
}
/* If this is a vpiForce, then instead of writing to the
signal input port, we write to the special "force" port. */
int dest_port = 0;
if (flags == vpiForceFlag)
dest_port = 2;
/* This is the destination that I'm going to poke into. Make
it from the vvp_net_t pointer, and assume a write to
port-0. This is the port where signals receive input. */
vvp_net_ptr_t destination (rfp->node, dest_port);
vvp_send_vec4(destination, val);
return ref;
return val;
}
static const struct __vpirt vpip_reg_rt = {