diff --git a/ivl_target.h b/ivl_target.h index 8a2758a46..df108d13a 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -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); diff --git a/t-dll-api.cc b/t-dll-api.cc index 5f80a5d50..b10b3fb1b 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -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_; diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index a7d8591cb..325f171e6 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -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))); } } } diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 6ae7c7fc4..a0da8a9de 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -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. diff --git a/vvp/arith.cc b/vvp/arith.cc index 424e204e7..b060e27ba 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -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); } diff --git a/vvp/array.cc b/vvp/array.cc index 9b301fbec..011ad86d9 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -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 (vsig->node->fun); + vvp_signal_value*sig = dynamic_cast (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 (vsig->node->fun); + vvp_signal_value*sig = dynamic_cast (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 (vsig->net->fun); + vvp_signal_value*sig = dynamic_cast (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(net->fun); + vvp_vpi_callback*fun = dynamic_cast(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(net->fun); + vvp_vpi_callback*fun = dynamic_cast(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()); } } diff --git a/vvp/array.h b/vvp/array.h index 167fc9387..6a4f83ed8 100644 --- a/vvp/array.h +++ b/vvp/array.h @@ -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); diff --git a/vvp/bufif.cc b/vvp/bufif.cc index edd9170fa..21fadbece 100644 --- a/vvp/bufif.cc +++ b/vvp/bufif.cc @@ -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); } diff --git a/vvp/compile.cc b/vvp/compile.cc index d694bf820..67356aed9 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -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); diff --git a/vvp/concat.cc b/vvp/concat.cc index 9b0ee161d..853610ed5 100644 --- a/vvp/concat.cc +++ b/vvp/concat.cc @@ -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) diff --git a/vvp/delay.cc b/vvp/delay.cc index 53330868d..85e33e9a6 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -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]) diff --git a/vvp/dff.cc b/vvp/dff.cc index 0b6b58725..8c1cf1856 100644 --- a/vvp/dff.cc +++ b/vvp/dff.cc @@ -24,6 +24,7 @@ # include # include # include +# include #ifdef HAVE_MALLOC_H # include #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 + // 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; } } diff --git a/vvp/event.cc b/vvp/event.cc index 550325e4f..02e02c77b 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -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); } /* diff --git a/vvp/event.h b/vvp/event.h index 55582d79b..d30da2be7 100644 --- a/vvp/event.h +++ b/vvp/event.h @@ -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); diff --git a/vvp/extend.cc b/vvp/extend.cc index 93dc1e99c..c4e1cc132 100644 --- a/vvp/extend.cc +++ b/vvp/extend.cc @@ -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); } diff --git a/vvp/logic.cc b/vvp/logic.cc index 471c9103d..2ed65d138 100644 --- a/vvp/logic.cc +++ b/vvp/logic.cc @@ -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); diff --git a/vvp/npmos.cc b/vvp/npmos.cc index 72464ef68..95c91d8ef 100644 --- a/vvp/npmos.cc +++ b/vvp/npmos.cc @@ -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() diff --git a/vvp/part.cc b/vvp/part.cc index f96623fc1..9631b6163 100644 --- a/vvp/part.cc +++ b/vvp/part.cc @@ -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; diff --git a/vvp/reduce.cc b/vvp/reduce.cc index d1e936662..1c44539dd 100644 --- a/vvp/reduce.cc +++ b/vvp/reduce.cc @@ -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 { diff --git a/vvp/resolv.cc b/vvp/resolv.cc index 4919a1223..a5d0263d6 100644 --- a/vvp/resolv.cc +++ b/vvp/resolv.cc @@ -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) diff --git a/vvp/schedule.cc b/vvp/schedule.cc index f9ba88888..a3c951da6 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -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; diff --git a/vvp/schedule.h b/vvp/schedule.h index fcb1111b0..27f92ba2e 100644 --- a/vvp/schedule.h +++ b/vvp/schedule.h @@ -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); /* diff --git a/vvp/udp.cc b/vvp/udp.cc index 1fcb6e4a6..ae65c5cc0 100644 --- a/vvp/udp.cc +++ b/vvp/udp.cc @@ -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 { diff --git a/vvp/ufunc.cc b/vvp/ufunc.cc index 662630d81..c74ef7b65 100644 --- a/vvp/ufunc.cc +++ b/vvp/ufunc.cc @@ -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(result_->fun)) - - propagate_real(sig->real_value()); + propagate_real(sig->real_unfiltered_value()); if (vvp_fun_signal_vec*sig = dynamic_cast(result_->fun)) - propagate_vec4(sig->vec4_value()); + propagate_vec4(sig->vec4_unfiltered_value()); } /* diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index bafc05745..95f7045c8 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -29,6 +29,7 @@ # include "vvp_net.h" # include "schedule.h" # include "event.h" +# include "vvp_net_sig.h" # include "config.h" # include # include @@ -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(sig->node->fun); - assert(sig_fun); + vvp_net_fil_t*sig_fil; + sig_fil = dynamic_cast(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); +} diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index cb8093679..1b210c1db 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -19,6 +19,7 @@ # include "compile.h" # include "vpi_priv.h" +# include "vvp_net_sig.h" # include "schedule.h" # include # include @@ -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(rfp->net->fun); + vvp_signal_value*fil + = dynamic_cast(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(rfp->net->fun); + vvp_vpi_callback*obj = dynamic_cast(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) diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index b85fa2efb..871595f7b 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -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(rfp->node->fun); + vvp_signal_value*vsig = dynamic_cast(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(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(rfp->net->fun); + vvp_signal_value*sig = dynamic_cast(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(rfp->net->fun); + vvp_signal_value*sig = dynamic_cast(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(obj->net->fun); - assert(sig_fun); + vvp_vpi_callback*sig_fil; + sig_fil = dynamic_cast(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 diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index 245c95575..c662367a5 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -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; } diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 13744c924..c36334094 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -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 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 (cp->net->fun); + vvp_signal_value*sig = dynamic_cast (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 (cp->net->fun); + vvp_signal_value*sig = dynamic_cast (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 (cp->net->fun); + vvp_signal_value*sig = dynamic_cast (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(dst->fun); + = dynamic_cast(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 (net->fun); + vvp_signal_value*sig = dynamic_cast (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(net->fun); + vvp_signal_value*fil = dynamic_cast (net->fil); + assert(fil); + vvp_fun_signal_vec*sig = dynamic_cast(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(net->fun); + vvp_fun_signal_real*sig = dynamic_cast(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(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(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 (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(net->fun); + vvp_signal_value*sig = dynamic_cast(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(net->fun); + vvp_signal_value*sig = dynamic_cast(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 (net->fun); + vvp_signal_value*sig = dynamic_cast (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 (net->fun); + vvp_signal_value*sig = dynamic_cast (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(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(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(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 (net->fun); + vvp_signal_value*sig = dynamic_cast (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; } diff --git a/vvp/vvp_island.cc b/vvp/vvp_island.cc index 434739c51..9620199ee 100644 --- a/vvp/vvp_island.cc +++ b/vvp/vvp_island.cc @@ -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); } /* diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index cdf3cfe67..159b5f390 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -108,6 +108,54 @@ void vvp_net_t::operator delete(void*) assert(0); } +vvp_net_t::vvp_net_t() +{ + out_ = vvp_net_ptr_t(0,0); + fun = 0; + fil = 0; +} + +void vvp_net_t::link(vvp_net_ptr_t port) +{ + vvp_net_t*net = port.ptr(); + net->port[port.port()] = out_; + out_ = port; +} + +/* + * 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. + */ +void vvp_net_t::unlink(vvp_net_ptr_t dst_ptr) +{ + vvp_net_t*net = dst_ptr.ptr(); + unsigned net_port = dst_ptr.port(); + + if (out_ == dst_ptr) { + /* If the drive fan-out list starts with this pointer, + then the unlink is easy. Pull the list forward. */ + out_ = net->port[net_port]; + } else if (! out_.nil()) { + /* Scan the linked list, looking for the net_ptr_t + pointer *before* the one we wish to remove. */ + vvp_net_ptr_t cur = out_; + assert(!cur.nil()); + vvp_net_t*cur_net = cur.ptr(); + unsigned cur_port = cur.port(); + while (cur_net && cur_net->port[cur_port] != dst_ptr) { + cur = cur_net->port[cur_port]; + cur_net = cur.ptr(); + cur_port = cur.port(); + } + /* Unlink. */ + if (cur_net) cur_net->port[cur_port] = net->port[net_port]; + } + + net->port[net_port] = vvp_net_ptr_t(0,0); +} + void* vvp_net_fun_t::operator new(size_t size) { // Link in an initial chunk of space for net_fun_t @@ -146,6 +194,113 @@ void vvp_net_fun_t::operator delete(void*) assert(0); } + +vvp_net_fil_t::vvp_net_fil_t() +{ + force_link_ = 0; + force_propagate_ = false; +} + +vvp_net_fil_t::~vvp_net_fil_t() +{ + assert(force_link_ == 0); +} + +vvp_net_fil_t::prop_t vvp_net_fil_t::filter_vec4(const vvp_vector4_t&val, vvp_vector4_t&, unsigned, unsigned) +{ + return PROP; +} + +vvp_net_fil_t::prop_t vvp_net_fil_t::filter_vec8(const vvp_vector8_t&val, vvp_vector8_t&, unsigned, unsigned) +{ + return PROP; +} + +vvp_net_fil_t::prop_t vvp_net_fil_t::filter_real(double&) +{ + return PROP; +} + +vvp_net_fil_t::prop_t vvp_net_fil_t::filter_long(long&) +{ + return PROP; +} + +void vvp_net_fil_t::force_mask(vvp_vector2_t mask) +{ + if (force_mask_.size() == 0) + force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, mask.size()); + + assert(force_mask_.size() == mask.size()); + for (unsigned idx = 0 ; idx < mask.size() ; idx += 1) { + if (mask.value(idx) == 0) + continue; + + force_mask_.set_bit(idx, 1); + force_propagate_ = true; + } +} + +void vvp_net_fil_t::release_mask(vvp_vector2_t mask) +{ + if (force_mask_.size() == 0) + return; + + assert(force_mask_.size() == mask.size()); + for (unsigned idx = 0 ; idx < mask.size() ; idx += 1) { + if (mask.value(idx)) + force_mask_.set_bit(idx, 0); + } + + if (force_mask_.is_zero()) + force_mask_ = vvp_vector2_t(); +} + +/* + * Force link/unlink uses a thunk vvp_net_t node with a vvp_fun_force + * functor to translate the net values to filter commands. The ports + * of this vvp_net_t object are use a little differently: + * + * port[3] - Point to the destination node where the forced + * filter resides. + * + * port[2] - Point to the input node that drives port[0] for use + * by the unlink method. + * + * port[0] - This is the normal input. + */ +void vvp_net_fil_t::force_link(vvp_net_t*dst, vvp_net_t*src) +{ + assert(dst->fil == this); + + if (force_link_ == 0) { + force_link_ = new vvp_net_t; + // Use port[3] to hold the force destination. + force_link_->port[3] = vvp_net_ptr_t(dst, 0); + force_link_->port[2] = vvp_net_ptr_t(0,0); + force_link_->fun = new vvp_fun_force; + } + + force_unlink(); + assert(force_link_->port[2] == vvp_net_ptr_t(0,0)); + + // Use port[2] to hold the force source. + force_link_->port[2] = vvp_net_ptr_t(src,0); + + vvp_net_ptr_t dst_ptr(force_link_, 0); + src->link(dst_ptr); +} + +void vvp_net_fil_t::force_unlink(void) +{ + if (force_link_ == 0) return; + vvp_net_t*src = force_link_->port[2].ptr(); + if (src == 0) return; + + src->unlink(vvp_net_ptr_t(force_link_,0)); + force_link_->port[2] = vvp_net_ptr_t(0,0); +} + /* *** BIT operations *** */ vvp_bit4_t add_with_carry(vvp_bit4_t a, vvp_bit4_t b, vvp_bit4_t&c) { @@ -311,6 +466,8 @@ void vvp_send_long_pv(vvp_net_ptr_t ptr, long val, } } +const vvp_vector4_t vvp_vector4_t::nil; + void vvp_vector4_t::copy_bits(const vvp_vector4_t&that) { @@ -1563,19 +1720,6 @@ vvp_vector4_t vvp_vector4array_aa::get_word(unsigned index) const return get_word_(cell); } -template 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; -} - vvp_vector2_t::vvp_vector2_t() { vec_ = 0; @@ -2226,6 +2370,19 @@ vvp_vector4_t vector2_to_vector4(const vvp_vector2_t&that, unsigned wid) return res; } +bool c4string_test(const char*str) +{ + if (strncmp(str, "C4<", 3) != 0) + return false; + size_t value_size = strspn(str+3, "01xz"); + if (str[3+value_size] != '>') + return false; + if (str[3+value_size+1] != 0) + return false; + + return true; +} + vvp_vector4_t c4string_to_vector4(const char*str) { assert((str[0]=='C') && (str[1]=='4') && (str[2]=='<')); @@ -2305,6 +2462,8 @@ vvp_vector8_t::vvp_vector8_t(const vvp_vector4_t&that, } +const vvp_vector8_t vvp_vector8_t::nil; + vvp_vector8_t& vvp_vector8_t::operator= (const vvp_vector8_t&that) { // Assign to self. @@ -2355,6 +2514,13 @@ vvp_vector8_t vvp_vector8_t::subvalue(unsigned base, unsigned wid) const return tmp; } +void vvp_vector8_t::set_vec(unsigned base, const vvp_vector8_t&that) +{ + assert((base+that.size()) <= size()); + for (unsigned idx = 0 ; idx < that.size() ; idx += 1) + set_bit(base+idx, that.value(idx)); +} + vvp_vector8_t part_expand(const vvp_vector8_t&that, unsigned wid, unsigned off) { assert(off < wid); @@ -2373,6 +2539,60 @@ vvp_vector8_t part_expand(const vvp_vector8_t&that, unsigned wid, unsigned off) return tmp; } +bool c8string_test(const char*str) +{ + const char*cp; + if (str[0] != 'C') return false; + if (str[1] != '8') return false; + if (str[2] != '<') return false; + + cp = str+3; + for (;; cp += 1) { + if (cp[0] == '>' && cp[1] == 0) return true; + if (cp[0] >= '0' && cp[0] <= '9') continue; + if (cp[0] == 'x') continue; + if (cp[0] == 'z') continue; + return false; + } + return false; +} +/* + * The format of a C8<> string is: + * C8 + * where aaa... is a 3 character bit descriptor. + */ +vvp_vector8_t c8string_to_vector8(const char*str) +{ + size_t vsize = strlen(str)-4; + assert(vsize%3 == 0); + vsize /= 3; + vvp_vector8_t tmp (vsize); + + for (size_t idx = 0 ; idx < vsize ; idx += 1) { + const char*cp = str+3+3*idx; + vvp_bit4_t bit = BIT4_X; + unsigned dr0 = cp[0]-'0'; + unsigned dr1 = cp[1]-'0'; + switch (cp[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)); + } + + return tmp; +} + ostream& operator<<(ostream&out, const vvp_vector8_t&that) { out << "C8<"; @@ -2461,767 +2681,10 @@ void vvp_fun_drive::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t) { assert(port.port() == 0); - vvp_send_vec8(port.ptr()->out, vvp_vector8_t(bit, drive0_, drive1_)); + port.ptr()->send_vec8(vvp_vector8_t(bit, drive0_, drive1_)); } -/* **** vvp_fun_signal methods **** */ - -vvp_fun_signal_base::vvp_fun_signal_base() -{ - needs_init_ = true; - continuous_assign_active_ = false; - force_link = 0; - cassign_link = 0; - count_functors_sig += 1; -} - -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(); - } -} - -/* - * The signal functor takes commands as long values to port-3. This - * method interprets those commands. - */ -void vvp_fun_signal_base::recv_long(vvp_net_ptr_t ptr, long bit) -{ - switch (ptr.port()) { - case 3: // Command port - switch (bit) { - case 1: // deassign command - deassign(); - break; - case 2: // release/net - release(ptr, true); - break; - case 3: // release/reg - release(ptr, false); - break; - default: - fprintf(stderr, "Unsupported command %ld.\n", bit); - assert(0); - break; - } - break; - - default: // Other ports are errors. - fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); - assert(0); - break; - } -} - -void vvp_fun_signal_base::recv_long_pv(vvp_net_ptr_t ptr, long bit, - unsigned base, unsigned wid) -{ - switch (ptr.port()) { - case 3: // Command port - switch (bit) { - case 1: // deassign command - deassign_pv(base, wid); - break; - case 2: // release/net - release_pv(ptr, true, base, wid); - break; - case 3: // release/reg - release_pv(ptr, false, base, wid); - break; - default: - fprintf(stderr, "Unsupported command %ld.\n", bit); - assert(0); - break; - } - break; - - default: // Other ports are errors. - fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); - assert(0); - break; - } -} - -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)) { - bits4_ = bit; - needs_init_ = false; - calculate_output_(ptr); - } - } 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; - calculate_output_(ptr); - } - } - break; - - case 1: // Continuous assign value - bits4_ = bit; - assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); - calculate_output_(ptr); - break; - - case 2: // Force value - - // Force from a node may not have been sized completely - // by the source, so coerce the size here. - if (bit.size() != size()) - force_ = coerce_to_width(bit, size()); - else - force_ = bit; - - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); - calculate_output_(ptr); - 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; - calculate_output_(ptr); - } 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; - calculate_output_(ptr); - } - } - break; - - case 1: // Continuous assign value - if (assign_mask_.size() == 0) - assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, 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); - } - calculate_output_(ptr); - break; - - case 2: // Force value - - if (force_mask_.size() == 0) - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, size()); - if (force_.size() == 0) - force_ = vvp_vector4_t(vwid, BIT4_Z); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - force_mask_.set_bit(base+idx, 1); - force_.set_bit(base+idx, bit.value(idx)); - } - - calculate_output_(ptr); - 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_signal4_sa::calculate_output_(vvp_net_ptr_t ptr) -{ - if (force_mask_.size()) { - assert(bits4_.size() == force_mask_.size()); - assert(bits4_.size() == force_.size()); - vvp_vector4_t bits (bits4_); - for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { - if (force_mask_.value(idx)) - bits.set_bit(idx, force_.value(idx)); - } - vvp_send_vec4(ptr.ptr()->out, bits, 0); - } else { - vvp_send_vec4(ptr.ptr()->out, bits4_, 0); - } - - run_vpi_callbacks(); -} - -void vvp_fun_signal4_sa::release(vvp_net_ptr_t ptr, bool net) -{ - force_mask_ = vvp_vector2_t(); - if (net) { - vvp_send_vec4(ptr.ptr()->out, bits4_, 0); - run_vpi_callbacks(); - } else { - bits4_ = force_; - } -} - -void vvp_fun_signal4_sa::release_pv(vvp_net_ptr_t ptr, bool net, - unsigned base, unsigned wid) -{ - assert(bits4_.size() >= base + wid); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - force_mask_.set_bit(base+idx, 0); - if (!net) bits4_.set_bit(base+idx, force_.value(base+idx)); - } - if (force_mask_.is_zero()) force_mask_ = vvp_vector2_t(); - - if (net) calculate_output_(ptr); -} - -unsigned vvp_fun_signal4_sa::size() const -{ - if (force_mask_.size()) - return force_.size(); - else - return bits4_.size(); -} - -vvp_bit4_t vvp_fun_signal4_sa::value(unsigned idx) const -{ - if (force_mask_.size() && force_mask_.value(idx)) { - return force_.value(idx); - } else { - return bits4_.value(idx); - } -} - -vvp_scalar_t vvp_fun_signal4_sa::scalar_value(unsigned idx) const -{ - if (force_mask_.size() && force_mask_.value(idx)) { - return vvp_scalar_t(force_.value(idx), 6, 6); - } else { - return vvp_scalar_t(bits4_.value(idx), 6, 6); - } -} - -vvp_vector4_t vvp_fun_signal4_sa::vec4_value() const -{ - if (force_mask_.size()) { - assert(bits4_.size() == force_mask_.size()); - assert(bits4_.size() == force_.size()); - vvp_vector4_t bits (bits4_); - for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { - if (force_mask_.value(idx)) - bits.set_bit(idx, force_.value(idx)); - } - return bits; - } else { - 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_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_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_get_context_item(context, context_idx_)); - - if (!bits4->eeq(bit)) { - *bits4 = bit; - vvp_send_vec4(ptr.ptr()->out, *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_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)); - } - vvp_send_vec4(ptr.ptr()->out, *bits4, context); -} - -void vvp_fun_signal4_aa::release(vvp_net_ptr_t ptr, bool net) -{ - /* Automatic variables can't be forced. */ - assert(0); -} - -void vvp_fun_signal4_aa::release_pv(vvp_net_ptr_t ptr, bool net, - unsigned base, unsigned wid) -{ - /* Automatic variables can't be forced. */ - assert(0); -} - -unsigned vvp_fun_signal4_aa::size() const -{ - return size_; -} - -vvp_bit4_t vvp_fun_signal4_aa::value(unsigned idx) const -{ - vvp_vector4_t*bits4 = static_cast - (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 - (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 - (vthread_get_rd_context_item(context_idx_)); - - return *bits4; -} - -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; - calculate_output_(ptr); - } - 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; - - case 2: // Force value - - // Force from a node may not have been sized completely - // by the source, so coerce the size here. - if (bit.size() != size()) - force_ = coerce_to_width(bit, size()); - else - force_ = bit; - - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); - calculate_output_(ptr); - 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; - calculate_output_(ptr); - 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; - - case 2: // Force value - - if (force_mask_.size() == 0) - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, size()); - if (force_.size() == 0) - force_ = vvp_vector8_t(vvp_vector4_t(vwid, BIT4_Z),6,6); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - force_mask_.set_bit(base+idx, 1); - force_.set_bit(base+idx, bit.value(idx)); - } - - calculate_output_(ptr); - break; - - default: - fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); - assert(0); - break; - } -} - -void vvp_fun_signal8::calculate_output_(vvp_net_ptr_t ptr) -{ - if (force_mask_.size()) { - assert(bits8_.size() == force_mask_.size()); - assert(bits8_.size() == force_.size()); - vvp_vector8_t bits (bits8_); - for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { - if (force_mask_.value(idx)) - bits.set_bit(idx, force_.value(idx)); - } - vvp_send_vec8(ptr.ptr()->out, bits); - - } else { - vvp_send_vec8(ptr.ptr()->out, bits8_); - } - - run_vpi_callbacks(); -} - -void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net) -{ - force_mask_ = vvp_vector2_t(); - if (net) { - vvp_send_vec8(ptr.ptr()->out, bits8_); - run_vpi_callbacks(); - } else { - bits8_ = force_; - } -} - -void vvp_fun_signal8::release_pv(vvp_net_ptr_t ptr, bool net, - unsigned base, unsigned wid) -{ - assert(bits8_.size() >= base + wid); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - force_mask_.set_bit(base+idx, 0); - if (!net) bits8_.set_bit(base+idx, force_.value(base+idx)); - } - if (force_mask_.is_zero()) force_mask_ = vvp_vector2_t(); - - if (net) calculate_output_(ptr); -} - -unsigned vvp_fun_signal8::size() const -{ - if (force_mask_.size()) - return force_.size(); - else - return bits8_.size(); -} - -vvp_bit4_t vvp_fun_signal8::value(unsigned idx) const -{ - if (force_mask_.size() && force_mask_.value(idx)) - return force_.value(idx).value(); - else - return bits8_.value(idx).value(); -} - -vvp_vector4_t vvp_fun_signal8::vec4_value() const -{ - if (force_mask_.size()) { - vvp_vector8_t bits (bits8_); - for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) { - if (force_mask_.value(idx)) - bits.set_bit(idx, force_.value(idx)); - } - return reduce4(bits); - } else - return reduce4(bits8_); -} - -vvp_scalar_t vvp_fun_signal8::scalar_value(unsigned idx) const -{ - if (force_mask_.size() && force_mask_.value(idx)) - return force_.value(idx); - else - return bits8_.value(idx); -} - -/* - * 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_value() const -{ - if (force_mask_.size()) - return force_; - else - 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; - vvp_send_real(ptr.ptr()->out, bit, 0); - run_vpi_callbacks(); - } - } - break; - - case 1: // Continuous assign value - continuous_assign_active_ = true; - bits_ = bit; - vvp_send_real(ptr.ptr()->out, bit, 0); - run_vpi_callbacks(); - break; - - case 2: // Force value - force_mask_ = vvp_vector2_t(1, 1); - force_ = bit; - vvp_send_real(ptr.ptr()->out, bit, 0); - run_vpi_callbacks(); - break; - - default: - fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); - assert(0); - break; - } -} - -void vvp_fun_signal_real_sa::release(vvp_net_ptr_t ptr, bool net) -{ - force_mask_ = vvp_vector2_t(); - if (net) { - vvp_send_real(ptr.ptr()->out, bits_, 0); - run_vpi_callbacks(); - } else { - bits_ = force_; - } -} - -void vvp_fun_signal_real_sa::release_pv(vvp_net_ptr_t ptr, bool net, - unsigned base, unsigned wid) -{ - fprintf(stderr, "Error: cannot take bit/part select of a real value!\n"); - assert(0); -} - -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 - (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 - (vvp_get_context_item(context, context_idx_)); - delete bits; -} -#endif - -double vvp_fun_signal_real_aa::real_value() const -{ - double*bits = static_cast - (vthread_get_rd_context_item(context_idx_)); - - return *bits; -} - -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 - (vvp_get_context_item(context, context_idx_)); - - if (!bits_equal(*bits,bit)) { - *bits = bit; - vvp_send_real(ptr.ptr()->out, bit, context); - } -} - -void vvp_fun_signal_real_aa::release(vvp_net_ptr_t ptr, bool net) -{ - /* Automatic variables can't be forced. */ - assert(0); -} - -void vvp_fun_signal_real_aa::release_pv(vvp_net_ptr_t ptr, bool net, - unsigned base, unsigned wid) -{ - /* Automatic variables can't be forced. */ - assert(0); -} - /* **** vvp_wide_fun_* methods **** */ vvp_wide_fun_core::vvp_wide_fun_core(vvp_net_t*net, unsigned nports) @@ -3242,9 +2705,9 @@ void vvp_wide_fun_core::propagate_vec4(const vvp_vector4_t&bit, vvp_time64_t delay) { if (delay) - schedule_assign_plucked_vector(ptr_->out, delay, bit, 0, bit.size()); + schedule_propagate_plucked_vector(ptr_, delay, bit, 0, bit.size()); else - vvp_send_vec4(ptr_->out, bit, 0); + ptr_->send_vec4(bit, 0); } void vvp_wide_fun_core::propagate_real(double bit, @@ -3254,7 +2717,7 @@ void vvp_wide_fun_core::propagate_real(double bit, // schedule_assign_vector(ptr_->out, bit, delay); assert(0); // Need a real-value version of assign_vector. } else { - vvp_send_real(ptr_->out, bit, 0); + ptr_->send_real(bit, 0); } } diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 55fcf987a..a22b8fd07 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -21,6 +21,7 @@ # include "config.h" # include "vpi_user.h" +# include "vvp_vpi_callback.h" # include # include # include @@ -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 ostream& operator << (ostream&out, vvp_sub_pointer_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 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 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 diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc new file mode 100644 index 000000000..55e64511f --- /dev/null +++ b/vvp/vvp_net_sig.cc @@ -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 +#ifdef CHECK_WITH_VALGRIND +# include +# include +#endif + +# include + +template 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 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_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_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_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_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 + (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 + (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 + (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 + (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 + (vvp_get_context_item(context, context_idx_)); + delete bits; +} +#endif + +double vvp_fun_signal_real_aa::real_unfiltered_value() const +{ + double*bits = static_cast + (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 + (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_; +} diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h new file mode 100644 index 000000000..3739df303 --- /dev/null +++ b/vvp/vvp_net_sig.h @@ -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 +# include +# include +# include +# include + +#ifdef HAVE_IOSFWD +# include +#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 diff --git a/vvp/vvp_vpi_callback.h b/vvp/vvp_vpi_callback.h new file mode 100644 index 000000000..8b96e5afc --- /dev/null +++ b/vvp/vvp_vpi_callback.h @@ -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 diff --git a/vvp/words.cc b/vvp/words.cc index cd1a06d51..20c2f0700 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -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 # include @@ -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(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: * - *