diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 6ae7c7fc4..a0da8a9de 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -76,7 +76,7 @@ concat.o \ dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \ ufunc.o codes.o \ vthread.o schedule.o statistics.o tables.o udp.o vvp_island.o vvp_net.o \ -event.o logic.o delay.o words.o island_tran.o $V +vvp_net_sig.o event.o logic.o delay.o words.o island_tran.o $V ifeq (@WIN32@,yes) # Under Windows (mingw) I need to make the ivl.exe in two steps. diff --git a/vvp/array.cc b/vvp/array.cc index 9c79a5669..9bab08a85 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -21,6 +21,7 @@ #include "symbols.h" #include "schedule.h" #include "vpi_priv.h" +#include "vvp_net_sig.h" #include "config.h" #ifdef CHECK_WITH_VALGRIND #include "vvp_cleanup.h" diff --git a/vvp/ufunc.cc b/vvp/ufunc.cc index 662630d81..a6a136068 100644 --- a/vvp/ufunc.cc +++ b/vvp/ufunc.cc @@ -22,6 +22,7 @@ # include "symbols.h" # include "codes.h" # include "ufunc.h" +# include "vvp_net_sig.h" # include "vthread.h" # include "schedule.h" #ifdef HAVE_MALLOC_H diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index bafc05745..ab122c81a 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -29,6 +29,7 @@ # include "vvp_net.h" # include "schedule.h" # include "event.h" +# include "vvp_net_sig.h" # include "config.h" # include # include diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index cb8093679..ede9ed3f0 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -19,6 +19,7 @@ # include "compile.h" # include "vpi_priv.h" +# include "vvp_net_sig.h" # include "schedule.h" # include # include diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 582c9c6b2..bccbc2e5f 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -24,6 +24,7 @@ # include "compile.h" # include "vpi_priv.h" +# include "vvp_net_sig.h" # include "schedule.h" # include "statistics.h" # include "config.h" diff --git a/vvp/vthread.cc b/vvp/vthread.cc index befa557a7..e7611fdba 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -24,6 +24,7 @@ # include "ufunc.h" # include "event.h" # include "vpi_priv.h" +# include "vvp_net_sig.h" #ifdef CHECK_WITH_VALGRIND # include "vvp_cleanup.h" #endif diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index c6f040368..27b39e96e 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -111,6 +111,8 @@ void vvp_net_t::operator delete(void*) vvp_net_t::vvp_net_t() { out_ = vvp_net_ptr_t(0,0); + fun = 0; + fil = 0; } void vvp_net_t::link(vvp_net_ptr_t port) @@ -1610,19 +1612,6 @@ vvp_vector4_t vvp_vector4array_aa::get_word(unsigned index) const return get_word_(cell); } -template T coerce_to_width(const T&that, unsigned width) -{ - if (that.size() == width) - return that; - - assert(that.size() > width); - T res (width); - for (unsigned idx = 0 ; idx < width ; idx += 1) - res.set_bit(idx, that.value(idx)); - - return res; -} - vvp_vector2_t::vvp_vector2_t() { vec_ = 0; @@ -2512,763 +2501,6 @@ void vvp_fun_drive::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, } -/* **** vvp_fun_signal methods **** */ - -vvp_fun_signal_base::vvp_fun_signal_base() -{ - needs_init_ = true; - continuous_assign_active_ = false; - force_link = 0; - cassign_link = 0; - count_functors_sig += 1; -} - -void vvp_fun_signal_base::deassign() -{ - continuous_assign_active_ = false; - assign_mask_ = vvp_vector2_t(); -} - -void vvp_fun_signal_base::deassign_pv(unsigned base, unsigned wid) -{ - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - assign_mask_.set_bit(base+idx, 0); - } - - if (assign_mask_.is_zero()) { - assign_mask_ = vvp_vector2_t(); - } -} - -/* - * The signal functor takes commands as long values to port-3. This - * method interprets those commands. - */ -void vvp_fun_signal_base::recv_long(vvp_net_ptr_t ptr, long bit) -{ - switch (ptr.port()) { - case 3: // Command port - switch (bit) { - case 1: // deassign command - deassign(); - break; - case 2: // release/net - release(ptr, true); - break; - case 3: // release/reg - release(ptr, false); - break; - default: - fprintf(stderr, "Unsupported command %ld.\n", bit); - assert(0); - break; - } - break; - - default: // Other ports are errors. - fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); - assert(0); - break; - } -} - -void vvp_fun_signal_base::recv_long_pv(vvp_net_ptr_t ptr, long bit, - unsigned base, unsigned wid) -{ - switch (ptr.port()) { - case 3: // Command port - switch (bit) { - case 1: // deassign command - deassign_pv(base, wid); - break; - case 2: // release/net - release_pv(ptr, true, base, wid); - break; - case 3: // release/reg - release_pv(ptr, false, base, wid); - break; - default: - fprintf(stderr, "Unsupported command %ld.\n", bit); - assert(0); - break; - } - break; - - default: // Other ports are errors. - fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); - assert(0); - break; - } -} - -vvp_fun_signal4_sa::vvp_fun_signal4_sa(unsigned wid, vvp_bit4_t init) -: bits4_(wid, init) -{ -} - -/* - * Nets simply reflect their input to their output. - * - * NOTE: It is a quirk of vvp_fun_signal that it has an initial value - * that needs to be propagated, but after that it only needs to - * propagate if the value changes. Eliminating duplicate propagations - * should improve performance, but has the quirk that an input that - * matches the initial value might not be propagated. The hack used - * herein is to keep a "needs_init_" flag that is turned false after - * the first propagation, and forces the first propagation to happen - * even if it matches the initial value. - */ -void vvp_fun_signal4_sa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, - vvp_context_t) -{ - switch (ptr.port()) { - case 0: // Normal input (feed from net, or set from process) - /* If we don't have a continuous assign mask then just - copy the bits, otherwise we need to see if there are - any holes in the mask so we can set those bits. */ - if (assign_mask_.size() == 0) { - if (needs_init_ || !bits4_.eeq(bit)) { - bits4_ = bit; - needs_init_ = false; - calculate_output_(ptr); - } - } else { - bool changed = false; - assert(bits4_.size() == assign_mask_.size()); - for (unsigned idx = 0 ; idx < bit.size() ; idx += 1) { - if (idx >= bits4_.size()) break; - if (assign_mask_.value(idx)) continue; - bits4_.set_bit(idx, bit.value(idx)); - changed = true; - } - if (changed) { - needs_init_ = false; - calculate_output_(ptr); - } - } - break; - - case 1: // Continuous assign value - bits4_ = bit; - assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); - calculate_output_(ptr); - break; - - case 2: // Force value - - // Force from a node may not have been sized completely - // by the source, so coerce the size here. - if (bit.size() != size()) - force_ = coerce_to_width(bit, size()); - else - force_ = bit; - - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); - calculate_output_(ptr); - break; - - default: - fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); - assert(0); - break; - } -} - -void vvp_fun_signal4_sa::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit) -{ - recv_vec4(ptr, reduce4(bit), 0); -} - -void vvp_fun_signal4_sa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, - unsigned base, unsigned wid, unsigned vwid, - vvp_context_t) -{ - assert(bit.size() == wid); - assert(bits4_.size() == vwid); - - switch (ptr.port()) { - case 0: // Normal input - if (assign_mask_.size() == 0) { - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - if (base+idx >= bits4_.size()) break; - bits4_.set_bit(base+idx, bit.value(idx)); - } - needs_init_ = false; - calculate_output_(ptr); - } else { - bool changed = false; - assert(bits4_.size() == assign_mask_.size()); - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - if (base+idx >= bits4_.size()) break; - if (assign_mask_.value(base+idx)) continue; - bits4_.set_bit(base+idx, bit.value(idx)); - changed = true; - } - if (changed) { - needs_init_ = false; - calculate_output_(ptr); - } - } - break; - - case 1: // Continuous assign value - if (assign_mask_.size() == 0) - assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, size()); - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - if (base+idx >= bits4_.size()) - break; - bits4_.set_bit(base+idx, bit.value(idx)); - assign_mask_.set_bit(base+idx, 1); - } - calculate_output_(ptr); - break; - - case 2: // Force value - - if (force_mask_.size() == 0) - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, size()); - if (force_.size() == 0) - force_ = vvp_vector4_t(vwid, BIT4_Z); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - force_mask_.set_bit(base+idx, 1); - force_.set_bit(base+idx, bit.value(idx)); - } - - calculate_output_(ptr); - break; - - default: - fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); - assert(0); - break; - } -} - -void vvp_fun_signal4_sa::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, - unsigned base, unsigned wid, unsigned vwid) -{ - recv_vec4_pv(ptr, reduce4(bit), base, wid, vwid, 0); -} - -void vvp_fun_signal4_sa::calculate_output_(vvp_net_ptr_t ptr) -{ - if (force_mask_.size()) { - assert(bits4_.size() == force_mask_.size()); - assert(bits4_.size() == force_.size()); - vvp_vector4_t bits (bits4_); - for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { - if (force_mask_.value(idx)) - bits.set_bit(idx, force_.value(idx)); - } - ptr.ptr()->send_vec4(bits, 0); - } else { - ptr.ptr()->send_vec4(bits4_, 0); - } - - run_vpi_callbacks(); -} - -void vvp_fun_signal4_sa::release(vvp_net_ptr_t ptr, bool net) -{ - force_mask_ = vvp_vector2_t(); - if (net) { - ptr.ptr()->send_vec4(bits4_, 0); - run_vpi_callbacks(); - } else { - bits4_ = force_; - } -} - -void vvp_fun_signal4_sa::release_pv(vvp_net_ptr_t ptr, bool net, - unsigned base, unsigned wid) -{ - assert(bits4_.size() >= base + wid); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - force_mask_.set_bit(base+idx, 0); - if (!net) bits4_.set_bit(base+idx, force_.value(base+idx)); - } - if (force_mask_.is_zero()) force_mask_ = vvp_vector2_t(); - - if (net) calculate_output_(ptr); -} - -unsigned vvp_fun_signal4_sa::size() const -{ - if (force_mask_.size()) - return force_.size(); - else - return bits4_.size(); -} - -vvp_bit4_t vvp_fun_signal4_sa::value(unsigned idx) const -{ - if (force_mask_.size() && force_mask_.value(idx)) { - return force_.value(idx); - } else { - return bits4_.value(idx); - } -} - -vvp_scalar_t vvp_fun_signal4_sa::scalar_value(unsigned idx) const -{ - if (force_mask_.size() && force_mask_.value(idx)) { - return vvp_scalar_t(force_.value(idx), 6, 6); - } else { - return vvp_scalar_t(bits4_.value(idx), 6, 6); - } -} - -vvp_vector4_t vvp_fun_signal4_sa::vec4_value() const -{ - if (force_mask_.size()) { - assert(bits4_.size() == force_mask_.size()); - assert(bits4_.size() == force_.size()); - vvp_vector4_t bits (bits4_); - for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { - if (force_mask_.value(idx)) - bits.set_bit(idx, force_.value(idx)); - } - return bits; - } else { - return bits4_; - } -} - -vvp_fun_signal4_aa::vvp_fun_signal4_aa(unsigned wid, vvp_bit4_t init) -{ - context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope()); - size_ = wid; -} - -void vvp_fun_signal4_aa::alloc_instance(vvp_context_t context) -{ - vvp_set_context_item(context, context_idx_, new vvp_vector4_t(size_)); -} - -void vvp_fun_signal4_aa::reset_instance(vvp_context_t context) -{ - vvp_vector4_t*bits = static_cast - (vvp_get_context_item(context, context_idx_)); - - bits->set_to_x(); -} - -#ifdef CHECK_WITH_VALGRIND -void vvp_fun_signal4_aa::free_instance(vvp_context_t context) -{ - vvp_vector4_t*bits = static_cast - (vvp_get_context_item(context, context_idx_)); - delete bits; -} -#endif - -/* - * Continuous and forced assignments are not permitted on automatic - * variables. So we only expect to receive on port 0. - */ -void vvp_fun_signal4_aa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, - vvp_context_t context) -{ - assert(ptr.port() == 0); - assert(context); - - vvp_vector4_t*bits4 = static_cast - (vvp_get_context_item(context, context_idx_)); - - if (!bits4->eeq(bit)) { - *bits4 = bit; - ptr.ptr()->send_vec4(*bits4, context); - } -} - -void vvp_fun_signal4_aa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, - unsigned base, unsigned wid, unsigned vwid, - vvp_context_t context) -{ - assert(ptr.port() == 0); - assert(bit.size() == wid); - assert(size_ == vwid); - assert(context); - - vvp_vector4_t*bits4 = static_cast - (vvp_get_context_item(context, context_idx_)); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - if (base+idx >= bits4->size()) break; - bits4->set_bit(base+idx, bit.value(idx)); - } - ptr.ptr()->send_vec4(*bits4, context); -} - -void vvp_fun_signal4_aa::release(vvp_net_ptr_t ptr, bool net) -{ - /* Automatic variables can't be forced. */ - assert(0); -} - -void vvp_fun_signal4_aa::release_pv(vvp_net_ptr_t ptr, bool net, - unsigned base, unsigned wid) -{ - /* Automatic variables can't be forced. */ - assert(0); -} - -unsigned vvp_fun_signal4_aa::size() const -{ - return size_; -} - -vvp_bit4_t vvp_fun_signal4_aa::value(unsigned idx) const -{ - vvp_vector4_t*bits4 = static_cast - (vthread_get_rd_context_item(context_idx_)); - - return bits4->value(idx); -} - -vvp_scalar_t vvp_fun_signal4_aa::scalar_value(unsigned idx) const -{ - vvp_vector4_t*bits4 = static_cast - (vthread_get_rd_context_item(context_idx_)); - - return vvp_scalar_t(bits4->value(idx), 6, 6); -} - -vvp_vector4_t vvp_fun_signal4_aa::vec4_value() const -{ - vvp_vector4_t*bits4 = static_cast - (vthread_get_rd_context_item(context_idx_)); - - return *bits4; -} - -vvp_fun_signal8::vvp_fun_signal8(unsigned wid) -: bits8_(wid) -{ -} - -void vvp_fun_signal8::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, - vvp_context_t) -{ - recv_vec8(ptr, vvp_vector8_t(bit,6,6)); -} - -void vvp_fun_signal8::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit) -{ - switch (ptr.port()) { - case 0: // Normal input (feed from net, or set from process) - if (needs_init_ || !bits8_.eeq(bit)) { - bits8_ = bit; - needs_init_ = false; - calculate_output_(ptr); - } - break; - - case 1: // Continuous assign value - /* This is a procedural continuous assign and it can - * only be used on a register and a register is never - * strength aware. */ - assert(0); - break; - - case 2: // Force value - - // Force from a node may not have been sized completely - // by the source, so coerce the size here. - if (bit.size() != size()) - force_ = coerce_to_width(bit, size()); - else - force_ = bit; - - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); - calculate_output_(ptr); - break; - - default: - fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); - assert(0); - break; - } -} - -void vvp_fun_signal8::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, - unsigned base, unsigned wid, unsigned vwid, - vvp_context_t) -{ - recv_vec8_pv(ptr, vvp_vector8_t(bit,6,6), base, wid, vwid); -} - -void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, - unsigned base, unsigned wid, unsigned vwid) -{ - assert(bit.size() == wid); - assert(bits8_.size() == vwid); - - switch (ptr.port()) { - case 0: // Normal input - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - if (base+idx >= bits8_.size()) break; - bits8_.set_bit(base+idx, bit.value(idx)); - } - needs_init_ = false; - calculate_output_(ptr); - break; - - case 1: // Continuous assign value - /* This is a procedural continuous assign and it can - * only be used on a register and a register is never - * strength aware. */ - assert(0); - break; - - case 2: // Force value - - if (force_mask_.size() == 0) - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, size()); - if (force_.size() == 0) - force_ = vvp_vector8_t(vvp_vector4_t(vwid, BIT4_Z),6,6); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - force_mask_.set_bit(base+idx, 1); - force_.set_bit(base+idx, bit.value(idx)); - } - - calculate_output_(ptr); - break; - - default: - fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); - assert(0); - break; - } -} - -void vvp_fun_signal8::calculate_output_(vvp_net_ptr_t ptr) -{ - if (force_mask_.size()) { - assert(bits8_.size() == force_mask_.size()); - assert(bits8_.size() == force_.size()); - vvp_vector8_t bits (bits8_); - for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { - if (force_mask_.value(idx)) - bits.set_bit(idx, force_.value(idx)); - } - ptr.ptr()->send_vec8(bits); - - } else { - ptr.ptr()->send_vec8(bits8_); - } - - run_vpi_callbacks(); -} - -void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net) -{ - force_mask_ = vvp_vector2_t(); - if (net) { - ptr.ptr()->send_vec8(bits8_); - run_vpi_callbacks(); - } else { - bits8_ = force_; - } -} - -void vvp_fun_signal8::release_pv(vvp_net_ptr_t ptr, bool net, - unsigned base, unsigned wid) -{ - assert(bits8_.size() >= base + wid); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - force_mask_.set_bit(base+idx, 0); - if (!net) bits8_.set_bit(base+idx, force_.value(base+idx)); - } - if (force_mask_.is_zero()) force_mask_ = vvp_vector2_t(); - - if (net) calculate_output_(ptr); -} - -unsigned vvp_fun_signal8::size() const -{ - if (force_mask_.size()) - return force_.size(); - else - return bits8_.size(); -} - -vvp_bit4_t vvp_fun_signal8::value(unsigned idx) const -{ - if (force_mask_.size() && force_mask_.value(idx)) - return force_.value(idx).value(); - else - return bits8_.value(idx).value(); -} - -vvp_vector4_t vvp_fun_signal8::vec4_value() const -{ - if (force_mask_.size()) { - vvp_vector8_t bits (bits8_); - for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { - if (force_mask_.value(idx)) - bits.set_bit(idx, force_.value(idx)); - } - return reduce4(bits); - } else - return reduce4(bits8_); -} - -vvp_scalar_t vvp_fun_signal8::scalar_value(unsigned idx) const -{ - if (force_mask_.size() && force_mask_.value(idx)) - return force_.value(idx); - else - return bits8_.value(idx); -} - -/* - * Testing for equality, we want a bitwise test instead of an - * arithmetic test because we want to treat for example -0 different - * from +0. - */ -bool bits_equal(double a, double b) -{ - return memcmp(&a, &b, sizeof a) == 0; -} - -vvp_fun_signal_real_sa::vvp_fun_signal_real_sa() -{ - bits_ = 0.0; -} - -double vvp_fun_signal_real_sa::real_value() const -{ - if (force_mask_.size()) - return force_; - else - return bits_; -} - -void vvp_fun_signal_real_sa::recv_real(vvp_net_ptr_t ptr, double bit, - vvp_context_t) -{ - switch (ptr.port()) { - case 0: - if (!continuous_assign_active_) { - if (needs_init_ || !bits_equal(bits_, bit)) { - bits_ = bit; - needs_init_ = false; - ptr.ptr()->send_real(bit, 0); - run_vpi_callbacks(); - } - } - break; - - case 1: // Continuous assign value - continuous_assign_active_ = true; - bits_ = bit; - ptr.ptr()->send_real(bit, 0); - run_vpi_callbacks(); - break; - - case 2: // Force value - force_mask_ = vvp_vector2_t(1, 1); - force_ = bit; - ptr.ptr()->send_real(bit, 0); - run_vpi_callbacks(); - break; - - default: - fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); - assert(0); - break; - } -} - -void vvp_fun_signal_real_sa::release(vvp_net_ptr_t ptr, bool net) -{ - force_mask_ = vvp_vector2_t(); - if (net) { - ptr.ptr()->send_real(bits_, 0); - run_vpi_callbacks(); - } else { - bits_ = force_; - } -} - -void vvp_fun_signal_real_sa::release_pv(vvp_net_ptr_t ptr, bool net, - unsigned base, unsigned wid) -{ - fprintf(stderr, "Error: cannot take bit/part select of a real value!\n"); - assert(0); -} - -vvp_fun_signal_real_aa::vvp_fun_signal_real_aa() -{ - context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope()); -} - -void vvp_fun_signal_real_aa::alloc_instance(vvp_context_t context) -{ - double*bits = new double; - vvp_set_context_item(context, context_idx_, bits); - - *bits = 0.0; -} - -void vvp_fun_signal_real_aa::reset_instance(vvp_context_t context) -{ - double*bits = static_cast - (vvp_get_context_item(context, context_idx_)); - - *bits = 0.0; -} - -#ifdef CHECK_WITH_VALGRIND -void vvp_fun_signal_real_aa::free_instance(vvp_context_t context) -{ - double*bits = static_cast - (vvp_get_context_item(context, context_idx_)); - delete bits; -} -#endif - -double vvp_fun_signal_real_aa::real_value() const -{ - double*bits = static_cast - (vthread_get_rd_context_item(context_idx_)); - - return *bits; -} - -void vvp_fun_signal_real_aa::recv_real(vvp_net_ptr_t ptr, double bit, - vvp_context_t context) -{ - assert(ptr.port() == 0); - assert(context); - - double*bits = static_cast - (vvp_get_context_item(context, context_idx_)); - - if (!bits_equal(*bits,bit)) { - *bits = bit; - ptr.ptr()->send_real(bit, context); - } -} - -void vvp_fun_signal_real_aa::release(vvp_net_ptr_t ptr, bool net) -{ - /* Automatic variables can't be forced. */ - assert(0); -} - -void vvp_fun_signal_real_aa::release_pv(vvp_net_ptr_t ptr, bool net, - unsigned base, unsigned wid) -{ - /* Automatic variables can't be forced. */ - assert(0); -} - /* **** vvp_wide_fun_* methods **** */ vvp_wide_fun_core::vvp_wide_fun_core(vvp_net_t*net, unsigned nports) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index b1894b6a2..808b61b52 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -42,6 +42,7 @@ class vvp_scalar_t; /* Basic netlist types. */ class vvp_net_t; class vvp_net_fun_t; +class vvp_net_fil_t; /* Core net function types. */ class vvp_fun_concat; @@ -961,7 +962,9 @@ template ostream& operator << (ostream&out, vvp_sub_pointer_t val) * the fan-out is unlimited. * * The vvp_send_*() functions take as input a vvp_net_ptr_t and follow - * all the fan-out chain, delivering the specified value. + * all the fan-out chain, delivering the specified value. The send_*() + * methods of the vvp_net_t class are similar, but they follow the + * output, possibly filtered, from the vvp_net_t. */ class vvp_net_t { public: @@ -972,6 +975,7 @@ class vvp_net_t { #endif vvp_net_ptr_t port[4]; vvp_net_fun_t*fun; + vvp_net_fil_t*fil; public: // Connect the port to the output from this net. @@ -1066,6 +1070,30 @@ class vvp_net_fun_t { static void operator delete[](void*); }; +/* + * A vvp_net_fil_t is a filter object that filters an output from a + * vvp_net_t. The send_*() methods of the vvp_net_t object call the + * filter of the output being transmitted. The filter function will + * decide if this value is to be propagated, and return true or + * 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. + */ +class vvp_net_fil_t { + + public: + vvp_net_fil_t(); + virtual ~vvp_net_fil_t(); + + public: + virtual bool filter_vec4(const vvp_vector4_t&bit); + virtual bool filter_vec8(const vvp_vector8_t&val); + virtual bool filter_real(double val); + virtual bool filter_long(long val); +}; + /* **** Some core net functions **** */ /* vvp_fun_concat @@ -1159,60 +1187,6 @@ class vvp_fun_extend_signed : public vvp_net_fun_t { unsigned width_; }; -/* 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 - * the type of its port-0 input. If vvp_vector4_t values come in - * through port-0, then vvp_vector4_t values are propagated. If - * vvp_vector8_t values come in through port-0, then vvp_vector8_t - * values are propagated. Thus, this node is slightly polymorphic. - * - * If the signal is a net (i.e. a wire or tri) then this node will - * have an input that is the data source. The data source will connect - * through port-0. - * - * If the signal is a reg, then there will be no netlist input, the - * values will be written by behavioral statements. The %set and - * %assign statements will write through port-0. - * - * In any case, behavioral code is able to read the value that this - * node last propagated, by using the value() method. That is important - * functionality of this node. - * - * Continuous assignments are made through port-1. When a value is - * written here, continuous assign mode is activated, and input - * through port-0 is ignored until continuous assign mode is turned - * off again. Writing into this port can be done in behavioral code - * using the %cassign/v instruction, or can be done by the network by - * hooking the output of a vvp_net_t to this port. - * - * Force assignments are made through port-2. When a value is written - * here, force mode is activated. In force mode, port-0 data (or - * port-1 data if in continuous assign mode) is tracked but not - * propagated. The force value is propagated and is what is readable - * through the value method. - * - * Port-3 is a command port, intended for use by procedural - * instructions. The client must write long values to this port to - * invoke the command of interest. The command values are: - * - * 1 -- deassign - * The deassign command takes the node out of continuous - * assignment mode. The output value is unchanged, and force - * mode, if active, remains in effect. - * - * 2 -- release/net - * The release/net command takes the node out of force mode, - * and propagates the tracked port-0 value to the signal - * output. This acts like a release of a net signal. - * - * 3 -- release/reg - * The release/reg command is similar to the release/net - * command, but the port-0 value is not propagated. Changes - * to port-0 (or port-1 if continuous assign is active) will - * propagate starting at the next input change. - */ - /* * Things derived from vvp_vpi_callback may also be array'ed, so it * includes some members that arrays use. @@ -1249,235 +1223,6 @@ class vvp_vpi_callback_wordable : public vvp_vpi_callback { unsigned long array_word_; }; -class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback_wordable { - - public: - vvp_fun_signal_base(); - void recv_long(vvp_net_ptr_t port, long bit); - void recv_long_pv(vvp_net_ptr_t port, long bit, - unsigned base, unsigned wid); - - public: - - /* 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. */ - struct vvp_net_t*force_link; - struct vvp_net_t*cassign_link; - - protected: - - // This is true until at least one propagation happens. - bool needs_init_; - bool continuous_assign_active_; - vvp_vector2_t force_mask_; - vvp_vector2_t assign_mask_; - - void deassign(); - void deassign_pv(unsigned base, unsigned wid); - 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; -}; - -/* - * This abstract class is a little more specific than the signal_base - * class, in that it adds vector access methods. - */ -class vvp_fun_signal_vec : public vvp_fun_signal_base { - - public: - // For vector signal types, this returns the vector count. - virtual unsigned size() const =0; - virtual vvp_bit4_t value(unsigned idx) const =0; - virtual vvp_scalar_t scalar_value(unsigned idx) const =0; - virtual vvp_vector4_t vec4_value() const =0; -}; - -class vvp_fun_signal4 : public vvp_fun_signal_vec { - - public: - explicit vvp_fun_signal4() {}; - - void get_value(struct t_vpi_value*value); - -}; - -/* - * Statically allocated vvp_fun_signal4. - */ -class vvp_fun_signal4_sa : public vvp_fun_signal4 { - - public: - explicit vvp_fun_signal4_sa(unsigned wid, vvp_bit4_t init=BIT4_X); - - void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, - vvp_context_t); - void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit); - - // Part select variants of above - void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, - unsigned base, unsigned wid, unsigned vwid, - vvp_context_t); - void recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit, - unsigned base, unsigned wid, unsigned vwid); - - // Get information about the vector value. - unsigned size() const; - vvp_bit4_t value(unsigned idx) const; - vvp_scalar_t scalar_value(unsigned idx) const; - vvp_vector4_t vec4_value() const; - - // Commands - void release(vvp_net_ptr_t port, bool net); - void release_pv(vvp_net_ptr_t port, bool net, - unsigned base, unsigned wid); - - private: - void calculate_output_(vvp_net_ptr_t ptr); - - vvp_vector4_t bits4_; - vvp_vector4_t force_; -}; - -/* - * Automatically allocated vvp_fun_signal4. - */ -class vvp_fun_signal4_aa : public vvp_fun_signal4, public automatic_hooks_s { - - public: - explicit vvp_fun_signal4_aa(unsigned wid, vvp_bit4_t init=BIT4_X); - - 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 recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, - vvp_context_t context); - - // Part select variants of above - void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, - unsigned base, unsigned wid, unsigned vwid, - vvp_context_t); - - // Get information about the vector value. - unsigned size() const; - vvp_bit4_t value(unsigned idx) const; - vvp_scalar_t scalar_value(unsigned idx) const; - vvp_vector4_t vec4_value() const; - - // Commands - void release(vvp_net_ptr_t port, bool net); - void release_pv(vvp_net_ptr_t port, bool net, - unsigned base, unsigned wid); - - private: - unsigned context_idx_; - unsigned size_; -}; - -class vvp_fun_signal8 : public vvp_fun_signal_vec { - - public: - explicit vvp_fun_signal8(unsigned wid); - - void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, - vvp_context_t context); - void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit); - - // Part select variants of above - void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, - unsigned base, unsigned wid, unsigned vwid, - vvp_context_t context); - void recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit, - unsigned base, unsigned wid, unsigned vwid); - - // Get information about the vector value. - unsigned size() const; - vvp_bit4_t value(unsigned idx) const; - vvp_scalar_t scalar_value(unsigned idx) const; - vvp_vector4_t vec4_value() const; - - // Commands - void release(vvp_net_ptr_t port, bool net); - void release_pv(vvp_net_ptr_t port, bool net, - unsigned base, unsigned wid); - - void get_value(struct t_vpi_value*value); - - private: - void calculate_output_(vvp_net_ptr_t ptr); - - vvp_vector8_t bits8_; - vvp_vector8_t force_; -}; - -class vvp_fun_signal_real : public vvp_fun_signal_base { - - public: - explicit vvp_fun_signal_real() {}; - - // Get information about the vector value. - virtual double real_value() const = 0; - - void get_value(struct t_vpi_value*value); -}; - -/* - * Statically allocated vvp_fun_signal_real. - */ -class vvp_fun_signal_real_sa : public vvp_fun_signal_real { - - public: - explicit vvp_fun_signal_real_sa(); - - void recv_real(vvp_net_ptr_t port, double bit, - vvp_context_t); - - // Get information about the vector value. - double real_value() const; - - // Commands - void release(vvp_net_ptr_t port, bool net); - void release_pv(vvp_net_ptr_t port, bool net, - unsigned base, unsigned wid); - - private: - double bits_; - double force_; -}; - -/* - * Automatically allocated vvp_fun_signal_real. - */ -class vvp_fun_signal_real_aa : public vvp_fun_signal_real, public automatic_hooks_s { - - public: - explicit vvp_fun_signal_real_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 recv_real(vvp_net_ptr_t port, double bit, - vvp_context_t context); - - // Get information about the vector value. - double real_value() const; - - // Commands - void release(vvp_net_ptr_t port, bool net); - void release_pv(vvp_net_ptr_t port, bool net, - unsigned base, unsigned wid); - - private: - unsigned context_idx_; -}; - /* * Wide Functors: * Wide functors represent special devices that may have more than 4 @@ -1626,6 +1371,9 @@ inline void vvp_net_t::send_vec8_pv(const vvp_vector8_t&val, inline void vvp_net_t::send_vec4(const vvp_vector4_t&val, vvp_context_t context) { + if (fil && ! fil->filter_vec4(val)) + return; + vvp_send_vec4(out_, val, context); } @@ -1638,11 +1386,17 @@ inline void vvp_net_t::send_vec4_pv(const vvp_vector4_t&val, inline void vvp_net_t::send_vec8(const vvp_vector8_t&val) { + if (fil && ! fil->filter_vec8(val)) + return; + vvp_send_vec8(out_, val); } inline void vvp_net_t::send_real(double val, vvp_context_t context) { + if (fil && ! fil->filter_real(val)) + return; + vvp_send_real(out_, val, context); } diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc new file mode 100644 index 000000000..cff276760 --- /dev/null +++ b/vvp/vvp_net_sig.cc @@ -0,0 +1,800 @@ +/* + * Copyright (c) 2004-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 "vvp_net.h" +# include "vvp_net_sig.h" +# include "statistics.h" +# include "vpi_priv.h" +# include +#ifdef CHECK_WITH_VALGRIND +# include +# include +#endif + +template T coerce_to_width(const T&that, unsigned width) +{ + if (that.size() == width) + return that; + + assert(that.size() > width); + T res (width); + for (unsigned idx = 0 ; idx < width ; idx += 1) + res.set_bit(idx, that.value(idx)); + + return res; +} + +/* **** vvp_fun_signal methods **** */ + +vvp_fun_signal_base::vvp_fun_signal_base() +{ + needs_init_ = true; + continuous_assign_active_ = false; + force_link = 0; + cassign_link = 0; + count_functors_sig += 1; +} + +void vvp_fun_signal_base::deassign() +{ + continuous_assign_active_ = false; + assign_mask_ = vvp_vector2_t(); +} + +void vvp_fun_signal_base::deassign_pv(unsigned base, unsigned wid) +{ + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + assign_mask_.set_bit(base+idx, 0); + } + + if (assign_mask_.is_zero()) { + assign_mask_ = vvp_vector2_t(); + } +} + +/* + * The signal functor takes commands as long values to port-3. This + * method interprets those commands. + */ +void vvp_fun_signal_base::recv_long(vvp_net_ptr_t ptr, long bit) +{ + switch (ptr.port()) { + case 3: // Command port + switch (bit) { + case 1: // deassign command + deassign(); + break; + case 2: // release/net + release(ptr, true); + break; + case 3: // release/reg + release(ptr, false); + break; + default: + fprintf(stderr, "Unsupported command %ld.\n", bit); + assert(0); + break; + } + break; + + default: // Other ports are errors. + fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); + assert(0); + break; + } +} + +void vvp_fun_signal_base::recv_long_pv(vvp_net_ptr_t ptr, long bit, + unsigned base, unsigned wid) +{ + switch (ptr.port()) { + case 3: // Command port + switch (bit) { + case 1: // deassign command + deassign_pv(base, wid); + break; + case 2: // release/net + release_pv(ptr, true, base, wid); + break; + case 3: // release/reg + release_pv(ptr, false, base, wid); + break; + default: + fprintf(stderr, "Unsupported command %ld.\n", bit); + assert(0); + break; + } + break; + + default: // Other ports are errors. + fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); + assert(0); + break; + } +} + +vvp_fun_signal4_sa::vvp_fun_signal4_sa(unsigned wid, vvp_bit4_t init) +: bits4_(wid, init) +{ +} + +/* + * Nets simply reflect their input to their output. + * + * NOTE: It is a quirk of vvp_fun_signal that it has an initial value + * that needs to be propagated, but after that it only needs to + * propagate if the value changes. Eliminating duplicate propagations + * should improve performance, but has the quirk that an input that + * matches the initial value might not be propagated. The hack used + * herein is to keep a "needs_init_" flag that is turned false after + * the first propagation, and forces the first propagation to happen + * even if it matches the initial value. + */ +void vvp_fun_signal4_sa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + vvp_context_t) +{ + switch (ptr.port()) { + case 0: // Normal input (feed from net, or set from process) + /* If we don't have a continuous assign mask then just + copy the bits, otherwise we need to see if there are + any holes in the mask so we can set those bits. */ + if (assign_mask_.size() == 0) { + if (needs_init_ || !bits4_.eeq(bit)) { + bits4_ = bit; + needs_init_ = false; + calculate_output_(ptr); + } + } else { + bool changed = false; + assert(bits4_.size() == assign_mask_.size()); + for (unsigned idx = 0 ; idx < bit.size() ; idx += 1) { + if (idx >= bits4_.size()) break; + if (assign_mask_.value(idx)) continue; + bits4_.set_bit(idx, bit.value(idx)); + changed = true; + } + if (changed) { + needs_init_ = false; + calculate_output_(ptr); + } + } + break; + + case 1: // Continuous assign value + bits4_ = bit; + assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); + calculate_output_(ptr); + break; + + case 2: // Force value + + // Force from a node may not have been sized completely + // by the source, so coerce the size here. + if (bit.size() != size()) + force_ = coerce_to_width(bit, size()); + else + force_ = bit; + + force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); + calculate_output_(ptr); + break; + + default: + fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); + assert(0); + break; + } +} + +void vvp_fun_signal4_sa::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit) +{ + recv_vec4(ptr, reduce4(bit), 0); +} + +void vvp_fun_signal4_sa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t) +{ + assert(bit.size() == wid); + assert(bits4_.size() == vwid); + + switch (ptr.port()) { + case 0: // Normal input + if (assign_mask_.size() == 0) { + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + if (base+idx >= bits4_.size()) break; + bits4_.set_bit(base+idx, bit.value(idx)); + } + needs_init_ = false; + calculate_output_(ptr); + } else { + bool changed = false; + assert(bits4_.size() == assign_mask_.size()); + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + if (base+idx >= bits4_.size()) break; + if (assign_mask_.value(base+idx)) continue; + bits4_.set_bit(base+idx, bit.value(idx)); + changed = true; + } + if (changed) { + needs_init_ = false; + calculate_output_(ptr); + } + } + break; + + case 1: // Continuous assign value + if (assign_mask_.size() == 0) + assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, size()); + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + if (base+idx >= bits4_.size()) + break; + bits4_.set_bit(base+idx, bit.value(idx)); + assign_mask_.set_bit(base+idx, 1); + } + calculate_output_(ptr); + break; + + case 2: // Force value + + if (force_mask_.size() == 0) + force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, size()); + if (force_.size() == 0) + force_ = vvp_vector4_t(vwid, BIT4_Z); + + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + force_mask_.set_bit(base+idx, 1); + force_.set_bit(base+idx, bit.value(idx)); + } + + calculate_output_(ptr); + break; + + default: + fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); + assert(0); + break; + } +} + +void vvp_fun_signal4_sa::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid) +{ + recv_vec4_pv(ptr, reduce4(bit), base, wid, vwid, 0); +} + +void vvp_fun_signal4_sa::calculate_output_(vvp_net_ptr_t ptr) +{ + if (force_mask_.size()) { + assert(bits4_.size() == force_mask_.size()); + assert(bits4_.size() == force_.size()); + vvp_vector4_t bits (bits4_); + for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { + if (force_mask_.value(idx)) + bits.set_bit(idx, force_.value(idx)); + } + ptr.ptr()->send_vec4(bits, 0); + } else { + ptr.ptr()->send_vec4(bits4_, 0); + } + + run_vpi_callbacks(); +} + +void vvp_fun_signal4_sa::release(vvp_net_ptr_t ptr, bool net) +{ + force_mask_ = vvp_vector2_t(); + if (net) { + ptr.ptr()->send_vec4(bits4_, 0); + run_vpi_callbacks(); + } else { + bits4_ = force_; + } +} + +void vvp_fun_signal4_sa::release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) +{ + assert(bits4_.size() >= base + wid); + + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + force_mask_.set_bit(base+idx, 0); + if (!net) bits4_.set_bit(base+idx, force_.value(base+idx)); + } + if (force_mask_.is_zero()) force_mask_ = vvp_vector2_t(); + + if (net) calculate_output_(ptr); +} + +unsigned vvp_fun_signal4_sa::size() const +{ + if (force_mask_.size()) + return force_.size(); + else + return bits4_.size(); +} + +vvp_bit4_t vvp_fun_signal4_sa::value(unsigned idx) const +{ + if (force_mask_.size() && force_mask_.value(idx)) { + return force_.value(idx); + } else { + return bits4_.value(idx); + } +} + +vvp_scalar_t vvp_fun_signal4_sa::scalar_value(unsigned idx) const +{ + if (force_mask_.size() && force_mask_.value(idx)) { + return vvp_scalar_t(force_.value(idx), 6, 6); + } else { + return vvp_scalar_t(bits4_.value(idx), 6, 6); + } +} + +vvp_vector4_t vvp_fun_signal4_sa::vec4_value() const +{ + if (force_mask_.size()) { + assert(bits4_.size() == force_mask_.size()); + assert(bits4_.size() == force_.size()); + vvp_vector4_t bits (bits4_); + for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { + if (force_mask_.value(idx)) + bits.set_bit(idx, force_.value(idx)); + } + return bits; + } else { + return bits4_; + } +} + +vvp_fun_signal4_aa::vvp_fun_signal4_aa(unsigned wid, vvp_bit4_t init) +{ + context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope()); + size_ = wid; +} + +void vvp_fun_signal4_aa::alloc_instance(vvp_context_t context) +{ + vvp_set_context_item(context, context_idx_, new vvp_vector4_t(size_)); +} + +void vvp_fun_signal4_aa::reset_instance(vvp_context_t context) +{ + vvp_vector4_t*bits = static_cast + (vvp_get_context_item(context, context_idx_)); + + bits->set_to_x(); +} + +#ifdef CHECK_WITH_VALGRIND +void vvp_fun_signal4_aa::free_instance(vvp_context_t context) +{ + vvp_vector4_t*bits = static_cast + (vvp_get_context_item(context, context_idx_)); + delete bits; +} +#endif + +/* + * Continuous and forced assignments are not permitted on automatic + * variables. So we only expect to receive on port 0. + */ +void vvp_fun_signal4_aa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + vvp_context_t context) +{ + assert(ptr.port() == 0); + assert(context); + + vvp_vector4_t*bits4 = static_cast + (vvp_get_context_item(context, context_idx_)); + + if (!bits4->eeq(bit)) { + *bits4 = bit; + ptr.ptr()->send_vec4(*bits4, context); + } +} + +void vvp_fun_signal4_aa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t context) +{ + assert(ptr.port() == 0); + assert(bit.size() == wid); + assert(size_ == vwid); + assert(context); + + vvp_vector4_t*bits4 = static_cast + (vvp_get_context_item(context, context_idx_)); + + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + if (base+idx >= bits4->size()) break; + bits4->set_bit(base+idx, bit.value(idx)); + } + ptr.ptr()->send_vec4(*bits4, context); +} + +void vvp_fun_signal4_aa::release(vvp_net_ptr_t ptr, bool net) +{ + /* Automatic variables can't be forced. */ + assert(0); +} + +void vvp_fun_signal4_aa::release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) +{ + /* Automatic variables can't be forced. */ + assert(0); +} + +unsigned vvp_fun_signal4_aa::size() const +{ + return size_; +} + +vvp_bit4_t vvp_fun_signal4_aa::value(unsigned idx) const +{ + vvp_vector4_t*bits4 = static_cast + (vthread_get_rd_context_item(context_idx_)); + + return bits4->value(idx); +} + +vvp_scalar_t vvp_fun_signal4_aa::scalar_value(unsigned idx) const +{ + vvp_vector4_t*bits4 = static_cast + (vthread_get_rd_context_item(context_idx_)); + + return vvp_scalar_t(bits4->value(idx), 6, 6); +} + +vvp_vector4_t vvp_fun_signal4_aa::vec4_value() const +{ + vvp_vector4_t*bits4 = static_cast + (vthread_get_rd_context_item(context_idx_)); + + return *bits4; +} + +vvp_fun_signal8::vvp_fun_signal8(unsigned wid) +: bits8_(wid) +{ +} + +void vvp_fun_signal8::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + vvp_context_t) +{ + recv_vec8(ptr, vvp_vector8_t(bit,6,6)); +} + +void vvp_fun_signal8::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit) +{ + switch (ptr.port()) { + case 0: // Normal input (feed from net, or set from process) + if (needs_init_ || !bits8_.eeq(bit)) { + bits8_ = bit; + needs_init_ = false; + calculate_output_(ptr); + } + break; + + case 1: // Continuous assign value + /* This is a procedural continuous assign and it can + * only be used on a register and a register is never + * strength aware. */ + assert(0); + break; + + case 2: // Force value + + // Force from a node may not have been sized completely + // by the source, so coerce the size here. + if (bit.size() != size()) + force_ = coerce_to_width(bit, size()); + else + force_ = bit; + + force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); + calculate_output_(ptr); + break; + + default: + fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); + assert(0); + break; + } +} + +void vvp_fun_signal8::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t) +{ + recv_vec8_pv(ptr, vvp_vector8_t(bit,6,6), base, wid, vwid); +} + +void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid) +{ + assert(bit.size() == wid); + assert(bits8_.size() == vwid); + + switch (ptr.port()) { + case 0: // Normal input + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + if (base+idx >= bits8_.size()) break; + bits8_.set_bit(base+idx, bit.value(idx)); + } + needs_init_ = false; + calculate_output_(ptr); + break; + + case 1: // Continuous assign value + /* This is a procedural continuous assign and it can + * only be used on a register and a register is never + * strength aware. */ + assert(0); + break; + + case 2: // Force value + + if (force_mask_.size() == 0) + force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, size()); + if (force_.size() == 0) + force_ = vvp_vector8_t(vvp_vector4_t(vwid, BIT4_Z),6,6); + + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + force_mask_.set_bit(base+idx, 1); + force_.set_bit(base+idx, bit.value(idx)); + } + + calculate_output_(ptr); + break; + + default: + fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); + assert(0); + break; + } +} + +void vvp_fun_signal8::calculate_output_(vvp_net_ptr_t ptr) +{ + if (force_mask_.size()) { + assert(bits8_.size() == force_mask_.size()); + assert(bits8_.size() == force_.size()); + vvp_vector8_t bits (bits8_); + for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { + if (force_mask_.value(idx)) + bits.set_bit(idx, force_.value(idx)); + } + ptr.ptr()->send_vec8(bits); + + } else { + ptr.ptr()->send_vec8(bits8_); + } + + run_vpi_callbacks(); +} + +void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net) +{ + force_mask_ = vvp_vector2_t(); + if (net) { + ptr.ptr()->send_vec8(bits8_); + run_vpi_callbacks(); + } else { + bits8_ = force_; + } +} + +void vvp_fun_signal8::release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) +{ + assert(bits8_.size() >= base + wid); + + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + force_mask_.set_bit(base+idx, 0); + if (!net) bits8_.set_bit(base+idx, force_.value(base+idx)); + } + if (force_mask_.is_zero()) force_mask_ = vvp_vector2_t(); + + if (net) calculate_output_(ptr); +} + +unsigned vvp_fun_signal8::size() const +{ + if (force_mask_.size()) + return force_.size(); + else + return bits8_.size(); +} + +vvp_bit4_t vvp_fun_signal8::value(unsigned idx) const +{ + if (force_mask_.size() && force_mask_.value(idx)) + return force_.value(idx).value(); + else + return bits8_.value(idx).value(); +} + +vvp_vector4_t vvp_fun_signal8::vec4_value() const +{ + if (force_mask_.size()) { + vvp_vector8_t bits (bits8_); + for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { + if (force_mask_.value(idx)) + bits.set_bit(idx, force_.value(idx)); + } + return reduce4(bits); + } else + return reduce4(bits8_); +} + +vvp_scalar_t vvp_fun_signal8::scalar_value(unsigned idx) const +{ + if (force_mask_.size() && force_mask_.value(idx)) + return force_.value(idx); + else + return bits8_.value(idx); +} + + +/* + * Testing for equality, we want a bitwise test instead of an + * arithmetic test because we want to treat for example -0 different + * from +0. + */ +bool bits_equal(double a, double b) +{ + return memcmp(&a, &b, sizeof a) == 0; +} + +vvp_fun_signal_real_sa::vvp_fun_signal_real_sa() +{ + bits_ = 0.0; +} + +double vvp_fun_signal_real_sa::real_value() const +{ + if (force_mask_.size()) + return force_; + else + return bits_; +} + +void vvp_fun_signal_real_sa::recv_real(vvp_net_ptr_t ptr, double bit, + vvp_context_t) +{ + switch (ptr.port()) { + case 0: + if (!continuous_assign_active_) { + if (needs_init_ || !bits_equal(bits_, bit)) { + bits_ = bit; + needs_init_ = false; + ptr.ptr()->send_real(bit, 0); + run_vpi_callbacks(); + } + } + break; + + case 1: // Continuous assign value + continuous_assign_active_ = true; + bits_ = bit; + ptr.ptr()->send_real(bit, 0); + run_vpi_callbacks(); + break; + + case 2: // Force value + force_mask_ = vvp_vector2_t(1, 1); + force_ = bit; + ptr.ptr()->send_real(bit, 0); + run_vpi_callbacks(); + break; + + default: + fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); + assert(0); + break; + } +} + +void vvp_fun_signal_real_sa::release(vvp_net_ptr_t ptr, bool net) +{ + force_mask_ = vvp_vector2_t(); + if (net) { + ptr.ptr()->send_real(bits_, 0); + run_vpi_callbacks(); + } else { + bits_ = force_; + } +} + +void vvp_fun_signal_real_sa::release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) +{ + fprintf(stderr, "Error: cannot take bit/part select of a real value!\n"); + assert(0); +} + +vvp_fun_signal_real_aa::vvp_fun_signal_real_aa() +{ + context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope()); +} + +void vvp_fun_signal_real_aa::alloc_instance(vvp_context_t context) +{ + double*bits = new double; + vvp_set_context_item(context, context_idx_, bits); + + *bits = 0.0; +} + +void vvp_fun_signal_real_aa::reset_instance(vvp_context_t context) +{ + double*bits = static_cast + (vvp_get_context_item(context, context_idx_)); + + *bits = 0.0; +} + +#ifdef CHECK_WITH_VALGRIND +void vvp_fun_signal_real_aa::free_instance(vvp_context_t context) +{ + double*bits = static_cast + (vvp_get_context_item(context, context_idx_)); + delete bits; +} +#endif + +double vvp_fun_signal_real_aa::real_value() const +{ + double*bits = static_cast + (vthread_get_rd_context_item(context_idx_)); + + return *bits; +} + +void vvp_fun_signal_real_aa::recv_real(vvp_net_ptr_t ptr, double bit, + vvp_context_t context) +{ + assert(ptr.port() == 0); + assert(context); + + double*bits = static_cast + (vvp_get_context_item(context, context_idx_)); + + if (!bits_equal(*bits,bit)) { + *bits = bit; + ptr.ptr()->send_real(bit, context); + } +} + +void vvp_fun_signal_real_aa::release(vvp_net_ptr_t ptr, bool net) +{ + /* Automatic variables can't be forced. */ + assert(0); +} + +void vvp_fun_signal_real_aa::release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) +{ + /* Automatic variables can't be forced. */ + assert(0); +} diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h new file mode 100644 index 000000000..ef6e6d44d --- /dev/null +++ b/vvp/vvp_net_sig.h @@ -0,0 +1,323 @@ +#ifndef __vvp_net_sig_H +#define __vvp_net_sig_H +/* + * Copyright (c) 2004-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" +# include "vvp_net.h" +# include +# include +# include +# include +# include + +#ifdef HAVE_IOSFWD +# include +#else +class ostream; +#endif + +using namespace std; + +/* 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 + * the type of its port-0 input. If vvp_vector4_t values come in + * through port-0, then vvp_vector4_t values are propagated. If + * vvp_vector8_t values come in through port-0, then vvp_vector8_t + * values are propagated. Thus, this node is slightly polymorphic. + * + * If the signal is a net (i.e. a wire or tri) then this node will + * have an input that is the data source. The data source will connect + * through port-0. + * + * If the signal is a reg, then there will be no netlist input, the + * values will be written by behavioral statements. The %set and + * %assign statements will write through port-0. + * + * In any case, behavioral code is able to read the value that this + * node last propagated, by using the value() method. That is important + * functionality of this node. + * + * Continuous assignments are made through port-1. When a value is + * written here, continuous assign mode is activated, and input + * through port-0 is ignored until continuous assign mode is turned + * off again. Writing into this port can be done in behavioral code + * using the %cassign/v instruction, or can be done by the network by + * hooking the output of a vvp_net_t to this port. + * + * Force assignments are made through port-2. When a value is written + * here, force mode is activated. In force mode, port-0 data (or + * port-1 data if in continuous assign mode) is tracked but not + * propagated. The force value is propagated and is what is readable + * through the value method. + * + * Port-3 is a command port, intended for use by procedural + * instructions. The client must write long values to this port to + * invoke the command of interest. The command values are: + * + * 1 -- deassign + * The deassign command takes the node out of continuous + * assignment mode. The output value is unchanged, and force + * mode, if active, remains in effect. + * + * 2 -- release/net + * The release/net command takes the node out of force mode, + * and propagates the tracked port-0 value to the signal + * output. This acts like a release of a net signal. + * + * 3 -- release/reg + * The release/reg command is similar to the release/net + * command, but the port-0 value is not propagated. Changes + * to port-0 (or port-1 if continuous assign is active) will + * propagate starting at the next input change. + */ + +class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback_wordable { + + public: + vvp_fun_signal_base(); + void recv_long(vvp_net_ptr_t port, long bit); + void recv_long_pv(vvp_net_ptr_t port, long bit, + unsigned base, unsigned wid); + + public: + + /* 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. */ + struct vvp_net_t*force_link; + struct vvp_net_t*cassign_link; + + protected: + + // This is true until at least one propagation happens. + bool needs_init_; + bool continuous_assign_active_; + vvp_vector2_t force_mask_; + vvp_vector2_t assign_mask_; + + void deassign(); + void deassign_pv(unsigned base, unsigned wid); + 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; +}; + +/* + * This abstract class is a little more specific than the signal_base + * class, in that it adds vector access methods. + */ +class vvp_fun_signal_vec : public vvp_fun_signal_base { + + public: + // For vector signal types, this returns the vector count. + virtual unsigned size() const =0; + virtual vvp_bit4_t value(unsigned idx) const =0; + virtual vvp_scalar_t scalar_value(unsigned idx) const =0; + virtual vvp_vector4_t vec4_value() const =0; +}; + +class vvp_fun_signal4 : public vvp_fun_signal_vec { + + public: + explicit vvp_fun_signal4() {}; + + void get_value(struct t_vpi_value*value); + +}; + +/* + * Statically allocated vvp_fun_signal4. + */ +class vvp_fun_signal4_sa : public vvp_fun_signal4 { + + public: + explicit vvp_fun_signal4_sa(unsigned wid, vvp_bit4_t init=BIT4_X); + + void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, + vvp_context_t); + void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit); + + // Part select variants of above + void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t); + void recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid); + + // Get information about the vector value. + unsigned size() const; + vvp_bit4_t value(unsigned idx) const; + vvp_scalar_t scalar_value(unsigned idx) const; + vvp_vector4_t vec4_value() const; + + // Commands + void release(vvp_net_ptr_t port, bool net); + void release_pv(vvp_net_ptr_t port, bool net, + unsigned base, unsigned wid); + + private: + void calculate_output_(vvp_net_ptr_t ptr); + + vvp_vector4_t bits4_; + vvp_vector4_t force_; +}; + +/* + * Automatically allocated vvp_fun_signal4. + */ +class vvp_fun_signal4_aa : public vvp_fun_signal4, public automatic_hooks_s { + + public: + explicit vvp_fun_signal4_aa(unsigned wid, vvp_bit4_t init=BIT4_X); + + 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 recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, + vvp_context_t context); + + // Part select variants of above + void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t); + + // Get information about the vector value. + unsigned size() const; + vvp_bit4_t value(unsigned idx) const; + vvp_scalar_t scalar_value(unsigned idx) const; + vvp_vector4_t vec4_value() const; + + // Commands + void release(vvp_net_ptr_t port, bool net); + void release_pv(vvp_net_ptr_t port, bool net, + unsigned base, unsigned wid); + + private: + unsigned context_idx_; + unsigned size_; +}; + +class vvp_fun_signal8 : public vvp_fun_signal_vec { + + public: + explicit vvp_fun_signal8(unsigned wid); + + void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, + vvp_context_t context); + void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit); + + // Part select variants of above + void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t context); + void recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit, + unsigned base, unsigned wid, unsigned vwid); + + // Get information about the vector value. + unsigned size() const; + vvp_bit4_t value(unsigned idx) const; + vvp_scalar_t scalar_value(unsigned idx) const; + vvp_vector4_t vec4_value() const; + + // Commands + void release(vvp_net_ptr_t port, bool net); + void release_pv(vvp_net_ptr_t port, bool net, + unsigned base, unsigned wid); + + void get_value(struct t_vpi_value*value); + + private: + void calculate_output_(vvp_net_ptr_t ptr); + + vvp_vector8_t bits8_; + vvp_vector8_t force_; +}; + +class vvp_fun_signal_real : public vvp_fun_signal_base { + + public: + explicit vvp_fun_signal_real() {}; + + // Get information about the vector value. + virtual double real_value() const = 0; + + void get_value(struct t_vpi_value*value); +}; + +/* + * Statically allocated vvp_fun_signal_real. + */ +class vvp_fun_signal_real_sa : public vvp_fun_signal_real { + + public: + explicit vvp_fun_signal_real_sa(); + + void recv_real(vvp_net_ptr_t port, double bit, + vvp_context_t); + + // Get information about the vector value. + double real_value() const; + + // Commands + void release(vvp_net_ptr_t port, bool net); + void release_pv(vvp_net_ptr_t port, bool net, + unsigned base, unsigned wid); + + private: + double bits_; + double force_; +}; + +/* + * Automatically allocated vvp_fun_signal_real. + */ +class vvp_fun_signal_real_aa : public vvp_fun_signal_real, public automatic_hooks_s { + + public: + explicit vvp_fun_signal_real_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 recv_real(vvp_net_ptr_t port, double bit, + vvp_context_t context); + + // Get information about the vector value. + double real_value() const; + + // Commands + void release(vvp_net_ptr_t port, bool net); + void release_pv(vvp_net_ptr_t port, bool net, + unsigned base, unsigned wid); + + private: + unsigned context_idx_; +}; + + +#endif diff --git a/vvp/words.cc b/vvp/words.cc index cd1a06d51..935b5bfa2 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -20,6 +20,7 @@ # include "compile.h" # include "vpi_priv.h" # include "array.h" +# include "vvp_net_sig.h" # include "schedule.h" # include # include