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:
parent
29a47efa81
commit
bc6f3cc905
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue