Merge branch 'vvp-net-out-rework'

This commit is contained in:
Stephen Williams 2009-09-23 17:16:37 -07:00
commit b0d5a3b8a2
36 changed files with 2680 additions and 1713 deletions

View File

@ -1739,6 +1739,7 @@ extern int ivl_scope_time_units(ivl_scope_t net);
* Returns the file and line where this signal is defined.
*/
extern ivl_scope_t ivl_signal_scope(ivl_signal_t net);
extern ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word);
extern int ivl_signal_array_base(ivl_signal_t net);
extern unsigned ivl_signal_array_count(ivl_signal_t net);

View File

@ -1926,6 +1926,12 @@ extern "C" int ivl_signal_lsb(ivl_signal_t net)
return net->lsb_index;
}
extern "C" ivl_scope_t ivl_signal_scope(ivl_signal_t net)
{
assert(net);
return net->scope_;
}
extern "C" unsigned ivl_signal_width(ivl_signal_t net)
{
return net->width_;

View File

@ -479,6 +479,12 @@ static void draw_net_in_scope(ivl_signal_t sig)
iword, msb, lsb, driver,
nex_data->drivers_count,
strength_aware_flag?", strength-aware":"");
} else if (ivl_signal_local(sig) && ivl_scope_is_auto(ivl_signal_scope(sig))) {
assert(word_count == 1);
fprintf(vvp_out, "; Elide net v%p_%u name=%s\n",
sig, iword, ivl_signal_basename(sig));
} else {
/* If this is an isolated word, it uses its
own name. */
@ -897,15 +903,15 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
sig = ivl_expr_signal(rise_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0", sig);
fprintf(vvp_out, ", %s", draw_net_input(ivl_signal_nex(sig,0)));
sig = ivl_expr_signal(fall_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0", sig);
fprintf(vvp_out, ", %s", draw_net_input(ivl_signal_nex(sig,0)));
sig = ivl_expr_signal(decay_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0;\n", sig);
fprintf(vvp_out, ", %s;\n", draw_net_input(ivl_signal_nex(sig,0)));
}
}
}

View File

@ -76,7 +76,7 @@ concat.o \
dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \
ufunc.o codes.o \
vthread.o schedule.o statistics.o tables.o udp.o vvp_island.o vvp_net.o \
event.o logic.o delay.o words.o island_tran.o $V
vvp_net_sig.o event.o logic.o delay.o words.o island_tran.o $V
ifeq (@WIN32@,yes)
# Under Windows (mingw) I need to make the ivl.exe in two steps.

View File

@ -82,14 +82,14 @@ void vvp_arith_abs::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
break;
}
vvp_send_vec4(ptr.ptr()->out, out, 0);
ptr.ptr()->send_vec4(out, 0);
}
void vvp_arith_abs::recv_real(vvp_net_ptr_t ptr, double bit,
vvp_context_t)
{
double out = fabs(bit);
vvp_send_real(ptr.ptr()->out, out, 0);
ptr.ptr()->send_real(out, 0);
}
vvp_arith_cast_int::vvp_arith_cast_int(unsigned wid)
@ -104,7 +104,7 @@ vvp_arith_cast_int::~vvp_arith_cast_int()
void vvp_arith_cast_int::recv_real(vvp_net_ptr_t ptr, double bit,
vvp_context_t)
{
vvp_send_vec4(ptr.ptr()->out, vvp_vector4_t(wid_, bit), 0);
ptr.ptr()->send_vec4(vvp_vector4_t(wid_, bit), 0);
}
vvp_arith_cast_real::vvp_arith_cast_real(bool signed_flag)
@ -121,7 +121,7 @@ void vvp_arith_cast_real::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
{
double val;
vector4_to_value(bit, val, signed_);
vvp_send_real(ptr.ptr()->out, val, 0);
ptr.ptr()->send_real(val, 0);
}
// Division
@ -139,13 +139,13 @@ void vvp_arith_div::wide4_(vvp_net_ptr_t ptr)
{
vvp_vector2_t a2 (op_a_);
if (a2.is_NaN()) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
vvp_vector2_t b2 (op_b_);
if (b2.is_NaN() || b2.is_zero()) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
@ -162,7 +162,7 @@ void vvp_arith_div::wide4_(vvp_net_ptr_t ptr)
}
vvp_vector2_t res = a2 / b2;
if (negate) res = -res;
vvp_send_vec4(ptr.ptr()->out, vector2_to_vector4(res, wid_), 0);
ptr.ptr()->send_vec4(vector2_to_vector4(res, wid_), 0);
}
void vvp_arith_div::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
@ -177,13 +177,13 @@ void vvp_arith_div::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned long a;
if (! vector4_to_value(op_a_, a)) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
unsigned long b;
if (! vector4_to_value(op_b_, b)) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
@ -216,7 +216,7 @@ void vvp_arith_div::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
for (unsigned idx = 0 ; idx < wid_ ; idx += 1)
xval.set_bit(idx, BIT4_X);
vvp_send_vec4(ptr.ptr()->out, xval, 0);
ptr.ptr()->send_vec4(xval, 0);
return;
}
@ -236,7 +236,7 @@ void vvp_arith_div::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
val >>= 1;
}
vvp_send_vec4(ptr.ptr()->out, vval, 0);
ptr.ptr()->send_vec4(vval, 0);
}
@ -253,13 +253,13 @@ void vvp_arith_mod::wide_(vvp_net_ptr_t ptr)
{
vvp_vector2_t a2 (op_a_);
if (a2.is_NaN()) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
vvp_vector2_t b2 (op_b_);
if (b2.is_NaN() || b2.is_zero()) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
@ -275,7 +275,7 @@ void vvp_arith_mod::wide_(vvp_net_ptr_t ptr)
}
vvp_vector2_t res = a2 % b2;
if (negate) res = -res;
vvp_send_vec4(ptr.ptr()->out, vector2_to_vector4(res, res.size()), 0);
ptr.ptr()->send_vec4(vector2_to_vector4(res, res.size()), 0);
}
void vvp_arith_mod::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
@ -290,13 +290,13 @@ void vvp_arith_mod::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned long a;
if (! vector4_to_value(op_a_, a)) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
unsigned long b;
if (! vector4_to_value(op_b_, b)) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
@ -328,7 +328,7 @@ void vvp_arith_mod::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
for (unsigned idx = 0 ; idx < wid_ ; idx += 1)
xval.set_bit(idx, BIT4_X);
vvp_send_vec4(ptr.ptr()->out, xval, 0);
ptr.ptr()->send_vec4(xval, 0);
return;
}
@ -348,7 +348,7 @@ void vvp_arith_mod::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
val >>= 1;
}
vvp_send_vec4(ptr.ptr()->out, vval, 0);
ptr.ptr()->send_vec4(vval, 0);
}
@ -369,14 +369,14 @@ void vvp_arith_mult::wide_(vvp_net_ptr_t ptr)
vvp_vector2_t b2 (op_b_);
if (a2.is_NaN() || b2.is_NaN()) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
vvp_vector2_t result = a2 * b2;
vvp_vector4_t res4 = vector2_to_vector4(result, wid_);
vvp_send_vec4(ptr.ptr()->out, res4, 0);
ptr.ptr()->send_vec4(res4, 0);
}
void vvp_arith_mult::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
@ -391,13 +391,13 @@ void vvp_arith_mult::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
long a;
if (! vector4_to_value(op_a_, a, false, true)) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
long b;
if (! vector4_to_value(op_b_, b, false, true)) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
@ -414,7 +414,7 @@ void vvp_arith_mult::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
val >>= 1;
}
vvp_send_vec4(ptr.ptr()->out, vval, 0);
ptr.ptr()->send_vec4(vval, 0);
}
@ -437,7 +437,7 @@ void vvp_arith_pow::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_vector4_t res4;
if (signed_flag_) {
if (op_a_.has_xz() || op_b_.has_xz()) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
@ -451,7 +451,7 @@ void vvp_arith_pow::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_vector2_t b2 (op_b_);
if (a2.is_NaN() || b2.is_NaN()) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
@ -459,7 +459,7 @@ void vvp_arith_pow::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
res4 = vector2_to_vector4(result, wid_);
}
vvp_send_vec4(ptr.ptr()->out, res4, 0);
ptr.ptr()->send_vec4(res4, 0);
}
@ -494,14 +494,14 @@ void vvp_arith_sum::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_bit4_t cur = add_with_carry(a, b, carry);
if (cur == BIT4_X) {
vvp_send_vec4(net->out, x_val_, 0);
net->send_vec4(x_val_, 0);
return;
}
value.set_bit(idx, cur);
}
vvp_send_vec4(net->out, value, 0);
net->send_vec4(value, 0);
}
vvp_arith_sub::vvp_arith_sub(unsigned wid)
@ -539,14 +539,14 @@ void vvp_arith_sub::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_bit4_t cur = add_with_carry(a, b, carry);
if (cur == BIT4_X) {
vvp_send_vec4(net->out, x_val_, 0);
net->send_vec4(x_val_, 0);
return;
}
value.set_bit(idx, cur);
}
vvp_send_vec4(net->out, value, 0);
net->send_vec4(value, 0);
}
vvp_cmp_eeq::vvp_cmp_eeq(unsigned wid)
@ -571,7 +571,7 @@ void vvp_cmp_eeq::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_net_t*net = ptr.ptr();
vvp_send_vec4(net->out, eeq, 0);
net->send_vec4(eeq, 0);
}
vvp_cmp_nee::vvp_cmp_nee(unsigned wid)
@ -596,7 +596,7 @@ void vvp_cmp_nee::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_net_t*net = ptr.ptr();
vvp_send_vec4(net->out, eeq, 0);
net->send_vec4(eeq, 0);
}
vvp_cmp_eq::vvp_cmp_eq(unsigned wid)
@ -643,7 +643,7 @@ void vvp_cmp_eq::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
}
vvp_net_t*net = ptr.ptr();
vvp_send_vec4(net->out, res, 0);
net->send_vec4(res, 0);
}
@ -691,7 +691,7 @@ void vvp_cmp_ne::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
}
vvp_net_t*net = ptr.ptr();
vvp_send_vec4(net->out, res, 0);
net->send_vec4(res, 0);
}
@ -712,7 +712,7 @@ void vvp_cmp_gtge_base_::recv_vec4_base_(vvp_net_ptr_t ptr,
: compare_gtge(op_a_, op_b_, out_if_equal);
vvp_vector4_t val (1);
val.set_bit(0, out);
vvp_send_vec4(ptr.ptr()->out, val, 0);
ptr.ptr()->send_vec4(val, 0);
return;
}
@ -759,7 +759,7 @@ void vvp_shiftl::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned long shift;
if (! vector4_to_value(op_b_, shift)) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
@ -772,7 +772,7 @@ void vvp_shiftl::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
for (unsigned idx = shift ; idx < out.size() ; idx += 1)
out.set_bit(idx, op_a_.value(idx-shift));
vvp_send_vec4(ptr.ptr()->out, out, 0);
ptr.ptr()->send_vec4(out, 0);
}
vvp_shiftr::vvp_shiftr(unsigned wid, bool signed_flag)
@ -793,7 +793,7 @@ void vvp_shiftr::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned long shift;
if (! vector4_to_value(op_b_, shift)) {
vvp_send_vec4(ptr.ptr()->out, x_val_, 0);
ptr.ptr()->send_vec4(x_val_, 0);
return;
}
@ -810,7 +810,7 @@ void vvp_shiftr::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
for (unsigned idx = 0 ; idx < shift ; idx += 1)
out.set_bit(idx+out.size()-shift, pad);
vvp_send_vec4(ptr.ptr()->out, out, 0);
ptr.ptr()->send_vec4(out, 0);
}
@ -851,7 +851,7 @@ void vvp_arith_mult_real::recv_real(vvp_net_ptr_t ptr, double bit,
dispatch_operand_(ptr, bit);
double val = op_a_ * op_b_;
vvp_send_real(ptr.ptr()->out, val, 0);
ptr.ptr()->send_real(val, 0);
}
/* Real power. */
@ -869,7 +869,7 @@ void vvp_arith_pow_real::recv_real(vvp_net_ptr_t ptr, double bit,
dispatch_operand_(ptr, bit);
double val = pow(op_a_, op_b_);
vvp_send_real(ptr.ptr()->out, val, 0);
ptr.ptr()->send_real(val, 0);
}
/* Real division. */
@ -887,7 +887,7 @@ void vvp_arith_div_real::recv_real(vvp_net_ptr_t ptr, double bit,
dispatch_operand_(ptr, bit);
double val = op_a_ / op_b_;
vvp_send_real(ptr.ptr()->out, val, 0);
ptr.ptr()->send_real(val, 0);
}
/* Real modulus. */
@ -905,7 +905,7 @@ void vvp_arith_mod_real::recv_real(vvp_net_ptr_t ptr, double bit,
dispatch_operand_(ptr, bit);
double val = fmod(op_a_, op_b_);
vvp_send_real(ptr.ptr()->out, val, 0);
ptr.ptr()->send_real(val, 0);
}
/* Real summation. */
@ -923,7 +923,7 @@ void vvp_arith_sum_real::recv_real(vvp_net_ptr_t ptr, double bit,
dispatch_operand_(ptr, bit);
double val = op_a_ + op_b_;
vvp_send_real(ptr.ptr()->out, val, 0);
ptr.ptr()->send_real(val, 0);
}
/* Real subtraction. */
@ -941,7 +941,7 @@ void vvp_arith_sub_real::recv_real(vvp_net_ptr_t ptr, double bit,
dispatch_operand_(ptr, bit);
double val = op_a_ - op_b_;
vvp_send_real(ptr.ptr()->out, val, 0);
ptr.ptr()->send_real(val, 0);
}
/* Real compare equal. */
@ -958,7 +958,7 @@ void vvp_cmp_eq_real::recv_real(vvp_net_ptr_t ptr, const double bit,
if (op_a_ == op_b_) res.set_bit(0, BIT4_1);
else res.set_bit(0, BIT4_0);
vvp_send_vec4(ptr.ptr()->out, res, 0);
ptr.ptr()->send_vec4(res, 0);
}
/* Real compare not equal. */
@ -975,7 +975,7 @@ void vvp_cmp_ne_real::recv_real(vvp_net_ptr_t ptr, const double bit,
if (op_a_ != op_b_) res.set_bit(0, BIT4_1);
else res.set_bit(0, BIT4_0);
vvp_send_vec4(ptr.ptr()->out, res, 0);
ptr.ptr()->send_vec4(res, 0);
}
/* Real compare greater than or equal. */
@ -992,7 +992,7 @@ void vvp_cmp_ge_real::recv_real(vvp_net_ptr_t ptr, const double bit,
if (op_a_ >= op_b_) res.set_bit(0, BIT4_1);
else res.set_bit(0, BIT4_0);
vvp_send_vec4(ptr.ptr()->out, res, 0);
ptr.ptr()->send_vec4(res, 0);
}
/* Real compare greater than. */
@ -1009,5 +1009,5 @@ void vvp_cmp_gt_real::recv_real(vvp_net_ptr_t ptr, const double bit,
if (op_a_ > op_b_) res.set_bit(0, BIT4_1);
else res.set_bit(0, BIT4_0);
vvp_send_vec4(ptr.ptr()->out, res, 0);
ptr.ptr()->send_vec4(res, 0);
}

View File

@ -21,6 +21,7 @@
#include "symbols.h"
#include "schedule.h"
#include "vpi_priv.h"
#include "vvp_net_sig.h"
#include "config.h"
#ifdef CHECK_WITH_VALGRIND
#include "vvp_cleanup.h"
@ -886,8 +887,7 @@ void array_set_word(vvp_array_t arr,
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
assert(vsig);
vvp_net_ptr_t ptr (vsig->node, 0);
vvp_send_vec4_pv(ptr, val, part_off, val.size(), vpip_size(vsig), 0);
vsig->node->send_vec4_pv(val, part_off, val.size(), vpip_size(vsig), 0);
array_word_change(arr, address);
}
@ -917,17 +917,18 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address)
// width by looking at a word that we know is present.
assert(arr->array_count > 0);
vpiHandle word = arr->nets[0];
assert(word);
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
assert(vsig);
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (vsig->node->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (vsig->node->fil);
assert(sig);
return vvp_vector4_t(sig->size(), BIT4_X);
return vvp_vector4_t(sig->value_size(), BIT4_X);
}
vpiHandle word = arr->nets[address];
struct __vpiSignal*vsig = vpip_signal_from_handle(word);
assert(vsig);
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (vsig->node->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (vsig->node->fil);
assert(sig);
vvp_vector4_t val = sig->vec4_value();
@ -946,7 +947,7 @@ double array_get_word_r(vvp_array_t arr, unsigned address)
vpiHandle word = arr->nets[address];
struct __vpiRealVar*vsig = vpip_realvar_from_handle(word);
assert(vsig);
vvp_fun_signal_real*sig = dynamic_cast<vvp_fun_signal_real*> (vsig->net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (vsig->net->fil);
assert(sig);
double val = sig->real_value();
@ -1023,7 +1024,7 @@ void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word)
array->nets[addr] = word;
}
void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
void array_attach_word(vvp_array_t array, unsigned addr, vpiHandle word)
{
assert(addr < array->array_count);
assert(array->nets);
@ -1032,7 +1033,7 @@ void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
if (struct __vpiSignal*sig = vpip_signal_from_handle(word)) {
vvp_net_t*net = sig->node;
assert(net);
vvp_fun_signal_base*fun = dynamic_cast<vvp_fun_signal_base*>(net->fun);
vvp_vpi_callback*fun = dynamic_cast<vvp_vpi_callback*>(net->fil);
assert(fun);
fun->attach_as_word(array, addr);
sig->is_netarray = 1;
@ -1044,7 +1045,7 @@ void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word)
if (struct __vpiRealVar*sig = (struct __vpiRealVar*)word) {
vvp_net_t*net = sig->net;
assert(net);
vvp_fun_signal_base*fun = dynamic_cast<vvp_fun_signal_base*>(net->fun);
vvp_vpi_callback*fun = dynamic_cast<vvp_vpi_callback*>(net->fil);
assert(fun);
fun->attach_as_word(array, addr);
sig->is_netarray = 1;
@ -1192,12 +1193,13 @@ void vvp_fun_arrayport_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit
case 0: // Address input
addr_valid_flag = vector4_to_value(bit, addr_);
if (! addr_valid_flag) addr_ = arr_->array_count;
if (vpi_array_is_real(arr_)) {
vvp_send_real(net_->out, array_get_word_r(arr_, addr_), 0);
} else {
vvp_send_vec4(net_->out, array_get_word(arr_, addr_), 0);
}
if (! addr_valid_flag)
addr_ = arr_->array_count;
if (vpi_array_is_real(arr_))
port.ptr()->send_real(array_get_word_r(arr_, addr_), 0);
else
port.ptr()->send_vec4(array_get_word(arr_,addr_), 0);
break;
default:
@ -1211,9 +1213,9 @@ void vvp_fun_arrayport_sa::check_word_change(unsigned long addr)
if (addr != addr_) return;
if (vpi_array_is_real(arr_)) {
vvp_send_real(net_->out, array_get_word_r(arr_, addr_), 0);
net_->send_real(array_get_word_r(arr_, addr_), 0);
} else {
vvp_send_vec4(net_->out, array_get_word(arr_, addr_), 0);
net_->send_vec4(array_get_word(arr_, addr_), 0);
}
}
@ -1298,13 +1300,11 @@ void vvp_fun_arrayport_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit
addr_valid_flag = vector4_to_value(bit, *addr);
if (! addr_valid_flag) *addr = arr_->array_count;
if (vpi_array_is_real(arr_)) {
vvp_send_real(port.ptr()->out,
array_get_word_r(arr_, *addr),
context);
port.ptr()->send_real(array_get_word_r(arr_, *addr),
context);
} else {
vvp_send_vec4(port.ptr()->out,
array_get_word(arr_, *addr),
context);
port.ptr()->send_vec4(array_get_word(arr_, *addr),
context);
}
break;
@ -1330,10 +1330,10 @@ void vvp_fun_arrayport_aa::check_word_change(unsigned long addr)
return;
if (vpi_array_is_real(arr_)) {
vvp_send_real(net_->out, array_get_word_r(arr_, addr),
vthread_get_wt_context());
net_->send_real(array_get_word_r(arr_, addr),
vthread_get_wt_context());
} else {
vvp_send_vec4(net_->out, array_get_word(arr_, addr),
net_->send_vec4(array_get_word(arr_, addr),
vthread_get_wt_context());
}
}

View File

@ -34,8 +34,7 @@ extern vpiHandle array_index_iterate(int code, vpiHandle ref);
extern void array_word_change(vvp_array_t array, unsigned long addr);
extern void array_attach_word(vvp_array_t array, unsigned long addr,
vpiHandle word);
extern void array_attach_word(vvp_array_t array, unsigned addr, vpiHandle word);
extern void array_alias_word(vvp_array_t array, unsigned long addr,
vpiHandle word);

View File

@ -79,5 +79,5 @@ void vvp_fun_bufif::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
}
}
vvp_send_vec8(ptr.ptr()->out, out);
ptr.ptr()->send_vec8(out);
}

