diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 7e1d13698..e00e07c20 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2299,23 +2299,6 @@ bool of_EVCTLS(vthread_t thr, vvp_code_t cp) return true; } -static void unlink_force(vvp_net_t*net) -{ - vvp_filter_wire_base*sig - = reinterpret_cast(net->fun); - /* This node must be a signal... */ - assert(sig); - /* This signal is being forced. */ - assert(sig->force_link); - - vvp_net_t*src = sig->force_link; - sig->force_link = 0; - - /* We are looking for this pointer. */ - vvp_net_ptr_t net_ptr (net, 2); - src->unlink(net_ptr); -} - /* * the %force/link instruction connects a source node to a * destination node. The destination node must be a signal, as it is @@ -2329,24 +2312,10 @@ bool of_FORCE_LINK(vthread_t thr, vvp_code_t cp) vvp_net_t*src = cp->net2; vvp_filter_wire_base*sig - = reinterpret_cast(dst->fun); + = dynamic_cast(dst->fun); assert(sig); - /* Detect the special case that we are already forced the - source onto the destination. */ - if (sig->force_link == src) - return true; - - /* If there is a linked force already, then unlink it. */ - if (sig->force_link) - unlink_force(dst); - - sig->force_link = src; - - /* Link the output of the src to the port[2] (the force - port) of the destination. */ - vvp_net_ptr_t dst_ptr (dst, 2); - src->link(dst_ptr); + sig->force_link(dst, src); return true; } @@ -3945,15 +3914,8 @@ bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp) bool full_sig = base == 0 && width == sig->size(); - if (sig->force_link) { - if (!full_sig) { - fprintf(stderr, "Sorry: when a signal is forcing a " - "net, I cannot release part of it.\n"); - exit(1); - } - unlink_force(net); - } - assert(sig->force_link == 0); + // XXXX Can't really do this if this is a partial release? + sig->force_unlink(); /* Do we release all or part of the net? */ vvp_net_ptr_t ptr (net, 0); @@ -3981,18 +3943,8 @@ bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp) bool full_sig = base == 0 && width == sig->size(); - // This is the net that is forcing me... - if (vvp_net_t*src = sig->force_link) { - if (!full_sig) { - fprintf(stderr, "Sorry: when a signal is forcing a " - "register, I cannot release part of it.\n"); - exit(1); - } - // And this is the pointer to be removed. - vvp_net_ptr_t dst_ptr (net, 2); - src->unlink(dst_ptr); - sig->force_link = 0; - } + // XXXX Can't really do this if this is a partial release? + sig->force_unlink(); // Send a command to this signal to unforce itself. /* Do we release all or part of the net? */ @@ -4015,13 +3967,7 @@ bool of_RELEASE_WR(vthread_t thr, vvp_code_t cp) vvp_fun_signal_real*sig = reinterpret_cast(net->fun); assert(sig); - // This is the net that is forcing me... - if (vvp_net_t*src = sig->force_link) { - // And this is the pointer to be removed. - vvp_net_ptr_t dst_ptr (net, 2); - src->unlink(dst_ptr); - sig->force_link = 0; - } + sig->force_unlink(); // Send a command to this signal to unforce itself. vvp_net_ptr_t ptr (net, 0); diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index f484b5671..a66e834bb 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -31,10 +31,12 @@ vvp_filter_wire_base::vvp_filter_wire_base() { 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) @@ -66,6 +68,35 @@ template const T*vvp_filter_wire_base::filter_mask_(const T&val, const } } +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; + } + + // 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) { run_vpi_callbacks(); @@ -214,7 +245,6 @@ vvp_fun_signal_base::vvp_fun_signal_base() { continuous_assign_active_ = false; needs_init_ = true; - force_link = 0; cassign_link = 0; count_functors_sig += 1; } @@ -803,3 +833,23 @@ void vvp_fun_signal_real_aa::release_pv(vvp_net_ptr_t ptr, bool net, /* Automatic variables can't be forced. */ assert(0); } + +vvp_fun_force::vvp_fun_force() +{ +} + +vvp_fun_force::~vvp_fun_force() +{ +} + +void vvp_fun_force::recv_real(vvp_net_ptr_t ptr, double bit, vvp_context_t) +{ + assert(ptr.port() == 0); + vvp_net_t*net = ptr.ptr(); + + vvp_net_t*dst = net->port[3].ptr(); + vvp_fun_signal_real*sig = dynamic_cast (dst->fil); + assert(sig); + + sig->force_real(bit, vvp_vector2_t(vvp_vector2_t::FILL1, 1)); +} diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index f7a964b2f..bf88a02aa 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -154,7 +154,11 @@ class vvp_filter_wire_base : public vvp_net_fil_t, public vvp_vpi_callback { /* 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; + 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 @@ -449,4 +453,19 @@ 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. + */ +class vvp_fun_force : public vvp_net_fun_t { + + public: + vvp_fun_force(); + ~vvp_fun_force(); + + void recv_real(vvp_net_ptr_t port, double bit, vvp_context_t); +}; + + #endif