diff --git a/vpi/sys_display.c b/vpi/sys_display.c index e92ca15b6..c291d00e3 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -1122,6 +1122,7 @@ static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name) case vpiReg: case vpiIntegerVar: case vpiRealVar: + case vpiMemoryWord: /* Monitoring reg and net values involves setting a callback for value changes. Pass the storage pointer for the callback itself as user_data so diff --git a/vvp/array.cc b/vvp/array.cc index 8341c218c..3593bbda5 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -63,6 +63,7 @@ struct __vpiArray { struct __vpiArrayWord*vals_words; class vvp_fun_arrayport*ports_; + struct __vpiCallback *vpi_callbacks; }; struct __vpiArrayIterator { @@ -192,11 +193,25 @@ static const struct __vpirt vpip_array_vthr_A_rt = { # 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 struct __vpiArrayWord* array_var_word_from_handle(vpiHandle ref) +{ + if (ref == 0) + return 0; + if (ref->vpi_type != &vpip_array_var_word_rt) + return 0; -# define ARRAY_VTHR_A_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemoryWord), \ - (struct __vpiArrayVthrA*)ref) + return (struct __vpiArrayWord*) ref; +} + +static struct __vpiArrayVthrA* array_vthr_a_from_handle(vpiHandle ref) +{ + if (ref == 0) + return 0; + if (ref->vpi_type != &vpip_array_vthr_A_rt) + return 0; + + return (struct __vpiArrayVthrA*) ref; +} static void array_make_vals_words(struct __vpiArray*parent) { @@ -315,9 +330,10 @@ static vpiHandle vpi_array_index(vpiHandle ref, int index) static int vpi_array_var_word_get(int code, vpiHandle ref) { - struct __vpiArrayWord*obj = ARRAY_VAR_WORD(ref); + struct __vpiArrayWord*obj = array_var_word_from_handle(ref); struct __vpiArray*parent; + assert(obj); decode_array_word_pointer(obj, parent); switch (code) { @@ -331,9 +347,10 @@ static int vpi_array_var_word_get(int code, vpiHandle ref) static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value) { - struct __vpiArrayWord*obj = ARRAY_VAR_WORD(ref); + struct __vpiArrayWord*obj = array_var_word_from_handle(ref); struct __vpiArray*parent; + assert(obj); unsigned index = decode_array_word_pointer(obj, parent); vpip_vec4_get_value(parent->vals[index], parent->vals_width, @@ -342,9 +359,10 @@ static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value) static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags) { - struct __vpiArrayWord*obj = ARRAY_VAR_WORD(ref); + 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); @@ -426,7 +444,8 @@ static int array_index_free_object(vpiHandle ref) static int vpi_array_vthr_A_get(int code, vpiHandle ref) { - struct __vpiArrayVthrA*obj = ARRAY_VTHR_A_HANDLE(ref); + struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + assert(obj); struct __vpiArray*parent = obj->array; switch (code) { @@ -443,7 +462,8 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref) } static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value) { - struct __vpiArrayVthrA*obj = ARRAY_VTHR_A_HANDLE(ref); + struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + assert(obj); struct __vpiArray*parent = obj->array; assert(parent); @@ -456,7 +476,8 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value) static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int) { - struct __vpiArrayVthrA*obj = ARRAY_VTHR_A_HANDLE(ref); + struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + assert(obj); struct __vpiArray*parent = obj->array; unsigned index = obj->address; @@ -579,6 +600,7 @@ static vpiHandle vpip_make_array(char*label, const char*name, // 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) @@ -745,6 +767,42 @@ 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 attatched to the array itself. + struct __vpiCallback *next = array->vpi_callbacks; + struct __vpiCallback *prev = 0; + + while (next) { + struct __vpiCallback*cur = next; + next = cur->next; + + // Skip callbacks for callbacks not for me. + if (cur->extra_data != (long)addr) { + prev = cur; + continue; + } + + if (cur->cb_data.cb_rtn != 0) { + if (cur->cb_data.value) + vpip_vec4_get_value(array->vals[addr], array->vals_width, + false, cur->cb_data.value); + + callback_execute(cur); + prev = cur; + + } else if (prev == 0) { + + array->vpi_callbacks = next; + cur->next = 0; + delete_vpi_callback(cur); + + } else { + assert(prev->next == cur); + prev->next = next; + cur->next = 0; + delete_vpi_callback(cur); + } + } } class array_port_resolv_list_t : public resolv_list_s { @@ -780,6 +838,23 @@ bool array_port_resolv_list_t::resolve(bool mes) return true; } +void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle obj) +{ + struct __vpiArray*parent = 0; + if (struct __vpiArrayWord*word = array_var_word_from_handle(obj)) { + unsigned addr = decode_array_word_pointer(word, parent); + cb->extra_data = addr; + + } else if (struct __vpiArrayVthrA*word = array_vthr_a_from_handle(obj)) { + parent = word->array; + cb->extra_data = word->address; + } + + assert(parent); + cb->next = parent->vpi_callbacks; + parent->vpi_callbacks = cb; +} + void compile_array_port(char*label, char*array, char*addr) { array_port_resolv_list_t*resolv_mem diff --git a/vvp/array.h b/vvp/array.h index c081a4eb6..e67832761 100644 --- a/vvp/array.h +++ b/vvp/array.h @@ -45,6 +45,11 @@ extern void array_set_word(vvp_array_t arr, extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned adddress); +/* VPI hooks */ + +extern void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle word); + +/* Compile hooks */ extern void compile_variablew(char*label, vvp_array_t array, unsigned long array_addr, int msb, int lsb, char signed_flag); diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 2348d9e65..6313c3896 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -103,7 +103,7 @@ struct __vpiCallback* new_vpi_callback() return obj; } -static void delete_vpi_callback(struct __vpiCallback* ref) +void delete_vpi_callback(struct __vpiCallback* ref) { assert(ref); assert(ref->base.vpi_type); @@ -162,6 +162,10 @@ static struct __vpiCallback* make_value_change(p_cb_data data) nev->callbacks = obj; break; + case vpiMemoryWord: + vpip_array_word_change(obj, data->obj); + break; + case vpiModule: case vpiConstant: case vpiParameter: @@ -461,14 +465,11 @@ void callback_execute(struct __vpiCallback*cur) vvp_vpi_callback::vvp_vpi_callback() { vpi_callbacks_ = 0; - array_ = 0; - array_word_ = 0; } vvp_vpi_callback::~vvp_vpi_callback() { assert(vpi_callbacks_ == 0); - assert(array_ == 0); } void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb) @@ -477,13 +478,6 @@ void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb) vpi_callbacks_ = cb; } -void vvp_vpi_callback::attach_as_word(vvp_array_t arr, unsigned long addr) -{ - assert(array_ == 0); - array_ = arr; - array_word_ = addr; -} - /* * A vvp_fun_signal uses this method to run its callbacks whenever it * has a value change. If the cb_rtn is non-nil, then call the @@ -495,8 +489,6 @@ void vvp_vpi_callback::run_vpi_callbacks() struct __vpiCallback *next = vpi_callbacks_; struct __vpiCallback *prev = 0; - if (array_) array_word_change(array_, array_word_); - while (next) { struct __vpiCallback*cur = next; next = cur->next; @@ -523,6 +515,31 @@ void vvp_vpi_callback::run_vpi_callbacks() } } +vvp_vpi_callback_wordable::vvp_vpi_callback_wordable() +{ + array_ = 0; + array_word_ = 0; +} + +vvp_vpi_callback_wordable::~vvp_vpi_callback_wordable() +{ + assert(array_ == 0); +} + +void vvp_vpi_callback_wordable::run_vpi_callbacks() +{ + if (array_) array_word_change(array_, array_word_); + + vvp_vpi_callback::run_vpi_callbacks(); +} + +void vvp_vpi_callback_wordable::attach_as_word(vvp_array_t arr, unsigned long addr) +{ + assert(array_ == 0); + array_ = arr; + array_word_ = addr; +} + void vvp_fun_signal::get_value(struct t_vpi_value*vp) { switch (vp->format) { diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 77e685e36..fc43caeff 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -141,11 +141,15 @@ struct __vpiCallback { // scheduled event struct sync_cb* cb_sync; + // The calback holder may use this for various purposes. + long extra_data; + // Used for listing callbacks. struct __vpiCallback*next; }; extern struct __vpiCallback* new_vpi_callback(); +extern void delete_vpi_callback(struct __vpiCallback* ref); extern void callback_execute(struct __vpiCallback*cur); struct __vpiSystemTime { diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index bcf2638c7..db99205a2 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -882,20 +882,29 @@ class vvp_vpi_callback { vvp_vpi_callback(); virtual ~vvp_vpi_callback(); - void run_vpi_callbacks(); + virtual void run_vpi_callbacks(); void add_vpi_callback(struct __vpiCallback*); virtual void get_value(struct t_vpi_value*value) =0; + private: + struct __vpiCallback*vpi_callbacks_; +}; + +class vvp_vpi_callback_wordable : public vvp_vpi_callback { + public: + vvp_vpi_callback_wordable(); + ~vvp_vpi_callback_wordable(); + + void run_vpi_callbacks(); void attach_as_word(class __vpiArray* arr, unsigned long addr); private: - struct __vpiCallback*vpi_callbacks_; class __vpiArray* array_; unsigned long array_word_; }; -class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback { +class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback_wordable { public: vvp_fun_signal_base();