View File

@ -370,9 +370,7 @@ bool vvp_net_resolv_list_s::resolve(bool mes)
if (tmp) {
// Link the input port to the located output.
vvp_net_t*net = port.ptr();
net->port[port.port()] = tmp->out;
tmp->out = port;
tmp->link(port);
return true;
}
@ -732,12 +730,27 @@ void compile_vpi_time_precision(long pre)
*
* The real value is sign * (mant ** exp).
*/
double crstring_to_double(char*label)
bool crstring_test(const char*str)
{
char*cp = label+3;
if (strncmp(str, "Cr<", 3) != 0) return false;
const char*tp = strchr(str, '>');
if (tp == 0) return false;
if (tp[1] != 0) return false;
if ((strspn(str+3, "0123456789abcdefmg")+3) != (tp - str))
return false;
return true;
}
double crstring_to_double(const char*label)
{
const char*cp = label+3;
assert(*cp == 'm');
cp += 1;
uint64_t mant = strtoull(cp, &cp, 16);
char*ep;
uint64_t mant = strtoull(cp, &ep, 16);
cp = ep;
assert(*cp == 'g');
cp += 1;
int exp = strtoul(cp, 0, 16);
@ -776,13 +789,9 @@ double crstring_to_double(char*label)
void input_connect(vvp_net_t*fdx, unsigned port, char*label)
{
vvp_net_ptr_t ifdx = vvp_net_ptr_t(fdx, port);
char*tp;
/* Is this a vvp_vector4_t constant value? */
if ((strncmp(label, "C4<", 3) == 0)
&& ((tp = strchr(label,'>')))
&& (tp[1] == 0)
&& (strspn(label+3, "01xz")+3 == (unsigned)(tp-label))) {
if (c4string_test(label)) {
vvp_vector4_t tmp = c4string_to_vector4(label);
@ -800,40 +809,9 @@ void input_connect(vvp_net_t*fdx, unsigned port, char*label)
}
/* Is this a vvp_vector8_t constant value? */
if ((strncmp(label, "C8<", 3) == 0)
&& ((tp = strchr(label,'>')))
&& (tp[1] == 0)
&& (strspn(label+3, "01234567xz")+3 == (unsigned)(tp-label))) {
size_t vsize = tp-label-3;
assert(vsize%3 == 0);
vsize /= 3;
vvp_vector8_t tmp (vsize);
for (unsigned idx = 0 ; idx < vsize ; idx += 1) {
vvp_bit4_t bit = BIT4_Z;
unsigned dr0 = label[3+idx*3+0] - '0';
unsigned dr1 = label[3+idx*3+1] - '0';
switch (label[3+idx*3+2]) {
case '0':
bit = BIT4_0;
break;
case '1':
bit = BIT4_1;
break;
case 'x':
bit = BIT4_X;
break;
case 'z':
bit = BIT4_Z;
break;
}
tmp.set_bit(vsize-idx-1, vvp_scalar_t(bit, dr0, dr1));
}
if (c8string_test(label)) {
vvp_vector8_t tmp = c8string_to_vector8(label);
schedule_set_vector(ifdx, tmp);
free(label);
@ -842,10 +820,7 @@ void input_connect(vvp_net_t*fdx, unsigned port, char*label)
/* Handle the Cr<> constant driver, which is a real-value
driver. */
if ((strncmp(label, "Cr<", 3) == 0)
&& ((tp = strchr(label,'>')))
&& (tp[1] == 0)
&& (strspn(label+3, "0123456789abcdefmg")+3 == (unsigned)(tp-label))) {
if (crstring_test(label)) {
double tmp = crstring_to_double(label);

View File

@ -64,7 +64,7 @@ void vvp_fun_concat::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
val_.set_bit(off+idx, bit.value(idx));
}
vvp_send_vec4(port.ptr()->out, val_, 0);
port.ptr()->send_vec4(val_, 0);
}
void compile_concat(char*label, unsigned w0, unsigned w1,
@ -107,7 +107,7 @@ void vvp_fun_repeat::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
}
vvp_send_vec4(port.ptr()->out, val, 0);
port.ptr()->send_vec4(val, 0);
}
void compile_repeat(char*label, long width, long repeat, struct symb_s arg)

View File

@ -295,7 +295,7 @@ void vvp_fun_delay::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
if (use_delay == 0) {
cur_vec4_ = bit;
initial_ = false;
vvp_send_vec4(net_->out, cur_vec4_, 0);
net_->send_vec4(cur_vec4_, 0);
} else {
struct event_*cur = new struct event_(use_simtime);
cur->run_run_ptr = &vvp_fun_delay::run_run_vec4_;
@ -353,7 +353,7 @@ void vvp_fun_delay::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
if (use_delay == 0) {
cur_vec8_ = bit;
initial_ = false;
vvp_send_vec8(net_->out, cur_vec8_);
net_->send_vec8(cur_vec8_);
} else {
struct event_*cur = new struct event_(use_simtime);
cur->ptr_vec8 = bit;
@ -412,7 +412,7 @@ void vvp_fun_delay::recv_real(vvp_net_ptr_t port, double bit,
if (use_delay == 0) {
cur_real_ = bit;
initial_ = false;
vvp_send_real(net_->out, cur_real_, 0);
net_->send_real(cur_real_, 0);
} else {
struct event_*cur = new struct event_(use_simtime);
cur->run_run_ptr = &vvp_fun_delay::run_run_real_;
@ -441,19 +441,19 @@ void vvp_fun_delay::run_run()
void vvp_fun_delay::run_run_vec4_(struct event_*cur)
{
cur_vec4_ = cur->ptr_vec4;
vvp_send_vec4(net_->out, cur_vec4_, 0);
net_->send_vec4(cur_vec4_, 0);
}
void vvp_fun_delay::run_run_vec8_(struct vvp_fun_delay::event_*cur)
{
cur_vec8_ = cur->ptr_vec8;
vvp_send_vec8(net_->out, cur_vec8_);
net_->send_vec8(cur_vec8_);
}
void vvp_fun_delay::run_run_real_(struct vvp_fun_delay::event_*cur)
{
cur_real_ = cur->ptr_real;
vvp_send_real(net_->out, cur_real_, 0);
net_->send_real(cur_real_, 0);
}
vvp_fun_modpath::vvp_fun_modpath(vvp_net_t*net)
@ -617,7 +617,7 @@ void vvp_fun_modpath::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
void vvp_fun_modpath::run_run()
{
vvp_send_vec4(net_->out, cur_vec4_, 0);
net_->send_vec4(cur_vec4_, 0);
}
vvp_fun_modpath_src::vvp_fun_modpath_src(vvp_time64_t del[12])

View File

@ -24,6 +24,7 @@
# include <stdio.h>
# include <assert.h>
# include <stdlib.h>
# include <iostream>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
@ -58,7 +59,7 @@ void vvp_dff::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
tmp = clk_cur_;
clk_cur_ = bit.value(0);
if (clk_cur_ == BIT4_1 && tmp != BIT4_1)
vvp_send_vec4(port.ptr()->out, d_, 0);
port.ptr()->send_vec4(d_, 0);
break;
case 2: // CE
@ -67,8 +68,17 @@ void vvp_dff::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
break;
case 3: // Asynch-D
d_ = bit;
vvp_send_vec4(port.ptr()->out, d_, 0);
// FIXME! The code generator is writing an input C4<z>
// no matter what the intent of this device. This is
// almost certainly NOT correct, nor do we want to
// propagate that. But that needs to be fixed later.
if (bit.size() == 1 && bit.value(0)==BIT4_Z)
break;
if (d_.size() > bit.size())
d_ .copy_bits(bit);
else
d_ = bit;
port.ptr()->send_vec4(d_, 0);
break;
}
}

View File

@ -267,7 +267,18 @@ void vvp_fun_edge_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
{
if (recv_vec4_(port, bit, bits_[port.port()], threads_)) {
vvp_net_t*net = port.ptr();
vvp_send_vec4(net->out, bit, 0);
net->send_vec4(bit, 0);
}
}
void vvp_fun_edge_sa::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t)
{
assert(base == 0);
if (recv_vec4_(port, bit, bits_[port.port()], threads_)) {
vvp_net_t*net = port.ptr();
net->send_vec4_pv(bit, base, wid, vwid, 0);
}
}
@ -327,7 +338,7 @@ void vvp_fun_edge_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
if (recv_vec4_(port, bit, state->bits[port.port()], state->threads)) {
vvp_net_t*net = port.ptr();
vvp_send_vec4(net->out, bit, context);
net->send_vec4(bit, context);
}
} else {
context = context_scope_->live_contexts;
@ -418,7 +429,25 @@ void vvp_fun_anyedge_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
{
if (recv_vec4_(port, bit, bits_[port.port()], threads_)) {
vvp_net_t*net = port.ptr();
vvp_send_vec4(net->out, bit, 0);
net->send_vec4(bit, 0);
}
}
void vvp_fun_anyedge_sa::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t)
{
vvp_vector4_t tmp = bits_[port.port()];
if (tmp.size() == 0)
tmp = vvp_vector4_t(vwid, BIT4_Z);
assert(wid == bit.size());
assert(base+wid <= vwid);
assert(tmp.size() == vwid);
tmp.set_vec(base, bit);
if (recv_vec4_(port, tmp, bits_[port.port()], threads_)) {
vvp_net_t*net = port.ptr();
net->send_vec4(bit, 0);
}
}
@ -427,7 +456,7 @@ void vvp_fun_anyedge_sa::recv_real(vvp_net_ptr_t port, double bit,
{
if (recv_real_(port, bit, bitsr_[port.port()], threads_)) {
vvp_net_t*net = port.ptr();
vvp_send_vec4(net->out, vvp_vector4_t(), 0);
net->send_vec4(vvp_vector4_t(), 0);
}
}
@ -488,7 +517,7 @@ void vvp_fun_anyedge_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
if (recv_vec4_(port, bit, state->bits[port.port()], state->threads)) {
vvp_net_t*net = port.ptr();
vvp_send_vec4(net->out, bit, context);
net->send_vec4(bit, context);
}
} else {
context = context_scope_->live_contexts;
@ -509,7 +538,7 @@ void vvp_fun_anyedge_aa::recv_real(vvp_net_ptr_t port, double bit,
if (recv_real_(port, bit, state->bitsr[port.port()], state->threads)) {
vvp_net_t*net = port.ptr();
vvp_send_vec4(net->out, vvp_vector4_t(), context);
net->send_vec4(vvp_vector4_t(), context);
}
} else {
context = context_scope_->live_contexts;
@ -551,7 +580,7 @@ void vvp_fun_event_or_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
{
run_waiting_threads_(threads_);
vvp_net_t*net = port.ptr();
vvp_send_vec4(net->out, bit, 0);
net->send_vec4(bit, 0);
}
vvp_fun_event_or_aa::vvp_fun_event_or_aa()
@ -606,7 +635,7 @@ void vvp_fun_event_or_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
run_waiting_threads_(state->threads);
vvp_net_t*net = port.ptr();
vvp_send_vec4(net->out, bit, context);
net->send_vec4(bit, context);
} else {
context = context_scope_->live_contexts;
while (context) {
@ -647,7 +676,7 @@ void vvp_named_event_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
{
run_waiting_threads_(threads_);
vvp_net_t*net = port.ptr();
vvp_send_vec4(net->out, bit, 0);
net->send_vec4(bit, 0);
vpip_run_named_event_callbacks(handle_);
}
@ -705,7 +734,7 @@ void vvp_named_event_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
run_waiting_threads_(state->threads);
vvp_net_t*net = port.ptr();
vvp_send_vec4(net->out, bit, context);
net->send_vec4(bit, context);
}
/*

View File

@ -182,6 +182,9 @@ class vvp_fun_edge_sa : public vvp_fun_edge {
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t context);
private:
vthread_t threads_;
@ -252,6 +255,9 @@ class vvp_fun_anyedge_sa : public vvp_fun_anyedge {
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t context);
void recv_real(vvp_net_ptr_t port, double bit,
vvp_context_t context);

View File

@ -36,7 +36,7 @@ void vvp_fun_extend_signed::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bi
vvp_context_t)
{
if (bit.size() >= width_) {
vvp_send_vec4(port.ptr()->out, bit, 0);
port.ptr()->send_vec4(bit, 0);
return;
}
@ -49,5 +49,5 @@ void vvp_fun_extend_signed::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bi
for (unsigned idx = bit.size() ; idx < res.size() ; idx += 1)
res.set_bit(idx, pad);
vvp_send_vec4(port.ptr()->out, res, 0);
port.ptr()->send_vec4(res, 0);
}

View File

@ -108,7 +108,7 @@ void vvp_fun_and::run_run()
result.set_bit(idx, bitbit);
}
vvp_send_vec4(ptr->out, result, 0);
ptr->send_vec4(result, 0);
}
vvp_fun_buf::vvp_fun_buf()
@ -149,7 +149,7 @@ void vvp_fun_buf::run_run()
vvp_vector4_t tmp (input_);
tmp.change_z2x();
vvp_send_vec4(ptr->out, tmp, 0);
ptr->send_vec4(tmp, 0);
}
vvp_fun_bufz::vvp_fun_bufz()
@ -171,7 +171,7 @@ void vvp_fun_bufz::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
if (ptr.port() != 0)
return;
vvp_send_vec4(ptr.ptr()->out, bit, 0);
ptr.ptr()->send_vec4(bit, 0);
}
void vvp_fun_bufz::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
@ -179,7 +179,7 @@ void vvp_fun_bufz::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
if (ptr.port() != 0)
return;
vvp_send_vec8(ptr.ptr()->out, bit);
ptr.ptr()->send_vec8(bit);
}
void vvp_fun_bufz::recv_real(vvp_net_ptr_t ptr, double bit,
@ -188,7 +188,7 @@ void vvp_fun_bufz::recv_real(vvp_net_ptr_t ptr, double bit,
if (ptr.port() != 0)
return;
vvp_send_real(ptr.ptr()->out, bit, 0);
ptr.ptr()->send_real(bit, 0);
}
vvp_fun_muxr::vvp_fun_muxr()
@ -267,16 +267,16 @@ void vvp_fun_muxr::run_run()
switch (select_) {
case SEL_PORT0:
vvp_send_real(ptr->out, a_, 0);
ptr->send_real(a_, 0);
break;
case SEL_PORT1:
vvp_send_real(ptr->out, b_, 0);
ptr->send_real(b_, 0);
break;
default:
if (a_ == b_) {
vvp_send_real(ptr->out, a_, 0);
ptr->send_real(a_, 0);
} else {
vvp_send_real(ptr->out, 0.0, 0); // Should this be NaN?
ptr->send_real(0.0, 0); // Should this be NaN?
}
break;
}
@ -347,10 +347,10 @@ void vvp_fun_muxz::run_run()
switch (select_) {
case SEL_PORT0:
vvp_send_vec4(ptr->out, a_, 0);
ptr->send_vec4(a_, 0);
break;
case SEL_PORT1:
vvp_send_vec4(ptr->out, b_, 0);
ptr->send_vec4(b_, 0);
break;
default:
{
@ -373,7 +373,7 @@ void vvp_fun_muxz::run_run()
for (unsigned idx = min_size ; idx < max_size ; idx += 1)
res.set_bit(idx, BIT4_X);
vvp_send_vec4(ptr->out, res, 0);
ptr->send_vec4(res, 0);
}
break;
}
@ -421,7 +421,7 @@ void vvp_fun_not::run_run()
result.set_bit(idx, bitbit);
}
vvp_send_vec4(ptr->out, result, 0);
ptr->send_vec4(result, 0);
}
vvp_fun_or::vvp_fun_or(unsigned wid, bool invert)
@ -457,7 +457,7 @@ void vvp_fun_or::run_run()
result.set_bit(idx, bitbit);
}
vvp_send_vec4(ptr->out, result, 0);
ptr->send_vec4(result, 0);
}
vvp_fun_xor::vvp_fun_xor(unsigned wid, bool invert)
@ -493,7 +493,7 @@ void vvp_fun_xor::run_run()
result.set_bit(idx, bitbit);
}
vvp_send_vec4(ptr->out, result, 0);
ptr->send_vec4(result, 0);
}
/*
@ -607,7 +607,7 @@ void compile_functor(char*label, char*type, unsigned width,
net_drv->fun = obj_drv;
/* Point the gate to the drive node. */
net->out = vvp_net_ptr_t(net_drv, 0);
net->link(vvp_net_ptr_t(net_drv, 0));
define_functor_symbol(label, net_drv);
free(label);

View File

@ -75,7 +75,7 @@ void vvp_fun_pmos_::generate_output_(vvp_net_ptr_t ptr)
}
if (out.size() > 0)
vvp_send_vec8(ptr.ptr()->out, out);
ptr.ptr()->send_vec8(out);
}
@ -178,7 +178,7 @@ void vvp_fun_cmos_::generate_output_(vvp_net_ptr_t ptr)
}
if (out.size() > 0)
vvp_send_vec8(ptr.ptr()->out, out);
ptr.ptr()->send_vec8(out);
}
vvp_fun_cmos::vvp_fun_cmos()

View File

@ -96,8 +96,7 @@ void vvp_fun_part_sa::run_run()
{
vvp_net_t*ptr = net_;
net_ = 0;
vvp_send_vec4(ptr->out, val_, 0);
ptr->send_vec4(val_, 0);
}
vvp_fun_part_aa::vvp_fun_part_aa(unsigned base, unsigned wid)
@ -149,7 +148,7 @@ void vvp_fun_part_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
}
if (!val->eeq( tmp )) {
*val = tmp;
vvp_send_vec4(port.ptr()->out, tmp, context);
port.ptr()->send_vec4(tmp, context);
}
} else {
context = context_scope_->live_contexts;
@ -211,7 +210,7 @@ void vvp_fun_part_pv::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
}
assert(bit.size() == wid_);
vvp_send_vec4_pv(port.ptr()->out, bit, base_, wid_, vwid_, context);
port.ptr()->send_vec4_pv(bit, base_, wid_, vwid_, context);
}
void vvp_fun_part_pv::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
@ -226,7 +225,7 @@ void vvp_fun_part_pv::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
}
assert(bit.size() == wid_);
vvp_send_vec8_pv(port.ptr()->out, bit, base_, wid_, vwid_);
port.ptr()->send_vec8_pv(bit, base_, wid_, vwid_);
}
vvp_fun_part_var::vvp_fun_part_var(unsigned w, bool is_signed)
@ -291,7 +290,7 @@ void vvp_fun_part_var_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t)
{
if (recv_vec4_(port, bit, base_, source_, ref_)) {
vvp_send_vec4(port.ptr()->out, ref_, 0);
port.ptr()->send_vec4(ref_, 0);
}
}
@ -361,7 +360,7 @@ void vvp_fun_part_var_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
(vvp_get_context_item(context, context_idx_));
if (recv_vec4_(port, bit, state->base, state->source, state->ref)) {
vvp_send_vec4(port.ptr()->out, state->ref, context);
port.ptr()->send_vec4(state->ref, context);
}
} else {
context = context_scope_->live_contexts;

View File

@ -66,7 +66,7 @@ void vvp_reduce_base::recv_vec4(vvp_net_ptr_t prt, const vvp_vector4_t&bit,
bits_ = bit;
vvp_bit4_t res = calculate_result();
vvp_vector4_t rv (1, res);
vvp_send_vec4(prt.ptr()->out, rv, context);
prt.ptr()->send_vec4(rv, context);
}
void vvp_reduce_base::recv_vec4_pv(vvp_net_ptr_t prt, const vvp_vector4_t&bit,
@ -82,7 +82,7 @@ void vvp_reduce_base::recv_vec4_pv(vvp_net_ptr_t prt, const vvp_vector4_t&bit,
bits_.set_vec(base, bit);
vvp_bit4_t res = calculate_result();
vvp_vector4_t rv (1, res);
vvp_send_vec4(prt.ptr()->out, rv, context);
prt.ptr()->send_vec4(rv, context);
}
class vvp_reduce_and : public vvp_reduce_base {

View File

@ -96,7 +96,7 @@ void resolv_functor::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
<< " in=" << val_[0] << ", " << val_[1]
<< ", " << val_[2] << ", " << val_[3] << endl;
vvp_send_vec8(ptr->out, out);
ptr->send_vec8(out);
}
void resolv_functor::recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit,
@ -146,7 +146,7 @@ void resolv_wired_logic::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
out = wired_logic_math_(out, val_[idx]);
}
vvp_send_vec4(ptr->out, out, 0);
ptr->send_vec4(out, 0);
}
vvp_vector4_t resolv_triand::wired_logic_math_(vvp_vector4_t&a, vvp_vector4_t&b)

