diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 3e150b181..cdaf3d3dd 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -4060,6 +4060,7 @@ static bool do_release_vec(vthread_t thr, vvp_code_t cp, bool net_flag) } else { net->fil->release_pv(ptr, base, width, net_flag); } + net->fun->force_flag(); return true; } diff --git a/vvp/vvp_island.cc b/vvp/vvp_island.cc index 6b4a76343..03bfdd52c 100644 --- a/vvp/vvp_island.cc +++ b/vvp/vvp_island.cc @@ -213,6 +213,11 @@ void vvp_island_port::recv_vec8_pv(vvp_net_ptr_t p, const vvp_vector8_t&bit, island_->flag_island(); } +void vvp_island_port::force_flag(void) +{ + island_->flag_island(); +} + vvp_island_branch::~vvp_island_branch() { } diff --git a/vvp/vvp_island.h b/vvp/vvp_island.h index 419990454..90745dcef 100644 --- a/vvp/vvp_island.h +++ b/vvp/vvp_island.h @@ -21,6 +21,7 @@ # include "config.h" # include "vvp_net.h" +# include "vvp_net_sig.h" # include "symbols.h" # include "schedule.h" # include @@ -120,6 +121,7 @@ class vvp_island_port : public vvp_net_fun_t { explicit vvp_island_port(vvp_island*ip); ~vvp_island_port(); + public: // Implement vvp_net_fun_t methods virtual void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t); virtual void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, @@ -129,6 +131,12 @@ class vvp_island_port : public vvp_net_fun_t { virtual void recv_vec8_pv(vvp_net_ptr_t p, const vvp_vector8_t&bit, unsigned base, unsigned wid, unsigned vwid); + // This is painful, but necessary. If the island is connected + // to a forced net, we need to rerun the calculations whenever + // a force/release happens to the net. + virtual void force_flag(void); + + public: vvp_vector8_t invalue; vvp_vector8_t outvalue; @@ -143,7 +151,24 @@ class vvp_island_port : public vvp_net_fun_t { inline vvp_vector8_t island_get_value(vvp_net_t*net) { vvp_island_port*fun = dynamic_cast(net->fun); - return fun->invalue; + vvp_wire_vec8*fil = dynamic_cast(net->fil); + + if (fil == 0) { + return fun->invalue; + } else { + // This is painful, but necessary. If the island is + // connected to a forced net, then run the input through + // the force filter first. The island must used the + // forced value for its deliberations. + vvp_vector8_t rep; + switch (fil->filter_input_vec8(fun->invalue, rep)) { + default: + case vvp_net_fil_t::PROP: + return fun->invalue; + case vvp_net_fil_t::REPL: + return rep; + } + } } extern void island_send_value(vvp_net_t*net, const vvp_vector8_t&val); diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 787c32f31..ac7e4c445 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -2849,6 +2849,10 @@ void vvp_net_fun_t::recv_long_pv(vvp_net_ptr_t, long, unsigned, unsigned) assert(0); } +void vvp_net_fun_t::force_flag(void) +{ +} + /* **** vvp_fun_drive methods **** */ vvp_fun_drive::vvp_fun_drive(vvp_bit4_t init, unsigned str0, unsigned str1) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 4c646f01a..dddb6d52e 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1114,6 +1114,12 @@ class vvp_net_fun_t { virtual void recv_long_pv(vvp_net_ptr_t port, long bit, unsigned base, unsigned wid); + // This method is called when the net it forced or + // released. This is very rarely needed; island ports use it + // to know that the net is being forced and that it needs to + // do something about it. + virtual void force_flag(void); + public: // These objects are only permallocated. static void* operator new(std::size_t size) { return heap_.alloc(size); } static void operator delete(void*); // not implemented @@ -1150,13 +1156,16 @@ class vvp_net_fil_t : public vvp_vpi_callback { public: enum prop_t { STOP=0, PROP, REPL }; - // Return a non-empty vector if the filter allows an - // output. The output result may be different from the - // input. If the output is nil, then suppress propagation. - // Return true if the value is to be propagated, or false if - // propagation is suppressed. The value may be edited by the - // filter, or overridden by the rep argument if present. + // These filter methods are used by the vvp_net_t::send_*() + // methods to test the output (from the functor) bit value + // against any force filters. If none of the bits are forced, + // then the method returns PROP and the caller propagates the + // bit value. If bits were changed by the force mask, then the + // method returns REPL and the caller should propagate the rep + // value instead. If the function returns STOP, then all the + // output bits are filtered by the force mask ans there is + // nothing to propagate. virtual prop_t filter_vec4(const vvp_vector4_t&bit, vvp_vector4_t&rep, unsigned base, unsigned vwid); virtual prop_t filter_vec8(const vvp_vector8_t&val, vvp_vector8_t&rep, @@ -1176,7 +1185,9 @@ class vvp_net_fil_t : public vvp_vpi_callback { virtual unsigned filter_size() const =0; public: - // Suport for force methods + // Suport for force methods. These are calloed by the + // vvp_net_t::force_* methods to set the force value and mask + // for the filter. virtual void force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) =0; virtual void force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) =0; virtual void force_fil_real(double val, vvp_vector2_t mask) =0; @@ -1215,6 +1226,12 @@ class vvp_net_fil_t : public vvp_vpi_callback { // native types that are not so expensive to edit in place. template prop_t filter_mask_(T&val, T force); + // These templates are similar to filter_mask_, but are + // idempotent. Then do not trigger callbacks or otherwise + // cause any locak changes. These methods are used to test + // arbitrary values against the force mask. + template prop_t filter_input_mask_(const T&val, const T&force, T&rep) const; + private: // Mask of forced bits vvp_vector2_t force_mask_; diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 526c2d560..5e35165f8 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -71,6 +71,22 @@ template vvp_net_fil_t::prop_t vvp_net_fil_t::filter_mask_(T&val, T fo return PROP; } +template vvp_net_fil_t::prop_t vvp_net_fil_t::filter_input_mask_(const T&val, const T&force, T&rep) const +{ + if (test_force_mask_is_zero()) + return PROP; + + assert(force_mask_.size() == force.size()); + + rep = val; + for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + if (force_mask_.value(idx)) + rep.set_bit(idx, force.value(idx)); + } + + return REPL; +} + vvp_signal_value::~vvp_signal_value() { } @@ -85,6 +101,7 @@ void vvp_net_t::force_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) { assert(fil); fil->force_fil_vec4(val, mask); + fun->force_flag(); vvp_send_vec4(out_, val, 0); } @@ -92,6 +109,7 @@ void vvp_net_t::force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) { assert(fil); fil->force_fil_vec8(val, mask); + fun->force_flag(); vvp_send_vec8(out_, val); } @@ -99,6 +117,7 @@ void vvp_net_t::force_real(double val, vvp_vector2_t mask) { assert(fil); fil->force_fil_real(val, mask); + fun->force_flag(); vvp_send_real(out_, val, 0); } @@ -777,6 +796,11 @@ vvp_net_fil_t::prop_t vvp_wire_vec8::filter_vec8(const vvp_vector8_t&bit, vvp_ve return filter_mask_(bit, force8_, rep, base); } +vvp_net_fil_t::prop_t vvp_wire_vec8::filter_input_vec8(const vvp_vector8_t&bit, vvp_vector8_t&rep) const +{ + return filter_input_mask_(bit, force8_, rep); +} + unsigned vvp_wire_vec8::filter_size() const { return bits8_.size(); diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 3121a8655..58e749d0c 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -324,6 +324,11 @@ class vvp_wire_vec8 : public vvp_wire_base { prop_t filter_vec8(const vvp_vector8_t&val, vvp_vector8_t&rep, unsigned base, unsigned vwid); + // island ports use this method to filter arbitrary values + // through the force filter. + prop_t filter_input_vec8(const vvp_vector8_t&val, vvp_vector8_t&rep) const; + + // Abstract methods from vvp_vpi_callback void get_value(struct t_vpi_value*value); // Abstract methods from vvp_net_fit_t