Fix various bugs in vpi_put_value.
When putting a value onto a wire, the value needs to be sent to the filter, not the functor (the functor may be part of the expression that drives the wire). Force and release weren't implemented properly (or at all in the case of real values). They need to behave the same as the force and release operations in vthread.cc.
This commit is contained in:
parent
05a52e55e9
commit
637fc40dd9
|
|
@ -499,11 +499,12 @@ struct __vpiRealVar : public __vpiHandle {
|
|||
vpiHandle index;
|
||||
} id;
|
||||
unsigned is_netarray : 1; // This is word of a net array
|
||||
unsigned is_wire : 1; // This is a wire, not a variable
|
||||
vvp_net_t*net;
|
||||
};
|
||||
|
||||
extern struct __vpiScope* vpip_scope(__vpiRealVar*sig);
|
||||
extern vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net);
|
||||
extern vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net, bool is_wire);
|
||||
|
||||
class __vpiBaseVar : public __vpiHandle {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003-2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2015 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
|
||||
|
|
@ -124,14 +124,33 @@ static void real_var_get_value(vpiHandle ref, s_vpi_value*vp)
|
|||
fil->get_signal_value(vp);
|
||||
}
|
||||
|
||||
static vpiHandle real_var_put_value(vpiHandle ref, p_vpi_value vp, int)
|
||||
static vpiHandle real_var_put_value(vpiHandle ref, p_vpi_value vp, int flags)
|
||||
{
|
||||
double result = real_from_vpi_value(vp);
|
||||
|
||||
struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref);
|
||||
assert(rfp);
|
||||
vvp_net_ptr_t destination (rfp->net, 0);
|
||||
vvp_send_real(destination, result, vthread_get_wt_context());
|
||||
|
||||
/* If this is a release, then we are not really putting a
|
||||
value. Instead, issue a release "command" to the signal
|
||||
node to cause it to release a forced value. */
|
||||
if (flags == vpiReleaseFlag) {
|
||||
assert(rfp->net->fil);
|
||||
rfp->net->fil->force_unlink();
|
||||
rfp->net->fil->release(destination, rfp->is_wire);
|
||||
real_var_get_value(ref, vp);
|
||||
return ref;
|
||||
}
|
||||
|
||||
double result = real_from_vpi_value(vp);
|
||||
|
||||
if (flags == vpiForceFlag) {
|
||||
vvp_vector2_t mask (vvp_vector2_t::FILL1, 1);
|
||||
rfp->net->force_real(result, mask);
|
||||
} else if (rfp->is_wire) {
|
||||
rfp->net->send_real(result, vthread_get_wt_context());
|
||||
} else {
|
||||
vvp_send_real(destination, result, vthread_get_wt_context());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -159,12 +178,13 @@ vpiHandle __vpiRealVar::vpi_handle(int code)
|
|||
vpiHandle __vpiRealVar::vpi_iterate(int code)
|
||||
{ return real_var_iterate(code, this); }
|
||||
|
||||
vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net)
|
||||
vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net, bool is_wire)
|
||||
{
|
||||
struct __vpiRealVar*obj = new __vpiRealVar;
|
||||
|
||||
obj->id.name = name ? vpip_name_string(name) : 0;
|
||||
obj->is_netarray = 0;
|
||||
obj->is_wire = is_wire;
|
||||
obj->net = net;
|
||||
|
||||
obj->within.scope = vpip_peek_current_scope();
|
||||
|
|
|
|||
|
|
@ -802,17 +802,19 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
|
|||
unsigned wid;
|
||||
struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref);
|
||||
assert(rfp);
|
||||
vvp_net_ptr_t dest(rfp->node, 0);
|
||||
|
||||
bool net_flag = ref->get_type_code()==vpiNet;
|
||||
|
||||
/* If this is a release, then we are not really putting a
|
||||
value. Instead, issue a release "command" to the signal
|
||||
node to cause it to release a forced value. */
|
||||
if (flags == vpiReleaseFlag) {
|
||||
vvp_net_fil_t*sig
|
||||
= reinterpret_cast<vvp_net_fil_t*>(rfp->node->fil);
|
||||
assert(sig);
|
||||
|
||||
vvp_net_ptr_t ptr(rfp->node, 0);
|
||||
sig->release(ptr, false);
|
||||
assert(rfp->node->fil);
|
||||
rfp->node->fil->force_unlink();
|
||||
rfp->node->fil->release(dest, net_flag);
|
||||
rfp->node->fun->force_flag();
|
||||
signal_get_value(ref, vp);
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
|
@ -823,22 +825,16 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
|
|||
? (rfp->msb.get_value() - rfp->lsb.get_value() + 1)
|
||||
: (rfp->lsb.get_value() - rfp->msb.get_value() + 1);
|
||||
|
||||
|
||||
vvp_vector4_t val = vec4_from_vpi_value(vp, wid);
|
||||
|
||||
/* If this is a vpiForce, then instead of writing to the
|
||||
signal input port, we write to the special "force" port. */
|
||||
int dest_port = 0;
|
||||
if (flags == vpiForceFlag)
|
||||
dest_port = 2;
|
||||
|
||||
/* This is the destination that I'm going to poke into. Make
|
||||
it from the vvp_net_t pointer, and assume a write to
|
||||
port-0. This is the port where signals receive input. */
|
||||
vvp_net_ptr_t destination (rfp->node, dest_port);
|
||||
|
||||
vvp_send_vec4(destination, val, vthread_get_wt_context());
|
||||
|
||||
if (flags == vpiForceFlag) {
|
||||
vvp_vector2_t mask (vvp_vector2_t::FILL1, wid);
|
||||
rfp->node->force_vec4(val, mask);
|
||||
} else if (net_flag) {
|
||||
rfp->node->send_vec4(val, vthread_get_wt_context());
|
||||
} else {
|
||||
vvp_send_vec4(dest, val, vthread_get_wt_context());
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
|
@ -1296,7 +1292,7 @@ static void PV_get_value(vpiHandle ref, p_vpi_value vp)
|
|||
}
|
||||
}
|
||||
|
||||
static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int)
|
||||
static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int flags)
|
||||
{
|
||||
struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref);
|
||||
assert(rfp);
|
||||
|
|
@ -1309,7 +1305,10 @@ static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int)
|
|||
if (base >= (signed) sig_size) return 0;
|
||||
if (base + (signed) width < 0) return 0;
|
||||
|
||||
vvp_vector4_t val = vec4_from_vpi_value(vp, width);
|
||||
vvp_vector4_t val;
|
||||
if (flags != vpiReleaseFlag) {
|
||||
val = vec4_from_vpi_value(vp, width);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the base is less than zero then trim off any unneeded
|
||||
|
|
@ -1317,7 +1316,9 @@ static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int)
|
|||
*/
|
||||
if (base < 0) {
|
||||
width += base;
|
||||
val = val.subvalue(-base, width);
|
||||
if (flags != vpiReleaseFlag) {
|
||||
val = val.subvalue(-base, width);
|
||||
}
|
||||
base = 0;
|
||||
}
|
||||
|
||||
|
|
@ -1327,20 +1328,68 @@ static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int)
|
|||
*/
|
||||
if (base+width > sig_size) {
|
||||
width = sig_size - base;
|
||||
val = val.subvalue(0, width);
|
||||
if (flags != vpiReleaseFlag) {
|
||||
val = val.subvalue(0, width);
|
||||
}
|
||||
}
|
||||
|
||||
assert(rfp->parent);
|
||||
bool net_flag = rfp->parent->get_type_code()==vpiNet;
|
||||
bool full_sig = base == 0 && width == sig_size;
|
||||
|
||||
vvp_net_ptr_t dest(rfp->net, 0);
|
||||
|
||||
if (full_sig) {
|
||||
vvp_send_vec4(dest, val, vthread_get_wt_context());
|
||||
} else {
|
||||
vvp_send_vec4_pv(dest, val, base, width, sig_size,
|
||||
vthread_get_wt_context());
|
||||
/* If this is a release, then we are not really putting a
|
||||
value. Instead, issue a release "command" to the signal
|
||||
node to cause it to release a forced value. */
|
||||
if (flags == vpiReleaseFlag) {
|
||||
assert(rfp->net->fil);
|
||||
// XXXX Can't really do this if this is a partial release?
|
||||
rfp->net->fil->force_unlink();
|
||||
if (full_sig) {
|
||||
rfp->net->fil->release(dest, net_flag);
|
||||
} else {
|
||||
rfp->net->fil->release_pv(dest, base, width, net_flag);
|
||||
}
|
||||
rfp->net->fun->force_flag();
|
||||
PV_get_value(ref, vp);
|
||||
return ref;
|
||||
}
|
||||
|
||||
if (flags == vpiForceFlag) {
|
||||
if (full_sig) {
|
||||
vvp_vector2_t mask (vvp_vector2_t::FILL1, sig_size);
|
||||
rfp->net->force_vec4(val, mask);
|
||||
} else {
|
||||
vvp_vector2_t mask (vvp_vector2_t::FILL0, sig_size);
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1)
|
||||
mask.set_bit(base+idx, 1);
|
||||
|
||||
vvp_vector4_t tmp (sig_size, BIT4_Z);
|
||||
|
||||
// vvp_net_t::force_vec4 propagates all the bits of the
|
||||
// forced vector value, regardless of the mask. This
|
||||
// ensures the unforced bits retain their current value.
|
||||
sig->vec4_value(tmp);
|
||||
|
||||
tmp.set_vec(base, val);
|
||||
rfp->net->force_vec4(tmp, mask);
|
||||
}
|
||||
} else if (net_flag) {
|
||||
if (full_sig) {
|
||||
rfp->net->send_vec4(val, vthread_get_wt_context());
|
||||
} else {
|
||||
rfp->net->send_vec4_pv(val, base, width, sig_size,
|
||||
vthread_get_wt_context());
|
||||
}
|
||||
} else {
|
||||
if (full_sig) {
|
||||
vvp_send_vec4(dest, val, vthread_get_wt_context());
|
||||
} else {
|
||||
vvp_send_vec4_pv(dest, val, base, width, sig_size,
|
||||
vthread_get_wt_context());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2015 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
|
||||
|
|
@ -48,7 +48,7 @@ static void __compile_var_real(char*label, char*name,
|
|||
|
||||
define_functor_symbol(label, net);
|
||||
|
||||
vpiHandle obj = vpip_make_real_var(name, net);
|
||||
vpiHandle obj = vpip_make_real_var(name, net, false);
|
||||
compile_vpi_symbol(label, obj);
|
||||
|
||||
if (name) {
|
||||
|
|
@ -481,7 +481,7 @@ static void __compile_real_net2(vvp_net_t*node, vvp_array_t array,
|
|||
|
||||
vpiHandle obj = 0;
|
||||
if (!local_flag) {
|
||||
obj = vpip_make_real_var(name, node);
|
||||
obj = vpip_make_real_var(name, node, true);
|
||||
compile_vpi_symbol(my_label, obj);
|
||||
}
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
|
|
|
|||
Loading…
Reference in New Issue