View File

@ -257,6 +257,27 @@ void assign_array_word_s::operator delete(void*ptr)
unsigned long count_assign_aword_pool(void) { return array_w_heap.pool; }
/*
* This class supports the propagation of vec4 outputs from a
* vvp_net_t object.
*/
struct propagate_vector4_event_s : public event_s {
propagate_vector4_event_s(const vvp_vector4_t&that, unsigned adr, unsigned wid)
: val(that,adr,wid) { }
/* Propagate the output of this net. */
vvp_net_t*net;
/* value to propagate */
vvp_vector4_t val;
/* Action */
void run_run(void);
};
void propagate_vector4_event_s::run_run(void)
{
net->send_vec4(val, 0);
}
struct assign_array_r_word_s : public event_s {
vvp_array_t mem;
unsigned adr;
@ -626,6 +647,17 @@ void schedule_assign_plucked_vector(vvp_net_ptr_t ptr,
schedule_event_(cur, delay, SEQ_NBASSIGN);
}
void schedule_propagate_plucked_vector(vvp_net_t*net,
vvp_time64_t delay,
const vvp_vector4_t&src,
unsigned adr, unsigned wid)
{
struct propagate_vector4_event_s*cur
= new struct propagate_vector4_event_s(src,adr,wid);
cur->net = net;
schedule_event_(cur, delay, SEQ_NBASSIGN);
}
void schedule_assign_array_word(vvp_array_t mem,
unsigned word_addr,
unsigned off,
@ -687,6 +719,15 @@ void schedule_init_vector(vvp_net_ptr_t ptr, vvp_vector4_t bit)
schedule_init_list = cur;
}
void schedule_init_vector(vvp_net_ptr_t ptr, vvp_vector8_t bit)
{
struct assign_vector8_event_s*cur = new struct assign_vector8_event_s;
cur->ptr = ptr;
cur->val = bit;
cur->next = schedule_init_list;
schedule_init_list = cur;
}
void schedule_init_vector(vvp_net_ptr_t ptr, double bit)
{
struct assign_real_event_s*cur = new struct assign_real_event_s;

View File

@ -62,6 +62,14 @@ extern void schedule_assign_array_word(vvp_array_t mem,
unsigned word_address,
double val,
vvp_time64_t delay);
/*
* Create an event to propagate the output of a net.
*/
extern void schedule_propagate_plucked_vector(vvp_net_t*ptr,
vvp_time64_t delay,
const vvp_vector4_t&val,
unsigned adr, unsigned wid);
/*
* This is very similar to schedule_assign_vector, but generates an
* event in the active queue. It is used at link time to assign a
@ -83,6 +91,7 @@ extern void schedule_set_vector(vvp_net_ptr_t ptr, double val);
* (propagated as events) through the rest of the net.
*/
extern void schedule_init_vector(vvp_net_ptr_t ptr, vvp_vector4_t val);
extern void schedule_init_vector(vvp_net_ptr_t ptr, vvp_vector8_t val);
extern void schedule_init_vector(vvp_net_ptr_t ptr, double val);
/*

View File

@ -989,7 +989,7 @@ void compile_udp_functor(char*label, char*type,
delete delay;
net_drv->fun = obj_drv;
ptr->out = vvp_net_ptr_t(net_drv,0);
ptr->link(vvp_net_ptr_t(net_drv,0));
define_functor_symbol(label, net_drv);
} else {

View File

@ -22,6 +22,7 @@
# include "symbols.h"
# include "codes.h"
# include "ufunc.h"
# include "vvp_net_sig.h"
# include "vthread.h"
# include "schedule.h"
#ifdef HAVE_MALLOC_H
@ -83,11 +84,10 @@ void ufunc_core::finish_thread(vthread_t thr)
{
thread_ = 0;
if (vvp_fun_signal_real*sig = dynamic_cast<vvp_fun_signal_real*>(result_->fun))
propagate_real(sig->real_value());
propagate_real(sig->real_unfiltered_value());
if (vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*>(result_->fun))
propagate_vec4(sig->vec4_value());
propagate_vec4(sig->vec4_unfiltered_value());
}
/*

View File

@ -29,6 +29,7 @@
# include "vvp_net.h"
# include "schedule.h"
# include "event.h"
# include "vvp_net_sig.h"
# include "config.h"
# include <stdio.h>
# include <assert.h>
@ -156,12 +157,12 @@ static struct __vpiCallback* make_value_change(p_cb_data data)
struct __vpiSignal*sig;
sig = reinterpret_cast<__vpiSignal*>(data->obj);
vvp_fun_signal_base*sig_fun;
sig_fun = dynamic_cast<vvp_fun_signal_base*>(sig->node->fun);
assert(sig_fun);
vvp_net_fil_t*sig_fil;
sig_fil = dynamic_cast<vvp_net_fil_t*>(sig->node->fil);
assert(sig_fil);
/* Attach the __vpiCallback object to the signal. */
sig_fun->add_vpi_callback(obj);
sig_fil->add_vpi_callback(obj);
break;
case vpiRealVar:
@ -503,11 +504,21 @@ void callback_execute(struct __vpiCallback*cur)
vvp_vpi_callback::vvp_vpi_callback()
{
vpi_callbacks_ = 0;
array_ = 0;
array_word_ = 0;
}
vvp_vpi_callback::~vvp_vpi_callback()
{
assert(vpi_callbacks_ == 0);
assert(array_ == 0);
}
void vvp_vpi_callback::attach_as_word(vvp_array_t arr, unsigned long addr)
{
assert(array_ == 0);
array_ = arr;
array_word_ = addr;
}
void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb)
@ -535,6 +546,8 @@ void vvp_vpi_callback::clear_all_callbacks()
*/
void vvp_vpi_callback::run_vpi_callbacks()
{
if (array_) array_word_change(array_, array_word_);
struct __vpiCallback *next = vpi_callbacks_;
struct __vpiCallback *prev = 0;
@ -564,32 +577,7 @@ void vvp_vpi_callback::run_vpi_callbacks()
}
}
vvp_vpi_callback_wordable::vvp_vpi_callback_wordable()
{
array_ = 0;
array_word_ = 0;
}
vvp_vpi_callback_wordable::~vvp_vpi_callback_wordable()
{
assert(array_ == 0);
}
void vvp_vpi_callback_wordable::run_vpi_callbacks()
{
if (array_) array_word_change(array_, array_word_);
vvp_vpi_callback::run_vpi_callbacks();
}
void vvp_vpi_callback_wordable::attach_as_word(vvp_array_t arr, unsigned long addr)
{
assert(array_ == 0);
array_ = arr;
array_word_ = addr;
}
void vvp_fun_signal4::get_value(struct t_vpi_value*vp)
void vvp_signal_value::get_signal_value(struct t_vpi_value*vp)
{
switch (vp->format) {
case vpiScalarVal:
@ -607,7 +595,7 @@ void vvp_fun_signal4::get_value(struct t_vpi_value*vp)
case vpiVectorVal:
case vpiStringVal:
case vpiRealVal: {
unsigned wid = size();
unsigned wid = value_size();
vvp_vector4_t vec4(wid);
for (unsigned idx = 0; idx < wid; idx += 1) {
vec4.set_bit(idx, value(idx));
@ -626,22 +614,7 @@ void vvp_fun_signal4::get_value(struct t_vpi_value*vp)
}
}
void vvp_fun_signal8::get_value(struct t_vpi_value*vp)
{
switch (vp->format) {
case vpiScalarVal:
vp->value.scalar = value(0);
break;
case vpiSuppressVal:
break;
default:
fprintf(stderr, "vpi_callback: value "
"format %d not supported (fun_signal8)\n",
vp->format);
}
}
void vvp_fun_signal_real::get_value(struct t_vpi_value*vp)
static void real_signal_value(struct t_vpi_value*vp, double rval)
{
char*rbuf = need_result_buf(64 + 1, RBUF_VAL);
@ -650,25 +623,25 @@ void vvp_fun_signal_real::get_value(struct t_vpi_value*vp)
vp->format = vpiRealVal;
case vpiRealVal:
vp->value.real = real_value();
vp->value.real = rval;
break;
case vpiIntVal:
vp->value.integer = (int)(real_value() + 0.5);
vp->value.integer = (int)(rval + 0.5);
break;
case vpiDecStrVal:
sprintf(rbuf, "%0.0f", real_value());
sprintf(rbuf, "%0.0f", rval);
vp->value.str = rbuf;
break;
case vpiHexStrVal:
sprintf(rbuf, "%lx", (long)real_value());
sprintf(rbuf, "%lx", (long)rval);
vp->value.str = rbuf;
break;
case vpiBinStrVal: {
unsigned long val = (unsigned long)real_value();
unsigned long val = (unsigned long)rval;
unsigned len = 0;
while (val > 0) {
@ -676,7 +649,7 @@ void vvp_fun_signal_real::get_value(struct t_vpi_value*vp)
val /= 2;
}
val = (unsigned long)real_value();
val = (unsigned long)rval;
for (unsigned idx = 0 ; idx < len ; idx += 1) {
rbuf[len-idx-1] = (val & 1)? '1' : '0';
val /= 2;
@ -700,3 +673,28 @@ void vvp_fun_signal_real::get_value(struct t_vpi_value*vp)
vp->format);
}
}
void vvp_fun_signal_real_aa::get_signal_value(struct t_vpi_value*vp)
{
real_signal_value(vp, real_value());
}
void vvp_wire_real::get_signal_value(struct t_vpi_value*vp)
{
real_signal_value(vp, real_value());
}
void vvp_wire_vec4::get_value(struct t_vpi_value*value)
{
get_signal_value(value);
}
void vvp_wire_vec8::get_value(struct t_vpi_value*value)
{
get_signal_value(value);
}
void vvp_wire_real::get_value(struct t_vpi_value*value)
{
get_signal_value(value);
}

View File

@ -19,6 +19,7 @@
# include "compile.h"
# include "vpi_priv.h"
# include "vvp_net_sig.h"
# include "schedule.h"
# include <stdio.h>
# include <stdlib.h>
@ -131,10 +132,10 @@ static void real_var_get_value(vpiHandle ref, s_vpi_value*vp)
struct __vpiRealVar*rfp
= (struct __vpiRealVar*)ref;
vvp_fun_signal_real*fun
= dynamic_cast<vvp_fun_signal_real*>(rfp->net->fun);
vvp_signal_value*fil
= dynamic_cast<vvp_signal_value*>(rfp->net->fil);
fun->get_value(vp);
fil->get_signal_value(vp);
}
static vpiHandle real_var_put_value(vpiHandle ref, p_vpi_value vp, int)
@ -170,10 +171,10 @@ void vpip_real_value_change(struct __vpiCallback*cbh,
{
struct __vpiRealVar*rfp
= (struct __vpiRealVar*)ref;
vvp_fun_signal_real*fun
= dynamic_cast<vvp_fun_signal_real*>(rfp->net->fun);
vvp_vpi_callback*obj = dynamic_cast<vvp_vpi_callback*>(rfp->net->fil);
assert(obj);
fun->add_vpi_callback(cbh);
obj->add_vpi_callback(cbh);
}
vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net)

View File

@ -24,6 +24,7 @@
# include "compile.h"
# include "vpi_priv.h"
# include "vvp_net_sig.h"
# include "schedule.h"
# include "statistics.h"
# include "config.h"
@ -134,13 +135,13 @@ char *generic_get_str(int code, vpiHandle ref, const char *name, const char *ind
* They work with full or partial signals.
*/
static void format_vpiBinStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
static void format_vpiBinStrVal(vvp_signal_value*sig, int base, unsigned wid,
s_vpi_value*vp)
{
char *rbuf = need_result_buf(wid+1, RBUF_VAL);
long end = base + (signed)wid;
long offset = end - 1;
long ssize = (signed)sig->size();
long ssize = (signed)sig->value_size();
for (long idx = base ; idx < end ; idx += 1) {
if (idx < 0 || idx >= ssize) {
@ -154,13 +155,13 @@ static void format_vpiBinStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
vp->value.str = rbuf;
}
static void format_vpiOctStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
static void format_vpiOctStrVal(vvp_signal_value*sig, int base, unsigned wid,
s_vpi_value*vp)
{
unsigned dwid = (wid + 2) / 3;
char *rbuf = need_result_buf(dwid+1, RBUF_VAL);
long end = base + (signed)wid;
long ssize = (signed)sig->size();
long ssize = (signed)sig->value_size();
unsigned val = 0;
rbuf[dwid] = 0;
@ -210,13 +211,13 @@ static void format_vpiOctStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
vp->value.str = rbuf;
}
static void format_vpiHexStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
static void format_vpiHexStrVal(vvp_signal_value*sig, int base, unsigned wid,
s_vpi_value*vp)
{
unsigned dwid = (wid + 3) / 4;
char *rbuf = need_result_buf(dwid+1, RBUF_VAL);
long end = base + (signed)wid;
long ssize = (signed)sig->size();
long ssize = (signed)sig->value_size();
unsigned val = 0;
rbuf[dwid] = 0;
@ -270,12 +271,12 @@ static void format_vpiHexStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
vp->value.str = rbuf;
}
static void format_vpiDecStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
static void format_vpiDecStrVal(vvp_signal_value*sig, int base, unsigned wid,
int signed_flag, s_vpi_value*vp)
{
unsigned hwid = (sig->size()+2) / 3 + 1;
unsigned hwid = (sig->value_size()+2) / 3 + 1;
char *rbuf = need_result_buf(hwid, RBUF_VAL);
long ssize = (signed)sig->size();
long ssize = (signed)sig->value_size();
long end = base + (signed)wid;
/* Do we have an end outside of the real signal vector. */
@ -313,7 +314,7 @@ static void format_vpiDecStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
vp->value.str = rbuf;
}
static void format_vpiIntVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
static void format_vpiIntVal(vvp_signal_value*sig, int base, unsigned wid,
int signed_flag, s_vpi_value*vp)
{
vvp_vector4_t sub = sig->vec4_value().subvalue(base, wid);
@ -322,11 +323,11 @@ static void format_vpiIntVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
vp->value.integer = val;
}
static void format_vpiRealVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
static void format_vpiRealVal(vvp_signal_value*sig, int base, unsigned wid,
int signed_flag, s_vpi_value*vp)
{
vvp_vector4_t vec4(wid);
long ssize = (signed)sig->size();
long ssize = (signed)sig->value_size();
long end = base + (signed)wid;
if (end > ssize) end = ssize;
@ -338,7 +339,7 @@ static void format_vpiRealVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
vector4_to_value(vec4, vp->value.real, signed_flag);
}
static void format_vpiStringVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
static void format_vpiStringVal(vvp_signal_value*sig, int base, unsigned wid,
s_vpi_value*vp)
{
/* The result will use a character for each 8 bits of the
@ -351,7 +352,7 @@ static void format_vpiStringVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
for (long idx = base+(signed)wid-1; idx >= base; idx -= 1) {
tmp <<= 1;
if (idx >=0 && idx < (signed)sig->size() &&
if (idx >=0 && idx < (signed)sig->value_size() &&
sig->value(idx) == BIT4_1) {
tmp |= 1;
}
@ -371,10 +372,10 @@ static void format_vpiStringVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
vp->value.str = rbuf;
}
static void format_vpiScalarVal(vvp_fun_signal_vec*sig, int base,
static void format_vpiScalarVal(vvp_signal_value*sig, int base,
s_vpi_value*vp)
{
if (base >= 0 && base < (signed)sig->size()) {
if (base >= 0 && base < (signed)sig->value_size()) {
switch (sig->value(base)) {
case BIT4_0:
vp->value.scalar = vpi0;
@ -398,7 +399,7 @@ static void format_vpiScalarVal(vvp_fun_signal_vec*sig, int base,
}
}
static void format_vpiStrengthVal(vvp_fun_signal_vec*sig, int base,
static void format_vpiStrengthVal(vvp_signal_value*sig, int base,
unsigned wid, s_vpi_value*vp)
{
long end = base + (signed)wid;
@ -408,7 +409,7 @@ static void format_vpiStrengthVal(vvp_fun_signal_vec*sig, int base,
need_result_buf(wid * sizeof(s_vpi_strengthval), RBUF_VAL);
for (long idx = base ; idx < end ; idx += 1) {
if (idx >=0 && idx < (signed)sig->size()) {
if (idx >=0 && idx < (signed)sig->value_size()) {
vvp_scalar_t val = sig->scalar_value(idx);
/* vvp_scalar_t strengths are 0-7, but the vpi strength
@ -452,7 +453,7 @@ static void format_vpiStrengthVal(vvp_fun_signal_vec*sig, int base,
vp->value.strength = op;
}
static void format_vpiVectorVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
static void format_vpiVectorVal(vvp_signal_value*sig, int base, unsigned wid,
s_vpi_value*vp)
{
long end = base + (signed)wid;
@ -465,7 +466,7 @@ static void format_vpiVectorVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
op->aval = op->bval = 0;
for (long idx = base ; idx < end ; idx += 1) {
if (base >= 0 && base < (signed)sig->size()) {
if (base >= 0 && base < (signed)sig->value_size()) {
switch (sig->value(idx)) {
case BIT4_0:
op->aval &= ~(1 << obit);
@ -659,7 +660,7 @@ static void signal_get_value(vpiHandle ref, s_vpi_value*vp)
unsigned wid = signal_width(rfp);
vvp_fun_signal_vec*vsig = dynamic_cast<vvp_fun_signal_vec*>(rfp->node->fun);
vvp_signal_value*vsig = dynamic_cast<vvp_signal_value*>(rfp->node->fil);
assert(vsig);
switch (vp->format) {
@ -757,9 +758,12 @@ static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
value. Instead, issue a release "command" to the signal
node to cause it to release a forced value. */
if (flags == vpiReleaseFlag) {
vvp_net_ptr_t dest_cmd(rfp->node, 3);
/* Assume this is a net. (XXXX Are we sure?) */
vvp_send_long(dest_cmd, 2 /* release/net */);
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);
return ref;
}
@ -1111,7 +1115,7 @@ static void PV_get_value(vpiHandle ref, p_vpi_value vp)
assert(ref->vpi_type->type_code == vpiPartSelect);
struct __vpiPV*rfp = (struct __vpiPV*)ref;
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*>(rfp->net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*>(rfp->net->fil);
assert(sig);
switch (vp->format) {
@ -1168,10 +1172,10 @@ static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int)
{
assert(ref->vpi_type->type_code == vpiPartSelect);
struct __vpiPV*rfp = (struct __vpiPV*)ref;
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*>(rfp->net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*>(rfp->net->fil);
assert(sig);
unsigned sig_size = sig->size();
unsigned sig_size = sig->value_size();
unsigned width = rfp->width;
int base = PV_get_base(rfp);
if (base >= (signed) sig_size) return 0;
@ -1314,12 +1318,12 @@ void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle ref)
struct __vpiPV*obj = vpip_PV_from_handle(ref);
assert(obj);
vvp_fun_signal_base*sig_fun;
sig_fun = dynamic_cast<vvp_fun_signal_base*>(obj->net->fun);
assert(sig_fun);
vvp_vpi_callback*sig_fil;
sig_fil = dynamic_cast<vvp_vpi_callback*>(obj->net->fil);
assert(sig_fil);
/* Attach the __vpiCallback object to the signal. */
sig_fun->add_vpi_callback(cbh);
sig_fil->add_vpi_callback(cbh);
}
#ifdef CHECK_WITH_VALGRIND

View File

@ -426,7 +426,7 @@ static vpiHandle sysfunc_put_4net_value(vpiHandle ref, p_vpi_value vp, int)
assert(0);
}
vvp_send_vec4(rfp->fnet->out, val, vthread_get_wt_context());
rfp->fnet->send_vec4(val, vthread_get_wt_context());
return 0;
}
@ -450,7 +450,7 @@ static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int)
assert(0);
}
vvp_send_real(rfp->fnet->out, val, vthread_get_wt_context());
rfp->fnet->send_real(val, vthread_get_wt_context());
return 0;
}

