Properly handle value change callbacks on part selects.

cbValueChange callbacks on part selects have to go through some extra
effort to make sure the value they are watching really is changing.
This commit is contained in:
Stephen Williams 2012-01-30 19:12:20 -08:00
parent 53585c9209
commit c7a54891c4
5 changed files with 119 additions and 50 deletions

View File

@ -74,6 +74,8 @@ int __vpiCallback::get_type_code(void) const
class value_callback : public __vpiCallback {
public:
explicit value_callback(p_cb_data data);
// Return true if the callback really is ready to be called
virtual bool test_value_callback_ready(void);
public:
// user supplied callback data
@ -81,7 +83,7 @@ class value_callback : public __vpiCallback {
struct t_vpi_value cb_value;
};
inline value_callback::value_callback(p_cb_data data)
value_callback::value_callback(p_cb_data data)
{
cb_data = *data;
if (data->time) {
@ -98,6 +100,104 @@ inline value_callback::value_callback(p_cb_data data)
cb_data.value = &cb_value;
}
/*
* Normally, any assign to a value triggers a value change callback,
* so return a constant true here. This is a stub.
*/
bool value_callback::test_value_callback_ready(void)
{
return true;
}
static void vpip_real_value_change(value_callback*cbh, vpiHandle ref)
{
struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref);
assert(rfp);
vvp_vpi_callback*obj = dynamic_cast<vvp_vpi_callback*>(rfp->net->fil);
assert(obj);
obj->add_vpi_callback(cbh);
}
class value_part_callback : public value_callback {
public:
explicit value_part_callback(p_cb_data data);
~value_part_callback();
bool test_value_callback_ready(void);
private:
char*value_bits_;
size_t value_off_;
};
inline value_part_callback::value_part_callback(p_cb_data data)
: value_callback(data)
{
struct __vpiPV*pobj = dynamic_cast<__vpiPV*>(data->obj);
assert(pobj);
vvp_vpi_callback*sig_fil;
sig_fil = dynamic_cast<vvp_vpi_callback*>(pobj->net->fil);
assert(sig_fil);
sig_fil->add_vpi_callback(this);
// Get a reference value that can be used to compare with an
// updated value. Use the filter get_value to get the value,
// and get it in BinStr form so that compares are easy. Note
// that the vpiBinStr format has the MSB first, but the tbase
// is lsb first.
s_vpi_value tmp_value;
tmp_value.format = vpiBinStrVal;
sig_fil->get_value(&tmp_value);
value_bits_ = new char[pobj->width+1];
value_off_ = pobj->parent->vpi_get(vpiSize) - pobj->width - pobj->tbase;
memcpy(value_bits_, tmp_value.value.str + value_off_, pobj->width);
value_bits_[pobj->width] = 0;
}
value_part_callback::~value_part_callback()
{
delete[]value_bits_;
}
bool value_part_callback::test_value_callback_ready(void)
{
struct __vpiPV*pobj = dynamic_cast<__vpiPV*>(cb_data.obj);
assert(pobj);
vvp_vpi_callback*sig_fil;
sig_fil = dynamic_cast<vvp_vpi_callback*>(pobj->net->fil);
assert(sig_fil);
// Get a reference value that can be used to compare with an
// updated value.
s_vpi_value tmp_value;
tmp_value.format = vpiBinStrVal;
sig_fil->get_value(&tmp_value);
if (memcmp(value_bits_, tmp_value.value.str + value_off_, pobj->width) == 0)
return false;
memcpy(value_bits_, tmp_value.value.str + value_off_, pobj->width);
return true;
}
/*
* Attach the __vpiCallback to the object that this part select
* selects from. The part select itself is not a vvp_vpi_callback
* object, but it refers to a net that is a vvp_vpi_callback, so
* add the callback to that object.
*/
static value_callback*make_value_change_part(p_cb_data data)
{
/* Attach the __vpiCallback object to the signal. */
value_callback*cbh = new value_part_callback(data);
return cbh;
}
/*
* A value change callback is tripped when a bit of a signal
* changes. This function creates that value change callback and
@ -115,6 +215,10 @@ static value_callback* make_value_change(p_cb_data data)
return 0;
}
// Special case: the target object is a vpiPartSelect
if (data->obj->get_type_code() == vpiPartSelect)
return make_value_change_part(data);
value_callback*obj = new value_callback(data);
assert(data->obj);
@ -159,10 +263,6 @@ static value_callback* make_value_change(p_cb_data data)
vpip_array_change(obj, data->obj);
break;
case vpiPartSelect:
vpip_part_select_value_change(obj, data->obj);
break;
case vpiModule:
case vpiConstant:
case vpiParameter:
@ -537,7 +637,7 @@ void vvp_vpi_callback::attach_as_word(vvp_array_t arr, unsigned long addr)
array_word_ = addr;
}
void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb)
void vvp_vpi_callback::add_vpi_callback(value_callback*cb)
{
cb->next = vpi_callbacks_;
vpi_callbacks_ = cb;
@ -564,18 +664,20 @@ void vvp_vpi_callback::run_vpi_callbacks()
{
if (array_) array_word_change(array_, array_word_);
struct __vpiCallback *next = vpi_callbacks_;
struct __vpiCallback *prev = 0;
value_callback *next = vpi_callbacks_;
value_callback *prev = 0;
while (next) {
struct __vpiCallback*cur = next;
next = cur->next;
value_callback*cur = next;
next = dynamic_cast<value_callback*>(cur->next);
if (cur->cb_data.cb_rtn != 0) {
if (cur->cb_data.value)
get_value(cur->cb_data.value);
if (cur->test_value_callback_ready()) {
if (cur->cb_data.value)
get_value(cur->cb_data.value);
callback_execute(cur);
callback_execute(cur);
}
prev = cur;
} else if (prev == 0) {

View File

@ -325,9 +325,6 @@ extern vpiHandle vpip_make_PV(char*name, vpiHandle handle, int width);
extern vpiHandle vpip_make_PV(char*name, int tbase, int twid, char*is_signed,
int width);
extern void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle obj);
struct __vpiModPathTerm : public __vpiHandle {
__vpiModPathTerm();
int get_type_code(void) const;
@ -428,8 +425,6 @@ class __vpiNamedEvent : public __vpiHandle {
};
extern vpiHandle vpip_make_named_event(const char*name, vvp_net_t*f);
extern void vpip_real_value_change(struct __vpiCallback*cbh,
vpiHandle ref);
/*
* Memory is an array of bits that is accessible in N-bit chunks, with

View File

@ -159,17 +159,6 @@ vpiHandle __vpiRealVar::vpi_handle(int code)
vpiHandle __vpiRealVar::vpi_iterate(int code)
{ return real_var_iterate(code, this); }
void vpip_real_value_change(struct __vpiCallback*cbh,
vpiHandle ref)
{
struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref);
assert(rfp);
vvp_vpi_callback*obj = dynamic_cast<vvp_vpi_callback*>(rfp->net->fil);
assert(obj);
obj->add_vpi_callback(cbh);
}
vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net)
{
struct __vpiRealVar*obj = new __vpiRealVar;

View File

@ -1422,25 +1422,6 @@ vpiHandle vpip_make_PV(char*var, int tbase, int twid, char*is_signed, int width)
return obj;
}
/*
* Attach the __vpiCallback to the object that this part select
* selects from. The part select itself is not a vvp_vpi_callback
* object, but it refers to a net that is a vvp_vpi_callback, so
* add the callback to that object.
*/
void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle ref)
{
struct __vpiPV*obj = dynamic_cast<__vpiPV*>(ref);
assert(obj);
vvp_vpi_callback*sig_fil;
sig_fil = dynamic_cast<vvp_vpi_callback*>(obj->net->fil);
assert(sig_fil);
/* Attach the __vpiCallback object to the signal. */
sig_fil->add_vpi_callback(cbh);
}
#ifdef CHECK_WITH_VALGRIND
void PV_delete(vpiHandle item)
{

View File

@ -22,6 +22,8 @@
# include "config.h"
# include "vpi_user.h"
class value_callback;
/*
* Things derived from vvp_vpi_callback may have callbacks
* attached. This is how vpi callbacks are attached to the vvp
@ -38,7 +40,7 @@ class vvp_vpi_callback {
void attach_as_word(struct __vpiArray* arr, unsigned long addr);
void add_vpi_callback(struct __vpiCallback*);
void add_vpi_callback(value_callback*);
#ifdef CHECK_WITH_VALGRIND
/* This has only been tested at EOS. */
void clear_all_callbacks(void);
@ -54,7 +56,7 @@ class vvp_vpi_callback {
void run_vpi_callbacks();
private:
struct __vpiCallback*vpi_callbacks_;
value_callback*vpi_callbacks_;
struct __vpiArray* array_;
unsigned long array_word_;
};