Re-implement force/link to use a vvp_fun_force node.

The vvp_fun_force node converts its input to a call to the
force method of the target node. This eliminates the need for
linking a net to a force input of a signal.
This commit is contained in:
Stephen Williams 2009-06-06 11:01:12 -07:00
parent 29a47efa81
commit bc6f3cc905
3 changed files with 78 additions and 63 deletions

View File

@ -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<vvp_filter_wire_base*>(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<vvp_filter_wire_base*>(dst->fun);
= dynamic_cast<vvp_filter_wire_base*>(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<vvp_fun_signal_real*>(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);

View File

@ -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 <class T> const T*vvp_filter_wire_base::filter_mask_(const T&val, const T&force, T&filter)
@ -66,6 +68,35 @@ template <class T> 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 <class T> 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<vvp_fun_signal_real*> (dst->fil);
assert(sig);
sig->force_real(bit, vvp_vector2_t(vvp_vector2_t::FILL1, 1));
}

View File

@ -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