View File

@ -24,6 +24,7 @@
# include "ufunc.h"
# include "event.h"
# include "vpi_priv.h"
# include "vvp_net_sig.h"
#ifdef CHECK_WITH_VALGRIND
# include "vvp_cleanup.h"
#endif
@ -178,6 +179,19 @@ void vthread_put_real(struct vthread_s*thr, unsigned addr, double val)
thr->words[addr].w_real = val;
}
template <class T> T coerce_to_width(const T&that, unsigned width)
{
if (that.size() == width)
return that;
assert(that.size() > width);
T res (width);
for (unsigned idx = 0 ; idx < width ; idx += 1)
res.set_bit(idx, that.value(idx));
return res;
}
static unsigned long* vector_to_array(struct vthread_s*thr,
unsigned addr, unsigned wid)
{
@ -550,41 +564,6 @@ void vthread_run(vthread_t thr)
running_thread = 0;
}
/*
* Unlink a ptr object from the driver. The input is the driver in the
* form of a vvp_net_t pointer. The .out member of that object is the
* driver. The dst_ptr argument is the receiver pin to be located and
* removed from the fan-out list.
*/
static void unlink_from_driver(vvp_net_t*src, vvp_net_ptr_t dst_ptr)
{
vvp_net_t*net = dst_ptr.ptr();
unsigned net_port = dst_ptr.port();
if (src->out == dst_ptr) {
/* If the drive fan-out list starts with this pointer,
then the unlink is easy. Pull the list forward. */
src->out = net->port[net_port];
} else {
/* Scan the linked list, looking for the net_ptr_t
pointer *before* the one we wish to remove. */
vvp_net_ptr_t cur = src->out;
assert(!cur.nil());
vvp_net_t*cur_net = cur.ptr();
unsigned cur_port = cur.port();
while (cur_net->port[cur_port] != dst_ptr) {
cur = cur_net->port[cur_port];
assert(!cur.nil());
cur_net = cur.ptr();
cur_port = cur.port();
}
/* Unlink. */
cur_net->port[cur_port] = net->port[net_port];
}
net->port[net_port] = vvp_net_ptr_t(0,0);
}
/*
* The CHUNK_LINK instruction is a special next pointer for linking
* chunks of code space. It's like a simplified %jmp.
@ -1078,12 +1057,11 @@ bool of_ASSIGN_V0X1(vthread_t thr, vvp_code_t cp)
unsigned delay = cp->bit_idx[0];
unsigned bit = cp->bit_idx[1];
vvp_fun_signal_vec*sig
= reinterpret_cast<vvp_fun_signal_vec*> (cp->net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (cp->net->fil);
assert(sig);
// We fell off the MSB end.
if (off >= (long)sig->size()) return true;
if (off >= (long)sig->value_size()) return true;
else if (off < 0 ) {
// We fell off the LSB end.
if ((unsigned)-off >= wid ) return true;
@ -1098,7 +1076,7 @@ bool of_ASSIGN_V0X1(vthread_t thr, vvp_code_t cp)
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
vvp_net_ptr_t ptr (cp->net, 0);
schedule_assign_vector(ptr, off, sig->size(), value, delay);
schedule_assign_vector(ptr, off, sig->value_size(), value, delay);
return true;
}
@ -1115,12 +1093,11 @@ bool of_ASSIGN_V0X1D(vthread_t thr, vvp_code_t cp)
vvp_time64_t delay = thr->words[cp->bit_idx[0]].w_int;
unsigned bit = cp->bit_idx[1];
vvp_fun_signal_vec*sig
= reinterpret_cast<vvp_fun_signal_vec*> (cp->net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (cp->net->fil);
assert(sig);
// We fell off the MSB end.
if (off >= (long)sig->size()) return true;
if (off >= (long)sig->value_size()) return true;
else if (off < 0 ) {
// We fell off the LSB end.
if ((unsigned)-off >= wid ) return true;
@ -1135,7 +1112,7 @@ bool of_ASSIGN_V0X1D(vthread_t thr, vvp_code_t cp)
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
vvp_net_ptr_t ptr (cp->net, 0);
schedule_assign_vector(ptr, off, sig->size(), value, delay);
schedule_assign_vector(ptr, off, sig->value_size(), value, delay);
return true;
}
@ -1151,12 +1128,11 @@ bool of_ASSIGN_V0X1E(vthread_t thr, vvp_code_t cp)
long off = thr->words[1].w_int;
unsigned bit = cp->bit_idx[0];
vvp_fun_signal_vec*sig
= reinterpret_cast<vvp_fun_signal_vec*> (cp->net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (cp->net->fil);
assert(sig);
// We fell off the MSB end.
if (off >= (long)sig->size()) {
if (off >= (long)sig->value_size()) {
thr->event = 0;
thr->ecount = 0;
return true;
@ -1180,9 +1156,9 @@ bool of_ASSIGN_V0X1E(vthread_t thr, vvp_code_t cp)
vvp_net_ptr_t ptr (cp->net, 0);
// If the count is zero then just put the value.
if (thr->ecount == 0) {
schedule_assign_vector(ptr, off, sig->size(), value, 0);
schedule_assign_vector(ptr, off, sig->value_size(), value, 0);
} else {
schedule_evctl(ptr, value, off, sig->size(), thr->event,
schedule_evctl(ptr, value, off, sig->value_size(), thr->event,
thr->ecount);
}
@ -1321,7 +1297,7 @@ bool of_CASSIGN_LINK(vthread_t thr, vvp_code_t cp)
vvp_net_t*src = cp->net2;
vvp_fun_signal_base*sig
= reinterpret_cast<vvp_fun_signal_base*>(dst->fun);
= dynamic_cast<vvp_fun_signal_base*>(dst->fun);
assert(sig);
/* Detect the special case that we are already continuous
@ -1333,7 +1309,7 @@ bool of_CASSIGN_LINK(vthread_t thr, vvp_code_t cp)
unlink it. We can have only 1 cassign at a time. */
if (sig->cassign_link != 0) {
vvp_net_ptr_t tmp (dst, 1);
unlink_from_driver(sig->cassign_link, tmp);
sig->cassign_link->unlink(tmp);
}
sig->cassign_link = src;
@ -1341,8 +1317,7 @@ bool of_CASSIGN_LINK(vthread_t thr, vvp_code_t cp)
/* Link the output of the src to the port[1] (the cassign
port) of the destination. */
vvp_net_ptr_t dst_ptr (dst, 1);
dst->port[1] = src->out;
src->out = dst_ptr;
src->link(dst_ptr);
return true;
}
@ -1397,12 +1372,12 @@ bool of_CASSIGN_X0(vthread_t thr, vvp_code_t cp)
// X0 register.
long index = thr->words[0].w_int;
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (net->fil);
if (index < 0 && (wid <= (unsigned)-index))
return true;
if (index >= (long)sig->size())
if (index >= (long)sig->value_size())
return true;
if (index < 0) {
@ -1410,13 +1385,13 @@ bool of_CASSIGN_X0(vthread_t thr, vvp_code_t cp)
index = 0;
}
if (index+wid > sig->size())
wid = sig->size() - index;
if (index+wid > sig->value_size())
wid = sig->value_size() - index;
vvp_vector4_t vector = vthread_bits_to_vector(thr, base, wid);
vvp_net_ptr_t ptr (net, 1);
vvp_send_vec4_pv(ptr, vector, index, wid, sig->size(), 0);
vvp_send_vec4_pv(ptr, vector, index, wid, sig->value_size(), 0);
return true;
}
@ -1828,13 +1803,15 @@ bool of_DEASSIGN(vthread_t thr, vvp_code_t cp)
unsigned base = cp->bit_idx[0];
unsigned width = cp->bit_idx[1];
vvp_fun_signal_vec*sig = reinterpret_cast<vvp_fun_signal_vec*>(net->fun);
vvp_signal_value*fil = dynamic_cast<vvp_signal_value*> (net->fil);
assert(fil);
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*>(net->fun);
assert(sig);
if (base >= sig->size()) return true;
if (base+width > sig->size()) width = sig->size() - base;
if (base >= fil->value_size()) return true;
if (base+width > fil->value_size()) width = fil->value_size() - base;
bool full_sig = base == 0 && width == sig->size();
bool full_sig = base == 0 && width == fil->value_size();
// This is the net that is forcing me...
if (vvp_net_t*src = sig->cassign_link) {
@ -1845,16 +1822,15 @@ bool of_DEASSIGN(vthread_t thr, vvp_code_t cp)
}
// And this is the pointer to be removed.
vvp_net_ptr_t dst_ptr (net, 1);
unlink_from_driver(src, dst_ptr);
src->unlink(dst_ptr);
sig->cassign_link = 0;
}
/* Do we release all or part of the net? */
vvp_net_ptr_t ptr (net, 3);
if (full_sig) {
vvp_send_long(ptr, 1);
sig->deassign();
} else {
vvp_send_long_pv(ptr, 1, base, width);
sig->deassign_pv(base, width);
}
return true;
@ -1864,19 +1840,18 @@ bool of_DEASSIGN_WR(vthread_t thr, vvp_code_t cp)
{
vvp_net_t*net = cp->net;
vvp_fun_signal_real*sig = reinterpret_cast<vvp_fun_signal_real*>(net->fun);
vvp_fun_signal_real*sig = dynamic_cast<vvp_fun_signal_real*>(net->fun);
assert(sig);
// This is the net that is forcing me...
if (vvp_net_t*src = sig->cassign_link) {
// And this is the pointer to be removed.
vvp_net_ptr_t dst_ptr (net, 1);
unlink_from_driver(src, dst_ptr);
src->unlink(dst_ptr);
sig->cassign_link = 0;
}
vvp_net_ptr_t ptr (net, 3);
vvp_send_long(ptr, 1);
sig->deassign();
return true;
}
@ -2391,42 +2366,6 @@ bool of_EVCTLS(vthread_t thr, vvp_code_t cp)
return true;
}
static void unlink_force(vvp_net_t*net)
{
vvp_fun_signal_base*sig
= reinterpret_cast<vvp_fun_signal_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);
/* If net is first in the fan-out list, then simply pull it
from the front. */
if (src->out == net_ptr) {
src->out = net->port[2];
net->port[2] = vvp_net_ptr_t();
return;
}
/* Look for the pointer in the fan-out chain */
vvp_net_ptr_t cur_ptr = src->out;
assert(!cur_ptr.nil());
while (cur_ptr.ptr()->port[cur_ptr.port()] != net_ptr) {
cur_ptr = cur_ptr.ptr()->port[cur_ptr.port()];
assert( !cur_ptr.nil() );
}
/* Remove as if from a singly-linked list. */
cur_ptr.ptr()->port[cur_ptr.port()] = net->port[2];
net->port[2] = vvp_net_ptr_t();
}
/*
* the %force/link instruction connects a source node to a
* destination node. The destination node must be a signal, as it is
@ -2439,26 +2378,8 @@ bool of_FORCE_LINK(vthread_t thr, vvp_code_t cp)
vvp_net_t*dst = cp->net;
vvp_net_t*src = cp->net2;
vvp_fun_signal_base*sig
= reinterpret_cast<vvp_fun_signal_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);
dst->port[2] = src->out;
src->out = dst_ptr;
assert(dst->fil);
dst->fil->force_link(dst, src);
return true;
}
@ -2484,9 +2405,13 @@ bool of_FORCE_V(vthread_t thr, vvp_code_t cp)
/* Collect the thread bits into a vector4 item. */
vvp_vector4_t value = vthread_bits_to_vector(thr, base, wid);
/* Set the value into port 2 of the destination. */
vvp_net_ptr_t ptr (net, 2);
vvp_send_vec4(ptr, value, 0);
/* Send the force value to the filter on the node. */
assert(net->fil);
if (value.size() != net->fil->filter_size())
value = coerce_to_width(value, net->fil->filter_size());
net->force_vec4(value, vvp_vector2_t(vvp_vector2_t::FILL1, net->fil->filter_size()));
return true;
}
@ -2496,9 +2421,7 @@ bool of_FORCE_WR(vthread_t thr, vvp_code_t cp)
vvp_net_t*net = cp->net;
double value = thr->words[cp->bit_idx[0]].w_real;
/* Set the value into port 2 of the destination. */
vvp_net_ptr_t ptr (net, 2);
vvp_send_real(ptr, value, 0);
net->force_real(value, vvp_vector2_t(vvp_vector2_t::FILL1, 1));
return true;
}
@ -2510,30 +2433,38 @@ bool of_FORCE_X0(vthread_t thr, vvp_code_t cp)
unsigned base = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
assert(net->fil);
// Implicitly, we get the base into the target vector from the
// X0 register.
long index = thr->words[0].w_int;
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
if (index < 0 && (wid <= (unsigned)-index))
return true;
if (index >= (long)sig->size())
return true;
if (index < 0) {
wid -= (unsigned) -index;
index = 0;
}
if (index+wid > sig->size())
wid = sig->size() - index;
unsigned use_size = net->fil->filter_size();
if (index >= (long)use_size)
return true;
if (index+wid > use_size)
wid = use_size - index;
vvp_vector2_t mask(vvp_vector2_t::FILL0, use_size);
for (unsigned idx = 0 ; idx < wid ; idx += 1)
mask.set_bit(index+idx, 1);
vvp_vector4_t vector = vthread_bits_to_vector(thr, base, wid);
vvp_vector4_t value(use_size, BIT4_Z);
value.set_vec(index, vector);
vvp_net_ptr_t ptr (net, 2);
vvp_send_vec4_pv(ptr, vector, index, wid, sig->size(), 0);
net->force_vec4(value, mask);
return true;
}
@ -2749,10 +2680,11 @@ bool of_IX_GETV(vthread_t thr, vvp_code_t cp)
unsigned index = cp->bit_idx[0];
vvp_net_t*net = cp->net;
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*>(net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*>(net->fil);
if (sig == 0) {
assert(net->fil);
cerr << "%%ix/getv error: Net arg not a vector signal? "
<< typeid(*net->fun).name() << endl;
<< typeid(*net->fil).name() << endl;
}
assert(sig);
@ -2776,10 +2708,12 @@ bool of_IX_GETVS(vthread_t thr, vvp_code_t cp)
unsigned index = cp->bit_idx[0];
vvp_net_t*net = cp->net;
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*>(net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*>(net->fil);
if (sig == 0) {
cerr << "%%ix/getv/s error: Net arg not a vector signal? "
<< typeid(*net->fun).name() << endl;
<< "fun=" << typeid(*net->fil).name()
<< ", fil=" << (net->fil? typeid(*net->fil).name() : "<>")
<< endl;
}
assert(sig);
@ -3127,10 +3061,10 @@ static vvp_vector4_t load_base(vthread_t thr, vvp_code_t cp)
/* For the %load to work, the functor must actually be a
signal functor. Only signals save their vector value. */
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (net->fil);
if (sig == 0) {
cerr << "%%load/v error: Net arg not a vector signal? "
<< typeid(*net->fun).name() << endl;
cerr << "%%load/v error: Net arg not a signal? "
<< typeid(*net->fil).name() << endl;
assert(sig);
}
@ -3229,13 +3163,13 @@ bool of_LOAD_X1P(vthread_t thr, vvp_code_t cp)
// For the %load to work, the functor must actually be a
// signal functor. Only signals save their vector value.
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (net->fil);
assert(sig);
for (long idx = 0 ; idx < wid ; idx += 1) {
long use_index = index + idx;
vvp_bit4_t val;
if (use_index < 0 || use_index >= (signed)sig->size())
if (use_index < 0 || use_index >= (signed)sig->value_size())
val = BIT4_X;
else
val = sig->value(use_index);
@ -4076,79 +4010,43 @@ bool of_POW_WR(vthread_t thr, vvp_code_t cp)
* the release/reg command instead. These are very similar to the
* %deassign instruction.
*/
bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp)
static bool do_release_vec(vthread_t thr, vvp_code_t cp, bool net_flag)
{
vvp_net_t*net = cp->net;
unsigned base = cp->bit_idx[0];
unsigned width = cp->bit_idx[1];
vvp_fun_signal_vec*sig = reinterpret_cast<vvp_fun_signal_vec*>(net->fun);
assert(sig);
assert(net->fil);
if (base >= sig->size()) return true;
if (base+width > sig->size()) width = sig->size() - base;
if (base >= net->fil->filter_size()) return true;
if (base+width > net->fil->filter_size())
width = net->fil->filter_size() - base;
bool full_sig = base == 0 && width == sig->size();
bool full_sig = base == 0 && width == net->fil->filter_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?
net->fil->force_unlink();
/* Do we release all or part of the net? */
vvp_net_ptr_t ptr (net, 3);
vvp_net_ptr_t ptr (net, 0);
if (full_sig) {
vvp_send_long(ptr, 2);
net->fil->release(ptr, net_flag);
} else {
vvp_send_long_pv(ptr, 2, base, width);
net->fil->release_pv(ptr, base, width, net_flag);
}
return true;
}
bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp)
{
return do_release_vec(thr, cp, true);
}
bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp)
{
vvp_net_t*net = cp->net;
unsigned base = cp->bit_idx[0];
unsigned width = cp->bit_idx[1];
vvp_fun_signal_vec*sig = reinterpret_cast<vvp_fun_signal_vec*>(net->fun);
assert(sig);
if (base >= sig->size()) return true;
if (base+width > sig->size()) width = sig->size() - base;
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);
unlink_from_driver(src, dst_ptr);
sig->force_link = 0;
}
// Send a command to this signal to unforce itself.
/* Do we release all or part of the net? */
vvp_net_ptr_t ptr (net, 3);
if (full_sig) {
vvp_send_long(ptr, 3);
} else {
vvp_send_long_pv(ptr, 3, base, width);
}
return true;
return do_release_vec(thr, cp, false);
}
/* The type is 1 for registers and 0 for everything else. */
@ -4157,21 +4055,12 @@ bool of_RELEASE_WR(vthread_t thr, vvp_code_t cp)
vvp_net_t*net = cp->net;
unsigned type = cp->bit_idx[0];
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);
unlink_from_driver(src, dst_ptr);
sig->force_link = 0;
}
assert(net->fil);
net->fil->force_unlink();
// Send a command to this signal to unforce itself.
vvp_net_ptr_t ptr (net, 3);
vvp_send_long(ptr, 2 + type);
vvp_net_ptr_t ptr (net, 0);
net->fil->release(ptr, type==0);
return true;
}
@ -4269,7 +4158,8 @@ bool of_SET_X0(vthread_t thr, vvp_code_t cp)
// X0 register.
long index = thr->words[0].w_int;
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (net->fil);
assert(sig);
// If the entire part is below the beginning of the vector,
// then we are done.
@ -4278,7 +4168,7 @@ bool of_SET_X0(vthread_t thr, vvp_code_t cp)
// If the entire part is above then end of the vector, then we
// are done.
if (index >= (long)sig->size())
if (index >= (long)sig->value_size())
return true;
// If the part starts below the vector, then skip the first
@ -4291,8 +4181,8 @@ bool of_SET_X0(vthread_t thr, vvp_code_t cp)
}
// Reduce the width to keep the part inside the vector.
if (index+wid > sig->size())
wid = sig->size() - index;
if (index+wid > sig->value_size())
wid = sig->value_size() - index;
vvp_vector4_t bit_vec(wid);
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
@ -4303,7 +4193,7 @@ bool of_SET_X0(vthread_t thr, vvp_code_t cp)
}
vvp_net_ptr_t ptr (net, 0);
vvp_send_vec4_pv(ptr, bit_vec, index, wid, sig->size(), thr->wt_context);
vvp_send_vec4_pv(ptr, bit_vec, index, wid, sig->value_size(), thr->wt_context);
return true;
}

