iverilog/vvp/array.cc

2089 lines
56 KiB
C++

/*
* Copyright (c) 2007-2013 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "array.h"
# include "symbols.h"
# include "schedule.h"
# include "vpi_priv.h"
# include "vvp_net_sig.h"
# include "vvp_darray.h"
# include "config.h"
#ifdef CHECK_WITH_VALGRIND
#include "vvp_cleanup.h"
#endif
# include <cstdlib>
# include <cstring>
# include <climits>
# include <iostream>
# include "compile.h"
# include <cassert>
# include "ivl_alloc.h"
unsigned long count_net_arrays = 0;
unsigned long count_net_array_words = 0;
unsigned long count_var_arrays = 0;
unsigned long count_var_array_words = 0;
unsigned long count_real_arrays = 0;
unsigned long count_real_array_words = 0;
static symbol_map_s<struct __vpiArray>* array_table =0;
class vvp_fun_arrayport;
static void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
vvp_array_t array_find(const char*label)
{
if (array_table == 0)
return 0;
vvp_array_t v = array_table->sym_get_value(label);
return v;
}
/*
* 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
* 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 vals member points to a dynamic array objects that has an
* array of double variables. This is very much like the way the
* vector4 array works.
*/
struct __vpiArray : public __vpiHandle {
__vpiArray();
int get_type_code(void) const;
int vpi_get(int code);
char* vpi_get_str(int code);
vpiHandle vpi_handle(int code);
vpiHandle vpi_iterate(int code);
vpiHandle vpi_index(int idx);
struct __vpiScope*scope;
const char*name; /* Permanently allocated string */
unsigned array_count;
__vpiDecConst first_addr;
__vpiDecConst last_addr;
__vpiDecConst msb;
__vpiDecConst lsb;
unsigned vals_width;
// 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*vals4;
vvp_darray *vals;
struct __vpiArrayWord*vals_words;
vvp_fun_arrayport*ports_;
struct __vpiCallback *vpi_callbacks;
bool signed_flag;
bool swap_addr;
};
struct __vpiArrayIterator : public __vpiHandle {
__vpiArrayIterator();
int get_type_code(void) const;
vpiHandle vpi_index(int idx);
free_object_fun_t free_object_fun(void);
struct __vpiArray*array;
unsigned next;
};
struct __vpiArrayIndex : public __vpiHandle {
__vpiArrayIndex();
int get_type_code(void) const;
vpiHandle vpi_iterate(int code);
vpiHandle vpi_index(int idx);
free_object_fun_t free_object_fun(void);
__vpiDecConst *index;
unsigned done;
};
struct __vpiArrayVthrA : public __vpiHandle {
__vpiArrayVthrA();
int get_type_code(void) const;
int vpi_get(int code);
char* vpi_get_str(int code);
void vpi_get_value(p_vpi_value val);
vpiHandle vpi_put_value(p_vpi_value val, int flags);
vpiHandle vpi_handle(int code);
struct __vpiArray*array;
// If this is set, then use it to get the index value.
vpiHandle address_handle;
// If wid==0, then address is the address into the array.
unsigned address;
unsigned get_address() const
{
if (address_handle) {
s_vpi_value vp;
/* Check to see if the value is defined. */
vp.format = vpiVectorVal;
address_handle->vpi_get_value(&vp);
int words = (address_handle->vpi_get(vpiSize)-1)/32 + 1;
for(int idx = 0; idx < words; idx += 1) {
/* Return UINT_MAX to indicate an X base. */
if (vp.value.vector[idx].bval != 0) return UINT_MAX;
}
/* The value is defined so get and return it. */
vp.format = vpiIntVal;
address_handle->vpi_get_value(&vp);
return vp.value.integer;
}
return address;
}
};
struct __vpiArrayVthrAPV : public __vpiHandle {
__vpiArrayVthrAPV();
int get_type_code(void) const;
int vpi_get(int code);
char* vpi_get_str(int code);
void vpi_get_value(p_vpi_value val);
struct __vpiArray*array;
unsigned word_sel;
unsigned part_bit;
unsigned part_wid;
};
/* Get the array word size. */
unsigned get_array_word_size(vvp_array_t array)
{
unsigned width;
assert(array->array_count > 0);
/* For a net array we need to get the width from the first element. */
if (array->nets) {
assert(array->vals4 == 0 && array->vals == 0);
struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(array->nets[0]);
assert(vsig);
width = vpip_size(vsig);
/* For a variable array we can get the width from vals_width. */
} else {
assert(array->vals4 || array->vals);
width = array->vals_width;
}
return width;
}
bool is_net_array(vpiHandle obj)
{
struct __vpiArray*rfp = dynamic_cast<__vpiArray*> (obj);
assert(rfp);
if (rfp->nets != 0) return true;
return false;
}
/*
* 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.
*
* The vpiArrayWord is also used as a handle for the index (vpiIndex)
* for the word. To make that work, return the pointer to the as_index
* member instead of the as_word member. The result is a different set
* of vpi functions is bound to the same structure. All the details
* for the word also apply when treating this as an index.
*/
struct __vpiArrayWord {
struct as_word_t : public __vpiHandle {
as_word_t();
int get_type_code(void) const;
int vpi_get(int code);
char*vpi_get_str(int code);
void vpi_get_value(p_vpi_value val);
vpiHandle vpi_put_value(p_vpi_value val, int flags);
vpiHandle vpi_handle(int code);
} as_word;
struct as_index_t : public __vpiHandle {
as_index_t();
int get_type_code(void) const;
void vpi_get_value(p_vpi_value val);
} as_index;
union {
struct __vpiArray*parent;
struct __vpiArrayWord*word0;
};
};
static void array_make_vals_words(struct __vpiArray*parent);
static vpiHandle array_index_scan(vpiHandle ref, int);
static int vpi_array_var_word_get(int code, vpiHandle);
static char*vpi_array_var_word_get_str(int code, vpiHandle);
static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value vp);
static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp,
int);
static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref);
static void vpi_array_var_index_get_value(vpiHandle ref, p_vpi_value vp);
static int vpi_array_vthr_A_get(int code, vpiHandle);
static char*vpi_array_vthr_A_get_str(int code, vpiHandle);
static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value vp);
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int);
static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref);
static int vpi_array_vthr_APV_get(int code, vpiHandle);
static char*vpi_array_vthr_APV_get_str(int code, vpiHandle);
static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp);
inline __vpiArray::__vpiArray()
{ }
int __vpiArray::get_type_code(void) const
{ return vpiMemory; }
int __vpiArray::vpi_get(int code)
{
switch (code) {
case vpiLineNo:
return 0; // Not implemented for now!
case vpiSize:
return (int) array_count;
case vpiAutomatic:
return (int) scope->is_automatic;
default:
return 0;
}
}
char* __vpiArray::vpi_get_str(int code)
{
if (code == vpiFile) { // Not implemented for now!
return simple_set_rbuf_str(file_names[0]);
}
return generic_get_str(code, scope, name, NULL);
}
vpiHandle __vpiArray::vpi_handle(int code)
{
switch (code) {
case vpiLeftRange:
if (swap_addr) return &last_addr;
else return &first_addr;
case vpiRightRange:
if (swap_addr) return &first_addr;
else return &last_addr;
case vpiScope:
return scope;
case vpiModule:
return vpip_module(scope);
}
return 0;
}
vpiHandle __vpiArray::vpi_iterate(int code)
{
switch (code) {
case vpiMemoryWord: {
struct __vpiArrayIterator*res;
res = new __vpiArrayIterator;
res->array = this;
res->next = 0;
return res;
}
}
return 0;
}
/*
* VPI code passes indices that are not yet converted to canonical
* form, so this index function does it here.
*/
vpiHandle __vpiArray::vpi_index(int index)
{
index -= first_addr.get_value();
if (index >= (long)array_count)
return 0;
if (index < 0)
return 0;
if (nets != 0) {
return nets[index];
}
if (vals_words == 0)
array_make_vals_words(this);
return &(vals_words[index].as_word);
}
inline __vpiArrayIterator::__vpiArrayIterator()
{ }
int __vpiArrayIterator::get_type_code(void) const
{ return vpiIterator; }
vpiHandle __vpiArrayIterator::vpi_index(int)
{
if (next >= array->array_count) {
vpi_free_object(this);
return 0;
}
unsigned use_index = next;
next += 1;
if (array->nets) return array->nets[use_index];
assert(array->vals4 || array->vals);
if (array->vals_words == 0) array_make_vals_words(array);
return &(array->vals_words[use_index].as_word);
}
static int array_iterator_free_object(vpiHandle ref)
{
struct __vpiArrayIterator*obj = dynamic_cast<__vpiArrayIterator*>(ref);
delete obj;
return 1;
}
__vpiHandle::free_object_fun_t __vpiArrayIterator::free_object_fun(void)
{ return &array_iterator_free_object; }
inline __vpiArrayIndex::__vpiArrayIndex()
{ }
int __vpiArrayIndex::get_type_code(void) const
{ return vpiIterator; }
vpiHandle __vpiArrayIndex::vpi_iterate(int code)
{ return array_index_iterate(code, this); }
vpiHandle __vpiArrayIndex::vpi_index(int idx)
{ return array_index_scan(this, idx); }
static int array_index_free_object(vpiHandle ref)
{
struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref);
delete obj;
return 1;
}
__vpiHandle::free_object_fun_t __vpiArrayIndex::free_object_fun(void)
{ return &array_index_free_object; }
inline __vpiArrayWord::as_word_t::as_word_t()
{ }
int __vpiArrayWord::as_word_t::get_type_code(void) const
{ return vpiMemoryWord; }
int __vpiArrayWord::as_word_t::vpi_get(int code)
{ return vpi_array_var_word_get(code, this); }
char* __vpiArrayWord::as_word_t::vpi_get_str(int code)
{ return vpi_array_var_word_get_str(code, this); }
void __vpiArrayWord::as_word_t::vpi_get_value(p_vpi_value val)
{ vpi_array_var_word_get_value(this, val); }
vpiHandle __vpiArrayWord::as_word_t::vpi_put_value(p_vpi_value val, int flags)
{ return vpi_array_var_word_put_value(this, val, flags); }
vpiHandle __vpiArrayWord::as_word_t::vpi_handle(int code)
{ return vpi_array_var_word_get_handle(code, this); }
inline __vpiArrayWord::as_index_t::as_index_t()
{ }
int __vpiArrayWord::as_index_t::get_type_code(void) const
{ return vpiIndex; }
void __vpiArrayWord::as_index_t::vpi_get_value(p_vpi_value val)
{ vpi_array_var_index_get_value(this, val); }
inline __vpiArrayVthrA::__vpiArrayVthrA()
{ }
int __vpiArrayVthrA::get_type_code(void) const
{ return vpiMemoryWord; }
int __vpiArrayVthrA::vpi_get(int code)
{ return vpi_array_vthr_A_get(code, this); }
char* __vpiArrayVthrA::vpi_get_str(int code)
{ return vpi_array_vthr_A_get_str(code, this); }
void __vpiArrayVthrA::vpi_get_value(p_vpi_value val)
{ vpi_array_vthr_A_get_value(this, val); }
vpiHandle __vpiArrayVthrA::vpi_put_value(p_vpi_value val, int flags)
{ return vpi_array_vthr_A_put_value(this, val, flags); }
vpiHandle __vpiArrayVthrA::vpi_handle(int code)
{ return vpi_array_vthr_A_get_handle(code, this); }
inline __vpiArrayVthrAPV::__vpiArrayVthrAPV()
{ }
int __vpiArrayVthrAPV::get_type_code(void) const
{ return vpiMemoryWord; }
int __vpiArrayVthrAPV::vpi_get(int code)
{ return vpi_array_vthr_APV_get(code, this); }
char* __vpiArrayVthrAPV::vpi_get_str(int code)
{ return vpi_array_vthr_APV_get_str(code, this); }
void __vpiArrayVthrAPV::vpi_get_value(p_vpi_value val)
{ vpi_array_vthr_APV_get_value(this, val); }
static struct __vpiArrayWord* array_var_word_from_handle(vpiHandle ref)
{
if (ref == 0)
return 0;
__vpiArrayWord::as_word_t*ptr = dynamic_cast<__vpiArrayWord::as_word_t*> (ref);
if (ptr == 0)
return 0;
return (struct __vpiArrayWord*) ref;
}
static struct __vpiArrayWord* array_var_index_from_handle(vpiHandle ref)
{
if (ref == 0)
return 0;
__vpiArrayWord::as_index_t*ptr = dynamic_cast<__vpiArrayWord::as_index_t*> (ref);
if (ptr == 0)
return 0;
assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_index_t));
assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_word_t));
return (struct __vpiArrayWord*) (ref-1);
}
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].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_var_word_get(int code, vpiHandle ref)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
struct __vpiArray*parent;
assert(obj);
decode_array_word_pointer(obj, parent);
assert(parent->nets == 0);
switch (code) {
case vpiLineNo:
return 0; // Not implemented for now!
case vpiSize:
if (parent->vals4) {
assert(parent->vals == 0);
return (int) parent->vals4->width();
} else {
assert(parent->vals4 == 0);
return 1;
}
case vpiLeftRange:
return parent->msb.get_value();
case vpiRightRange:
return parent->lsb.get_value();
case vpiAutomatic:
return (int) parent->scope->is_automatic;
#if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX)
case _vpiFromThr:
return _vpiNoThr;
#endif
default:
return 0;
}
}
static char*vpi_array_var_word_get_str(int code, vpiHandle ref)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
struct __vpiArray*parent;
assert(obj);
unsigned index = decode_array_word_pointer(obj, parent);
if (code == vpiFile) { // Not implemented for now!
return simple_set_rbuf_str(file_names[0]);
}
char sidx [64];
snprintf(sidx, 63, "%d", (int)index + parent->first_addr.get_value());
return generic_get_str(code, parent->scope, parent->name, sidx);
}
static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value vp)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
struct __vpiArray*parent;
assert(obj);
unsigned index = decode_array_word_pointer(obj, parent);
unsigned width = parent->vals4->width();
vpip_vec4_get_value(parent->vals4->get_word(index), width,
parent->signed_flag, vp);
}
static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
struct __vpiArray*parent;
assert(obj);
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;
}
static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref)
{
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
struct __vpiArray*parent;
assert(obj);
decode_array_word_pointer(obj, parent);
switch (code) {
case vpiIndex:
return &(obj->as_index);
case vpiLeftRange:
return &parent->msb;
case vpiRightRange:
return &parent->lsb;
case vpiParent:
return parent;
case vpiScope:
return parent->scope;
case vpiModule:
return vpip_module(parent->scope);
}
return 0;
}
static void vpi_array_var_index_get_value(vpiHandle ref, p_vpi_value vp)
{
struct __vpiArrayWord*obj = array_var_index_from_handle(ref);
struct __vpiArray*parent;
assert(obj);
unsigned index = decode_array_word_pointer(obj, parent);
assert(vp->format == vpiIntVal);
vp->value.integer = index;
}
vpiHandle array_index_iterate(int code, vpiHandle ref)
{
__vpiDecConst *obj = dynamic_cast<__vpiDecConst*>(ref);
assert(obj);
if (code == vpiIndex) {
struct __vpiArrayIndex*res;
res = new __vpiArrayIndex;
res->index = obj;
res->done = 0;
return res;
}
return 0;
}
static vpiHandle array_index_scan(vpiHandle ref, int)
{
struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref);
if (obj->done == 0) {
obj->done = 1;
return obj->index;
}
vpi_free_object(ref);
return 0;
}
static int vpi_array_vthr_A_get(int code, vpiHandle ref)
{
struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref);
assert(obj);
struct __vpiArray*parent = obj->array;
switch (code) {
case vpiLineNo:
return 0; // Not implemented for now!
case vpiSize:
return get_array_word_size(parent);
case vpiLeftRange:
return parent->msb.get_value();
case vpiRightRange:
return parent->lsb.get_value();
case vpiIndex:
return (int)obj->get_address() + parent->first_addr.get_value();
case vpiAutomatic:
return (int) parent->scope->is_automatic;
#if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX)
case _vpiFromThr:
return _vpi_at_A;
#endif
// If address_handle is not zero we definitely have a
// variable.
case vpiConstantSelect:
return obj->address_handle == 0;
default:
return 0;
}
}
static char*vpi_array_vthr_A_get_str(int code, vpiHandle ref)
{
struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref);
assert(obj);
struct __vpiArray*parent = obj->array;
if (code == vpiFile) { // Not implemented for now!
return simple_set_rbuf_str(file_names[0]);
}
char sidx [64];
snprintf(sidx, 63, "%d", (int)obj->get_address() + parent->first_addr.get_value());
return generic_get_str(code, parent->scope, parent->name, sidx);
}
// This function return true if the underlying array words are real.
static bool vpi_array_is_real(vvp_array_t arr)
{
// Check to see if this is a variable/register array.
if (arr->vals4 != 0) // A bit based variable/register array.
return false;
if (dynamic_cast<vvp_darray_real*> (arr->vals))
return true;
if (arr->vals != 0)
return false;
// This must be a net array so look at element 0 to find the type.
assert(arr->nets != 0);
assert(arr->array_count > 0);
struct __vpiRealVar*rsig = dynamic_cast<__vpiRealVar*>(arr->nets[0]);
if (rsig) {
return true;
}
return false;
}
static bool vpi_array_is_string(vvp_array_t arr)
{
// Check to see if this is a variable/register array.
if (arr->vals4 != 0) // A bit based variable/register array.
return false;
if (dynamic_cast<vvp_darray_string*> (arr->vals))
return true;
return false;
}
static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value vp)
{
struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref);
assert(obj);
struct __vpiArray*parent = obj->array;
assert(parent);
unsigned index = obj->get_address();
if (vpi_array_is_real(parent)) {
double tmp = array_get_word_r(parent, index);
vpip_real_get_value(tmp, vp);
} else if (vpi_array_is_string(parent)) {
string tmp = array_get_word_str(parent, index);
vpip_string_get_value(tmp, vp);
} else {
vvp_vector4_t tmp = array_get_word(parent, index);
unsigned width = get_array_word_size(parent);
vpip_vec4_get_value(tmp, width, parent->signed_flag, vp);
}
}
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
{
struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref);
assert(obj);
struct __vpiArray*parent = obj->array;
unsigned index = obj->get_address();
assert(parent);
assert(index < parent->array_count);
if (vpi_array_is_real(parent)) {
double val = real_from_vpi_value(vp);
array_set_word(parent, index, val);
} else {
unsigned width = get_array_word_size(parent);
vvp_vector4_t val = vec4_from_vpi_value(vp, width);
array_set_word(parent, index, 0, val);
}
return ref;
}
static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref)
{
struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref);
assert(obj);
struct __vpiArray*parent = obj->array;
switch (code) {
case vpiIndex:
break; // Not implemented!
case vpiLeftRange:
return &parent->msb;
case vpiRightRange:
return &parent->lsb;
case vpiParent:
return parent;
case vpiScope:
return parent->scope;
case vpiModule:
return vpip_module(parent->scope);
}
return 0;
}
static int vpi_array_vthr_APV_get(int code, vpiHandle ref)
{
struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref);
struct __vpiArray*parent = obj->array;
switch (code) {
case vpiLineNo:
return 0; // Not implemented for now!
case vpiSize:
return obj->part_wid;
case vpiLeftRange:
return parent->msb.get_value();
case vpiRightRange:
return parent->lsb.get_value();
case vpiIndex:
return (int)obj->word_sel;
case vpiAutomatic:
return (int) parent->scope->is_automatic;
#if defined(CHECK_WITH_VALGRIND) || defined(BR916_STOPGAP_FIX)
case _vpiFromThr:
return _vpi_at_APV;
#endif
case vpiConstantSelect:
return 1;
default:
return 0;
}
}
static char*vpi_array_vthr_APV_get_str(int code, vpiHandle ref)
{
struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref);
assert(obj);
struct __vpiArray*parent = obj->array;
if (code == vpiFile) { // Not implemented for now!
return simple_set_rbuf_str(file_names[0]);
}
char sidx [64];
snprintf(sidx, 63, "%u", obj->word_sel + parent->first_addr.get_value());
return generic_get_str(code, parent->scope, parent->name, sidx);
}
static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp)
{
struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref);
assert(obj);
struct __vpiArray*parent = obj->array;
assert(parent);
unsigned index = obj->word_sel;
if (vpi_array_is_real(parent)) {
double tmp = array_get_word_r(parent, index);
vpip_real_get_value(tmp, vp);
} else {
vvp_vector4_t tmp = array_get_word(parent, index);
tmp = tmp.subvalue(obj->part_bit, obj->part_wid);
vpip_vec4_get_value(tmp, obj->part_wid, parent->signed_flag, vp);
}
}
void array_set_word(vvp_array_t arr,
unsigned address,
unsigned part_off,
vvp_vector4_t val)
{
if (address >= arr->array_count)
return;
if (arr->vals4) {
assert(arr->nets == 0);
if (part_off != 0 || val.size() != arr->vals_width) {
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()
<< " arr->vals[address].size()=" << tmp.size()
<< " arr->vals_width=" << arr->vals_width << endl;
assert(0);
}
tmp.set_vec(part_off, val);
arr->vals4->set_word(address, tmp);
} else {
arr->vals4->set_word(address, val);
}
array_word_change(arr, address);
return;
}
if (arr->vals) {
assert(arr->nets == 0);
// FIXME: For now, assume no part select of word?
assert(part_off==0);
assert(val.size() == arr->vals_width);
arr->vals->set_word(address, val);
array_word_change(arr, address);
return;
}
assert(arr->nets != 0);
// Select the word of the array that we affect.
vpiHandle word = arr->nets[address];
struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word);
assert(vsig);
vsig->node->send_vec4_pv(val, part_off, val.size(), vpip_size(vsig), 0);
array_word_change(arr, address);
}
void array_set_word(vvp_array_t arr, unsigned address, double val)
{
assert(arr->vals != 0);
assert(arr->nets == 0);
if (address >= arr->vals->get_size())
return;
arr->vals->set_word(address, val);
array_word_change(arr, address);
}
void array_set_word(vvp_array_t arr, unsigned address, const string&val)
{
assert(arr->vals != 0);
assert(arr->nets == 0);
if (address >= arr->vals->get_size())
return;
arr->vals->set_word(address, val);
array_word_change(arr, address);
}
void array_set_word(vvp_array_t arr, unsigned address, const vvp_object_t&val)
{
assert(arr->vals != 0);
assert(arr->nets == 0);
if (address >= arr->vals->get_size())
return;
arr->vals->set_word(address, val);
array_word_change(arr, address);
}
vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
{
if (arr->vals4) {
assert(arr->nets == 0);
assert(arr->vals == 0);
return arr->vals4->get_word(address);
}
if (arr->vals) {
assert(arr->nets == 0);
assert(arr->vals4== 0);
if (address >= arr->vals->get_size())
return vvp_vector4_t(arr->vals_width, BIT4_X);
vvp_vector4_t val;
arr->vals->get_word(address, val);
return val;
}
assert(arr->vals4 == 0);
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->nets[0];
assert(word);
struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word);
assert(vsig);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (vsig->node->fil);
assert(sig);
return vvp_vector4_t(sig->value_size(), BIT4_X);
}
vpiHandle word = arr->nets[address];
struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word);
assert(vsig);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (vsig->node->fil);
assert(sig);
vvp_vector4_t val;
sig->vec4_value(val);
return val;
}
double array_get_word_r(vvp_array_t arr, unsigned address)
{
if (arr->vals) {
assert(arr->vals4 == 0);
assert(arr->nets == 0);
// In this context, address out of bounds returns 0.0
// instead of an error.
if (address >= arr->vals->get_size())
return 0.0;
double val;
arr->vals->get_word(address, val);
return val;
}
assert(arr->nets);
vpiHandle word = arr->nets[address];
struct __vpiRealVar*vsig = dynamic_cast<__vpiRealVar*>(word);
assert(vsig);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (vsig->net->fil);
assert(sig);
double val = sig->real_value();
return val;
}
void array_get_word_obj(vvp_array_t arr, unsigned address, vvp_object_t&val)
{
if (arr->vals) {
assert(arr->vals4 == 0);
assert(arr->nets == 0);
// In this context, address out of bounds returns 0.0
// instead of an error.
if (address >= arr->vals->get_size()) {
val = vvp_object_t();
return;
}
arr->vals->get_word(address, val);
return;
}
assert(arr->nets);
// Arrays of string nets not implemented!
assert(0);
return;
}
string array_get_word_str(vvp_array_t arr, unsigned address)
{
if (arr->vals) {
assert(arr->vals4 == 0);
assert(arr->nets == 0);
// In this context, address out of bounds returns 0.0
// instead of an error.
if (address >= arr->vals->get_size())
return "";
string val;
arr->vals->get_word(address, val);
return val;
}
assert(arr->nets);
// Arrays of string nets not implemented!
assert(0);
return "";
}
static vpiHandle vpip_make_array(char*label, const char*name,
int first_addr, int last_addr,
bool signed_flag)
{
struct __vpiArray*obj = new __vpiArray;
obj->signed_flag = signed_flag;
// Assume increasing addresses.
if (last_addr >= first_addr) {
obj->swap_addr = false;
} else {
obj->swap_addr = true;
int tmp = last_addr;
last_addr = first_addr;
first_addr = tmp;
}
assert(last_addr >= first_addr);
unsigned array_count = last_addr+1-first_addr;
// For now, treat all arrays as memories. This is not quite
// correct, as arrays are arrays with memories a special case.
obj->scope = vpip_peek_current_scope();
obj->name = vpip_name_string(name);
obj->array_count = array_count;
obj->first_addr.set_value(first_addr);
obj->last_addr .set_value(last_addr);
// Start off now knowing if we are nets or variables.
obj->nets = 0;
obj->vals4 = 0;
obj->vals = 0;
obj->vals_width = 0;
obj->vals_words = 0;
// Initialize (clear) the read-ports list.
obj->ports_ = 0;
obj->vpi_callbacks = 0;
/* Add this symbol to the array_symbols table for later lookup. */
if (!array_table)
array_table = new symbol_map_s<struct __vpiArray>;
assert(!array_find(label));
array_table->sym_set_value(label, obj);
/* 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 array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word,
int msb, int lsb)
{
assert(array->msb.get_value() == msb);
assert(array->lsb.get_value() == lsb);
assert(addr < array->array_count);
assert(array->nets);
array->nets[addr] = word;
}
void array_attach_word(vvp_array_t array, unsigned addr, vpiHandle word)
{
assert(addr < array->array_count);
assert(array->nets);
array->nets[addr] = word;
if (struct __vpiSignal*sig = dynamic_cast<__vpiSignal*>(word)) {
vvp_net_t*net = sig->node;
assert(net);
vvp_vpi_callback*fun = dynamic_cast<vvp_vpi_callback*>(net->fil);
assert(fun);
fun->attach_as_word(array, addr);
sig->is_netarray = 1;
sig->within.parent = array;
sig->id.index = new __vpiDecConst(addr + array->first_addr.get_value());
// Now we know the data type, update the array signed_flag.
array->signed_flag = sig->signed_flag;
return;
}
if (struct __vpiRealVar*sig = dynamic_cast<__vpiRealVar*>(word)) {
vvp_net_t*net = sig->net;
assert(net);
vvp_vpi_callback*fun = dynamic_cast<vvp_vpi_callback*>(net->fil);
assert(fun);
fun->attach_as_word(array, addr);
sig->is_netarray = 1;
sig->within.parent = array;
sig->id.index = new __vpiDecConst(addr + array->first_addr.get_value());
// Now we know the data type, update the array signed_flag.
array->signed_flag = true;
return;
}
}
void compile_var_array(char*label, char*name, int last, int first,
int msb, int lsb, char signed_flag)
{
vpiHandle obj = vpip_make_array(label, name, first, last,
signed_flag != 0);
struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
/* Make the words. */
arr->vals_width = labs(msb-lsb) + 1;
if (vpip_peek_current_scope()->is_automatic) {
arr->vals4 = new vvp_vector4array_aa(arr->vals_width,
arr->array_count);
} else {
arr->vals4 = new vvp_vector4array_sa(arr->vals_width,
arr->array_count);
}
arr->msb.set_value(msb);
arr->lsb.set_value(lsb);
count_var_arrays += 1;
count_var_array_words += arr->array_count;
free(label);
delete[] name;
}
void compile_var2_array(char*label, char*name, int last, int first,
int msb, int lsb, bool signed_flag)
{
vpiHandle obj = vpip_make_array(label, name, first, last, signed_flag);
struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
/* Make the words. */
arr->msb.set_value(msb);
arr->lsb.set_value(lsb);
arr->vals_width = labs(msb-lsb) + 1;
assert(! arr->nets);
if (lsb == 0 && msb == 7 && signed_flag) {
arr->vals = new vvp_darray_atom<int8_t>(arr->array_count);
} else if (lsb == 0 && msb == 7 && !signed_flag) {
arr->vals = new vvp_darray_atom<uint8_t>(arr->array_count);
} else if (lsb == 0 && msb == 15 && signed_flag) {
arr->vals = new vvp_darray_atom<int16_t>(arr->array_count);
} else if (lsb == 0 && msb == 15 && !signed_flag) {
arr->vals = new vvp_darray_atom<uint16_t>(arr->array_count);
} else if (lsb == 0 && msb == 31 && signed_flag) {
arr->vals = new vvp_darray_atom<int32_t>(arr->array_count);
} else if (lsb == 0 && msb == 31 && !signed_flag) {
arr->vals = new vvp_darray_atom<uint32_t>(arr->array_count);
} else if (lsb == 0 && msb == 63 && signed_flag) {
arr->vals = new vvp_darray_atom<int64_t>(arr->array_count);
} else if (lsb == 0 && msb == 63 && !signed_flag) {
arr->vals = new vvp_darray_atom<uint64_t>(arr->array_count);
} else {
// For now, only support the atom sizes.
assert(0);
}
count_var_arrays += 1;
count_var_array_words += arr->array_count;
free(label);
delete[] name;
}
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 = dynamic_cast<__vpiArray*>(obj);
/* Make the words. */
arr->vals = new vvp_darray_real(arr->array_count);
arr->vals_width = 1;
count_real_arrays += 1;
count_real_array_words += arr->array_count;
free(label);
delete[] name;
}
void compile_string_array(char*label, char*name, int last, int first)
{
vpiHandle obj = vpip_make_array(label, name, first, last, true);
struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
/* Make the words. */
arr->vals = new vvp_darray_string(arr->array_count);
arr->vals_width = 1;
count_real_arrays += 1;
count_real_array_words += arr->array_count;
free(label);
delete[] name;
}
void compile_object_array(char*label, char*name, int last, int first)
{
vpiHandle obj = vpip_make_array(label, name, first, last, true);
struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
/* Make the words. */
arr->vals = new vvp_darray_object(arr->array_count);
arr->vals_width = 1;
count_real_arrays += 1;
count_real_array_words += arr->array_count;
free(label);
delete[] name;
}
void compile_net_array(char*label, char*name, int last, int first)
{
// At this point we don't know the array data type, so we
// initialise signed_flag to false. This will be corrected
// (if necessary) when we attach words to the array.
vpiHandle obj = vpip_make_array(label, name, first, last, false);
struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj);
arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle));
count_net_arrays += 1;
count_net_array_words += arr->array_count;
free(label);
delete[] name;
}
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();
virtual void check_word_change(unsigned long addr) = 0;
protected:
vvp_array_t arr_;
vvp_net_t *net_;
unsigned long addr_;
friend void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
friend void array_word_change(vvp_array_t, unsigned long);
vvp_fun_arrayport*next_;
};
vvp_fun_arrayport::vvp_fun_arrayport(vvp_array_t mem, vvp_net_t*net)
: arr_(mem), net_(net), addr_(0)
{
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()
{
}
class vvp_fun_arrayport_sa : public vvp_fun_arrayport {
public:
explicit vvp_fun_arrayport_sa(vvp_array_t mem, vvp_net_t*net);
explicit vvp_fun_arrayport_sa(vvp_array_t mem, vvp_net_t*net, long addr);
~vvp_fun_arrayport_sa();
void check_word_change(unsigned long addr);
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t);
private:
};
vvp_fun_arrayport_sa::vvp_fun_arrayport_sa(vvp_array_t mem, vvp_net_t*net)
: vvp_fun_arrayport(mem, net)
{
}
vvp_fun_arrayport_sa::vvp_fun_arrayport_sa(vvp_array_t mem, vvp_net_t*net, long addr)
: vvp_fun_arrayport(mem, net, addr)
{
}
vvp_fun_arrayport_sa::~vvp_fun_arrayport_sa()
{
}
void vvp_fun_arrayport_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t)
{
bool addr_valid_flag;
switch (port.port()) {
case 0: // Address input
addr_valid_flag = vector4_to_value(bit, addr_);
if (! addr_valid_flag)
addr_ = arr_->array_count;
if (vpi_array_is_real(arr_))
port.ptr()->send_real(array_get_word_r(arr_, addr_), 0);
else
port.ptr()->send_vec4(array_get_word(arr_,addr_), 0);
break;
default:
fprintf(stdout, "XXXX write ports not implemented.\n");
assert(0);
}
}
void vvp_fun_arrayport_sa::check_word_change(unsigned long addr)
{
if (addr != addr_) return;
if (vpi_array_is_real(arr_)) {
net_->send_real(array_get_word_r(arr_, addr_), 0);
} else {
net_->send_vec4(array_get_word(arr_, addr_), 0);
}
}
class vvp_fun_arrayport_aa : public vvp_fun_arrayport, public automatic_hooks_s {
public:
explicit vvp_fun_arrayport_aa(vvp_array_t mem, vvp_net_t*net);
explicit vvp_fun_arrayport_aa(vvp_array_t mem, vvp_net_t*net, long addr);
~vvp_fun_arrayport_aa();
void alloc_instance(vvp_context_t context);
void reset_instance(vvp_context_t context);
#ifdef CHECK_WITH_VALGRIND
void free_instance(vvp_context_t context);
#endif
void check_word_change(unsigned long addr);
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
private:
void check_word_change_(unsigned long addr, vvp_context_t context);
struct __vpiScope*context_scope_;
unsigned context_idx_;
};
vvp_fun_arrayport_aa::vvp_fun_arrayport_aa(vvp_array_t mem, vvp_net_t*net)
: vvp_fun_arrayport(mem, net)
{
context_scope_ = vpip_peek_context_scope();
context_idx_ = vpip_add_item_to_context(this, context_scope_);
}
vvp_fun_arrayport_aa::vvp_fun_arrayport_aa(vvp_array_t mem, vvp_net_t*net, long addr)
: vvp_fun_arrayport(mem, net, addr)
{
context_scope_ = vpip_peek_context_scope();
context_idx_ = vpip_add_item_to_context(this, context_scope_);
}
vvp_fun_arrayport_aa::~vvp_fun_arrayport_aa()
{
}
void vvp_fun_arrayport_aa::alloc_instance(vvp_context_t context)
{
unsigned long*addr = new unsigned long;
vvp_set_context_item(context, context_idx_, addr);
*addr = addr_;
}
void vvp_fun_arrayport_aa::reset_instance(vvp_context_t context)
{
unsigned long*addr = static_cast<unsigned long*>
(vvp_get_context_item(context, context_idx_));
*addr = addr_;
}
#ifdef CHECK_WITH_VALGRIND
void vvp_fun_arrayport_aa::free_instance(vvp_context_t context)
{
unsigned long*addr = static_cast<unsigned long*>
(vvp_get_context_item(context, context_idx_));
delete addr;
}
#endif
void vvp_fun_arrayport_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context)
{
if (context) {
unsigned long*addr = static_cast<unsigned long*>
(vvp_get_context_item(context, context_idx_));
bool addr_valid_flag;
switch (port.port()) {
case 0: // Address input
addr_valid_flag = vector4_to_value(bit, *addr);
if (! addr_valid_flag) *addr = arr_->array_count;
if (vpi_array_is_real(arr_)) {
port.ptr()->send_real(array_get_word_r(arr_, *addr),
context);
} else {
port.ptr()->send_vec4(array_get_word(arr_, *addr),
context);
}
break;
default:
fprintf(stdout, "XXXX write ports not implemented.\n");
assert(0);
}
} else {
context = context_scope_->live_contexts;
while (context) {
recv_vec4(port, bit, context);
context = vvp_get_next_context(context);
}
}
}
void vvp_fun_arrayport_aa::check_word_change_(unsigned long addr,
vvp_context_t context)
{
unsigned long*port_addr = static_cast<unsigned long*>
(vvp_get_context_item(context, context_idx_));
if (addr != *port_addr)
return;
if (vpi_array_is_real(arr_)) {
net_->send_real(array_get_word_r(arr_, addr), context);
} else {
net_->send_vec4(array_get_word(arr_, addr), context);
}
}
void vvp_fun_arrayport_aa::check_word_change(unsigned long addr)
{
if (arr_->scope->is_automatic) {
assert(vthread_get_wt_context());
check_word_change_(addr, vthread_get_wt_context());
} else {
vvp_context_t context = context_scope_->live_contexts;
while (context) {
check_word_change_(addr, context);
context = vvp_get_next_context(context);
}
}
}
static void array_attach_port(vvp_array_t array, vvp_fun_arrayport*fun)
{
assert(fun->next_ == 0);
fun->next_ = array->ports_;
array->ports_ = fun;
if (!array->scope->is_automatic) {
/* propagate initial values for variable arrays */
if (array->vals4) {
vvp_vector4_t tmp(array->vals_width, BIT4_X);
schedule_init_propagate(fun->net_, tmp);
}
if (array->vals) {
schedule_init_propagate(fun->net_, 0.0);
}
}
}
class array_word_value_callback : public value_callback {
public:
inline explicit array_word_value_callback(p_cb_data data)
: value_callback(data)
{ }
public:
long word_addr;
};
void array_word_change(vvp_array_t array, unsigned long addr)
{
for (vvp_fun_arrayport*cur = array->ports_; cur; cur = cur->next_)
cur->check_word_change(addr);
// Run callbacks attached to the array itself.
struct __vpiCallback *next = array->vpi_callbacks;
struct __vpiCallback *prev = 0;
while (next) {
array_word_value_callback*cur = dynamic_cast<array_word_value_callback*>(next);
next = cur->next;
// Skip callbacks that are not for me. -1 is for every element.
if (cur->word_addr != (long)addr && cur->word_addr != -1) {
prev = cur;
continue;
}
// For whole array callbacks we need to set the index.
if (cur->word_addr == -1) {
cur->cb_data.index = (PLI_INT32) ((int)addr +
array->first_addr.get_value());
}
if (cur->cb_data.cb_rtn != 0) {
if (cur->test_value_callback_ready()) {
if (cur->cb_data.value) {
if (vpi_array_is_real(array)) {
double val = 0.0;
if (addr < array->vals->get_size())
array->vals->get_word(addr, val);
vpip_real_get_value(val, cur->cb_data.value);
} else {
vpip_vec4_get_value(array->vals4->get_word(addr),
array->vals_width,
array->signed_flag,
cur->cb_data.value);
}
}
callback_execute(cur);
}
prev = cur;
} else if (prev == 0) {
array->vpi_callbacks = next;
cur->next = 0;
delete cur;
} else {
assert(prev->next == cur);
prev->next = next;
cur->next = 0;
delete cur;
}
}
}
class array_resolv_list_t : public resolv_list_s {
public:
explicit array_resolv_list_t(char*lab) : resolv_list_s(lab) {
array = 0;
}
vvp_array_t*array;
bool resolve(bool mes);
private:
};
bool array_resolv_list_t::resolve(bool mes)
{
*array = array_find(label());
if (*array == 0) {
assert(!mes);
return false;
}
return true;
}
class array_port_resolv_list_t : public resolv_list_s {
public:
explicit array_port_resolv_list_t(char* lab, bool use_addr__,
long addr__);
vvp_net_t*ptr;
bool use_addr;
long addr;
bool resolve(bool mes);
private:
};
array_port_resolv_list_t::array_port_resolv_list_t(char *lab, bool use_addr__,
long addr__)
: resolv_list_s(lab), use_addr(use_addr__), addr(addr__)
{
ptr = new vvp_net_t;
}
bool array_port_resolv_list_t::resolve(bool mes)
{
vvp_array_t mem = array_find(label());
if (mem == 0) {
assert(mem || !mes);
return false;
}
vvp_fun_arrayport*fun;
if (use_addr)
if (vpip_peek_current_scope()->is_automatic)
fun = new vvp_fun_arrayport_aa(mem, ptr, addr);
else
fun = new vvp_fun_arrayport_sa(mem, ptr, addr);
else
if (vpip_peek_current_scope()->is_automatic)
fun = new vvp_fun_arrayport_aa(mem, ptr);
else
fun = new vvp_fun_arrayport_sa(mem, ptr);
ptr->fun = fun;
array_attach_port(mem, fun);
return true;
}
class array_word_part_callback : public array_word_value_callback {
public:
explicit array_word_part_callback(p_cb_data data);
~array_word_part_callback();
bool test_value_callback_ready(void);
private:
char*value_bits_;
};
array_word_part_callback::array_word_part_callback(p_cb_data data)
: array_word_value_callback(data)
{
// Get the initial value of the part, to use as a reference.
struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(data->obj);
s_vpi_value tmp_value;
tmp_value.format = vpiBinStrVal;
apvword->vpi_get_value(&tmp_value);
value_bits_ = new char[apvword->part_wid+1];
memcpy(value_bits_, tmp_value.value.str, apvword->part_wid);
value_bits_[apvword->part_wid] = 0;
}
array_word_part_callback::~array_word_part_callback()
{
delete[]value_bits_;
}
bool array_word_part_callback::test_value_callback_ready(void)
{
struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(cb_data.obj);
assert(apvword);
// Get a reference value that can be used to compare with an
// updated value.
s_vpi_value tmp_value;
tmp_value.format = vpiBinStrVal;
apvword->vpi_get_value(&tmp_value);
if (memcmp(value_bits_, tmp_value.value.str, apvword->part_wid) == 0)
return false;
memcpy(value_bits_, tmp_value.value.str, apvword->part_wid);
return true;
}
value_callback*vpip_array_word_change(p_cb_data data)
{
struct __vpiArray*parent = 0;
array_word_value_callback*cbh = 0;
if (struct __vpiArrayWord*word = array_var_word_from_handle(data->obj)) {
unsigned addr = decode_array_word_pointer(word, parent);
cbh = new array_word_value_callback(data);
cbh->word_addr = addr;
} else if (struct __vpiArrayVthrA*tword = dynamic_cast<__vpiArrayVthrA*>(data->obj)) {
parent = tword->array;
cbh = new array_word_value_callback(data);
cbh->word_addr = tword->address;
} else if (struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(data->obj)) {
parent = apvword->array;
cbh = new array_word_part_callback(data);
cbh->word_addr = apvword->word_sel;
}
assert(cbh);
assert(parent);
cbh->next = parent->vpi_callbacks;
parent->vpi_callbacks = cbh;
return cbh;
}
value_callback* vpip_array_change(p_cb_data data)
{
array_word_value_callback*cbh = new array_word_value_callback(data);
assert(data->obj);
struct __vpiArray*arr = dynamic_cast<__vpiArray*>(data->obj);
cbh->word_addr = -1; // This is a callback for every element.
cbh->next = arr->vpi_callbacks;
arr->vpi_callbacks = cbh;
return cbh;
}
void compile_array_port(char*label, char*array, char*addr)
{
array_port_resolv_list_t*resolv_mem
= new array_port_resolv_list_t(array, false, 0);
define_functor_symbol(label, resolv_mem->ptr);
free(label);
// Connect the port-0 input as the address.
input_connect(resolv_mem->ptr, 0, addr);
resolv_submit(resolv_mem);
}
void compile_array_port(char*label, char*array, long addr)
{
array_port_resolv_list_t*resolv_mem
= new array_port_resolv_list_t(array, true, addr);
define_functor_symbol(label, resolv_mem->ptr);
free(label);
resolv_submit(resolv_mem);
}
void compile_array_alias(char*label, char*name, char*src)
{
vvp_array_t mem = array_find(src);
assert(mem);
struct __vpiArray*obj = new __vpiArray;
obj->scope = vpip_peek_current_scope();
obj->name = vpip_name_string(name);
obj->array_count = mem->array_count;
obj->signed_flag = mem->signed_flag;
// Need to set an accurate range of addresses.
obj->first_addr = mem->first_addr;
obj->last_addr = mem->last_addr;
obj->swap_addr = mem->swap_addr;
obj->msb = mem->msb;
obj->lsb = mem->lsb;
// Share the words with the source array.
obj->nets = mem->nets;
obj->vals4 = mem->vals4;
obj->vals = mem->vals;
obj->vals_width = mem->vals_width;
obj->vals_words = mem->vals_words;
obj->ports_ = 0;
obj->vpi_callbacks = 0;
assert(array_table);
assert(!array_find(label));
array_table->sym_set_value(label, obj);
compile_vpi_symbol(label, obj);
vpip_attach_to_current_scope(obj);
free(label);
free(name);
free(src);
}
/*
* &A<label,addr>
* This represents a VPI handle for an addressed array. This comes
* from expressions like "label[addr]" where "label" is the array and
* "addr" is the canonical address of the desired word.
*/
vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
{
struct __vpiArrayVthrA*obj = new __vpiArrayVthrA;
array_resolv_list_t*resolv_mem
= new array_resolv_list_t(label);
resolv_mem->array = &obj->array;
resolv_submit(resolv_mem);
obj->address_handle = 0;
obj->address = addr;
return obj;
}
/*
* &A<label,symbol>
* This represents a VPI handle for an addressed word, where the
* word address is calculated from the VPI object that symbol
* represents. The expression that leads to this looks like label[symbol].
*/
vpiHandle vpip_make_vthr_A(char*label, char*symbol)
{
struct __vpiArrayVthrA*obj = new __vpiArrayVthrA;
array_resolv_list_t*resolv_mem
= new array_resolv_list_t(label);
resolv_mem->array = &obj->array;
resolv_submit(resolv_mem);
obj->address_handle = 0;
compile_vpi_lookup(&obj->address_handle, symbol);
obj->address = 0;
return obj;
}
vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle)
{
struct __vpiArrayVthrA*obj = new __vpiArrayVthrA;
array_resolv_list_t*resolv_mem
= new array_resolv_list_t(label);
resolv_mem->array = &obj->array;
resolv_submit(resolv_mem);
obj->address_handle = handle;
obj->address = 0;
return obj;
}
vpiHandle vpip_make_vthr_APV(char*label, unsigned index, unsigned bit, unsigned wid)
{
struct __vpiArrayVthrAPV*obj = new __vpiArrayVthrAPV;
array_resolv_list_t*resolv_mem
= new array_resolv_list_t(label);
resolv_mem->array = &obj->array;
resolv_submit(resolv_mem);
obj->word_sel = index;
obj->part_bit = bit;
obj->part_wid = wid;
return obj;
}
void compile_array_cleanup(void)
{
delete array_table;
array_table = 0;
}
#ifdef CHECK_WITH_VALGRIND
void memory_delete(vpiHandle item)
{
struct __vpiArray*arr = (struct __vpiArray*) item;
if (arr->vals_words) delete [] (arr->vals_words-1);
// if (arr->vals4) {}
// Delete the individual words?
// constant_delete(handle)?
delete arr->vals4;
// if (arr->vals) {}
// Delete the individual words?
// constant_delete(handle)?
delete arr->vals;
if (arr->nets) {
for (unsigned idx = 0; idx < arr->array_count; idx += 1) {
if (struct __vpiSignal*sig =
dynamic_cast<__vpiSignal*>(arr->nets[idx])) {
// Delete the individual words?
constant_delete(sig->id.index);
/* These should only be the real words. */
} else {
assert(arr->nets[idx]->get_type_code() ==
vpiRealVar);
struct __vpiRealVar *sigr = (struct __vpiRealVar *)
arr->nets[idx];
constant_delete(sigr->id.index);
// Why are only the real words still here?
delete arr->nets[idx];
}
}
free(arr->nets);
}
while (arr->vpi_callbacks) {
struct __vpiCallback*tmp = arr->vpi_callbacks->next;
delete arr->vpi_callbacks;
arr->vpi_callbacks = tmp;
}
delete arr;
}
void A_delete(vpiHandle item)
{
struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) item;
if (obj->address_handle) {
switch (obj->address_handle->get_type_code()) {
case vpiMemoryWord:
if (vpi_get(_vpiFromThr, obj->address_handle) == _vpi_at_A) {
A_delete(obj->address_handle);
}
break;
case vpiPartSelect:
assert(vpi_get(_vpiFromThr, obj->address_handle) ==
_vpi_at_PV);
PV_delete(obj->address_handle);
break;
}
}
delete obj;
}
void APV_delete(vpiHandle item)
{
struct __vpiArrayVthrAPV*obj = (struct __vpiArrayVthrAPV*) item;
delete obj;
}
#endif