diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 30a023a98..69e705d03 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2311,11 +2311,8 @@ bool of_FORCE_LINK(vthread_t thr, vvp_code_t cp) vvp_net_t*dst = cp->net; vvp_net_t*src = cp->net2; - vvp_filter_wire_base*sig - = dynamic_cast(dst->fun); - assert(sig); - - sig->force_link(dst, src); + assert(dst->fil); + dst->fil->force_link(dst, src); return true; } @@ -3936,6 +3933,7 @@ bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp) vvp_fun_signal_vec*sig = reinterpret_cast(net->fun); assert(sig); + assert(net->fil); if (base >= sig->size()) return true; if (base+width > sig->size()) width = sig->size() - base; @@ -3943,14 +3941,14 @@ bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp) bool full_sig = base == 0 && width == sig->size(); // XXXX Can't really do this if this is a partial release? - sig->force_unlink(); + net->fil->force_unlink(); /* Do we release all or part of the net? */ vvp_net_ptr_t ptr (net, 0); if (full_sig) { - sig->release(ptr, true); + net->fil->release(ptr, true); } else { - sig->release_pv(ptr, true, base, width); + net->fil->release_pv(ptr, true, base, width); } return true; @@ -3965,6 +3963,7 @@ bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp) vvp_fun_signal_vec*sig = reinterpret_cast(net->fun); assert(sig); + assert(net->fil); if (base >= sig->size()) return true; if (base+width > sig->size()) width = sig->size() - base; @@ -3972,15 +3971,15 @@ bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp) bool full_sig = base == 0 && width == sig->size(); // XXXX Can't really do this if this is a partial release? - sig->force_unlink(); + net->fil->force_unlink(); // Send a command to this signal to unforce itself. /* Do we release all or part of the net? */ vvp_net_ptr_t ptr (net, 0); if (full_sig) { - sig->release(ptr, false); + net->fil->release(ptr, false); } else { - sig->release_pv(ptr, false, base, width); + net->fil->release_pv(ptr, false, base, width); } return true; @@ -3992,14 +3991,12 @@ bool of_RELEASE_WR(vthread_t thr, vvp_code_t cp) vvp_net_t*net = cp->net; unsigned type = cp->bit_idx[0]; - vvp_fun_signal_real*sig = reinterpret_cast(net->fun); - assert(sig); - - sig->force_unlink(); + assert(net->fil); + net->fil->force_unlink(); // Send a command to this signal to unforce itself. vvp_net_ptr_t ptr (net, 0); - sig->release(ptr, type==0); + net->fil->release(ptr, type==0); return true; } diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 42ea332cd..2ca0c67f9 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -194,12 +194,16 @@ void vvp_net_fun_t::operator delete(void*) assert(0); } + vvp_net_fil_t::vvp_net_fil_t() { + force_link_ = 0; + force_propagate_ = false; } vvp_net_fil_t::~vvp_net_fil_t() { + assert(force_link_ == 0); } const vvp_vector4_t* vvp_net_fil_t::filter_vec4(const vvp_vector4_t&val) @@ -222,6 +226,81 @@ bool vvp_net_fil_t::filter_long(long&) return true; } +void vvp_net_fil_t::force_mask(vvp_vector2_t mask) +{ + if (force_mask_.size() == 0) + force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, mask.size()); + + assert(force_mask_.size() == mask.size()); + for (unsigned idx = 0 ; idx < mask.size() ; idx += 1) { + if (mask.value(idx) == 0) + continue; + + force_mask_.set_bit(idx, 1); + force_propagate_ = true; + } +} + +void vvp_net_fil_t::release_mask(vvp_vector2_t mask) +{ + if (force_mask_.size() == 0) + return; + + assert(force_mask_.size() == mask.size()); + for (unsigned idx = 0 ; idx < mask.size() ; idx += 1) { + if (mask.value(idx)) + force_mask_.set_bit(idx, 0); + } + + if (force_mask_.is_zero()) + force_mask_ = vvp_vector2_t(); +} + +/* + * Force link/unlink uses a thunk vvp_net_t node with a vvp_fun_force + * functor to translate the net values to filter commands. The ports + * of this vvp_net_t object are use a little differently: + * + * port[3] - Point to the destination node where the forced + * filter resides. + * + * port[2] - Point to the input node that drives port[0] for use + * by the unlink method. + * + * port[0] - This is the normal input. + */ +void vvp_net_fil_t::force_link(vvp_net_t*dst, vvp_net_t*src) +{ + assert(dst->fil == this); + + if (force_link_ == 0) { + force_link_ = new vvp_net_t; + // Use port[3] to hold the force destination. + force_link_->port[3] = vvp_net_ptr_t(dst, 0); + force_link_->port[2] = vvp_net_ptr_t(0,0); + force_link_->fun = new vvp_fun_force; + } + + force_unlink(); + assert(force_link_->port[2] == vvp_net_ptr_t(0,0)); + + // Use port[2] to hold the force source. + force_link_->port[2] = vvp_net_ptr_t(src,0); + + vvp_net_ptr_t dst_ptr(force_link_, 0); + src->link(dst_ptr); +} + +void vvp_net_fil_t::force_unlink(void) +{ + if (force_link_ == 0) return; + vvp_net_t*src = force_link_->port[2].ptr(); + if (src == 0) return; + + src->unlink(vvp_net_ptr_t(force_link_,0)); + force_link_->port[2] = vvp_net_ptr_t(0,0); +} + /* *** BIT operations *** */ vvp_bit4_t add_with_carry(vvp_bit4_t a, vvp_bit4_t b, vvp_bit4_t&c) { diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 5f47ad4e1..c00846ce4 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -21,6 +21,7 @@ # include "config.h" # include "vpi_user.h" +# include "vvp_vpi_callback.h" # include # include # include @@ -1097,10 +1098,10 @@ class vvp_net_fun_t { * false. If false, then send_*() continues as usual. If false, output * propagation is stopped. * - * The filter object can be used to implement force/release, and also - * can be used to implement vpi net object. + * The filter object also provides an implementation hooks for + * force/release. */ -class vvp_net_fil_t { +class vvp_net_fil_t : public vvp_vpi_callback { public: vvp_net_fil_t(); @@ -1117,6 +1118,37 @@ class vvp_net_fil_t { // propagation is suppressed. The value may be edited by the filter. virtual bool filter_real(double&val); virtual bool filter_long(long&val); + + virtual void release(vvp_net_ptr_t ptr, bool net) =0; + virtual void release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) =0; + + // The %force/link instruction needs a place to write the + // source node of the force, so that subsequent %force and + // %release instructions can undo the link as needed. */ + void force_link(vvp_net_t*dst, vvp_net_t*src); + void force_unlink(void); + + protected: + // Set bits of the filter force mask + void force_mask(vvp_vector2_t mask); + // Release the force on the bits set in the mask. + void release_mask(vvp_vector2_t mask); + // Test bits of the filter force mask; + bool test_force_mask(unsigned bit) const; + bool test_force_mask_is_zero() const; + + template const T*filter_mask_(const T&val, const T&force, T&buf); + template bool filter_mask_(T&val); + + private: + // Mask of forced bits + vvp_vector2_t force_mask_; + // True if the next filter must propagate. Need this to allow + // the forced value to get through. + bool force_propagate_; + // force link back. + struct vvp_net_t*force_link_; }; /* **** Some core net functions **** */ @@ -1147,6 +1179,27 @@ class vvp_fun_concat : public vvp_net_fun_t { vvp_vector4_t val_; }; +/* + * The vvp_fun_force class objects are net functors that use their input + * to force the associated filter. They do not actually have an + * output, they instead drive the force_* methods of the net filter. + * + * This functor is also special in that we know a priori that only + * port-0 is used, so we can use ports 1-3 for local storage. See the + * implementation of vvp_filter_wire_base::force_link in + * vvp_net_sig.cc for details. + */ +class vvp_fun_force : public vvp_net_fun_t { + + public: + vvp_fun_force(); + ~vvp_fun_force(); + + void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, + vvp_context_t context); + void recv_real(vvp_net_ptr_t port, double bit, vvp_context_t); +}; + /* vvp_fun_repeat * This node function create vectors by repeating the input. The width * is the width of the output vector, and the repeat is the number of @@ -1391,4 +1444,24 @@ inline void vvp_net_t::send_real(double val, vvp_context_t context) vvp_send_real(out_, val, context); } + +inline bool vvp_net_fil_t::test_force_mask(unsigned bit) const +{ + if (bit >= force_mask_.size()) + return false; + if (force_mask_.value(bit)) + return true; + else + return false; +} + +inline bool vvp_net_fil_t::test_force_mask_is_zero(void) const +{ + if (force_mask_.size() == 0) + return true; + if (force_mask_.is_zero()) + return true; + return false; +} + #endif diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 3c1669eeb..2901e57f9 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -30,20 +30,9 @@ # include -vvp_filter_wire_base::vvp_filter_wire_base() +template const T*vvp_net_fil_t::filter_mask_(const T&val, const T&force, T&filter) { - force_propagate_ = false; - force_link_ = 0; -} - -vvp_filter_wire_base::~vvp_filter_wire_base() -{ - assert(force_link_ == 0); -} - -template const T*vvp_filter_wire_base::filter_mask_(const T&val, const T&force, T&filter) -{ - if (force_mask_.size()) { + if (!test_force_mask_is_zero()) { bool propagate_flag = force_propagate_; force_propagate_ = false; assert(val.size() == force_mask_.size()); @@ -70,52 +59,7 @@ template const T*vvp_filter_wire_base::filter_mask_(const T&val, const } } -/* - * Force link/unlink uses a thunk vvp_net_t node with a vvp_fun_force - * functor to translate the net values to filter commands. The ports - * of this vvp_net_t object are use a little differently: - * - * port[3] - Point to the destination node where the forced - * filter resides. - * - * port[2] - Point to the input node that drives port[0] for use - * by the unlink method. - * - * port[0] - This is the normal input. - */ -void vvp_filter_wire_base::force_link(vvp_net_t*dst, vvp_net_t*src) -{ - assert(dst->fil == this); - - if (force_link_ == 0) { - force_link_ = new vvp_net_t; - // Use port[3] to hold the force destination. - force_link_->port[3] = vvp_net_ptr_t(dst, 0); - force_link_->port[2] = vvp_net_ptr_t(0,0); - force_link_->fun = new vvp_fun_force; - } - - force_unlink(); - assert(force_link_->port[2] == vvp_net_ptr_t(0,0)); - - // Use port[2] to hold the force source. - force_link_->port[2] = vvp_net_ptr_t(src,0); - - vvp_net_ptr_t dst_ptr(force_link_, 0); - src->link(dst_ptr); -} - -void vvp_filter_wire_base::force_unlink(void) -{ - if (force_link_ == 0) return; - vvp_net_t*src = force_link_->port[2].ptr(); - if (src == 0) return; - - src->unlink(vvp_net_ptr_t(force_link_,0)); - force_link_->port[2] = vvp_net_ptr_t(0,0); -} - -template bool vvp_filter_wire_base::filter_mask_(T&val) +template bool vvp_net_fil_t::filter_mask_(T&val) { run_vpi_callbacks(); return true; @@ -136,11 +80,6 @@ bool vvp_fun_signal_real::filter_real(double&val) return filter_mask_(val); } -bool vvp_filter_wire_base::filter_long(long&val) -{ - return filter_mask_(val); -} - void vvp_fun_signal4::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) { force_mask(mask); @@ -255,36 +194,6 @@ double vvp_fun_signal_real::filtered_real(double val) const return force_real_; } -void vvp_filter_wire_base::force_mask(vvp_vector2_t mask) -{ - if (force_mask_.size() == 0) - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, mask.size()); - - assert(force_mask_.size() == mask.size()); - for (unsigned idx = 0 ; idx < mask.size() ; idx += 1) { - if (mask.value(idx) == 0) - continue; - - force_mask_.set_bit(idx, 1); - force_propagate_ = true; - } -} - -void vvp_filter_wire_base::release_mask(vvp_vector2_t mask) -{ - if (force_mask_.size() == 0) - return; - - assert(force_mask_.size() == mask.size()); - for (unsigned idx = 0 ; idx < mask.size() ; idx += 1) { - if (mask.value(idx)) - force_mask_.set_bit(idx, 0); - } - - if (force_mask_.is_zero()) - force_mask_ = vvp_vector2_t(); -} - /* **** vvp_fun_signal methods **** */ vvp_fun_signal_base::vvp_fun_signal_base() diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 7aa72a1d4..324ef655a 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -36,43 +36,6 @@ class ostream; using namespace std; -/* - * Things derived from vvp_vpi_callback may have callbacks - * attached. This is how vpi callbacks are attached to the vvp - * structure. - * - * Things derived from vvp_vpi_callback may also be array'ed, so it - * includes some members that arrays use. - */ -class vvp_vpi_callback { - - public: - vvp_vpi_callback(); - virtual ~vvp_vpi_callback(); - - void attach_as_word(class __vpiArray* arr, unsigned long addr); - - void add_vpi_callback(struct __vpiCallback*); -#ifdef CHECK_WITH_VALGRIND - /* This has only been tested at EOS. */ - void clear_all_callbacks(void); -#endif - - // Derived classes implement this method to provide a way for - // vpi to get at the vvp value of the object. - virtual void get_value(struct t_vpi_value*value) =0; - - protected: - // Derived classes call this method to indicate that it is - // time to call the callback. - void run_vpi_callbacks(); - - private: - struct __vpiCallback*vpi_callbacks_; - class __vpiArray* array_; - unsigned long array_word_; -}; - /* vvp_fun_signal * This node is the place holder in a vvp network for signals, * including nets of various sort. The output from a signal follows @@ -128,78 +91,7 @@ class vvp_vpi_callback { */ -class vvp_filter_wire_base : public vvp_net_fil_t, public vvp_vpi_callback { - - public: - vvp_filter_wire_base(); - ~vvp_filter_wire_base(); - - // The filter_long is a placeholder here. This should be moved - // to a vvp_fun_signal_long when such a thing is implemented. - bool filter_long(long&val); - - public: - // Force/release work in the filter by setting the forced - // value using one of the force_* methods. This sets the - // forced value as a mask of the bits of the vector that are - // forced. The filter then automatically runs the filter on - // the outputs that pass through. You can also get at the - // filtering results using the filtered_* methods. The - // release_mask() method releases bits of the vector. - - virtual void release(vvp_net_ptr_t ptr, bool net) =0; - virtual void release_pv(vvp_net_ptr_t ptr, bool net, - unsigned base, unsigned wid) =0; - - /* The %force/link instruction needs a place to write the - source node of the force, so that subsequent %force and - %release instructions can undo the link as needed. */ - void force_link(vvp_net_t*dst, vvp_net_t*src); - void force_unlink(void); - - private: - struct vvp_net_t*force_link_; - - protected: - // Set bits of the filter force mask - void force_mask(vvp_vector2_t mask); - // Release the force on the bits set in the mask. - void release_mask(vvp_vector2_t mask); - // Test bits of the filter force mask; - bool test_force_mask(unsigned bit) const; - bool test_force_mask_is_zero() const; - - template const T*filter_mask_(const T&val, const T&force, T&buf); - template bool filter_mask_(T&val); - - private: - // Forced value - vvp_vector2_t force_mask_; - // True if the next filter must propagate. Need this to allow - // the forced value to get through. - bool force_propagate_; -}; - -inline bool vvp_filter_wire_base::test_force_mask(unsigned bit) const -{ - if (bit >= force_mask_.size()) - return false; - if (force_mask_.value(bit)) - return true; - else - return false; -} - -inline bool vvp_filter_wire_base::test_force_mask_is_zero(void) const -{ - if (force_mask_.size() == 0) - return true; - if (force_mask_.is_zero()) - return true; - return false; -} - -class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_filter_wire_base { +class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_net_fil_t { public: vvp_fun_signal_base(); @@ -449,26 +341,4 @@ class vvp_fun_signal_real_aa : public vvp_fun_signal_real, public automatic_hook }; -/* - * The vvp_fun_force class objects are net functors that use their input - * to force the associated filter. They do not actually have an - * output, they instead drive the force_* methods of the net filter. - * - * This functor is also special in that we know a priori that only - * port-0 is used, so we can use ports 1-3 for local storage. See the - * implementation of vvp_filter_wire_base::force_link in - * vvp_net_sig.cc for details. - */ -class vvp_fun_force : public vvp_net_fun_t { - - public: - vvp_fun_force(); - ~vvp_fun_force(); - - void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, - vvp_context_t context); - void recv_real(vvp_net_ptr_t port, double bit, vvp_context_t); -}; - - #endif diff --git a/vvp/vvp_vpi_callback.h b/vvp/vvp_vpi_callback.h new file mode 100644 index 000000000..8b96e5afc --- /dev/null +++ b/vvp/vvp_vpi_callback.h @@ -0,0 +1,63 @@ +#ifndef __vvp_vpi_callback_H +#define __vvp_vpi_callback_H +/* + * Copyright (c) 2009 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "config.h" +# include "vpi_user.h" + +/* + * Things derived from vvp_vpi_callback may have callbacks + * attached. This is how vpi callbacks are attached to the vvp + * structure. + * + * Things derived from vvp_vpi_callback may also be array'ed, so it + * includes some members that arrays use. + */ +class vvp_vpi_callback { + + public: + vvp_vpi_callback(); + virtual ~vvp_vpi_callback(); + + void attach_as_word(class __vpiArray* arr, unsigned long addr); + + void add_vpi_callback(struct __vpiCallback*); +#ifdef CHECK_WITH_VALGRIND + /* This has only been tested at EOS. */ + void clear_all_callbacks(void); +#endif + + // Derived classes implement this method to provide a way for + // vpi to get at the vvp value of the object. + virtual void get_value(struct t_vpi_value*value) =0; + + protected: + // Derived classes call this method to indicate that it is + // time to call the callback. + void run_vpi_callbacks(); + + private: + struct __vpiCallback*vpi_callbacks_; + class __vpiArray* array_; + unsigned long array_word_; +}; + + +#endif