View File

@ -40,7 +40,7 @@ void island_send_value(vvp_net_t*net, const vvp_vector8_t&val)
return;
fun->outvalue = val;
vvp_send_vec8(net->out, fun->outvalue);
net->send_vec8(fun->outvalue);
}
/*

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@
# include "config.h"
# include "vpi_user.h"
# include "vvp_vpi_callback.h"
# include <stddef.h>
# include <stdlib.h>
# include <string.h>
@ -42,6 +43,7 @@ class vvp_scalar_t;
/* Basic netlist types. */
class vvp_net_t;
class vvp_net_fun_t;
class vvp_net_fil_t;
/* Core net function types. */
class vvp_fun_concat;
@ -195,6 +197,9 @@ class vvp_vector4_t {
friend class vvp_vector4array_sa;
friend class vvp_vector4array_aa;
public:
static const vvp_vector4_t nil;
public:
explicit vvp_vector4_t(unsigned size =0, vvp_bit4_t bits =BIT4_X);
@ -634,9 +639,15 @@ extern vvp_vector2_t operator % (const vvp_vector2_t&, const vvp_vector2_t&);
vvp_vector2_t pow(const vvp_vector2_t&, vvp_vector2_t&);
extern vvp_vector4_t vector2_to_vector4(const vvp_vector2_t&, unsigned wid);
/* A c4string is of the form C4<...> where ... are bits. */
extern bool c4string_test(const char*str);
extern vvp_vector4_t c4string_to_vector4(const char*str);
/* A crstring is of the form Cr<...> where ... defines are real. */
extern bool crstring_test(const char*str);
extern double crstring_to_double(const char*str);
extern ostream& operator<< (ostream&, const vvp_vector2_t&);
/* Inline some of the vector2_t methods. */
@ -777,10 +788,15 @@ class vvp_vector8_t {
~vvp_vector8_t();
static const vvp_vector8_t nil;
public:
unsigned size() const { return size_; }
vvp_scalar_t value(unsigned idx) const;
vvp_vector8_t subvalue(unsigned adr, unsigned width) const;
void set_bit(unsigned idx, vvp_scalar_t val);
void set_vec(unsigned idx, const vvp_vector8_t&that);
// Test that the vectors are exactly equal
bool eeq(const vvp_vector8_t&that) const;
@ -821,6 +837,11 @@ extern vvp_vector8_t resistive_reduction(const vvp_vector8_t&a);
strength information in the process. */
extern vvp_vector4_t reduce4(const vvp_vector8_t&that);
extern vvp_vector8_t part_expand(const vvp_vector8_t&a, unsigned wid, unsigned off);
/* A c8string is of the form C8<...> where ... are bits. */
extern bool c8string_test(const char*str);
extern vvp_vector8_t c8string_to_vector8(const char*str);
/* Print a vector8 value to a stream. */
extern ostream& operator<< (ostream&, const vvp_vector8_t&);
@ -961,15 +982,52 @@ template <class T> ostream& operator << (ostream&out, vvp_sub_pointer_t<T> val)
* the fan-out is unlimited.
*
* The vvp_send_*() functions take as input a vvp_net_ptr_t and follow
* all the fan-out chain, delivering the specified value.
* all the fan-out chain, delivering the specified value. The send_*()
* methods of the vvp_net_t class are similar, but they follow the
* output, possibly filtered, from the vvp_net_t.
*/
struct vvp_net_t {
class vvp_net_t {
public:
vvp_net_t();
#ifdef CHECK_WITH_VALGRIND
vvp_net_t *pool;
#endif
vvp_net_ptr_t port[4];
vvp_net_ptr_t out;
vvp_net_fun_t*fun;
vvp_net_fil_t*fil;
public:
// Connect the port to the output from this net.
void link(vvp_net_ptr_t port);
// Disconnect the port from the output of this net.
void unlink(vvp_net_ptr_t port);
public: // Methods to propagate output from this node.
void send_vec4(const vvp_vector4_t&val, vvp_context_t context);
void send_vec8(const vvp_vector8_t&val);
void send_real(double val, vvp_context_t context);
void send_long(long val);
void send_vec4_pv(const vvp_vector4_t&val,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t context);
void send_vec8_pv(const vvp_vector8_t&val,
unsigned base, unsigned wid, unsigned vwid);
public: // Methods to arrange for the output of this net to be forced.
// The intent is that all efforts at force are directed to
// operate only on the vvp_net_t whose output is to be
// forced. These methods then communicate the force to the
// attached filter to set up the actual force.
void force_vec4(const vvp_vector4_t&val, vvp_vector2_t mask);
void force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask);
void force_real(double val, vvp_vector2_t mask);
private:
vvp_net_ptr_t out_;
public: // Need a better new for these objects.
static void* operator new(std::size_t size);
@ -1044,6 +1102,86 @@ class vvp_net_fun_t {
static void operator delete[](void*);
};
/*
* A vvp_net_fil_t is a filter object that filters an output from a
* vvp_net_t. The send_*() methods of the vvp_net_t object call the
* filter of the output being transmitted. The filter function will
* decide if this value is to be propagated, and return true or
* false. If false, then send_*() continues as usual. If false, output
* propagation is stopped.
*
* The filter object also provides an implementation hooks for
* force/release.
*/
class vvp_net_fil_t : public vvp_vpi_callback {
public:
vvp_net_fil_t();
virtual ~vvp_net_fil_t();
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.
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,
unsigned base, unsigned vwid);
virtual prop_t filter_real(double&val);
virtual prop_t filter_long(long&val);
virtual void release(vvp_net_ptr_t ptr, bool net_flag) =0;
virtual void release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag) =0;
// 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. */
void force_link(vvp_net_t*dst, vvp_net_t*src);
void force_unlink(void);
virtual unsigned filter_size() const =0;
public:
// Suport for force methods
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;
protected:
// Set bits of the filter force mask
void force_mask(vvp_vector2_t mask);
// Release the force on the bits set in the mask.
void release_mask(vvp_vector2_t mask);
// Test bits of the filter force mask;
bool test_force_mask(unsigned bit) const;
bool test_force_mask_is_zero() const;
// This template method is used by derived classes to process
// the val through the force mask. The force value is the
// currently forced value, and the buf is a value that this
// method will use to hold a filtered value, if needed. This
// method returns a pointer to val or buf.
template <class T> prop_t filter_mask_(const T&val, const T&force, T&rep, unsigned addr);
// This template method is similar to the above, but works for
// native types that are not so expensive to edit in place.
template <class T> prop_t filter_mask_(T&val, T force);
private:
// Mask of forced bits
vvp_vector2_t force_mask_;
// True if the next filter must propagate. Need this to allow
// the forced value to get through.
bool force_propagate_;
// force link back.
struct vvp_net_t*force_link_;
};
/* **** Some core net functions **** */
/* vvp_fun_concat
@ -1072,6 +1210,27 @@ class vvp_fun_concat : public vvp_net_fun_t {
vvp_vector4_t val_;
};
/*
* 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.
*
* This functor is also special in that we know a priori that only
* port-0 is used, so we can use ports 1-3 for local storage. See the
* implementation of vvp_filter_wire_base::force_link in
* vvp_net_sig.cc for details.
*/
class vvp_fun_force : public vvp_net_fun_t {
public:
vvp_fun_force();
~vvp_fun_force();
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
void recv_real(vvp_net_ptr_t port, double bit, vvp_context_t);
};
/* vvp_fun_repeat
* This node function create vectors by repeating the input. The width
* is the width of the output vector, and the repeat is the number of
@ -1137,325 +1296,6 @@ class vvp_fun_extend_signed : public vvp_net_fun_t {
unsigned width_;
};
/* vvp_fun_signal
* This node is the place holder in a vvp network for signals,
* including nets of various sort. The output from a signal follows
* the type of its port-0 input. If vvp_vector4_t values come in
* through port-0, then vvp_vector4_t values are propagated. If
* vvp_vector8_t values come in through port-0, then vvp_vector8_t
* values are propagated. Thus, this node is slightly polymorphic.
*
* If the signal is a net (i.e. a wire or tri) then this node will
* have an input that is the data source. The data source will connect
* through port-0.
*
* If the signal is a reg, then there will be no netlist input, the
* values will be written by behavioral statements. The %set and
* %assign statements will write through port-0.
*
* In any case, behavioral code is able to read the value that this
* node last propagated, by using the value() method. That is important
* functionality of this node.
*
* Continuous assignments are made through port-1. When a value is
* written here, continuous assign mode is activated, and input
* through port-0 is ignored until continuous assign mode is turned
* off again. Writing into this port can be done in behavioral code
* using the %cassign/v instruction, or can be done by the network by
* hooking the output of a vvp_net_t to this port.
*
* Force assignments are made through port-2. When a value is written
* here, force mode is activated. In force mode, port-0 data (or
* port-1 data if in continuous assign mode) is tracked but not
* propagated. The force value is propagated and is what is readable
* through the value method.
*
* Port-3 is a command port, intended for use by procedural
* instructions. The client must write long values to this port to
* invoke the command of interest. The command values are:
*
* 1 -- deassign
* The deassign command takes the node out of continuous
* assignment mode. The output value is unchanged, and force
* mode, if active, remains in effect.
*
* 2 -- release/net
* The release/net command takes the node out of force mode,
* and propagates the tracked port-0 value to the signal
* output. This acts like a release of a net signal.
*
* 3 -- release/reg
* The release/reg command is similar to the release/net
* command, but the port-0 value is not propagated. Changes
* to port-0 (or port-1 if continuous assign is active) will
* propagate starting at the next input change.
*/
/*
* Things derived from vvp_vpi_callback may also be array'ed, so it
* includes some members that arrays use.
*/
class vvp_vpi_callback {
public:
vvp_vpi_callback();
virtual ~vvp_vpi_callback();
virtual void run_vpi_callbacks();
void add_vpi_callback(struct __vpiCallback*);
#ifdef CHECK_WITH_VALGRIND
/* This has only been tested at EOS. */
void clear_all_callbacks(void);
#endif
virtual void get_value(struct t_vpi_value*value) =0;
private:
struct __vpiCallback*vpi_callbacks_;
};
class vvp_vpi_callback_wordable : public vvp_vpi_callback {
public:
vvp_vpi_callback_wordable();
~vvp_vpi_callback_wordable();
void run_vpi_callbacks();
void attach_as_word(class __vpiArray* arr, unsigned long addr);
private:
class __vpiArray* array_;
unsigned long array_word_;
};
class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback_wordable {
public:
vvp_fun_signal_base();
void recv_long(vvp_net_ptr_t port, long bit);
void recv_long_pv(vvp_net_ptr_t port, long bit,
unsigned base, unsigned wid);
public:
/* 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;
struct vvp_net_t*cassign_link;
protected:
// This is true until at least one propagation happens.
bool needs_init_;
bool continuous_assign_active_;
vvp_vector2_t force_mask_;
vvp_vector2_t assign_mask_;
void deassign();
void deassign_pv(unsigned base, unsigned wid);
virtual void release(vvp_net_ptr_t ptr, bool net) =0;
virtual void release_pv(vvp_net_ptr_t ptr, bool net,
unsigned base, unsigned wid) =0;
};
/*
* This abstract class is a little more specific than the signal_base
* class, in that it adds vector access methods.
*/
class vvp_fun_signal_vec : public vvp_fun_signal_base {
public:
// For vector signal types, this returns the vector count.
virtual unsigned size() const =0;
virtual vvp_bit4_t value(unsigned idx) const =0;
virtual vvp_scalar_t scalar_value(unsigned idx) const =0;
virtual vvp_vector4_t vec4_value() const =0;
};
class vvp_fun_signal4 : public vvp_fun_signal_vec {
public:
explicit vvp_fun_signal4() {};
void get_value(struct t_vpi_value*value);
};
/*
* Statically allocated vvp_fun_signal4.
*/
class vvp_fun_signal4_sa : public vvp_fun_signal4 {
public:
explicit vvp_fun_signal4_sa(unsigned wid, vvp_bit4_t init=BIT4_X);
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
// Part select variants of above
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t);
void recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid);
// Get information about the vector value.
unsigned size() const;
vvp_bit4_t value(unsigned idx) const;
vvp_scalar_t scalar_value(unsigned idx) const;
vvp_vector4_t vec4_value() const;
// Commands
void release(vvp_net_ptr_t port, bool net);
void release_pv(vvp_net_ptr_t port, bool net,
unsigned base, unsigned wid);
private:
void calculate_output_(vvp_net_ptr_t ptr);
vvp_vector4_t bits4_;
vvp_vector4_t force_;
};
/*
* Automatically allocated vvp_fun_signal4.
*/
class vvp_fun_signal4_aa : public vvp_fun_signal4, public automatic_hooks_s {
public:
explicit vvp_fun_signal4_aa(unsigned wid, vvp_bit4_t init=BIT4_X);
void alloc_instance(vvp_context_t context);
void reset_instance(vvp_context_t context);
#ifdef CHECK_WITH_VALGRIND
void free_instance(vvp_context_t context);
#endif
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
// Part select variants of above
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t);
// Get information about the vector value.
unsigned size() const;
vvp_bit4_t value(unsigned idx) const;
vvp_scalar_t scalar_value(unsigned idx) const;
vvp_vector4_t vec4_value() const;
// Commands
void release(vvp_net_ptr_t port, bool net);
void release_pv(vvp_net_ptr_t port, bool net,
unsigned base, unsigned wid);
private:
unsigned context_idx_;
unsigned size_;
};
class vvp_fun_signal8 : public vvp_fun_signal_vec {
public:
explicit vvp_fun_signal8(unsigned wid);
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
// Part select variants of above
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t context);
void recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid);
// Get information about the vector value.
unsigned size() const;
vvp_bit4_t value(unsigned idx) const;
vvp_scalar_t scalar_value(unsigned idx) const;
vvp_vector4_t vec4_value() const;
// Commands
void release(vvp_net_ptr_t port, bool net);
void release_pv(vvp_net_ptr_t port, bool net,
unsigned base, unsigned wid);
void get_value(struct t_vpi_value*value);
private:
void calculate_output_(vvp_net_ptr_t ptr);
vvp_vector8_t bits8_;
vvp_vector8_t force_;
};
class vvp_fun_signal_real : public vvp_fun_signal_base {
public:
explicit vvp_fun_signal_real() {};
// Get information about the vector value.
virtual double real_value() const = 0;
void get_value(struct t_vpi_value*value);
};
/*
* Statically allocated vvp_fun_signal_real.
*/
class vvp_fun_signal_real_sa : public vvp_fun_signal_real {
public:
explicit vvp_fun_signal_real_sa();
void recv_real(vvp_net_ptr_t port, double bit,
vvp_context_t);
// Get information about the vector value.
double real_value() const;
// Commands
void release(vvp_net_ptr_t port, bool net);
void release_pv(vvp_net_ptr_t port, bool net,
unsigned base, unsigned wid);
private:
double bits_;
double force_;
};
/*
* Automatically allocated vvp_fun_signal_real.
*/
class vvp_fun_signal_real_aa : public vvp_fun_signal_real, public automatic_hooks_s {
public:
explicit vvp_fun_signal_real_aa();
void alloc_instance(vvp_context_t context);
void reset_instance(vvp_context_t context);
#ifdef CHECK_WITH_VALGRIND
void free_instance(vvp_context_t context);
#endif
void recv_real(vvp_net_ptr_t port, double bit,
vvp_context_t context);
// Get information about the vector value.
double real_value() const;
// Commands
void release(vvp_net_ptr_t port, bool net);
void release_pv(vvp_net_ptr_t port, bool net,
unsigned base, unsigned wid);
private:
unsigned context_idx_;
};
/*
* Wide Functors:
* Wide functors represent special devices that may have more than 4
@ -1536,8 +1376,7 @@ class vvp_wide_fun_t : public vvp_net_fun_t {
};
inline void vvp_send_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&val,
vvp_context_t context)
inline void vvp_send_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&val, vvp_context_t context)
{
while (struct vvp_net_t*cur = ptr.ptr()) {
vvp_net_ptr_t next = cur->port[ptr.port()];
@ -1576,8 +1415,8 @@ extern void vvp_send_long_pv(vvp_net_ptr_t ptr, long val,
* mirror of the destination vector.
*/
inline void vvp_send_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&val,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t context)
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t context)
{
while (struct vvp_net_t*cur = ptr.ptr()) {
vvp_net_ptr_t next = cur->port[ptr.port()];
@ -1589,9 +1428,10 @@ inline void vvp_send_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&val,
}
}
inline void vvp_send_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&val,
unsigned base, unsigned wid, unsigned vwid)
inline void vvp_net_t::send_vec8_pv(const vvp_vector8_t&val,
unsigned base, unsigned wid, unsigned vwid)
{
vvp_net_ptr_t ptr = out_;
while (struct vvp_net_t*cur = ptr.ptr()) {
vvp_net_ptr_t next = cur->port[ptr.port()];
@ -1602,4 +1442,95 @@ inline void vvp_send_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&val,
}
}
inline void vvp_net_t::send_vec4(const vvp_vector4_t&val, vvp_context_t context)
{
if (fil == 0) {
vvp_send_vec4(out_, val, context);
return;
}
vvp_vector4_t rep;
switch (fil->filter_vec4(val, rep, 0, val.size())) {
case vvp_net_fil_t::STOP:
break;
case vvp_net_fil_t::PROP:
vvp_send_vec4(out_, val, context);
break;
case vvp_net_fil_t::REPL:
vvp_send_vec4(out_, rep, context);
break;
}
}
inline void vvp_net_t::send_vec4_pv(const vvp_vector4_t&val,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t context)
{
if (fil == 0) {
vvp_send_vec4_pv(out_, val, base, wid, vwid, context);
return;
}
assert(val.size() == wid);
vvp_vector4_t rep;
switch (fil->filter_vec4(val, rep, base, vwid)) {
case vvp_net_fil_t::STOP:
break;
case vvp_net_fil_t::PROP:
vvp_send_vec4_pv(out_, val, base, wid, vwid, context);
break;
case vvp_net_fil_t::REPL:
vvp_send_vec4_pv(out_, rep, base, wid, vwid, context);
break;
}
}
inline void vvp_net_t::send_vec8(const vvp_vector8_t&val)
{
if (fil == 0) {
vvp_send_vec8(out_, val);
return;
}
vvp_vector8_t rep;
switch (fil->filter_vec8(val, rep, 0, val.size())) {
case vvp_net_fil_t::STOP:
break;
case vvp_net_fil_t::PROP:
vvp_send_vec8(out_, val);
break;
case vvp_net_fil_t::REPL:
vvp_send_vec8(out_, rep);
break;
}
}
inline void vvp_net_t::send_real(double val, vvp_context_t context)
{
if (fil && ! fil->filter_real(val))
return;
vvp_send_real(out_, val, context);
}
inline bool vvp_net_fil_t::test_force_mask(unsigned bit) const
{
if (bit >= force_mask_.size())
return false;
if (force_mask_.value(bit))
return true;
else
return false;
}
inline bool vvp_net_fil_t::test_force_mask_is_zero(void) const
{
if (force_mask_.size() == 0)
return true;
if (force_mask_.is_zero())
return true;
return false;
}
#endif

994
vvp/vvp_net_sig.cc Normal file
View File

@ -0,0 +1,994 @@
/*
* Copyright (c) 2004-2009 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include "vvp_net.h"
# include "vvp_net_sig.h"
# include "statistics.h"
# include "vpi_priv.h"
# include <assert.h>
#ifdef CHECK_WITH_VALGRIND
# include <valgrind/memcheck.h>
# include <map>
#endif
# include <iostream>
template <class T> vvp_net_fil_t::prop_t vvp_net_fil_t::filter_mask_(const T&val, const T&force, T&filter, unsigned base)
{
if (!test_force_mask_is_zero()) {
bool propagate_flag = force_propagate_;
force_propagate_ = false;
assert(force_mask_.size() == force.size());
assert((base+val.size()) <= force_mask_.size());
filter = val;
for (unsigned idx = 0 ; idx < val.size() ; idx += 1) {
if (force_mask_.value(base+idx))
filter.set_bit(idx, force.value(base+idx));
else
propagate_flag = true;
}
if (propagate_flag) {
run_vpi_callbacks();
return REPL;
} else {
return STOP;
}
} else {
run_vpi_callbacks();
return PROP;
}
}
template <class T> vvp_net_fil_t::prop_t vvp_net_fil_t::filter_mask_(T&val, T force)
{
if (test_force_mask(0)) {
val = force;
run_vpi_callbacks();
return REPL;
}
run_vpi_callbacks();
return PROP;
}
vvp_signal_value::~vvp_signal_value()
{
}
double vvp_signal_value::real_value() const
{
assert(0);
return 0;
}
void vvp_net_t::force_vec4(const vvp_vector4_t&val, vvp_vector2_t mask)
{
assert(fil);
fil->force_fil_vec4(val, mask);
vvp_send_vec4(out_, val, 0);
}
void vvp_net_t::force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask)
{
assert(fil);
fil->force_fil_vec8(val, mask);
vvp_send_vec8(out_, val);
}
void vvp_net_t::force_real(double val, vvp_vector2_t mask)
{
assert(fil);
fil->force_fil_real(val, mask);
vvp_send_real(out_, val, 0);
}
/* **** vvp_fun_signal methods **** */
vvp_fun_signal_base::vvp_fun_signal_base()
{
continuous_assign_active_ = false;
needs_init_ = true;
cassign_link = 0;
count_functors_sig += 1;
}
vvp_fun_signal4_sa::vvp_fun_signal4_sa(unsigned wid, vvp_bit4_t init)
: bits4_(wid, init)
{
}
/*
* Nets simply reflect their input to their output.
*
* NOTE: It is a quirk of vvp_fun_signal that it has an initial value
* that needs to be propagated, but after that it only needs to
* propagate if the value changes. Eliminating duplicate propagations
* should improve performance, but has the quirk that an input that
* matches the initial value might not be propagated. The hack used
* herein is to keep a "needs_init_" flag that is turned false after
* the first propagation, and forces the first propagation to happen
* even if it matches the initial value.
*/
void vvp_fun_signal4_sa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_context_t)
{
switch (ptr.port()) {
case 0: // Normal input (feed from net, or set from process)
/* If we don't have a continuous assign mask then just
copy the bits, otherwise we need to see if there are
any holes in the mask so we can set those bits. */
if (assign_mask_.size() == 0) {
if (needs_init_ || !bits4_.eeq(bit)) {
assert(bit.size() == bits4_.size());
bits4_ = bit;
needs_init_ = false;
ptr.ptr()->send_vec4(bits4_, 0);
}
} else {
bool changed = false;
assert(bits4_.size() == assign_mask_.size());
for (unsigned idx = 0 ; idx < bit.size() ; idx += 1) {
if (idx >= bits4_.size()) break;
if (assign_mask_.value(idx)) continue;
bits4_.set_bit(idx, bit.value(idx));
changed = true;
}
if (changed) {
needs_init_ = false;
ptr.ptr()->send_vec4(bits4_, 0);
}
}
break;
case 1: // Continuous assign value
bits4_ = bit;
assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, bits4_.size());
ptr.ptr()->send_vec4(bits4_, 0);
break;
default:
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
assert(0);
break;
}
}
void vvp_fun_signal4_sa::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
{
recv_vec4(ptr, reduce4(bit), 0);
}
void vvp_fun_signal4_sa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t)
{
assert(bit.size() == wid);
assert(bits4_.size() == vwid);
switch (ptr.port()) {
case 0: // Normal input
if (assign_mask_.size() == 0) {
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (base+idx >= bits4_.size()) break;
bits4_.set_bit(base+idx, bit.value(idx));
}
needs_init_ = false;
ptr.ptr()->send_vec4(bits4_,0);
} else {
bool changed = false;
assert(bits4_.size() == assign_mask_.size());
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (base+idx >= bits4_.size()) break;
if (assign_mask_.value(base+idx)) continue;
bits4_.set_bit(base+idx, bit.value(idx));
changed = true;
}
if (changed) {
needs_init_ = false;
ptr.ptr()->send_vec4(bits4_,0);
}
}
break;
case 1: // Continuous assign value
if (assign_mask_.size() == 0)
assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, bits4_.size());
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (base+idx >= bits4_.size())
break;
bits4_.set_bit(base+idx, bit.value(idx));
assign_mask_.set_bit(base+idx, 1);
}
ptr.ptr()->send_vec4(bits4_,0);
break;
default:
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
assert(0);
break;
}
}
void vvp_fun_signal4_sa::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid)
{
recv_vec4_pv(ptr, reduce4(bit), base, wid, vwid, 0);
}
void vvp_fun_signal_base::deassign()
{
continuous_assign_active_ = false;
assign_mask_ = vvp_vector2_t();
}
void vvp_fun_signal_base::deassign_pv(unsigned base, unsigned wid)
{
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
assign_mask_.set_bit(base+idx, 0);
}
if (assign_mask_.is_zero()) {
assign_mask_ = vvp_vector2_t();
}
}
void automatic_signal_base::release(vvp_net_ptr_t,bool)
{
assert(0);
}
void automatic_signal_base::release_pv(vvp_net_ptr_t,unsigned,unsigned,bool)
{
assert(0);
}
unsigned automatic_signal_base::filter_size() const
{
assert(0);
}
void automatic_signal_base::force_fil_vec4(const vvp_vector4_t&, vvp_vector2_t)
{
assert(0);
}
void automatic_signal_base::force_fil_vec8(const vvp_vector8_t&, vvp_vector2_t)
{
assert(0);
}
void automatic_signal_base::force_fil_real(double, vvp_vector2_t)
{
assert(0);
}
void automatic_signal_base::get_value(struct t_vpi_value*)
{
assert(0);
}
vvp_vector4_t vvp_fun_signal4_sa::vec4_unfiltered_value() const
{
return bits4_;
}
vvp_fun_signal4_aa::vvp_fun_signal4_aa(unsigned wid, vvp_bit4_t init)
{
context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope());
size_ = wid;
}
void vvp_fun_signal4_aa::alloc_instance(vvp_context_t context)
{
vvp_set_context_item(context, context_idx_, new vvp_vector4_t(size_));
}
void vvp_fun_signal4_aa::reset_instance(vvp_context_t context)
{
vvp_vector4_t*bits = static_cast<vvp_vector4_t*>
(vvp_get_context_item(context, context_idx_));
bits->set_to_x();
}
#ifdef CHECK_WITH_VALGRIND
void vvp_fun_signal4_aa::free_instance(vvp_context_t context)
{
vvp_vector4_t*bits = static_cast<vvp_vector4_t*>
(vvp_get_context_item(context, context_idx_));
delete bits;
}
#endif
/*
* Continuous and forced assignments are not permitted on automatic
* variables. So we only expect to receive on port 0.
*/
void vvp_fun_signal4_aa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_context_t context)
{
assert(ptr.port() == 0);
assert(context);
vvp_vector4_t*bits4 = static_cast<vvp_vector4_t*>
(vvp_get_context_item(context, context_idx_));
if (!bits4->eeq(bit)) {
*bits4 = bit;
ptr.ptr()->send_vec4(*bits4, context);
}
}
void vvp_fun_signal4_aa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t context)
{
assert(ptr.port() == 0);
assert(bit.size() == wid);
assert(size_ == vwid);
assert(context);
vvp_vector4_t*bits4 = static_cast<vvp_vector4_t*>
(vvp_get_context_item(context, context_idx_));
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (base+idx >= bits4->size()) break;
bits4->set_bit(base+idx, bit.value(idx));
}
ptr.ptr()->send_vec4(*bits4, context);
}
unsigned vvp_fun_signal4_aa::value_size() const
{
return size_;
}
vvp_bit4_t vvp_fun_signal4_aa::value(unsigned idx) const
{
vvp_vector4_t*bits4 = static_cast<vvp_vector4_t*>
(vthread_get_rd_context_item(context_idx_));
return bits4->value(idx);
}
vvp_scalar_t vvp_fun_signal4_aa::scalar_value(unsigned idx) const
{
vvp_vector4_t*bits4 = static_cast<vvp_vector4_t*>
(vthread_get_rd_context_item(context_idx_));
return vvp_scalar_t(bits4->value(idx), 6, 6);
}
vvp_vector4_t vvp_fun_signal4_aa::vec4_value() const
{
vvp_vector4_t*bits4 = static_cast<vvp_vector4_t*>
(vthread_get_rd_context_item(context_idx_));
return *bits4;
}
vvp_vector4_t vvp_fun_signal4_aa::vec4_unfiltered_value() const
{
return vec4_value();
}
vvp_fun_signal8::vvp_fun_signal8(unsigned wid)
: bits8_(wid)
{
}
void vvp_fun_signal8::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_context_t)
{
recv_vec8(ptr, vvp_vector8_t(bit,6,6));
}
void vvp_fun_signal8::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
{
switch (ptr.port()) {
case 0: // Normal input (feed from net, or set from process)
if (needs_init_ || !bits8_.eeq(bit)) {
bits8_ = bit;
needs_init_ = false;
ptr.ptr()->send_vec8(bits8_);
}
break;
case 1: // Continuous assign value
/* This is a procedural continuous assign and it can
* only be used on a register and a register is never
* strength aware. */
assert(0);
break;
default:
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
assert(0);
break;
}
}
void vvp_fun_signal8::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t)
{
recv_vec8_pv(ptr, vvp_vector8_t(bit,6,6), base, wid, vwid);
}
void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid)
{
assert(bit.size() == wid);
assert(bits8_.size() == vwid);
switch (ptr.port()) {
case 0: // Normal input
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (base+idx >= bits8_.size()) break;
bits8_.set_bit(base+idx, bit.value(idx));
}
needs_init_ = false;
ptr.ptr()->send_vec8(bits8_);
break;
case 1: // Continuous assign value
/* This is a procedural continuous assign and it can
* only be used on a register and a register is never
* strength aware. */
assert(0);
break;
default:
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
assert(0);
break;
}
}
/*
* Testing for equality, we want a bitwise test instead of an
* arithmetic test because we want to treat for example -0 different
* from +0.
*/
bool bits_equal(double a, double b)
{
return memcmp(&a, &b, sizeof a) == 0;
}
vvp_fun_signal_real_sa::vvp_fun_signal_real_sa()
{
bits_ = 0.0;
}
double vvp_fun_signal_real_sa::real_unfiltered_value() const
{
return bits_;
}
void vvp_fun_signal_real_sa::recv_real(vvp_net_ptr_t ptr, double bit,
vvp_context_t)
{
switch (ptr.port()) {
case 0:
if (!continuous_assign_active_) {
if (needs_init_ || !bits_equal(bits_, bit)) {
bits_ = bit;
needs_init_ = false;
ptr.ptr()->send_real(bit, 0);
}
}
break;
case 1: // Continuous assign value
continuous_assign_active_ = true;
bits_ = bit;
ptr.ptr()->send_real(bit, 0);
break;
default:
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
assert(0);
break;
}
}
vvp_fun_signal_real_aa::vvp_fun_signal_real_aa()
{
context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope());
}
void vvp_fun_signal_real_aa::alloc_instance(vvp_context_t context)
{
double*bits = new double;
vvp_set_context_item(context, context_idx_, bits);
*bits = 0.0;
}
void vvp_fun_signal_real_aa::reset_instance(vvp_context_t context)
{
double*bits = static_cast<double*>
(vvp_get_context_item(context, context_idx_));
*bits = 0.0;
}
#ifdef CHECK_WITH_VALGRIND
void vvp_fun_signal_real_aa::free_instance(vvp_context_t context)
{
double*bits = static_cast<double*>
(vvp_get_context_item(context, context_idx_));
delete bits;
}
#endif
double vvp_fun_signal_real_aa::real_unfiltered_value() const
{
double*bits = static_cast<double*>
(vthread_get_rd_context_item(context_idx_));
return *bits;
}
double vvp_fun_signal_real_aa::real_value() const
{
return real_unfiltered_value();
}
void vvp_fun_signal_real_aa::recv_real(vvp_net_ptr_t ptr, double bit,
vvp_context_t context)
{
assert(ptr.port() == 0);
assert(context);
double*bits = static_cast<double*>
(vvp_get_context_item(context, context_idx_));
if (!bits_equal(*bits,bit)) {
*bits = bit;
ptr.ptr()->send_real(bit, context);
}
}
unsigned vvp_fun_signal_real_aa::value_size() const
{
assert(0);
return 1;
}
vvp_bit4_t vvp_fun_signal_real_aa::value(unsigned idx) const
{
assert(0);
}
vvp_scalar_t vvp_fun_signal_real_aa::scalar_value(unsigned idx) const
{
assert(0);
}
vvp_vector4_t vvp_fun_signal_real_aa::vec4_value() const
{
assert(0);
}
vvp_fun_force::vvp_fun_force()
{
}
vvp_fun_force::~vvp_fun_force()
{
}
void vvp_fun_force::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_context_t)
{
assert(ptr.port() == 0);
vvp_net_t*net = ptr.ptr();
vvp_net_t*dst = net->port[3].ptr();
assert(dst->fil);
dst->force_vec4(coerce_to_width(bit, dst->fil->filter_size()), vvp_vector2_t(vvp_vector2_t::FILL1, dst->fil->filter_size()));
}
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();
dst->force_real(bit, vvp_vector2_t(vvp_vector2_t::FILL1, 1));
}
vvp_wire_base::vvp_wire_base()
{
}
vvp_wire_base::~vvp_wire_base()
{
}
vvp_wire_vec4::vvp_wire_vec4(unsigned wid, vvp_bit4_t init)
: bits4_(wid, init)
{
needs_init_ = true;
}
vvp_net_fil_t::prop_t vvp_wire_vec4::filter_vec4(const vvp_vector4_t&bit, vvp_vector4_t&rep,
unsigned base, unsigned vwid)
{
// Special case! the input bit is 0 wid. Interpret this as a
// vector of BIT4_X to match the width of the bits4_ vector.
// FIXME! This is a hack to work around some buggy gate
// implementations! This should be removed!
if (base==0 && vwid==0) {
vvp_vector4_t tmp (bits4_.size(), BIT4_X);
if (bits4_ .eeq(tmp) && !needs_init_) return STOP;
bits4_ = tmp;
needs_init_ = false;
return filter_mask_(tmp, force4_, rep, 0);
}
if (vwid != bits4_.size()) {
cerr << "Internal error: Input vector expected width="
<< bits4_.size() << ", got "
<< "bit=" << bit << ", base=" << base << ", vwid=" << vwid
<< endl;
}
assert(bits4_.size() == vwid);
// Keep track of the value being driven from this net, even if
// it is not ultimately what survives the force filter.
if (base==0 && bit.size()==vwid) {
if (bits4_ .eeq( bit ) && !needs_init_) return STOP;
bits4_ = bit;
} else {
bits4_.set_vec(base, bit);
}
needs_init_ = false;
return filter_mask_(bit, force4_, rep, base);
}
vvp_net_fil_t::prop_t vvp_wire_vec4::filter_vec8(const vvp_vector8_t&bit, vvp_vector8_t&rep, unsigned base, unsigned vwid)
{
assert(bits4_.size() == bit.size());
bits4_ = reduce4(bit);
return filter_mask_(bit, vvp_vector8_t(force4_,6,6), rep, 0);
}
unsigned vvp_wire_vec4::filter_size() const
{
return bits4_.size();
}
void vvp_wire_vec4::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask)
{
force_mask(mask);
if (force4_.size() == 0) {
force4_ = val;
} else {
for (unsigned idx = 0; idx < mask.size() ; idx += 1) {
if (mask.value(idx) == 0)
continue;
force4_.set_bit(idx, val.value(idx));
}
}
run_vpi_callbacks();
}
void vvp_wire_vec4::force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask)
{
assert(0);
}
void vvp_wire_vec4::force_fil_real(double val, vvp_vector2_t mask)
{
assert(0);
}
void vvp_wire_vec4::release(vvp_net_ptr_t ptr, bool net_flag)
{
// Wires revert to their unforced value after release.
vvp_vector2_t mask (vvp_vector2_t::FILL1, bits4_.size());
release_mask(mask);
if (net_flag) {
ptr.ptr()->send_vec4(bits4_, 0);
run_vpi_callbacks();
} else {
ptr.ptr()->fun->recv_vec4(ptr, force4_, 0);
}
}
void vvp_wire_vec4::release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag)
{
assert(bits4_.size() >= base + wid);
vvp_vector2_t mask (vvp_vector2_t::FILL0, bits4_.size());
for (unsigned idx = 0 ; idx < wid ; idx += 1)
mask.set_bit(base+idx, 1);
release_mask(mask);
if (net_flag) {
ptr.ptr()->send_vec4_pv(bits4_.subvalue(base,wid),
base, wid, bits4_.size(), 0);
run_vpi_callbacks();
} else {
ptr.ptr()->fun->recv_vec4_pv(ptr, force4_.subvalue(base,wid),
base, wid, bits4_.size(), 0);
}
}
unsigned vvp_wire_vec4::value_size() const
{
return bits4_.size();
}
vvp_bit4_t vvp_wire_vec4::filtered_value_(unsigned idx) const
{
if (test_force_mask(idx))
return force4_.value(idx);
else
return bits4_.value(idx);
}
vvp_bit4_t vvp_wire_vec4::value(unsigned idx) const
{
return filtered_value_(idx);
}
vvp_scalar_t vvp_wire_vec4::scalar_value(unsigned idx) const
{
return vvp_scalar_t(value(idx),6,6);
}
vvp_vector4_t vvp_wire_vec4::vec4_value() const
{
vvp_vector4_t tmp = bits4_;
for (unsigned idx = 0 ; idx < bits4_.size() ; idx += 1)
tmp.set_bit(idx, filtered_value_(idx));
return tmp;
}
vvp_wire_vec8::vvp_wire_vec8(unsigned wid)
: bits8_(wid)
{
needs_init_ = true;
}
vvp_net_fil_t::prop_t vvp_wire_vec8::filter_vec4(const vvp_vector4_t&bit, vvp_vector4_t&rep,
unsigned base, unsigned vwid)
{
// QUESTION: Is it really correct to propagate a vec4 if this
// is a vec8 node? In fact, it is really possible for a vec4
// value to get through to a vec8 filter?
vvp_vector8_t rep8;
prop_t rc = filter_vec8(vvp_vector8_t(bit,6,6), rep8, 0, vwid);
if (rc == REPL)
rep = reduce4(rep8);
needs_init_ = false;
return rc;
}
vvp_net_fil_t::prop_t vvp_wire_vec8::filter_vec8(const vvp_vector8_t&bit, vvp_vector8_t&rep, unsigned base, unsigned vwid)
{
assert(vwid == bits8_.size());
// Keep track of the value being driven from this net, even if
// it is not ultimately what survives the force filter.
if (base==0 && bit.size()==vwid) {
bits8_ = bit;
} else {
if (bits8_.size() == 0)
bits8_ = vvp_vector8_t(vwid);
assert(bits8_.size() == vwid);
bits8_.set_vec(base, bit);
}
needs_init_ = false;
return filter_mask_(bit, force8_, rep, base);
}
unsigned vvp_wire_vec8::filter_size() const
{
return bits8_.size();
}
void vvp_wire_vec8::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask)
{
force_fil_vec8(vvp_vector8_t(val,6,6), mask);
}
void vvp_wire_vec8::force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask)
{
force_mask(mask);
if (force8_.size() == 0) {
force8_ = val;
} else {
for (unsigned idx = 0; idx < mask.size() ; idx += 1) {
if (mask.value(idx) == 0)
continue;
force8_.set_bit(idx, val.value(idx));
}
}
run_vpi_callbacks();
}
void vvp_wire_vec8::force_fil_real(double val, vvp_vector2_t mask)
{
assert(0);
}
void vvp_wire_vec8::release(vvp_net_ptr_t ptr, bool net_flag)
{
// Wires revert to their unforced value after release.
vvp_vector2_t mask (vvp_vector2_t::FILL1, bits8_.size());
release_mask(mask);
if (net_flag)
ptr.ptr()->send_vec8(bits8_);
else
ptr.ptr()->fun->recv_vec8(ptr, force8_);
}
void vvp_wire_vec8::release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag)
{
assert(bits8_.size() >= base + wid);
vvp_vector2_t mask (vvp_vector2_t::FILL0, bits8_.size());
for (unsigned idx = 0 ; idx < wid ; idx += 1)
mask.set_bit(base+idx, 1);
release_mask(mask);
if (net_flag) {
ptr.ptr()->send_vec8_pv(bits8_.subvalue(base,wid),
base, wid, bits8_.size());
run_vpi_callbacks();
} else {
ptr.ptr()->fun->recv_vec8_pv(ptr, force8_.subvalue(base,wid),
base, wid, force8_.size());
}
}
unsigned vvp_wire_vec8::value_size() const
{
return bits8_.size();
}
vvp_scalar_t vvp_wire_vec8::filtered_value_(unsigned idx) const
{
if (test_force_mask(idx))
return force8_.value(idx);
else
return bits8_.value(idx);
}
vvp_bit4_t vvp_wire_vec8::value(unsigned idx) const
{
return filtered_value_(idx).value();
}
vvp_scalar_t vvp_wire_vec8::scalar_value(unsigned idx) const
{
return filtered_value_(idx);
}
vvp_vector8_t vvp_wire_vec8::vec8_value() const
{
vvp_vector8_t tmp = bits8_;
for (unsigned idx = 0 ; idx < bits8_.size() ; idx += 1)
tmp.set_bit(idx, filtered_value_(idx));
return tmp;
}
vvp_vector4_t vvp_wire_vec8::vec4_value() const
{
return reduce4(vec8_value());
}
vvp_wire_real::vvp_wire_real()
{
}
vvp_net_fil_t::prop_t vvp_wire_real::filter_real(double&bit)
{
bit_ = bit;
return filter_mask_(bit, force_);
}
unsigned vvp_wire_real::filter_size() const
{
assert(0);
return 0;
}
void vvp_wire_real::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask)
{
assert(0);
}
void vvp_wire_real::force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask)
{
assert(0);
}
void vvp_wire_real::force_fil_real(double val, vvp_vector2_t mask)
{
force_mask(mask);
if (mask.value(0))
force_ = val;
run_vpi_callbacks();
}
void vvp_wire_real::release(vvp_net_ptr_t ptr, bool net_flag)
{
// Wires revert to their unforced value after release.
vvp_vector2_t mask (vvp_vector2_t::FILL1, 1);
release_mask(mask);
if (net_flag)
ptr.ptr()->send_real(bit_, 0);
else
ptr.ptr()->fun->recv_real(ptr, force_, 0);
}
void vvp_wire_real::release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag)
{
vvp_vector2_t mask (vvp_vector2_t::FILL0, 1);
for (unsigned idx = 0 ; idx < wid ; idx += 1)
mask.set_bit(base+idx, 1);
release_mask(mask);
if (net_flag)
ptr.ptr()->send_real(bit_, 0);
else
ptr.ptr()->fun->recv_real(ptr, force_, 0);
}
unsigned vvp_wire_real::value_size() const
{
assert(0);
return 1;
}
vvp_bit4_t vvp_wire_real::value(unsigned idx) const
{
assert(0);
}
vvp_scalar_t vvp_wire_real::scalar_value(unsigned idx) const
{
assert(0);
}
vvp_vector4_t vvp_wire_real::vec4_value() const
{
assert(0);
}
double vvp_wire_real::real_value() const
{
if (test_force_mask(0))
return force_;
else
return bit_;
}

396
vvp/vvp_net_sig.h Normal file
View File

@ -0,0 +1,396 @@
#ifndef __vvp_net_sig_H
#define __vvp_net_sig_H
/*
* Copyright (c) 2004-2009 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include "vpi_user.h"
# include "vvp_net.h"
# include <stddef.h>
# include <stdlib.h>
# include <string.h>
# include <new>
# include <assert.h>
#ifdef HAVE_IOSFWD
# include <iosfwd>
#else
class ostream;
#endif
using namespace std;
/* vvp_fun_signal
* This node is the place holder in a vvp network for signals,
* including nets of various sort. The output from a signal follows
* the type of its port-0 input. If vvp_vector4_t values come in
* through port-0, then vvp_vector4_t values are propagated. If
* vvp_vector8_t values come in through port-0, then vvp_vector8_t
* values are propagated. Thus, this node is slightly polymorphic.
*
* If the signal is a net (i.e. a wire or tri) then this node will
* have an input that is the data source. The data source will connect
* through port-0.
*
* If the signal is a reg, then there will be no netlist input, the
* values will be written by behavioral statements. The %set and
* %assign statements will write through port-0.
*
* In any case, behavioral code is able to read the value that this
* node last propagated, by using the value() method. That is important
* functionality of this node.
*
* Continuous assignments are made through port-1. When a value is
* written here, continuous assign mode is activated, and input
* through port-0 is ignored until continuous assign mode is turned
* off again. Writing into this port can be done in behavioral code
* using the %cassign/v instruction, or can be done by the network by
* hooking the output of a vvp_net_t to this port.
*/
class vvp_fun_signal_base : public vvp_net_fun_t {
public:
vvp_fun_signal_base();
void deassign();
void deassign_pv(unsigned base, unsigned wid);
public:
/* The %cassign/link instruction needs a place to write the
source node of the force, so that subsequent %cassign and
%deassign instructions can undo the link as needed. */
struct vvp_net_t*cassign_link;
protected:
bool continuous_assign_active_;
vvp_vector2_t assign_mask_;
protected:
// This is true until at least one propagation happens.
bool needs_init_;
};
/*
* Variables and wires can have their values accessed, so this base
* class offers the unified concept of an acessible value.
*/
class vvp_signal_value {
public:
virtual ~vvp_signal_value() =0;
virtual unsigned value_size() const =0;
virtual vvp_bit4_t value(unsigned idx) const =0;
virtual vvp_scalar_t scalar_value(unsigned idx) const =0;
virtual vvp_vector4_t vec4_value() const =0;
virtual double real_value() const;
virtual void get_signal_value(struct t_vpi_value*vp);
};
/*
* This abstract class is a little more specific than the signal_base
* class, in that it adds vector access methods.
*/
class vvp_fun_signal_vec : public vvp_fun_signal_base {
public:
virtual vvp_vector4_t vec4_unfiltered_value() const =0;
};
class automatic_signal_base : public vvp_signal_value, public vvp_net_fil_t {
public:
// Automatic variables cannot be forced or released. Provide
// stubs that assert.
virtual void release(vvp_net_ptr_t ptr, bool net_flag);
virtual void release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag);
virtual unsigned filter_size() const;
virtual void force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask);
virtual void force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask);
virtual void force_fil_real(double val, vvp_vector2_t mask);
virtual void get_value(struct t_vpi_value*value);
};
/*
* Statically allocated vvp_fun_signal4.
*/
class vvp_fun_signal4_sa : public vvp_fun_signal_vec {
public:
explicit vvp_fun_signal4_sa(unsigned wid, vvp_bit4_t init=BIT4_X);
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
// Part select variants of above
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t);
void recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid);
// Get information about the vector value.
vvp_vector4_t vec4_unfiltered_value() const;
private:
vvp_vector4_t bits4_;
};
/*
* Automatically allocated vvp_fun_signal4.
*/
class vvp_fun_signal4_aa : public vvp_fun_signal_vec, public automatic_signal_base, public automatic_hooks_s {
public:
explicit vvp_fun_signal4_aa(unsigned wid, vvp_bit4_t init=BIT4_X);
void alloc_instance(vvp_context_t context);
void reset_instance(vvp_context_t context);
#ifdef CHECK_WITH_VALGRIND
void free_instance(vvp_context_t context);
#endif
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
// Part select variants of above
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t);
// Get information about the vector value.
unsigned value_size() const;
vvp_bit4_t value(unsigned idx) const;
vvp_scalar_t scalar_value(unsigned idx) const;
vvp_vector4_t vec4_value() const;
vvp_vector4_t vec4_unfiltered_value() const;
private:
unsigned context_idx_;
unsigned size_;
};
class vvp_fun_signal8 : public vvp_fun_signal_vec {
public:
explicit vvp_fun_signal8(unsigned wid);
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
// Part select variants of above
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t context);
void recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid);
private:
vvp_vector8_t bits8_;
};
class vvp_fun_signal_real : public vvp_fun_signal_base {
public:
explicit vvp_fun_signal_real() {};
// Get information about the vector value.
virtual double real_unfiltered_value() const = 0;
unsigned size() const { return 1; }
};
/*
* Statically allocated vvp_fun_signal_real.
*/
class vvp_fun_signal_real_sa : public vvp_fun_signal_real {
public:
explicit vvp_fun_signal_real_sa();
void recv_real(vvp_net_ptr_t port, double bit,
vvp_context_t);
// Get information about the vector value.
double real_unfiltered_value() const;
private:
double bits_;
};
/*
* Automatically allocated vvp_fun_signal_real.
*/
class vvp_fun_signal_real_aa : public vvp_fun_signal_real, public automatic_signal_base, public automatic_hooks_s {
public:
explicit vvp_fun_signal_real_aa();
void alloc_instance(vvp_context_t context);
void reset_instance(vvp_context_t context);
#ifdef CHECK_WITH_VALGRIND
void free_instance(vvp_context_t context);
#endif
void recv_real(vvp_net_ptr_t port, double bit,
vvp_context_t context);
// Get information about the vector value.
double real_unfiltered_value() const;
// Get information about the vector value.
unsigned value_size() const;
vvp_bit4_t value(unsigned idx) const;
vvp_scalar_t scalar_value(unsigned idx) const;
vvp_vector4_t vec4_value() const;
double real_value() const;
void get_signal_value(struct t_vpi_value*vp);
private:
unsigned context_idx_;
};
/* vvp_wire
* The vvp_wire is different from vvp_variable objects in that it
* exists only as a filter. The vvp_wire class tree is for
* implementing verilog wires/nets (as opposed to regs/variables).
*/
class vvp_wire_base : public vvp_net_fil_t, public vvp_signal_value {
public:
vvp_wire_base();
~vvp_wire_base();
};
class vvp_wire_vec4 : public vvp_wire_base {
public:
vvp_wire_vec4(unsigned wid, vvp_bit4_t init);
// The main filter behavior for this class. These methods take
// the value that the node is driven to, and applies the firce
// filters. In wires, this also saves the driven value, so
// that when a force is released, we can revert to the driven value.
prop_t filter_vec4(const vvp_vector4_t&bit, vvp_vector4_t&rep,
unsigned base, unsigned vwid);
prop_t filter_vec8(const vvp_vector8_t&val, vvp_vector8_t&rep,
unsigned base, unsigned vwid);
// Abstract methods from vvp_vpi_callback
void get_value(struct t_vpi_value*value);
// Abstract methods from vvp_net_fit_t
unsigned filter_size() const;
void force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask);
void force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask);
void force_fil_real(double val, vvp_vector2_t mask);
void release(vvp_net_ptr_t ptr, bool net_flag);
void release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag);
// Implementation of vvp_signal_value methods
unsigned value_size() const;
vvp_bit4_t value(unsigned idx) const;
vvp_scalar_t scalar_value(unsigned idx) const;
vvp_vector4_t vec4_value() const;
private:
vvp_bit4_t filtered_value_(unsigned idx) const;
private:
bool needs_init_;
vvp_vector4_t bits4_; // The tracked driven value
vvp_vector4_t force4_; // the value being forced
};
class vvp_wire_vec8 : public vvp_wire_base {
public:
vvp_wire_vec8(unsigned wid);
// The main filter behavior for this class
prop_t filter_vec4(const vvp_vector4_t&bit, vvp_vector4_t&rep,
unsigned base, unsigned vwid);
prop_t filter_vec8(const vvp_vector8_t&val, vvp_vector8_t&rep,
unsigned base, unsigned vwid);
// Abstract methods from vvp_vpi_callback
void get_value(struct t_vpi_value*value);
// Abstract methods from vvp_net_fit_t
unsigned filter_size() const;
void force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask);
void force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask);
void force_fil_real(double val, vvp_vector2_t mask);
void release(vvp_net_ptr_t ptr, bool net_flag);
void release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag);
// Implementation of vvp_signal_value methods
unsigned value_size() const;
vvp_bit4_t value(unsigned idx) const;
vvp_scalar_t scalar_value(unsigned idx) const;
vvp_vector4_t vec4_value() const;
// This is new to vvp_wire_vec8
vvp_vector8_t vec8_value() const;
private:
vvp_scalar_t filtered_value_(unsigned idx) const;
private:
bool needs_init_;
vvp_vector8_t bits8_;
vvp_vector8_t force8_; // the value being forced
};
class vvp_wire_real : public vvp_wire_base {
public:
explicit vvp_wire_real(void);
// The main filter behavior for this class
prop_t filter_real(double&bit);
// Abstract methods from vvp_vpi_callback
void get_value(struct t_vpi_value*value);
// Abstract methods from vvp_net_fit_t
unsigned filter_size() const;
void force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask);
void force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask);
void force_fil_real(double val, vvp_vector2_t mask);
void release(vvp_net_ptr_t ptr, bool net_flag);
void release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag);
// Implementation of vvp_signal_value methods
unsigned value_size() const;
vvp_bit4_t value(unsigned idx) const;
vvp_scalar_t scalar_value(unsigned idx) const;
vvp_vector4_t vec4_value() const;
double real_value() const;
void get_signal_value(struct t_vpi_value*vp);
private:
double bit_;
double force_;
};
#endif

63
vvp/vvp_vpi_callback.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef __vvp_vpi_callback_H
#define __vvp_vpi_callback_H
/*
* Copyright (c) 2009 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include "vpi_user.h"
/*
* Things derived from vvp_vpi_callback may have callbacks
* attached. This is how vpi callbacks are attached to the vvp
* structure.
*
* Things derived from vvp_vpi_callback may also be array'ed, so it
* includes some members that arrays use.
*/
class vvp_vpi_callback {
public:
vvp_vpi_callback();
virtual ~vvp_vpi_callback();
void attach_as_word(class __vpiArray* arr, unsigned long addr);
void add_vpi_callback(struct __vpiCallback*);
#ifdef CHECK_WITH_VALGRIND
/* This has only been tested at EOS. */
void clear_all_callbacks(void);
#endif
// Derived classes implement this method to provide a way for
// vpi to get at the vvp value of the object.
virtual void get_value(struct t_vpi_value*value) =0;
protected:
// Derived classes call this method to indicate that it is
// time to call the callback.
void run_vpi_callbacks();
private:
struct __vpiCallback*vpi_callbacks_;
class __vpiArray* array_;
unsigned long array_word_;
};
#endif

View File

@ -20,6 +20,8 @@
# include "compile.h"
# include "vpi_priv.h"
# include "array.h"
# include "vvp_net_sig.h"
# include "logic.h"
# include "schedule.h"
# include <stdio.h>
# include <stdlib.h>
@ -34,14 +36,16 @@ static void __compile_var_real(char*label, char*name,
vvp_array_t array, unsigned long array_addr,
int msb, int lsb)
{
vvp_fun_signal_real*fun;
if (vpip_peek_current_scope()->is_automatic) {
fun = new vvp_fun_signal_real_aa;
} else {
fun = new vvp_fun_signal_real_sa;
}
vvp_net_t*net = new vvp_net_t;
net->fun = fun;
if (vpip_peek_current_scope()->is_automatic) {
vvp_fun_signal_real_aa*tmp = new vvp_fun_signal_real_aa;
net->fil = tmp;
net->fun = tmp;
} else {
net->fil = new vvp_wire_real;
net->fun = new vvp_fun_signal_real_sa;
}
define_functor_symbol(label, net);
@ -52,7 +56,7 @@ static void __compile_var_real(char*label, char*name,
assert(!array);
vpip_attach_to_current_scope(obj);
if (!vpip_peek_current_scope()->is_automatic)
schedule_init_vector(vvp_net_ptr_t(net,0), fun->real_value());
schedule_init_vector(vvp_net_ptr_t(net,0), 0.0);
}
if (array) {
assert(!name);
@ -84,23 +88,26 @@ static void __compile_var(char*label, char*name,
{
unsigned wid = ((msb > lsb)? msb-lsb : lsb-msb) + 1;
vvp_fun_signal_vec*vsig;
if (vpip_peek_current_scope()->is_automatic) {
vsig = new vvp_fun_signal4_aa(wid);
} else {
vsig = new vvp_fun_signal4_sa(wid);
}
vvp_net_t*node = new vvp_net_t;
node->fun = vsig;
vvp_net_t*net = new vvp_net_t;
define_functor_symbol(label, node);
if (vpip_peek_current_scope()->is_automatic) {
vvp_fun_signal4_aa*tmp = new vvp_fun_signal4_aa(wid);
net->fil = tmp;
net->fun = tmp;
} else {
net->fil = new vvp_wire_vec4(wid, BIT4_X);
net->fun = new vvp_fun_signal4_sa(wid);
}
vvp_signal_value*vfil = dynamic_cast<vvp_signal_value*>(net->fil);
define_functor_symbol(label, net);
vpiHandle obj = 0;
if (! local_flag && !array) {
/* Make the vpiHandle for the reg. */
obj = (signed_flag > 1) ?
vpip_make_int(name, msb, lsb, node) :
vpip_make_reg(name, msb, lsb, signed_flag!=0, node);
vpip_make_int(name, msb, lsb, net) :
vpip_make_reg(name, msb, lsb, signed_flag!=0, net);
compile_vpi_symbol(label, obj);
}
// If the signal has a name, then it goes into the current
@ -109,7 +116,7 @@ static void __compile_var(char*label, char*name,
assert(!array);
if (obj) vpip_attach_to_current_scope(obj);
if (!vpip_peek_current_scope()->is_automatic)
schedule_init_vector(vvp_net_ptr_t(node,0), vsig->vec4_value());
schedule_init_vector(vvp_net_ptr_t(net,0), vfil->vec4_value());
}
// If this is an array word, then it does not have a name, and
// it is attached to the addressed array.
@ -142,65 +149,176 @@ void compile_variablew(char*label, vvp_array_t array,
__compile_var(label, 0, array, array_addr, msb, lsb, signed_flag, false);
}
vvp_net_t* create_constant_node(const char*label, const char*val_str)
{
if (c4string_test(val_str)) {
vvp_net_t*net = new vvp_net_t;
net->fun = new vvp_fun_bufz;
schedule_init_vector(vvp_net_ptr_t(net,0), c4string_to_vector4(val_str));
return net;
}
if (c8string_test(val_str)) {
vvp_net_t*net = new vvp_net_t;
net->fun = new vvp_fun_bufz;
schedule_init_vector(vvp_net_ptr_t(net,0), c8string_to_vector8(val_str));
return net;
}
if (crstring_test(val_str)) {
vvp_net_t*net = new vvp_net_t;
net->fun = new vvp_fun_bufz;
schedule_init_vector(vvp_net_ptr_t(net,0), crstring_to_double(val_str));
return net;
}
return 0;
}
class base_net_resolv : public resolv_list_s {
public:
explicit base_net_resolv(char*ref_label, vvp_array_t array,
char*my_label, char*name,
unsigned array_addr, bool local_flag)
: resolv_list_s(ref_label)
{ my_label_ = my_label;
array_ = array;
name_ = name;
array_addr_ = array_addr;
local_flag_ = local_flag;
}
protected:
char*my_label_;
vvp_array_t array_;
char*name_;
unsigned array_addr_;
bool local_flag_;
};
class __compile_net_resolv : public base_net_resolv {
public:
explicit __compile_net_resolv(char*ref_label, vvp_array_t array,
char*my_label, char*name,
int msb, int lsb, unsigned array_addr,
bool signed_flag, bool net8_flag, bool local_flag)
: base_net_resolv(ref_label, array, my_label, name, array_addr, local_flag)
{ msb_ = msb;
lsb_ = lsb;
signed_flag_ = signed_flag;
}
~__compile_net_resolv() { }
bool resolve(bool message_flag);
private:
int msb_, lsb_;
bool signed_flag_, net8_flag_;
};
/*
* Here we handle .net records from the vvp source:
*
* <label> .net <name>, <msb>, <lsb>, <input> ;
* <label> .net/s <name>, <msb>, <lsb>, <input> ;
* <label> .net8 <name>, <msb>, <lsb>, <input> ;
* <label> .net8/s <name>, <msb>, <lsb>, <input> ;
* .net <name>, <msb>, <lsb>, <input> ;
* .net/s <name>, <msb>, <lsb>, <input> ;
* .net8 <name>, <msb>, <lsb>, <input> ;
* .net8/s <name>, <msb>, <lsb>, <input> ;
*
* Create a VPI handle to represent it, and fill that handle in with
* references into the net.
*/
static void __compile_net(char*label, char*name,
char*array_label, unsigned long array_addr,
int msb, int lsb,
bool signed_flag, bool net8_flag, bool local_flag,
unsigned argc, struct symb_s*argv)
static void __compile_net2(vvp_net_t*node, vvp_array_t array,
char*my_label, char*name,
int msb, int lsb, unsigned array_addr,
bool signed_flag, bool net8_flag, bool local_flag)
{
unsigned wid = ((msb > lsb)? msb-lsb : lsb-msb) + 1;
assert(node);
vvp_net_t*node = new vvp_net_t;
vvp_wire_base*vsig = dynamic_cast<vvp_wire_base*>(node->fil);
vvp_array_t array = array_label ? array_find(array_label) : 0;
assert(array_label ? array!=0 : true);
if (vsig == 0) {
vsig = net8_flag
? dynamic_cast<vvp_wire_base*>(new vvp_wire_vec8(wid))
: dynamic_cast<vvp_wire_base*>(new vvp_wire_vec4(wid,BIT4_Z));
vvp_fun_signal_base*vsig = net8_flag
? dynamic_cast<vvp_fun_signal_base*>(new vvp_fun_signal8(wid))
: dynamic_cast<vvp_fun_signal_base*>(new vvp_fun_signal4_sa(wid,BIT4_Z));
node->fun = vsig;
/* Add the label into the functor symbol table. */
define_functor_symbol(label, node);
assert(argc == 1);
/* Connect the source to my input. */
inputs_connect(node, 1, argv);
node->fil = vsig;
}
vpiHandle obj = 0;
if (! local_flag) {
/* Make the vpiHandle for the reg. */
obj = vpip_make_net(name, msb, lsb, signed_flag, node);
/* This attaches the label to the vpiHandle */
compile_vpi_symbol(label, obj);
compile_vpi_symbol(my_label, obj);
}
/* If this is an array word, then attach it to the
array. Otherwise, attach it to the current scope. */
// REMOVE ME! Giving the net a label is a legacy of the times
// when the .net was a functor of its own. In the long run, we
// must fix the code generator to not rely on the label of the
// .net, then we will remove that label.
define_functor_symbol(my_label, node);
if (array)
array_attach_word(array, array_addr, obj);
else if (obj)
vpip_attach_to_current_scope(obj);
free(label);
free(my_label);
if (name) delete[] name;
}
static void __compile_net(char*label,
char*name, char*array_label, unsigned long array_addr,
int msb, int lsb,
bool signed_flag, bool net8_flag, bool local_flag,
unsigned argc, struct symb_s*argv)
{
vvp_array_t array = array_label? array_find(array_label) : 0;
assert(array_label ? array!=0 : true);
if (array_label) free(array_label);
assert(argc == 1);
vvp_net_t*node = vvp_net_lookup(argv[0].text);
if (node == 0) {
/* No existing net, but the string value may be a
constant. In that case, we will wind up generating a
bufz node that can carry the constant value. */
node = create_constant_node(label, argv[0].text);
}
if (node == 0) {
__compile_net_resolv*res
= new __compile_net_resolv(argv[0].text,
array, label, name,
msb, lsb, array_addr,
signed_flag, net8_flag, local_flag);
resolv_submit(res);
return;
}
assert(node);
__compile_net2(node, array, label, name, msb, lsb, array_addr,
signed_flag, net8_flag, local_flag);
free(argv);
}
void compile_net(char*label, char*name,
int msb, int lsb,
bool __compile_net_resolv::resolve(bool msg_flag)
{
vvp_net_t*node = vvp_net_lookup(label());
if (node == 0) {
return false;
}
__compile_net2(node, array_, my_label_, name_, msb_, lsb_, array_addr_, signed_flag_, net8_flag_, local_flag_);
return true;
}
void compile_net(char*label, char*name, int msb, int lsb,
bool signed_flag, bool net8_flag, bool local_flag,
unsigned argc, struct symb_s*argv)
{
@ -219,44 +337,98 @@ void compile_netw(char*label, char*array_label, unsigned long array_addr,
argc, argv);
}
class __compile_real_net_resolv : public base_net_resolv {
public:
explicit __compile_real_net_resolv(char*ref_label, vvp_array_t array,
char*my_label, char*name,
unsigned array_addr, bool local_flag)
: base_net_resolv(ref_label, array, my_label, name, array_addr, local_flag)
{
}
~__compile_real_net_resolv() { }
bool resolve(bool message_flag);
private:
};
static void __compile_real_net2(vvp_net_t*node, vvp_array_t array,
char*my_label, char*name,
unsigned array_addr, bool local_flag)
{
vvp_wire_base*fil = dynamic_cast<vvp_wire_base*> (node->fil);
if (fil == 0) {
fil = new vvp_wire_real;
node->fil = fil;
}
vpiHandle obj = 0;
if (!local_flag) {
obj = vpip_make_real_var(name, node);
compile_vpi_symbol(my_label, obj);
}
// REMOVE ME! Giving the net a label is a legacy of the times
// when the .net was a functor of its own. In the long run, we
// must fix the code generator to not rely on the label of the
// .net, then we will remove that label.
define_functor_symbol(my_label, node);
if (array)
array_attach_word(array, array_addr, obj);
else if (obj)
vpip_attach_to_current_scope(obj);
free(my_label);
if (name) delete[]name;
}
static void __compile_real(char*label, char*name,
char*array_label, unsigned long array_addr,
int msb, int lsb, bool local_flag,
unsigned argc, struct symb_s*argv)
{
vvp_net_t*net = new vvp_net_t;
vvp_array_t array = array_label ? array_find(array_label) : 0;
assert(array_label ? array!=0 : true);
vvp_fun_signal_real*fun = new vvp_fun_signal_real_sa;
net->fun = fun;
/* Add the label into the functor symbol table. */
define_functor_symbol(label, net);
if (array_label) free(array_label);
assert(argc == 1);
/* Connect the source to my input. */
inputs_connect(net, 1, argv);
vpiHandle obj = 0;
if (! local_flag) {
/* Make the vpiHandle for the reg. */
obj = vpip_make_real_var(name, net);
/* This attaches the label to the vpiHandle */
compile_vpi_symbol(label, obj);
vvp_net_t*node = vvp_net_lookup(argv[0].text);
if (node == 0) {
/* No existing net, but the string value may be a
constant. In that case, we will wind up generating a
bufz node that can carry the constant value. */
node = create_constant_node(label, argv[0].text);
}
/* If this is an array word, then attach it to the
array. Otherwise, attach it to the current scope. */
if (array)
array_attach_word(array, array_addr, obj);
else if (obj)
vpip_attach_to_current_scope(obj);
free(label);
if (name) delete[] name;
if (array_label) free(array_label);
free(argv);
if (node == 0) {
__compile_real_net_resolv*res
= new __compile_real_net_resolv(argv[0].text, array,
label, name,
array_addr, local_flag);
resolv_submit(res);
return;
}
assert(node);
__compile_real_net2(node, array, label, name, array_addr, local_flag);
}
bool __compile_real_net_resolv::resolve(bool msg_flag)
{
vvp_net_t*node = vvp_net_lookup(label());
if (node == 0) {
if (msg_flag)
cerr << "Unable to resolve label " << label() << endl;
return false;
}
__compile_real_net2(node, array_, my_label_, name_, array_addr_, local_flag_);
return true;
}
void compile_net_real(char*label, char*name, int msb, int lsb, bool local_flag,
@ -284,6 +456,7 @@ void compile_aliasw(char*label, char*array_label, unsigned long array_addr,
vvp_net_t*node = vvp_net_lookup(argv[0].text);
/* Add the label into the functor symbol table. */
assert(node);
define_functor_symbol(label, node);
vpiHandle obj = vvp_lookup_handle(argv[0].text);
@ -296,46 +469,19 @@ void compile_aliasw(char*label, char*array_label, unsigned long array_addr,
free(argv);
}
/*
* The .alias is practically identical to a .net. We create all the
* VPI stuff for the new name (and put it in the local scope) but
* reference the node in the net.
*/
void compile_alias(char*label, char*name, int msb, int lsb, bool signed_flag,
unsigned argc, struct symb_s*argv)
{
assert(argc == 1);
vvp_net_t*node = vvp_net_lookup(argv[0].text);
/* Add the label into the functor symbol table. */
define_functor_symbol(label, node);
/* Make the vpiHandle for the reg. */
vpiHandle obj = vpip_make_net(name, msb, lsb, signed_flag, node);
compile_vpi_symbol(label, obj);
vpip_attach_to_current_scope(obj);
free(label);
delete[] name;
free(argv[0].text);
free(argv);
__compile_net(label, name, 0, 0, msb, lsb, signed_flag, false, false, argc, argv);
}
void compile_alias_real(char*label, char*name, int msb, int lsb,
unsigned argc, struct symb_s*argv)
{
assert(argc == 1);
vvp_net_t*node = vvp_net_lookup(argv[0].text);
/* Add the label into the functor symbol table. */
define_functor_symbol(label, node);
/* Make the vpiHandle for the reg. */
vpiHandle obj = vpip_make_real_var(name, node);
compile_vpi_symbol(label, obj);
vpip_attach_to_current_scope(obj);
free(label);
delete[] name;
free(argv[0].text);
free(argv);
__compile_real(label, name, 0, 0, msb, lsb, false, argc, argv);
}