From 6d34b41dcec029a3269468c05582880699902f26 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 3 Apr 2009 20:40:26 -0700 Subject: [PATCH 01/54] Hide the "out" member of the vvp_net_t object. The out pointer of a vvp_net_t object is going to be a bit more sophisticated when we redo the handling of net signals. Take a step towards this rework by making the pointer private and implementing methods needed to access it. --- vvp/arith.cc | 98 +++++++++++++++++++++++------------------------ vvp/array.cc | 12 +++--- vvp/bufif.cc | 2 +- vvp/compile.cc | 4 +- vvp/concat.cc | 4 +- vvp/delay.cc | 14 +++---- vvp/dff.cc | 4 +- vvp/event.cc | 20 +++++----- vvp/extend.cc | 4 +- vvp/logic.cc | 32 ++++++++-------- vvp/npmos.cc | 4 +- vvp/part.cc | 12 +++--- vvp/reduce.cc | 4 +- vvp/resolv.cc | 4 +- vvp/udp.cc | 2 +- vvp/vpi_tasks.cc | 4 +- vvp/vthread.cc | 72 ++++------------------------------ vvp/vvp_island.cc | 2 +- vvp/vvp_net.cc | 80 ++++++++++++++++++++++++++++++-------- vvp/vvp_net.h | 61 +++++++++++++++++++++++++---- 20 files changed, 235 insertions(+), 204 deletions(-) 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 4bac1fe3c..9c79a5669 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -836,8 +836,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); } @@ -1143,7 +1142,7 @@ void vvp_fun_arrayport_sa::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; - vvp_send_vec4(port.ptr()->out, array_get_word(arr_,addr_), 0); + port.ptr()->send_vec4(array_get_word(arr_,addr_), 0); break; default: @@ -1158,7 +1157,7 @@ void vvp_fun_arrayport_sa::check_word_change(unsigned long addr) return; vvp_vector4_t bit = array_get_word(arr_, addr_); - vvp_send_vec4(net_->out, bit, 0); + net_->send_vec4(bit, 0); } class vvp_fun_arrayport_aa : public vvp_fun_arrayport, public automatic_hooks_s { @@ -1242,8 +1241,7 @@ 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; - vvp_send_vec4(port.ptr()->out, array_get_word(arr_,*addr), - context); + port.ptr()->send_vec4(array_get_word(arr_,*addr), context); break; default: @@ -1268,7 +1266,7 @@ void vvp_fun_arrayport_aa::check_word_change(unsigned long addr) return; vvp_vector4_t bit = array_get_word(arr_, addr); - vvp_send_vec4(net_->out, bit, vthread_get_wt_context()); + net_->send_vec4(bit, vthread_get_wt_context()); } static void array_attach_port(vvp_array_t array, vvp_fun_arrayport*fun) 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 2f718395a..def82b3d2 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -367,9 +367,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; } 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 ab250c03d..3b36acdbf 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -253,7 +253,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_; @@ -278,7 +278,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; @@ -334,7 +334,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_; @@ -363,19 +363,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) @@ -539,7 +539,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..264b2aa8d 100644 --- a/vvp/dff.cc +++ b/vvp/dff.cc @@ -58,7 +58,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 @@ -68,7 +68,7 @@ void vvp_dff::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, case 3: // Asynch-D d_ = bit; - vvp_send_vec4(port.ptr()->out, d_, 0); + port.ptr()->send_vec4(d_, 0); break; } } diff --git a/vvp/event.cc b/vvp/event.cc index 7bb4aed4d..8e0982ca0 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -241,7 +241,7 @@ 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); } } @@ -300,7 +300,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; @@ -390,7 +390,7 @@ 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); } } @@ -399,7 +399,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); } } @@ -459,7 +459,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; @@ -479,7 +479,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; @@ -520,7 +520,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() @@ -575,7 +575,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) { @@ -616,7 +616,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_); } @@ -674,7 +674,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/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 827ccbd64..62c95fe5e 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 f3d98836e..4aa365af8 100644 --- a/vvp/part.cc +++ b/vvp/part.cc @@ -100,7 +100,7 @@ void vvp_fun_part_sa::run_run() if (idx + base_ < val_.size()) res.set_bit(idx, val_.value(base_+idx)); } - vvp_send_vec4(ptr->out, res, 0); + ptr->send_vec4(res, 0); } vvp_fun_part_aa::vvp_fun_part_aa(unsigned base, unsigned wid) @@ -152,7 +152,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; @@ -217,7 +217,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) @@ -232,7 +232,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) @@ -295,7 +295,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); } } @@ -365,7 +365,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/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/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 ce7b91d33..befa557a7 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -550,41 +550,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. @@ -1265,7 +1230,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; @@ -1273,8 +1238,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; } @@ -1777,7 +1741,7 @@ 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; } @@ -1803,7 +1767,7 @@ bool of_DEASSIGN_WR(vthread_t thr, vvp_code_t cp) 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; } @@ -2337,26 +2301,7 @@ static void unlink_force(vvp_net_t*net) /* 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(); + src->unlink(net_ptr); } /* @@ -2389,8 +2334,7 @@ bool of_FORCE_LINK(vthread_t thr, vvp_code_t cp) /* 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; + src->link(dst_ptr); return true; } @@ -4029,7 +3973,7 @@ bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp) } // And this is the pointer to be removed. vvp_net_ptr_t dst_ptr (net, 2); - unlink_from_driver(src, dst_ptr); + src->unlink(dst_ptr); sig->force_link = 0; } @@ -4058,7 +4002,7 @@ bool of_RELEASE_WR(vthread_t thr, vvp_code_t cp) 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); + src->unlink(dst_ptr); sig->force_link = 0; } 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 088ff6024..e470dfbea 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -108,6 +108,52 @@ void vvp_net_t::operator delete(void*) assert(0); } +vvp_net_t::vvp_net_t() +{ + out_ = vvp_net_ptr_t(0,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 @@ -2462,7 +2508,7 @@ 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_)); } @@ -2715,9 +2761,9 @@ void vvp_fun_signal4_sa::calculate_output_(vvp_net_ptr_t ptr) if (force_mask_.value(idx)) bits.set_bit(idx, force_.value(idx)); } - vvp_send_vec4(ptr.ptr()->out, bits, 0); + ptr.ptr()->send_vec4(bits, 0); } else { - vvp_send_vec4(ptr.ptr()->out, bits4_, 0); + ptr.ptr()->send_vec4(bits4_, 0); } run_vpi_callbacks(); @@ -2727,7 +2773,7 @@ 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); + ptr.ptr()->send_vec4(bits4_, 0); run_vpi_callbacks(); } else { bits4_ = force_; @@ -2833,7 +2879,7 @@ void vvp_fun_signal4_aa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, if (!bits4->eeq(bit)) { *bits4 = bit; - vvp_send_vec4(ptr.ptr()->out, *bits4, context); + ptr.ptr()->send_vec4(*bits4, context); } } @@ -2853,7 +2899,7 @@ void vvp_fun_signal4_aa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit if (base+idx >= bits4->size()) break; bits4->set_bit(base+idx, bit.value(idx)); } - vvp_send_vec4(ptr.ptr()->out, *bits4, context); + ptr.ptr()->send_vec4(*bits4, context); } void vvp_fun_signal4_aa::release(vvp_net_ptr_t ptr, bool net) @@ -3009,10 +3055,10 @@ void vvp_fun_signal8::calculate_output_(vvp_net_ptr_t ptr) if (force_mask_.value(idx)) bits.set_bit(idx, force_.value(idx)); } - vvp_send_vec8(ptr.ptr()->out, bits); + ptr.ptr()->send_vec8(bits); } else { - vvp_send_vec8(ptr.ptr()->out, bits8_); + ptr.ptr()->send_vec8(bits8_); } run_vpi_callbacks(); @@ -3022,7 +3068,7 @@ 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_); + ptr.ptr()->send_vec8(bits8_); run_vpi_callbacks(); } else { bits8_ = force_; @@ -3112,7 +3158,7 @@ void vvp_fun_signal_real_sa::recv_real(vvp_net_ptr_t ptr, double bit, if (needs_init_ || !bits_equal(bits_, bit)) { bits_ = bit; needs_init_ = false; - vvp_send_real(ptr.ptr()->out, bit, 0); + ptr.ptr()->send_real(bit, 0); run_vpi_callbacks(); } } @@ -3121,14 +3167,14 @@ void vvp_fun_signal_real_sa::recv_real(vvp_net_ptr_t ptr, double bit, case 1: // Continuous assign value continuous_assign_active_ = true; bits_ = bit; - vvp_send_real(ptr.ptr()->out, bit, 0); + ptr.ptr()->send_real(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); + ptr.ptr()->send_real(bit, 0); run_vpi_callbacks(); break; @@ -3143,7 +3189,7 @@ 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); + ptr.ptr()->send_real(bits_, 0); run_vpi_callbacks(); } else { bits_ = force_; @@ -3206,7 +3252,7 @@ void vvp_fun_signal_real_aa::recv_real(vvp_net_ptr_t ptr, double bit, if (!bits_equal(*bits,bit)) { *bits = bit; - vvp_send_real(ptr.ptr()->out, bit, context); + ptr.ptr()->send_real(bit, context); } } @@ -3243,9 +3289,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_assign_plucked_vector(ptr_->peek_out(), 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, @@ -3255,7 +3301,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..2c72cc6e9 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -963,14 +963,37 @@ template ostream& operator << (ostream&out, vvp_sub_pointer_t val) * The vvp_send_*() functions take as input a vvp_net_ptr_t and follow * all the fan-out chain, delivering the specified value. */ -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_ptr_t peek_out() const { return out_; } + 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); + private: + vvp_net_ptr_t out_; + public: // Need a better new for these objects. static void* operator new(std::size_t size); static void operator delete(void*); // not implemented @@ -1536,8 +1559,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 +1598,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 +1611,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 +1625,26 @@ 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) +{ + vvp_send_vec4(out_, val, context); +} + +inline void vvp_net_t::send_vec4_pv(const vvp_vector4_t&val, + unsigned base, unsigned wid, unsigned vwid, + vvp_context_t context) +{ + vvp_send_vec4_pv(out_, val, base, wid, vwid, context); +} + +inline void vvp_net_t::send_vec8(const vvp_vector8_t&val) +{ + vvp_send_vec8(out_, val); +} + +inline void vvp_net_t::send_real(double val, vvp_context_t context) +{ + vvp_send_real(out_, val, context); +} + #endif From 6f8b2296460fb912d14cd2d834e064caf39474c2 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 6 Apr 2009 21:47:21 -0700 Subject: [PATCH 02/54] Remove peek_out() access to the vvp_net_t out member. Fix up the last bits of code that accessed the ->out member of the vvp_net_t class. Now the out member is only accessed by send_* methods. --- vvp/schedule.cc | 32 ++++++++++++++++++++++++++++++++ vvp/schedule.h | 9 +++++++++ vvp/vvp_net.cc | 2 +- vvp/vvp_net.h | 1 - 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/vvp/schedule.cc b/vvp/schedule.cc index aca2ba308..0c9f7b63a 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 generic_event_s : public event_s { vvp_gen_event_t obj; bool delete_obj_when_done; @@ -595,6 +616,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, diff --git a/vvp/schedule.h b/vvp/schedule.h index 391643d2f..30f7bc5b5 100644 --- a/vvp/schedule.h +++ b/vvp/schedule.h @@ -57,6 +57,15 @@ extern void schedule_assign_array_word(vvp_array_t mem, unsigned off, vvp_vector4_t 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 diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index e470dfbea..c6f040368 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -3289,7 +3289,7 @@ void vvp_wide_fun_core::propagate_vec4(const vvp_vector4_t&bit, vvp_time64_t delay) { if (delay) - schedule_assign_plucked_vector(ptr_->peek_out(), delay, bit, 0, bit.size()); + schedule_propagate_plucked_vector(ptr_, delay, bit, 0, bit.size()); else ptr_->send_vec4(bit, 0); } diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 2c72cc6e9..b1894b6a2 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -973,7 +973,6 @@ class vvp_net_t { vvp_net_ptr_t port[4]; vvp_net_fun_t*fun; - vvp_net_ptr_t peek_out() const { return out_; } public: // Connect the port to the output from this net. void link(vvp_net_ptr_t port); From 5529182f1f644844b4e7b61d675273f62e08f133 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 15 Apr 2009 19:08:37 -0700 Subject: [PATCH 03/54] Spread the vvp_net.h contents out a bit. the vvp_net.h header file is getting pretty huge. This divides the obviously separable signal functor code out into its own header and source files. Also, fill out the use of the filter member of the vvp_net_t object. Test the output of the vvp_net_t against the filter. --- vvp/Makefile.in | 2 +- vvp/array.cc | 1 + vvp/ufunc.cc | 1 + vvp/vpi_callback.cc | 1 + vvp/vpi_real.cc | 1 + vvp/vpi_signal.cc | 1 + vvp/vthread.cc | 1 + vvp/vvp_net.cc | 772 +----------------------------------------- vvp/vvp_net.h | 322 +++--------------- vvp/vvp_net_sig.cc | 800 ++++++++++++++++++++++++++++++++++++++++++++ vvp/vvp_net_sig.h | 323 ++++++++++++++++++ vvp/words.cc | 1 + 12 files changed, 1171 insertions(+), 1055 deletions(-) create mode 100644 vvp/vvp_net_sig.cc create mode 100644 vvp/vvp_net_sig.h 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/array.cc b/vvp/array.cc index 9c79a5669..9bab08a85 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" diff --git a/vvp/ufunc.cc b/vvp/ufunc.cc index 662630d81..a6a136068 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 diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index bafc05745..ab122c81a 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 diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index cb8093679..ede9ed3f0 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 diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 582c9c6b2..bccbc2e5f 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" diff --git a/vvp/vthread.cc b/vvp/vthread.cc index befa557a7..e7611fdba 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 diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index c6f040368..27b39e96e 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -111,6 +111,8 @@ void vvp_net_t::operator delete(void*) 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) @@ -1610,19 +1612,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; @@ -2512,763 +2501,6 @@ void vvp_fun_drive::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, } -/* **** 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)); - } - ptr.ptr()->send_vec4(bits, 0); - } else { - ptr.ptr()->send_vec4(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) { - ptr.ptr()->send_vec4(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; - 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); -} - -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)); - } - ptr.ptr()->send_vec8(bits); - - } else { - ptr.ptr()->send_vec8(bits8_); - } - - run_vpi_callbacks(); -} - -void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net) -{ - force_mask_ = vvp_vector2_t(); - if (net) { - ptr.ptr()->send_vec8(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; - ptr.ptr()->send_real(bit, 0); - run_vpi_callbacks(); - } - } - break; - - case 1: // Continuous assign value - continuous_assign_active_ = true; - bits_ = bit; - ptr.ptr()->send_real(bit, 0); - run_vpi_callbacks(); - break; - - case 2: // Force value - force_mask_ = vvp_vector2_t(1, 1); - force_ = bit; - ptr.ptr()->send_real(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) { - ptr.ptr()->send_real(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; - ptr.ptr()->send_real(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) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index b1894b6a2..808b61b52 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -42,6 +42,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; @@ -961,7 +962,9 @@ 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. */ class vvp_net_t { public: @@ -972,6 +975,7 @@ class vvp_net_t { #endif vvp_net_ptr_t port[4]; vvp_net_fun_t*fun; + vvp_net_fil_t*fil; public: // Connect the port to the output from this net. @@ -1066,6 +1070,30 @@ 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 can be used to implement force/release, and also + * can be used to implement vpi net object. + */ +class vvp_net_fil_t { + + public: + vvp_net_fil_t(); + virtual ~vvp_net_fil_t(); + + public: + virtual bool filter_vec4(const vvp_vector4_t&bit); + virtual bool filter_vec8(const vvp_vector8_t&val); + virtual bool filter_real(double val); + virtual bool filter_long(long val); +}; + /* **** Some core net functions **** */ /* vvp_fun_concat @@ -1159,60 +1187,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. @@ -1249,235 +1223,6 @@ class vvp_vpi_callback_wordable : public vvp_vpi_callback { 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 @@ -1626,6 +1371,9 @@ inline void vvp_net_t::send_vec8_pv(const vvp_vector8_t&val, inline void vvp_net_t::send_vec4(const vvp_vector4_t&val, vvp_context_t context) { + if (fil && ! fil->filter_vec4(val)) + return; + vvp_send_vec4(out_, val, context); } @@ -1638,11 +1386,17 @@ inline void vvp_net_t::send_vec4_pv(const vvp_vector4_t&val, inline void vvp_net_t::send_vec8(const vvp_vector8_t&val) { + if (fil && ! fil->filter_vec8(val)) + return; + vvp_send_vec8(out_, val); } 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); } diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc new file mode 100644 index 000000000..cff276760 --- /dev/null +++ b/vvp/vvp_net_sig.cc @@ -0,0 +1,800 @@ +/* + * 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 + +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_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)); + } + ptr.ptr()->send_vec4(bits, 0); + } else { + ptr.ptr()->send_vec4(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) { + ptr.ptr()->send_vec4(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; + 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); +} + +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)); + } + ptr.ptr()->send_vec8(bits); + + } else { + ptr.ptr()->send_vec8(bits8_); + } + + run_vpi_callbacks(); +} + +void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net) +{ + force_mask_ = vvp_vector2_t(); + if (net) { + ptr.ptr()->send_vec8(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; + ptr.ptr()->send_real(bit, 0); + run_vpi_callbacks(); + } + } + break; + + case 1: // Continuous assign value + continuous_assign_active_ = true; + bits_ = bit; + ptr.ptr()->send_real(bit, 0); + run_vpi_callbacks(); + break; + + case 2: // Force value + force_mask_ = vvp_vector2_t(1, 1); + force_ = bit; + ptr.ptr()->send_real(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) { + ptr.ptr()->send_real(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; + ptr.ptr()->send_real(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); +} diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h new file mode 100644 index 000000000..ef6e6d44d --- /dev/null +++ b/vvp/vvp_net_sig.h @@ -0,0 +1,323 @@ +#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. + * + * 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. + */ + +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_; +}; + + +#endif diff --git a/vvp/words.cc b/vvp/words.cc index cd1a06d51..935b5bfa2 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -20,6 +20,7 @@ # include "compile.h" # include "vpi_priv.h" # include "array.h" +# include "vvp_net_sig.h" # include "schedule.h" # include # include From 7e9e50d3b02fa30e830cc0f196066c3ae5f3baa4 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 24 Apr 2009 21:50:00 -0700 Subject: [PATCH 04/54] The vvp_vpi_callback belongs with the vvp_set_sig stuff. Move the vvp_vpi_callback to the vvp_net_sig.h header file, and collapse some useless hierarchy. (Specifically, all callbackable items are also wordable.) Move the run_vpi_callback invocation for wires/variables from the output generator to the newly implemented filter object. This is starting to get the filter class working. --- vvp/vpi_callback.cc | 37 ++++++++--------------- vvp/vvp_net.cc | 28 +++++++++++++++++ vvp/vvp_net.h | 36 ---------------------- vvp/vvp_net_sig.cc | 60 ++++++++++++++++++++++++------------ vvp/vvp_net_sig.h | 74 +++++++++++++++++++++++++++++++++++++++------ vvp/words.cc | 4 +++ 6 files changed, 149 insertions(+), 90 deletions(-) diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index ab122c81a..829a7a537 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -504,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) @@ -536,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; @@ -565,31 +577,6 @@ 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) { switch (vp->format) { diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 27b39e96e..356d8fc73 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -194,6 +194,34 @@ void vvp_net_fun_t::operator delete(void*) assert(0); } +vvp_net_fil_t::vvp_net_fil_t() +{ +} + +vvp_net_fil_t::~vvp_net_fil_t() +{ +} + +bool vvp_net_fil_t::filter_vec4(const vvp_vector4_t&) +{ + return true; +} + +bool vvp_net_fil_t::filter_vec8(const vvp_vector8_t&) +{ + return true; +} + +bool vvp_net_fil_t::filter_real(double) +{ + return true; +} + +bool vvp_net_fil_t::filter_long(long) +{ + return true; +} + /* *** BIT operations *** */ vvp_bit4_t add_with_carry(vvp_bit4_t a, vvp_bit4_t b, vvp_bit4_t&c) { diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 808b61b52..75ca1f98d 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1187,42 +1187,6 @@ class vvp_fun_extend_signed : public vvp_net_fun_t { unsigned width_; }; -/* -* 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_; -}; - /* * Wide Functors: * Wide functors represent special devices that may have more than 4 diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index cff276760..4de87eaf6 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -41,24 +41,46 @@ template T coerce_to_width(const T&that, unsigned width) return res; } -/* **** vvp_fun_signal methods **** */ - -vvp_fun_signal_base::vvp_fun_signal_base() +vvp_filter_wire_base::vvp_filter_wire_base() { - needs_init_ = true; continuous_assign_active_ = false; - force_link = 0; - cassign_link = 0; - count_functors_sig += 1; } -void vvp_fun_signal_base::deassign() +vvp_filter_wire_base::~vvp_filter_wire_base() +{ +} + +bool vvp_filter_wire_base::filter_vec4(const vvp_vector4_t&) +{ + run_vpi_callbacks(); + return true; +} + +bool vvp_filter_wire_base::filter_vec8(const vvp_vector8_t&) +{ + run_vpi_callbacks(); + return true; +} + +bool vvp_filter_wire_base::filter_real(double) +{ + run_vpi_callbacks(); + return true; +} + +bool vvp_filter_wire_base::filter_long(long) +{ + run_vpi_callbacks(); + return true; +} + +void vvp_filter_wire_base::deassign() { continuous_assign_active_ = false; assign_mask_ = vvp_vector2_t(); } -void vvp_fun_signal_base::deassign_pv(unsigned base, unsigned wid) +void vvp_filter_wire_base::deassign_pv(unsigned base, unsigned wid) { for (unsigned idx = 0 ; idx < wid ; idx += 1) { assign_mask_.set_bit(base+idx, 0); @@ -69,6 +91,16 @@ void vvp_fun_signal_base::deassign_pv(unsigned base, unsigned wid) } } +/* **** vvp_fun_signal methods **** */ + +vvp_fun_signal_base::vvp_fun_signal_base() +{ + needs_init_ = true; + force_link = 0; + cassign_link = 0; + count_functors_sig += 1; +} + /* * The signal functor takes commands as long values to port-3. This * method interprets those commands. @@ -294,8 +326,6 @@ void vvp_fun_signal4_sa::calculate_output_(vvp_net_ptr_t ptr) } else { ptr.ptr()->send_vec4(bits4_, 0); } - - run_vpi_callbacks(); } void vvp_fun_signal4_sa::release(vvp_net_ptr_t ptr, bool net) @@ -303,7 +333,6 @@ void vvp_fun_signal4_sa::release(vvp_net_ptr_t ptr, bool net) force_mask_ = vvp_vector2_t(); if (net) { ptr.ptr()->send_vec4(bits4_, 0); - run_vpi_callbacks(); } else { bits4_ = force_; } @@ -589,8 +618,6 @@ void vvp_fun_signal8::calculate_output_(vvp_net_ptr_t ptr) } else { ptr.ptr()->send_vec8(bits8_); } - - run_vpi_callbacks(); } void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net) @@ -598,7 +625,6 @@ void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net) force_mask_ = vvp_vector2_t(); if (net) { ptr.ptr()->send_vec8(bits8_); - run_vpi_callbacks(); } else { bits8_ = force_; } @@ -689,7 +715,6 @@ void vvp_fun_signal_real_sa::recv_real(vvp_net_ptr_t ptr, double bit, bits_ = bit; needs_init_ = false; ptr.ptr()->send_real(bit, 0); - run_vpi_callbacks(); } } break; @@ -698,14 +723,12 @@ void vvp_fun_signal_real_sa::recv_real(vvp_net_ptr_t ptr, double bit, continuous_assign_active_ = true; bits_ = bit; ptr.ptr()->send_real(bit, 0); - run_vpi_callbacks(); break; case 2: // Force value force_mask_ = vvp_vector2_t(1, 1); force_ = bit; ptr.ptr()->send_real(bit, 0); - run_vpi_callbacks(); break; default: @@ -720,7 +743,6 @@ void vvp_fun_signal_real_sa::release(vvp_net_ptr_t ptr, bool net) force_mask_ = vvp_vector2_t(); if (net) { ptr.ptr()->send_real(bits_, 0); - run_vpi_callbacks(); } else { bits_ = force_; } diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index ef6e6d44d..5c9802e4d 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -36,6 +36,43 @@ class ostream; using namespace std; +/* + * 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_; +}; + /* 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 @@ -90,7 +127,33 @@ using namespace std; * propagate starting at the next input change. */ -class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback_wordable { + +class vvp_filter_wire_base : public vvp_net_fil_t, public vvp_vpi_callback { + + public: + vvp_filter_wire_base(); + ~vvp_filter_wire_base(); + + bool filter_vec4(const vvp_vector4_t&val); + bool filter_vec8(const vvp_vector8_t&val); + bool filter_real(double val); + bool filter_long(long val); + + public: + 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; + + protected: + bool continuous_assign_active_; + vvp_vector2_t force_mask_; + vvp_vector2_t assign_mask_; + +}; + +class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_filter_wire_base { public: vvp_fun_signal_base(); @@ -110,15 +173,6 @@ class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback_wordab // 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; }; /* diff --git a/vvp/words.cc b/vvp/words.cc index 935b5bfa2..f7d5173de 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -43,6 +43,7 @@ static void __compile_var_real(char*label, char*name, } vvp_net_t*net = new vvp_net_t; net->fun = fun; + net->fil = fun; define_functor_symbol(label, net); @@ -93,6 +94,7 @@ static void __compile_var(char*label, char*name, } vvp_net_t*node = new vvp_net_t; node->fun = vsig; + node->fil = vsig; define_functor_symbol(label, node); @@ -171,6 +173,7 @@ static void __compile_net(char*label, char*name, ? dynamic_cast(new vvp_fun_signal8(wid)) : dynamic_cast(new vvp_fun_signal4_sa(wid,BIT4_Z)); node->fun = vsig; + node->fil = vsig; /* Add the label into the functor symbol table. */ define_functor_symbol(label, node); @@ -232,6 +235,7 @@ static void __compile_real(char*label, char*name, vvp_fun_signal_real*fun = new vvp_fun_signal_real_sa; net->fun = fun; + net->fil = fun; /* Add the label into the functor symbol table. */ define_functor_symbol(label, net); From ba00c6caf7206722eb95f8e0f6f61023407fe1ce Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 4 May 2009 20:26:41 -0700 Subject: [PATCH 05/54] Change implementation of force/release to use filters. This is moving towards moving force/release out of the signal class. The end-game is to remove all of the wire implementation out of the functor and into the filter. Variables will remain in the functor. --- vvp/vvp_net.cc | 28 +-- vvp/vvp_net.h | 31 +++- vvp/vvp_net_sig.cc | 439 +++++++++++++++++++++++++++++---------------- vvp/vvp_net_sig.h | 56 ++++-- 4 files changed, 364 insertions(+), 190 deletions(-) diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 356d8fc73..205eb2704 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -202,22 +202,22 @@ vvp_net_fil_t::~vvp_net_fil_t() { } -bool vvp_net_fil_t::filter_vec4(const vvp_vector4_t&) +const vvp_vector4_t* vvp_net_fil_t::filter_vec4(const vvp_vector4_t&val) +{ + return &val; +} + +const vvp_vector8_t* vvp_net_fil_t::filter_vec8(const vvp_vector8_t&val) +{ + return &val; +} + +bool vvp_net_fil_t::filter_real(double&) { return true; } -bool vvp_net_fil_t::filter_vec8(const vvp_vector8_t&) -{ - return true; -} - -bool vvp_net_fil_t::filter_real(double) -{ - return true; -} - -bool vvp_net_fil_t::filter_long(long) +bool vvp_net_fil_t::filter_long(long&) { return true; } @@ -387,6 +387,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) { @@ -2369,6 +2371,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. diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 75ca1f98d..a433747bf 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -196,6 +196,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); @@ -778,6 +781,10 @@ 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; @@ -1088,10 +1095,16 @@ class vvp_net_fil_t { virtual ~vvp_net_fil_t(); public: - virtual bool filter_vec4(const vvp_vector4_t&bit); - virtual bool filter_vec8(const vvp_vector8_t&val); - virtual bool filter_real(double val); - virtual bool filter_long(long val); + // 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. + virtual const vvp_vector4_t* filter_vec4(const vvp_vector4_t&bit); + virtual const vvp_vector8_t* filter_vec8(const vvp_vector8_t&val); + + // Return true if the value is to be propagated, or false if + // propagation is suppressed. The value may be edited by the filter. + virtual bool filter_real(double&val); + virtual bool filter_long(long&val); }; /* **** Some core net functions **** */ @@ -1335,10 +1348,11 @@ inline void vvp_net_t::send_vec8_pv(const vvp_vector8_t&val, inline void vvp_net_t::send_vec4(const vvp_vector4_t&val, vvp_context_t context) { - if (fil && ! fil->filter_vec4(val)) + const vvp_vector4_t*val_out = fil? fil->filter_vec4(val) : &val; + if (val_out == 0) return; - vvp_send_vec4(out_, val, context); + vvp_send_vec4(out_, *val_out, context); } inline void vvp_net_t::send_vec4_pv(const vvp_vector4_t&val, @@ -1350,10 +1364,11 @@ inline void vvp_net_t::send_vec4_pv(const vvp_vector4_t&val, inline void vvp_net_t::send_vec8(const vvp_vector8_t&val) { - if (fil && ! fil->filter_vec8(val)) + const vvp_vector8_t*val_out = fil? fil->filter_vec8(val) : &val; + if (val_out == 0) return; - vvp_send_vec8(out_, val); + vvp_send_vec8(out_, *val_out); } inline void vvp_net_t::send_real(double val, vvp_context_t context) diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 4de87eaf6..4b3843366 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -43,58 +43,205 @@ template T coerce_to_width(const T&that, unsigned width) vvp_filter_wire_base::vvp_filter_wire_base() { - continuous_assign_active_ = false; } vvp_filter_wire_base::~vvp_filter_wire_base() { } -bool vvp_filter_wire_base::filter_vec4(const vvp_vector4_t&) +const vvp_vector4_t* vvp_filter_wire_base::filter_vec4(const vvp_vector4_t&val) +{ + if (force_mask_.size()) { + bool propagate_flag = false; + assert(val.size() == force_mask_.size()); + assert(val.size() == force4_.size()); + + filter4_ = val; + for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + if (force_mask_.value(idx)) + filter4_.set_bit(idx, force4_.value(idx)); + else + propagate_flag = true; + } + + if (propagate_flag) { + run_vpi_callbacks(); + return &filter4_; + } else { + return 0; + } + + } else { + run_vpi_callbacks(); + return &val; + } +} + +const vvp_vector8_t* vvp_filter_wire_base::filter_vec8(const vvp_vector8_t&val) +{ + if (force_mask_.size()) { + bool propagate_flag = false; + assert(val.size() == force_mask_.size()); + assert(val.size() == force8_.size()); + + filter8_ = val; + for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + if (force_mask_.value(idx)) + filter8_.set_bit(idx, force8_.value(idx)); + else + propagate_flag = true; + } + + if (propagate_flag) { + run_vpi_callbacks(); + return&filter8_; + } else { + return 0; + } + } else { + run_vpi_callbacks(); + return &val; + } +} + +bool vvp_filter_wire_base::filter_real(double&val) { run_vpi_callbacks(); return true; } -bool vvp_filter_wire_base::filter_vec8(const vvp_vector8_t&) +bool vvp_filter_wire_base::filter_long(long&) { run_vpi_callbacks(); return true; } -bool vvp_filter_wire_base::filter_real(double) +void vvp_filter_wire_base::force_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) { - run_vpi_callbacks(); - return true; + if (force_mask_.size() == 0) + force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, mask.size()); + if (force4_.size() == 0) + force4_ = val; + + 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); + force4_.set_bit(idx, val.value(idx)); + } } -bool vvp_filter_wire_base::filter_long(long) +void vvp_filter_wire_base::force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) { - run_vpi_callbacks(); - return true; + if (force_mask_.size() == 0) + force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, mask.size()); + if (force8_.size() == 0) + force8_ = val; + + 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); + force8_.set_bit(idx, val.value(idx)); + } } -void vvp_filter_wire_base::deassign() +void vvp_filter_wire_base::force_real(double val, vvp_vector2_t mask) { - continuous_assign_active_ = false; - assign_mask_ = vvp_vector2_t(); -} + if (force_mask_.size() == 0) + force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, mask.size()); -void vvp_filter_wire_base::deassign_pv(unsigned base, unsigned wid) -{ - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - assign_mask_.set_bit(base+idx, 0); + 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); } - if (assign_mask_.is_zero()) { - assign_mask_ = vvp_vector2_t(); + force_real_ = val; +} + +vvp_bit4_t vvp_filter_wire_base::filtered_value(const vvp_vector4_t&val, unsigned idx) const +{ + if (force_mask_.size() == 0) + return val.value(idx); + if (force_mask_.value(idx)) + return force4_.value(idx); + + return val.value(idx); +} + +vvp_scalar_t vvp_filter_wire_base::filtered_value(const vvp_vector8_t&val, unsigned idx) const +{ + if (force_mask_.size() == 0) + return val.value(idx); + if (force_mask_.value(idx)) + return force8_.value(idx); + + return val.value(idx); +} + +const vvp_vector4_t& vvp_filter_wire_base::filtered_vec4(const vvp_vector4_t&val) const +{ + if (force_mask_.size() == 0) + return val; + + filter4_ = val; + for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + if (force_mask_.value(idx)) + filter4_.set_bit(idx, force4_.value(idx)); } + return filter4_; +} + +const vvp_vector8_t& vvp_filter_wire_base::filtered_vec8(const vvp_vector8_t&val) const +{ + if (force_mask_.size() == 0) + return val; + + filter8_ = val; + for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + if (force_mask_.value(idx)) + filter8_.set_bit(idx, force8_.value(idx)); + } + return filter8_; +} + +double vvp_filter_wire_base::filtered_real(double val) const +{ + if (force_mask_.size() == 0) + return val; + if (force_mask_.value(0) == 0) + return val; + + return force_real_; +} + +void vvp_filter_wire_base::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(); } /* **** vvp_fun_signal methods **** */ vvp_fun_signal_base::vvp_fun_signal_base() { + continuous_assign_active_ = false; needs_init_ = true; force_link = 0; cassign_link = 0; @@ -216,17 +363,17 @@ void vvp_fun_signal4_sa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, break; case 2: // Force value + { vvp_vector4_t tmp (bit); - // 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 from a node may not have been sized completely + // by the source, so coerce the size here. + if (tmp.size() != size()) + tmp = coerce_to_width(tmp, size()); - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); - calculate_output_(ptr); - break; + ptr.ptr()->send_vec4(tmp, 0); + force_vec4(tmp, vvp_vector2_t(vvp_vector2_t::FILL1,tmp.size())); + } + break; default: fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); @@ -285,19 +432,16 @@ void vvp_fun_signal4_sa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit 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; + { vvp_vector2_t mask (vvp_vector2_t::FILL0, vwid); + vvp_vector4_t vec (vwid, BIT4_Z); + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + mask.set_bit(base+idx, 1); + vec.set_bit(base+idx, bit.value(idx)); + } + force_vec4(vec, mask); + calculate_output_(ptr); + break; + } default: fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); @@ -314,27 +458,39 @@ void vvp_fun_signal4_sa::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit 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)); - } - ptr.ptr()->send_vec4(bits, 0); - } else { - ptr.ptr()->send_vec4(bits4_, 0); - } + ptr.ptr()->send_vec4(bits4_, 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 vvp_fun_signal4_sa::release(vvp_net_ptr_t ptr, bool net) { - force_mask_ = vvp_vector2_t(); + vvp_vector2_t mask (vvp_vector2_t::FILL1, bits4_.size()); + if (net) { + // If releasing a net, then the output should revert to + // the un-forced value. + release_mask(mask); ptr.ptr()->send_vec4(bits4_, 0); } else { - bits4_ = force_; + // Variables keep their forced value after the release. + bits4_ = filtered_vec4(bits4_); + release_mask(mask); } } @@ -343,55 +499,38 @@ void vvp_fun_signal4_sa::release_pv(vvp_net_ptr_t ptr, bool net, { 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(); + vvp_vector2_t mask (vvp_vector2_t::FILL0, bits4_.size()); + for (unsigned idx = 0 ; idx < wid ; idx += 1) + mask.set_bit(base+idx, 1); + + if (net) { + release_mask(mask); + calculate_output_(ptr); + } else { + bits4_ = filtered_vec4(bits4_); + release_mask(mask); + } - if (net) calculate_output_(ptr); } unsigned vvp_fun_signal4_sa::size() const { - if (force_mask_.size()) - return force_.size(); - else - return bits4_.size(); + 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); - } + return filtered_value(bits4_, 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); - } + return vvp_scalar_t(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_; - } + return filtered_vec4(bits4_); } vvp_fun_signal4_aa::vvp_fun_signal4_aa(unsigned wid, vvp_bit4_t init) @@ -532,17 +671,22 @@ void vvp_fun_signal8::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit) break; case 2: // Force value + { vvp_vector8_t tmp(bit); - // 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 from a node may not have been sized completely + // by the source, so coerce the size here. + if (tmp.size() != size()) + tmp = coerce_to_width(tmp, size()); - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); - calculate_output_(ptr); - break; + // Propagate the forced value before setting the + // force mask. This is so that the forced value gets + // out to the network before the force filter is set + // up. If the force filter is set up first, then the + // filter will block the exact match. + ptr.ptr()->send_vec8(tmp); + force_vec8(tmp, vvp_vector2_t(vvp_vector2_t::FILL1,tmp.size())); + } + break; default: fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); @@ -582,19 +726,16 @@ void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, 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; + { vvp_vector2_t mask (vvp_vector2_t::FILL0, vwid); + vvp_vector8_t vec (vvp_vector4_t(vwid, BIT4_Z),6,6); + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + mask.set_bit(base+idx, 1); + vec.set_bit(base+idx, bit.value(idx)); + } + force_vec8(vec, mask); + calculate_output_(ptr); + break; + } default: fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); @@ -605,28 +746,22 @@ void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, 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)); - } - ptr.ptr()->send_vec8(bits); - - } else { - ptr.ptr()->send_vec8(bits8_); - } + ptr.ptr()->send_vec8(bits8_); } void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net) { - force_mask_ = vvp_vector2_t(); + vvp_vector2_t mask (vvp_vector2_t::FILL1, bits8_.size()); + if (net) { + // If releasing a net, then the output should revert to + // the un-forced value. + release_mask(mask); ptr.ptr()->send_vec8(bits8_); } else { - bits8_ = force_; + // Variables keep their forced value after the release. + bits8_ = filtered_vec8(bits8_); + release_mask(mask); } } @@ -635,50 +770,37 @@ void vvp_fun_signal8::release_pv(vvp_net_ptr_t ptr, bool net, { 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(); + vvp_vector2_t mask (vvp_vector2_t::FILL0, bits8_.size()); + for (unsigned idx = 0 ; idx < wid ; idx += 1) + mask.set_bit(base+idx, 1); - if (net) calculate_output_(ptr); + if (net) { + release_mask(mask); + calculate_output_(ptr); + } else { + bits8_ = filtered_vec8(bits8_); + release_mask(mask); + } } unsigned vvp_fun_signal8::size() const { - if (force_mask_.size()) - return force_.size(); - else - return bits8_.size(); + 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(); + return filtered_value(bits8_, 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_); + return reduce4(filtered_vec8(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); + return filtered_value(bits8_, idx); } @@ -699,10 +821,7 @@ vvp_fun_signal_real_sa::vvp_fun_signal_real_sa() double vvp_fun_signal_real_sa::real_value() const { - if (force_mask_.size()) - return force_; - else - return bits_; + return filtered_real(bits_); } void vvp_fun_signal_real_sa::recv_real(vvp_net_ptr_t ptr, double bit, @@ -726,8 +845,7 @@ void vvp_fun_signal_real_sa::recv_real(vvp_net_ptr_t ptr, double bit, break; case 2: // Force value - force_mask_ = vvp_vector2_t(1, 1); - force_ = bit; + force_real(bit, vvp_vector2_t(vvp_vector2_t::FILL1, 1)); ptr.ptr()->send_real(bit, 0); break; @@ -740,11 +858,14 @@ void vvp_fun_signal_real_sa::recv_real(vvp_net_ptr_t ptr, double bit, void vvp_fun_signal_real_sa::release(vvp_net_ptr_t ptr, bool net) { - force_mask_ = vvp_vector2_t(); + vvp_vector2_t mask (vvp_vector2_t::FILL1, 1); + if (net) { + release_mask(mask); ptr.ptr()->send_real(bits_, 0); } else { - bits_ = force_; + bits_ = filtered_real(bits_); + release_mask(mask); } } diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 5c9802e4d..2d9375c19 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -134,23 +134,51 @@ class vvp_filter_wire_base : public vvp_net_fil_t, public vvp_vpi_callback { vvp_filter_wire_base(); ~vvp_filter_wire_base(); - bool filter_vec4(const vvp_vector4_t&val); - bool filter_vec8(const vvp_vector8_t&val); - bool filter_real(double val); - bool filter_long(long val); + // These are the virtual methods that we implement to perform + // the wire-style filtering. + const vvp_vector4_t* filter_vec4(const vvp_vector4_t&val); + const vvp_vector8_t* filter_vec8(const vvp_vector8_t&val); + bool filter_real(double&val); + bool filter_long(long&val); public: - void deassign(); - void deassign_pv(unsigned base, unsigned wid); + // Force/release work in the filter by setting the forced + // value using one of the force_* methods. This sets the + // forced value as a mask of the bits of the vector that are + // forced. The filter then automatically runs the filter on + // the outputs that pass through. You can also get at the + // filtering results using the filtered_* methods. The + // release_mask() method releases bits of the vector. + + // Enable filter 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); + + // Test the value against the filter. + vvp_bit4_t filtered_value(const vvp_vector4_t&val, unsigned idx) const; + vvp_scalar_t filtered_value(const vvp_vector8_t&val, unsigned idx) const; + + const vvp_vector4_t& filtered_vec4(const vvp_vector4_t&val) const; + const vvp_vector8_t& filtered_vec8(const vvp_vector8_t&val) const; + double filtered_real(double val) const; + + // Release the force on the bits set in the mask. + void release_mask(vvp_vector2_t mask); + 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; - protected: - bool continuous_assign_active_; + private: + // Forced value vvp_vector2_t force_mask_; - vvp_vector2_t assign_mask_; - + vvp_vector4_t force4_; + vvp_vector8_t force8_; + double force_real_; + // This is used as a static return value. + mutable vvp_vector4_t filter4_; + mutable vvp_vector8_t filter8_; }; class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_filter_wire_base { @@ -161,6 +189,9 @@ class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_filter_wire_base { void recv_long_pv(vvp_net_ptr_t port, long bit, unsigned base, unsigned wid); + void deassign(); + void deassign_pv(unsigned base, unsigned wid); + public: /* The %force/link instruction needs a place to write the @@ -169,6 +200,10 @@ class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_filter_wire_base { struct vvp_net_t*force_link; 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. @@ -232,7 +267,6 @@ class vvp_fun_signal4_sa : public vvp_fun_signal4 { void calculate_output_(vvp_net_ptr_t ptr); vvp_vector4_t bits4_; - vvp_vector4_t force_; }; /* From a5046bd8c6db1def098eb3e4f9cf50d728db94ec Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 4 May 2009 20:39:26 -0700 Subject: [PATCH 06/54] Filters need to let through the forced value. When the forced value is first set, the filter needs to let that value through. Otherwise, the forced value will not propagate out from the net. --- vvp/vvp_net_sig.cc | 19 ++++++++++--------- vvp/vvp_net_sig.h | 3 +++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 4b3843366..b5d62c351 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -43,6 +43,7 @@ template T coerce_to_width(const T&that, unsigned width) vvp_filter_wire_base::vvp_filter_wire_base() { + force_propagate_ = false; } vvp_filter_wire_base::~vvp_filter_wire_base() @@ -52,7 +53,8 @@ vvp_filter_wire_base::~vvp_filter_wire_base() const vvp_vector4_t* vvp_filter_wire_base::filter_vec4(const vvp_vector4_t&val) { if (force_mask_.size()) { - bool propagate_flag = false; + bool propagate_flag = force_propagate_; + force_propagate_ = false; assert(val.size() == force_mask_.size()); assert(val.size() == force4_.size()); @@ -80,7 +82,8 @@ const vvp_vector4_t* vvp_filter_wire_base::filter_vec4(const vvp_vector4_t&val) const vvp_vector8_t* vvp_filter_wire_base::filter_vec8(const vvp_vector8_t&val) { if (force_mask_.size()) { - bool propagate_flag = false; + bool propagate_flag = force_propagate_; + force_propagate_ = false; assert(val.size() == force_mask_.size()); assert(val.size() == force8_.size()); @@ -130,6 +133,7 @@ void vvp_filter_wire_base::force_vec4(const vvp_vector4_t&val, vvp_vector2_t mas force_mask_.set_bit(idx, 1); force4_.set_bit(idx, val.value(idx)); + force_propagate_ = true; } } @@ -147,6 +151,7 @@ void vvp_filter_wire_base::force_vec8(const vvp_vector8_t&val, vvp_vector2_t mas force_mask_.set_bit(idx, 1); force8_.set_bit(idx, val.value(idx)); + force_propagate_ = true; } } @@ -161,6 +166,7 @@ void vvp_filter_wire_base::force_real(double val, vvp_vector2_t mask) continue; force_mask_.set_bit(idx, 1); + force_propagate_ = true; } force_real_ = val; @@ -370,8 +376,8 @@ void vvp_fun_signal4_sa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, if (tmp.size() != size()) tmp = coerce_to_width(tmp, size()); - ptr.ptr()->send_vec4(tmp, 0); force_vec4(tmp, vvp_vector2_t(vvp_vector2_t::FILL1,tmp.size())); + calculate_output_(ptr); } break; @@ -678,13 +684,8 @@ void vvp_fun_signal8::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit) if (tmp.size() != size()) tmp = coerce_to_width(tmp, size()); - // Propagate the forced value before setting the - // force mask. This is so that the forced value gets - // out to the network before the force filter is set - // up. If the force filter is set up first, then the - // filter will block the exact match. - ptr.ptr()->send_vec8(tmp); force_vec8(tmp, vvp_vector2_t(vvp_vector2_t::FILL1,tmp.size())); + calculate_output_(ptr); } break; diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 2d9375c19..115e0e1ab 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -176,6 +176,9 @@ class vvp_filter_wire_base : public vvp_net_fil_t, public vvp_vpi_callback { vvp_vector4_t force4_; vvp_vector8_t force8_; double force_real_; + // True if the next filter must propagate. Need this to allow + // the forced value to get through. + bool force_propagate_; // This is used as a static return value. mutable vvp_vector4_t filter4_; mutable vvp_vector8_t filter8_; From 682ab886d8571391de74416ac2e2a831ca59fe29 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 15 May 2009 20:49:07 -0700 Subject: [PATCH 07/54] Implement release and deassign more directly. There is no use implementing the release and deassign methods as port commands. It's confusing and a waste of vvp_net_t functionality. It also obscures what needs to be done to more force/release into the filter object. --- vvp/vpi_signal.cc | 8 ++++-- vvp/vthread.cc | 25 +++++++++---------- vvp/vvp_net_sig.cc | 61 ---------------------------------------------- vvp/vvp_net_sig.h | 3 --- 4 files changed, 17 insertions(+), 80 deletions(-) diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index bccbc2e5f..4ae87285e 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -757,9 +757,13 @@ 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); + vvp_fun_signal_base*sig + = reinterpret_cast(rfp->node->fun); + assert(sig); + + vvp_net_ptr_t ptr(rfp->node, 0); /* Assume this is a net. (XXXX Are we sure?) */ - vvp_send_long(dest_cmd, 2 /* release/net */); + sig->release(ptr, true); return ref; } diff --git a/vvp/vthread.cc b/vvp/vthread.cc index e7611fdba..b11a2f034 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1747,11 +1747,10 @@ bool of_DEASSIGN(vthread_t thr, vvp_code_t cp) } /* 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; @@ -1772,8 +1771,7 @@ bool of_DEASSIGN_WR(vthread_t thr, vvp_code_t cp) sig->cassign_link = 0; } - vvp_net_ptr_t ptr (net, 3); - vvp_send_long(ptr, 1); + sig->deassign(); return true; } @@ -3940,11 +3938,11 @@ bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp) assert(sig->force_link == 0); /* 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); + sig->release(ptr, true); } else { - vvp_send_long_pv(ptr, 2, base, width); + sig->release_pv(ptr, true, base, width); } return true; @@ -3980,11 +3978,11 @@ bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp) // 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); + vvp_net_ptr_t ptr (net, 0); if (full_sig) { - vvp_send_long(ptr, 3); + sig->release(ptr, false); } else { - vvp_send_long_pv(ptr, 3, base, width); + sig->release_pv(ptr, false, base, width); } return true; @@ -4008,9 +4006,8 @@ bool of_RELEASE_WR(vthread_t thr, vvp_code_t cp) } // 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); + sig->release(ptr, type==0); return true; } diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index b5d62c351..5a99f18de 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -254,67 +254,6 @@ vvp_fun_signal_base::vvp_fun_signal_base() count_functors_sig += 1; } -/* - * 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) { diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 115e0e1ab..049bf9a9b 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -188,9 +188,6 @@ class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_filter_wire_base { 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); void deassign(); void deassign_pv(unsigned base, unsigned wid); From 9a348e2174eab9eb027d8bdc4bdb05a713c9e772 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 23 May 2009 10:55:07 -0700 Subject: [PATCH 08/54] Split type-specific filters into type-specific derived classes. The wire base class cannot carry all the overhead for handling all the different net types, so split it out into derived classes. This will also move me closer to splitting wires away from variables. --- vvp/vvp_net_sig.cc | 194 ++++++++++++++++++++------------------------- vvp/vvp_net_sig.h | 93 +++++++++++++++------- 2 files changed, 151 insertions(+), 136 deletions(-) diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 5a99f18de..9749d20af 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -50,25 +50,25 @@ vvp_filter_wire_base::~vvp_filter_wire_base() { } -const vvp_vector4_t* vvp_filter_wire_base::filter_vec4(const vvp_vector4_t&val) +template const T*vvp_filter_wire_base::filter_mask_(const T&val, const T&force, T&filter) { if (force_mask_.size()) { bool propagate_flag = force_propagate_; force_propagate_ = false; assert(val.size() == force_mask_.size()); - assert(val.size() == force4_.size()); + assert(val.size() == force.size()); - filter4_ = val; + filter = val; for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { if (force_mask_.value(idx)) - filter4_.set_bit(idx, force4_.value(idx)); + filter.set_bit(idx, force.value(idx)); else propagate_flag = true; } if (propagate_flag) { run_vpi_callbacks(); - return &filter4_; + return &filter; } else { return 0; } @@ -79,83 +79,119 @@ const vvp_vector4_t* vvp_filter_wire_base::filter_vec4(const vvp_vector4_t&val) } } -const vvp_vector8_t* vvp_filter_wire_base::filter_vec8(const vvp_vector8_t&val) -{ - if (force_mask_.size()) { - bool propagate_flag = force_propagate_; - force_propagate_ = false; - assert(val.size() == force_mask_.size()); - assert(val.size() == force8_.size()); - - filter8_ = val; - for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { - if (force_mask_.value(idx)) - filter8_.set_bit(idx, force8_.value(idx)); - else - propagate_flag = true; - } - - if (propagate_flag) { - run_vpi_callbacks(); - return&filter8_; - } else { - return 0; - } - } else { - run_vpi_callbacks(); - return &val; - } -} - -bool vvp_filter_wire_base::filter_real(double&val) +template bool vvp_filter_wire_base::filter_mask_(T&val) { run_vpi_callbacks(); return true; } -bool vvp_filter_wire_base::filter_long(long&) +const vvp_vector4_t* vvp_fun_signal4::filter_vec4(const vvp_vector4_t&val) { - run_vpi_callbacks(); - return true; + return filter_mask_(val, force4_, filter4_); } -void vvp_filter_wire_base::force_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) +const vvp_vector8_t* vvp_fun_signal8::filter_vec8(const vvp_vector8_t&val) { - if (force_mask_.size() == 0) - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, mask.size()); + return filter_mask_(val, force8_, filter8_); +} + +bool vvp_fun_signal_real::filter_real(double&val) +{ + return filter_mask_(val); +} + +bool vvp_filter_wire_base::filter_long(long&val) +{ + return filter_mask_(val); +} + +void vvp_fun_signal4::force_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) +{ + force_mask(mask); + if (force4_.size() == 0) force4_ = val; - 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); force4_.set_bit(idx, val.value(idx)); - force_propagate_ = true; } } -void vvp_filter_wire_base::force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) +void vvp_fun_signal8::force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) { - if (force_mask_.size() == 0) - force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, mask.size()); + force_mask(mask); + if (force8_.size() == 0) force8_ = val; - 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); force8_.set_bit(idx, val.value(idx)); - force_propagate_ = true; } } -void vvp_filter_wire_base::force_real(double val, vvp_vector2_t mask) +void vvp_fun_signal_real::force_real(double val, vvp_vector2_t mask) +{ + force_mask(mask); + force_real_ = val; +} + +vvp_bit4_t vvp_fun_signal4::filtered_value(const vvp_vector4_t&val, unsigned idx) const +{ + if (test_force_mask(idx)) + return force4_.value(idx); + else + return val.value(idx); +} + +vvp_scalar_t vvp_fun_signal8::filtered_value(const vvp_vector8_t&val, unsigned idx) const +{ + if (test_force_mask(idx)) + return force8_.value(idx); + else + return val.value(idx); +} + +const vvp_vector4_t& vvp_fun_signal4::filtered_vec4(const vvp_vector4_t&val) const +{ + if (test_force_mask_is_zero()) + return val; + + filter4_ = val; + for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + if (test_force_mask(idx)) + filter4_.set_bit(idx, force4_.value(idx)); + } + return filter4_; +} + +const vvp_vector8_t& vvp_fun_signal8::filtered_vec8(const vvp_vector8_t&val) const +{ + if (test_force_mask_is_zero()) + return val; + + filter8_ = val; + for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { + if (test_force_mask(idx)) + filter8_.set_bit(idx, force8_.value(idx)); + } + return filter8_; +} + +double vvp_fun_signal_real::filtered_real(double val) const +{ + if (test_force_mask_is_zero()) + return val; + + return force_real_; +} + +void vvp_filter_wire_base::force_mask(vvp_vector2_t mask) { if (force_mask_.size() == 0) force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, mask.size()); @@ -168,64 +204,6 @@ void vvp_filter_wire_base::force_real(double val, vvp_vector2_t mask) force_mask_.set_bit(idx, 1); force_propagate_ = true; } - - force_real_ = val; -} - -vvp_bit4_t vvp_filter_wire_base::filtered_value(const vvp_vector4_t&val, unsigned idx) const -{ - if (force_mask_.size() == 0) - return val.value(idx); - if (force_mask_.value(idx)) - return force4_.value(idx); - - return val.value(idx); -} - -vvp_scalar_t vvp_filter_wire_base::filtered_value(const vvp_vector8_t&val, unsigned idx) const -{ - if (force_mask_.size() == 0) - return val.value(idx); - if (force_mask_.value(idx)) - return force8_.value(idx); - - return val.value(idx); -} - -const vvp_vector4_t& vvp_filter_wire_base::filtered_vec4(const vvp_vector4_t&val) const -{ - if (force_mask_.size() == 0) - return val; - - filter4_ = val; - for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { - if (force_mask_.value(idx)) - filter4_.set_bit(idx, force4_.value(idx)); - } - return filter4_; -} - -const vvp_vector8_t& vvp_filter_wire_base::filtered_vec8(const vvp_vector8_t&val) const -{ - if (force_mask_.size() == 0) - return val; - - filter8_ = val; - for (unsigned idx = 0 ; idx < val.size() ; idx += 1) { - if (force_mask_.value(idx)) - filter8_.set_bit(idx, force8_.value(idx)); - } - return filter8_; -} - -double vvp_filter_wire_base::filtered_real(double val) const -{ - if (force_mask_.size() == 0) - return val; - if (force_mask_.value(0) == 0) - return val; - - return force_real_; } void vvp_filter_wire_base::release_mask(vvp_vector2_t mask) diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 049bf9a9b..82d1f998f 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -134,11 +134,8 @@ class vvp_filter_wire_base : public vvp_net_fil_t, public vvp_vpi_callback { vvp_filter_wire_base(); ~vvp_filter_wire_base(); - // These are the virtual methods that we implement to perform - // the wire-style filtering. - const vvp_vector4_t* filter_vec4(const vvp_vector4_t&val); - const vvp_vector8_t* filter_vec8(const vvp_vector8_t&val); - bool filter_real(double&val); + // The filter_long is a placeholder here. This should be moved + // to a vvp_fun_signal_long when such a thing is implemented. bool filter_long(long&val); public: @@ -150,40 +147,49 @@ class vvp_filter_wire_base : public vvp_net_fil_t, public vvp_vpi_callback { // filtering results using the filtered_* methods. The // release_mask() method releases bits of the vector. - // Enable filter 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); - - // Test the value against the filter. - vvp_bit4_t filtered_value(const vvp_vector4_t&val, unsigned idx) const; - vvp_scalar_t filtered_value(const vvp_vector8_t&val, unsigned idx) const; - - const vvp_vector4_t& filtered_vec4(const vvp_vector4_t&val) const; - const vvp_vector8_t& filtered_vec8(const vvp_vector8_t&val) const; - double filtered_real(double val) const; - - // Release the force on the bits set in the mask. - void release_mask(vvp_vector2_t mask); - 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; + 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; + + template const T*filter_mask_(const T&val, const T&force, T&buf); + template bool filter_mask_(T&val); + private: // Forced value vvp_vector2_t force_mask_; - vvp_vector4_t force4_; - vvp_vector8_t force8_; - double force_real_; // True if the next filter must propagate. Need this to allow // the forced value to get through. bool force_propagate_; - // This is used as a static return value. - mutable vvp_vector4_t filter4_; - mutable vvp_vector8_t filter8_; }; +inline bool vvp_filter_wire_base::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_filter_wire_base::test_force_mask_is_zero(void) const +{ + if (force_mask_.size() == 0) + return true; + if (force_mask_.is_zero()) + return true; + return false; +} + class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_filter_wire_base { public: @@ -231,6 +237,17 @@ class vvp_fun_signal4 : public vvp_fun_signal_vec { void get_value(struct t_vpi_value*value); + public: + // Enable filter force. + void force_vec4(const vvp_vector4_t&val, vvp_vector2_t mask); + const vvp_vector4_t* filter_vec4(const vvp_vector4_t&val); + // Test the value against the filter. + vvp_bit4_t filtered_value(const vvp_vector4_t&val, unsigned idx) const; + const vvp_vector4_t& filtered_vec4(const vvp_vector4_t&val) const; + + private: + vvp_vector4_t force4_; + mutable vvp_vector4_t filter4_; }; /* @@ -336,11 +353,21 @@ class vvp_fun_signal8 : public vvp_fun_signal_vec { void get_value(struct t_vpi_value*value); + + public: + // Enable filter force. + void force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask); + const vvp_vector8_t* filter_vec8(const vvp_vector8_t&val); + // Test the value against the filter. + vvp_scalar_t filtered_value(const vvp_vector8_t&val, unsigned idx) const; + const vvp_vector8_t& filtered_vec8(const vvp_vector8_t&val) const; + private: void calculate_output_(vvp_net_ptr_t ptr); vvp_vector8_t bits8_; - vvp_vector8_t force_; + vvp_vector8_t force8_; + mutable vvp_vector8_t filter8_; }; class vvp_fun_signal_real : public vvp_fun_signal_base { @@ -352,6 +379,16 @@ class vvp_fun_signal_real : public vvp_fun_signal_base { virtual double real_value() const = 0; void get_value(struct t_vpi_value*value); + + public: + // Enable filter force. + void force_real(double val, vvp_vector2_t mask); + bool filter_real(double&val); + // Test the value against the filter. + double filtered_real(double val) const; + + private: + double force_real_; }; /* From 29a47efa81cc4ce9a5ecf9ca927893cb13cb1d64 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 27 May 2009 20:37:46 -0700 Subject: [PATCH 09/54] Remove the signal functor force-2 input port hack. The vvp_net_t port 2 was used to implement force behavior, but that is no longer how we plan to implement force, so remove it from the implementation of signal nodes. This currently breaks much of the force/release functionality, but we'll get it back by other means. --- vvp/vthread.cc | 38 ++++++++++++++++++++++--------- vvp/vvp_net_sig.cc | 56 ---------------------------------------------- vvp/vvp_net_sig.h | 12 ++++++---- 3 files changed, 36 insertions(+), 70 deletions(-) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 438a1761c..7e1d13698 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -179,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) { @@ -2288,8 +2301,8 @@ bool of_EVCTLS(vthread_t thr, vvp_code_t cp) static void unlink_force(vvp_net_t*net) { - vvp_fun_signal_base*sig - = reinterpret_cast(net->fun); + vvp_filter_wire_base*sig + = reinterpret_cast(net->fun); /* This node must be a signal... */ assert(sig); /* This signal is being forced. */ @@ -2315,8 +2328,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); + vvp_filter_wire_base*sig + = reinterpret_cast(dst->fun); assert(sig); /* Detect the special case that we are already forced the @@ -2359,9 +2372,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 signal on the node. */ + vvp_fun_signal4*sig = reinterpret_cast (net->fun); + assert(sig); + + if (value.size() != sig->size()) + value = coerce_to_width(value, sig->size()); + sig->force_vec4(value, vvp_vector2_t(vvp_vector2_t::FILL1, sig->size())); return true; } @@ -2371,9 +2388,10 @@ 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); + vvp_fun_signal_real*sig = reinterpret_cast(net->fun); + assert(sig); + + sig->force_real(value, vvp_vector2_t(vvp_vector2_t::FILL1, 1)); return true; } diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 9749d20af..f484b5671 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -28,19 +28,6 @@ # include #endif -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_filter_wire_base::vvp_filter_wire_base() { force_propagate_ = false; @@ -285,19 +272,6 @@ void vvp_fun_signal4_sa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, calculate_output_(ptr); break; - case 2: // Force value - { vvp_vector4_t tmp (bit); - - // Force from a node may not have been sized completely - // by the source, so coerce the size here. - if (tmp.size() != size()) - tmp = coerce_to_width(tmp, size()); - - force_vec4(tmp, vvp_vector2_t(vvp_vector2_t::FILL1,tmp.size())); - calculate_output_(ptr); - } - break; - default: fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); assert(0); @@ -354,18 +328,6 @@ void vvp_fun_signal4_sa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit calculate_output_(ptr); break; - case 2: // Force value - { vvp_vector2_t mask (vvp_vector2_t::FILL0, vwid); - vvp_vector4_t vec (vwid, BIT4_Z); - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - mask.set_bit(base+idx, 1); - vec.set_bit(base+idx, bit.value(idx)); - } - force_vec4(vec, mask); - calculate_output_(ptr); - break; - } - default: fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); assert(0); @@ -593,19 +555,6 @@ void vvp_fun_signal8::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit) assert(0); break; - case 2: // Force value - { vvp_vector8_t tmp(bit); - - // Force from a node may not have been sized completely - // by the source, so coerce the size here. - if (tmp.size() != size()) - tmp = coerce_to_width(tmp, size()); - - force_vec8(tmp, vvp_vector2_t(vvp_vector2_t::FILL1,tmp.size())); - calculate_output_(ptr); - } - break; - default: fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); assert(0); @@ -762,11 +711,6 @@ void vvp_fun_signal_real_sa::recv_real(vvp_net_ptr_t ptr, double bit, ptr.ptr()->send_real(bit, 0); break; - case 2: // Force value - force_real(bit, vvp_vector2_t(vvp_vector2_t::FILL1, 1)); - ptr.ptr()->send_real(bit, 0); - break; - default: fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); assert(0); diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 82d1f998f..f7a964b2f 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -151,6 +151,11 @@ class vvp_filter_wire_base : public vvp_net_fil_t, public vvp_vpi_callback { virtual void release_pv(vvp_net_ptr_t ptr, bool net, unsigned base, unsigned wid) =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. */ + struct vvp_net_t*force_link; + protected: // Set bits of the filter force mask void force_mask(vvp_vector2_t mask); @@ -200,10 +205,9 @@ class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_filter_wire_base { 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; + /* 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: From bc6f3cc90509d2be78a1f4d8fd7e25355678c813 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 6 Jun 2009 11:01:12 -0700 Subject: [PATCH 10/54] Re-implement force/link to use a vvp_fun_force node. The vvp_fun_force node converts its input to a call to the force method of the target node. This eliminates the need for linking a net to a force input of a signal. --- vvp/vthread.cc | 68 +++++----------------------------------------- vvp/vvp_net_sig.cc | 52 ++++++++++++++++++++++++++++++++++- vvp/vvp_net_sig.h | 21 +++++++++++++- 3 files changed, 78 insertions(+), 63 deletions(-) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 7e1d13698..e00e07c20 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2299,23 +2299,6 @@ bool of_EVCTLS(vthread_t thr, vvp_code_t cp) return true; } -static void unlink_force(vvp_net_t*net) -{ - vvp_filter_wire_base*sig - = reinterpret_cast(net->fun); - /* This node must be a signal... */ - assert(sig); - /* This signal is being forced. */ - assert(sig->force_link); - - vvp_net_t*src = sig->force_link; - sig->force_link = 0; - - /* We are looking for this pointer. */ - vvp_net_ptr_t net_ptr (net, 2); - src->unlink(net_ptr); -} - /* * the %force/link instruction connects a source node to a * destination node. The destination node must be a signal, as it is @@ -2329,24 +2312,10 @@ bool of_FORCE_LINK(vthread_t thr, vvp_code_t cp) vvp_net_t*src = cp->net2; vvp_filter_wire_base*sig - = reinterpret_cast(dst->fun); + = dynamic_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); - src->link(dst_ptr); + sig->force_link(dst, src); return true; } @@ -3945,15 +3914,8 @@ bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp) bool full_sig = base == 0 && width == sig->size(); - if (sig->force_link) { - if (!full_sig) { - fprintf(stderr, "Sorry: when a signal is forcing a " - "net, I cannot release part of it.\n"); - exit(1); - } - unlink_force(net); - } - assert(sig->force_link == 0); + // XXXX Can't really do this if this is a partial release? + sig->force_unlink(); /* Do we release all or part of the net? */ vvp_net_ptr_t ptr (net, 0); @@ -3981,18 +3943,8 @@ bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp) bool full_sig = base == 0 && width == sig->size(); - // This is the net that is forcing me... - if (vvp_net_t*src = sig->force_link) { - if (!full_sig) { - fprintf(stderr, "Sorry: when a signal is forcing a " - "register, I cannot release part of it.\n"); - exit(1); - } - // And this is the pointer to be removed. - vvp_net_ptr_t dst_ptr (net, 2); - src->unlink(dst_ptr); - sig->force_link = 0; - } + // XXXX Can't really do this if this is a partial release? + sig->force_unlink(); // Send a command to this signal to unforce itself. /* Do we release all or part of the net? */ @@ -4015,13 +3967,7 @@ bool of_RELEASE_WR(vthread_t thr, vvp_code_t cp) vvp_fun_signal_real*sig = reinterpret_cast(net->fun); assert(sig); - // This is the net that is forcing me... - if (vvp_net_t*src = sig->force_link) { - // And this is the pointer to be removed. - vvp_net_ptr_t dst_ptr (net, 2); - src->unlink(dst_ptr); - sig->force_link = 0; - } + sig->force_unlink(); // Send a command to this signal to unforce itself. vvp_net_ptr_t ptr (net, 0); diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index f484b5671..a66e834bb 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -31,10 +31,12 @@ vvp_filter_wire_base::vvp_filter_wire_base() { force_propagate_ = false; + force_link_ = 0; } vvp_filter_wire_base::~vvp_filter_wire_base() { + assert(force_link_ == 0); } template const T*vvp_filter_wire_base::filter_mask_(const T&val, const T&force, T&filter) @@ -66,6 +68,35 @@ template const T*vvp_filter_wire_base::filter_mask_(const T&val, const } } +void vvp_filter_wire_base::force_link(vvp_net_t*dst, vvp_net_t*src) +{ + assert(dst->fil == this); + + if (force_link_ == 0) { + force_link_ = new vvp_net_t; + // Use port[3] to hold the force destination. + force_link_->port[3] = vvp_net_ptr_t(dst, 0); + force_link_->port[2] = vvp_net_ptr_t(0,0); + force_link_->fun = new vvp_fun_force; + } + + // Use port[2] to hold the force source. + force_link_->port[2] = vvp_net_ptr_t(src,0); + + vvp_net_ptr_t dst_ptr(force_link_, 0); + src->link(dst_ptr); +} + +void vvp_filter_wire_base::force_unlink(void) +{ + if (force_link_ == 0) return; + vvp_net_t*src = force_link_->port[2].ptr(); + if (src == 0) return; + + src->unlink(vvp_net_ptr_t(force_link_,0)); + force_link_->port[2] = vvp_net_ptr_t(0,0); +} + template bool vvp_filter_wire_base::filter_mask_(T&val) { run_vpi_callbacks(); @@ -214,7 +245,6 @@ vvp_fun_signal_base::vvp_fun_signal_base() { continuous_assign_active_ = false; needs_init_ = true; - force_link = 0; cassign_link = 0; count_functors_sig += 1; } @@ -803,3 +833,23 @@ void vvp_fun_signal_real_aa::release_pv(vvp_net_ptr_t ptr, bool net, /* Automatic variables can't be forced. */ assert(0); } + +vvp_fun_force::vvp_fun_force() +{ +} + +vvp_fun_force::~vvp_fun_force() +{ +} + +void vvp_fun_force::recv_real(vvp_net_ptr_t ptr, double bit, vvp_context_t) +{ + assert(ptr.port() == 0); + vvp_net_t*net = ptr.ptr(); + + vvp_net_t*dst = net->port[3].ptr(); + vvp_fun_signal_real*sig = dynamic_cast (dst->fil); + assert(sig); + + sig->force_real(bit, vvp_vector2_t(vvp_vector2_t::FILL1, 1)); +} diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index f7a964b2f..bf88a02aa 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -154,7 +154,11 @@ class vvp_filter_wire_base : public vvp_net_fil_t, public vvp_vpi_callback { /* The %force/link instruction needs a place to write the source node of the force, so that subsequent %force and %release instructions can undo the link as needed. */ - struct vvp_net_t*force_link; + void force_link(vvp_net_t*dst, vvp_net_t*src); + void force_unlink(void); + + private: + struct vvp_net_t*force_link_; protected: // Set bits of the filter force mask @@ -449,4 +453,19 @@ class vvp_fun_signal_real_aa : public vvp_fun_signal_real, public automatic_hook }; +/* + * The vvp_fun_force class objects are net functors that use their input + * to force the associated filter. They do not actually have an + * output, they instead drive the force_* methods of the net filter. + */ +class vvp_fun_force : public vvp_net_fun_t { + + public: + vvp_fun_force(); + ~vvp_fun_force(); + + void recv_real(vvp_net_ptr_t port, double bit, vvp_context_t); +}; + + #endif From 90941648bfdf6416ded6aefaa6b6ffbd7bac18fa Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 8 Jun 2009 17:58:59 -0700 Subject: [PATCH 11/54] Implemented %force/x0 instruction using force filter. --- vvp/vthread.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index e00e07c20..83691a055 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2376,7 +2376,7 @@ bool of_FORCE_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_fun_signal4*sig = dynamic_cast (net->fun); if (index < 0 && (wid <= (unsigned)-index)) return true; @@ -2392,10 +2392,15 @@ bool of_FORCE_X0(vthread_t thr, vvp_code_t cp) if (index+wid > sig->size()) wid = sig->size() - index; - vvp_vector4_t vector = vthread_bits_to_vector(thr, base, wid); + vvp_vector2_t mask(vvp_vector2_t::FILL0, sig->size()); + for (unsigned idx = 0 ; idx < wid ; idx += 1) + mask.set_bit(index+idx, 1); - vvp_net_ptr_t ptr (net, 2); - vvp_send_vec4_pv(ptr, vector, index, wid, sig->size(), 0); + vvp_vector4_t vector = vthread_bits_to_vector(thr, base, wid); + vvp_vector4_t value(sig->size(), BIT4_Z); + value.set_vec(index, vector); + + sig->force_vec4(value, mask); return true; } From 23f7d606f8c341b59d978287e7983c76ea9dd996 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 11 Jun 2009 20:48:37 -0700 Subject: [PATCH 12/54] Force functor support for vec4 values. --- vvp/vvp_net_sig.cc | 31 +++++++++++++++++++++++++++++++ vvp/vvp_net_sig.h | 7 +++++++ 2 files changed, 38 insertions(+) diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index a66e834bb..eb0ebb996 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -28,6 +28,8 @@ # include #endif +# include + vvp_filter_wire_base::vvp_filter_wire_base() { force_propagate_ = false; @@ -68,6 +70,19 @@ template const T*vvp_filter_wire_base::filter_mask_(const T&val, const } } +/* + * 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_filter_wire_base::force_link(vvp_net_t*dst, vvp_net_t*src) { assert(dst->fil == this); @@ -80,6 +95,9 @@ void vvp_filter_wire_base::force_link(vvp_net_t*dst, vvp_net_t*src) 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); @@ -842,6 +860,19 @@ 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(); + vvp_fun_signal4*sig = dynamic_cast (dst->fil); + assert(sig); + + sig->force_vec4(bit, vvp_vector2_t(vvp_vector2_t::FILL1, sig->size())); +} + void vvp_fun_force::recv_real(vvp_net_ptr_t ptr, double bit, vvp_context_t) { assert(ptr.port() == 0); diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index bf88a02aa..72215fa85 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -457,6 +457,11 @@ class vvp_fun_signal_real_aa : public vvp_fun_signal_real, public automatic_hook * The vvp_fun_force class objects are net functors that use their input * to force the associated filter. They do not actually have an * output, they instead drive the force_* methods of the net filter. + * + * 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 { @@ -464,6 +469,8 @@ class vvp_fun_force : public vvp_net_fun_t { 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); }; From a3f16c9fba63055dd55779307dac8fea1ce59a97 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 11 Jun 2009 21:18:08 -0700 Subject: [PATCH 13/54] Indexed force of vector8 wire. --- vvp/vthread.cc | 53 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 83691a055..0b6de4289 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2376,32 +2376,57 @@ bool of_FORCE_X0(vthread_t thr, vvp_code_t cp) // X0 register. long index = thr->words[0].w_int; - vvp_fun_signal4*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; + if (vvp_fun_signal4*sig = dynamic_cast (net->fun)) { - vvp_vector2_t mask(vvp_vector2_t::FILL0, sig->size()); - for (unsigned idx = 0 ; idx < wid ; idx += 1) - mask.set_bit(index+idx, 1); + if (index >= (long)sig->size()) + return true; - vvp_vector4_t vector = vthread_bits_to_vector(thr, base, wid); - vvp_vector4_t value(sig->size(), BIT4_Z); - value.set_vec(index, vector); + if (index+wid > sig->size()) + wid = sig->size() - index; - sig->force_vec4(value, mask); + vvp_vector2_t mask(vvp_vector2_t::FILL0, sig->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(sig->size(), BIT4_Z); + value.set_vec(index, vector); + + sig->force_vec4(value, mask); + + return true; + } + + if (vvp_fun_signal8*sig = dynamic_cast (net->fun)) { + + if (index >= (long)sig->size()) + return true; + + if (index+wid > sig->size()) + wid = sig->size() - index; + + vvp_vector2_t mask(vvp_vector2_t::FILL0, sig->size()); + for (unsigned idx = 0 ; idx < wid ; idx += 1) + mask.set_bit(index+idx, 1); + + vvp_vector4_t vec4 = vthread_bits_to_vector(thr, base, wid); + vvp_vector4_t val4(sig->size(), BIT4_Z); + val4.set_vec(index, vec4); + + sig->force_vec8(vvp_vector8_t(val4,6,6), mask); + + return true; + } + + assert(0); return true; } From 42b503a24af74a95eb9afe69734074aabb4d6638 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 19 Jun 2009 21:15:08 -0700 Subject: [PATCH 14/54] Threads force to a net, not a signal. This mostly gets the public force methods out of the signal functor and into the vvp_net_t object. --- vvp/vthread.cc | 12 +++---- vvp/vvp_net.h | 12 +++++++ vvp/vvp_net_sig.cc | 89 ++++++++++++++++++++++++++-------------------- vvp/vvp_net_sig.h | 10 ++---- 4 files changed, 71 insertions(+), 52 deletions(-) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 0b6de4289..30a023a98 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2347,7 +2347,8 @@ bool of_FORCE_V(vthread_t thr, vvp_code_t cp) if (value.size() != sig->size()) value = coerce_to_width(value, sig->size()); - sig->force_vec4(value, vvp_vector2_t(vvp_vector2_t::FILL1, sig->size())); + + net->force_vec4(value, vvp_vector2_t(vvp_vector2_t::FILL1, sig->size())); return true; } @@ -2357,10 +2358,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; - vvp_fun_signal_real*sig = reinterpret_cast(net->fun); - assert(sig); - - sig->force_real(value, vvp_vector2_t(vvp_vector2_t::FILL1, 1)); + net->force_real(value, vvp_vector2_t(vvp_vector2_t::FILL1, 1)); return true; } @@ -2400,7 +2398,7 @@ bool of_FORCE_X0(vthread_t thr, vvp_code_t cp) vvp_vector4_t value(sig->size(), BIT4_Z); value.set_vec(index, vector); - sig->force_vec4(value, mask); + net->force_vec4(value, mask); return true; } @@ -2421,7 +2419,7 @@ bool of_FORCE_X0(vthread_t thr, vvp_code_t cp) vvp_vector4_t val4(sig->size(), BIT4_Z); val4.set_vec(index, vec4); - sig->force_vec8(vvp_vector8_t(val4,6,6), mask); + net->force_vec8(vvp_vector8_t(val4,6,6), mask); return true; } diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index a433747bf..5f47ad4e1 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1001,6 +1001,18 @@ class vvp_net_t { 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_; diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index eb0ebb996..3c1669eeb 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -141,22 +141,32 @@ bool vvp_filter_wire_base::filter_long(long&val) return filter_mask_(val); } -void vvp_fun_signal4::force_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) +void vvp_fun_signal4::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) { force_mask(mask); - if (force4_.size() == 0) + if (force4_.size() == 0) { force4_ = val; + } else { + for (unsigned idx = 0; idx < mask.size() ; idx += 1) { + if (mask.value(idx) == 0) + continue; - for (unsigned idx = 0; idx < mask.size() ; idx += 1) { - if (mask.value(idx) == 0) - continue; - - force4_.set_bit(idx, val.value(idx)); + force4_.set_bit(idx, val.value(idx)); + } } } -void vvp_fun_signal8::force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) +void vvp_net_t::force_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) +{ + vvp_fun_signal4*sig = dynamic_cast (fil); + assert(sig); + + sig->force_fil_vec4(val, mask); + send_vec4(val, 0); +} + +void vvp_fun_signal8::force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) { force_mask(mask); @@ -171,12 +181,30 @@ void vvp_fun_signal8::force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) } } -void vvp_fun_signal_real::force_real(double val, vvp_vector2_t mask) +void vvp_net_t::force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) +{ + vvp_fun_signal8*sig = dynamic_cast (fil); + assert(sig); + + sig->force_fil_vec8(val, mask); + send_vec8(val); +} + +void vvp_fun_signal_real::force_fil_real(double val, vvp_vector2_t mask) { force_mask(mask); force_real_ = val; } +void vvp_net_t::force_real(double val, vvp_vector2_t mask) +{ + vvp_fun_signal_real*sig = dynamic_cast (fil); + assert(sig); + + sig->force_fil_real(val, mask); + send_real(val, 0); +} + vvp_bit4_t vvp_fun_signal4::filtered_value(const vvp_vector4_t&val, unsigned idx) const { if (test_force_mask(idx)) @@ -296,7 +324,7 @@ void vvp_fun_signal4_sa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, if (needs_init_ || !bits4_.eeq(bit)) { bits4_ = bit; needs_init_ = false; - calculate_output_(ptr); + ptr.ptr()->send_vec4(bits4_, 0); } } else { bool changed = false; @@ -309,7 +337,7 @@ void vvp_fun_signal4_sa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, } if (changed) { needs_init_ = false; - calculate_output_(ptr); + ptr.ptr()->send_vec4(bits4_, 0); } } break; @@ -317,7 +345,7 @@ void vvp_fun_signal4_sa::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, case 1: // Continuous assign value bits4_ = bit; assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size()); - calculate_output_(ptr); + ptr.ptr()->send_vec4(bits4_, 0); break; default: @@ -347,7 +375,7 @@ void vvp_fun_signal4_sa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit bits4_.set_bit(base+idx, bit.value(idx)); } needs_init_ = false; - calculate_output_(ptr); + ptr.ptr()->send_vec4(bits4_,0); } else { bool changed = false; assert(bits4_.size() == assign_mask_.size()); @@ -359,7 +387,7 @@ void vvp_fun_signal4_sa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit } if (changed) { needs_init_ = false; - calculate_output_(ptr); + ptr.ptr()->send_vec4(bits4_,0); } } break; @@ -373,7 +401,7 @@ void vvp_fun_signal4_sa::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit bits4_.set_bit(base+idx, bit.value(idx)); assign_mask_.set_bit(base+idx, 1); } - calculate_output_(ptr); + ptr.ptr()->send_vec4(bits4_,0); break; default: @@ -389,12 +417,6 @@ void vvp_fun_signal4_sa::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit recv_vec4_pv(ptr, reduce4(bit), base, wid, vwid, 0); } -void vvp_fun_signal4_sa::calculate_output_(vvp_net_ptr_t ptr) -{ - ptr.ptr()->send_vec4(bits4_, 0); -} - - void vvp_fun_signal_base::deassign() { continuous_assign_active_ = false; @@ -438,7 +460,7 @@ void vvp_fun_signal4_sa::release_pv(vvp_net_ptr_t ptr, bool net, if (net) { release_mask(mask); - calculate_output_(ptr); + ptr.ptr()->send_vec4(bits4_,0); } else { bits4_ = filtered_vec4(bits4_); release_mask(mask); @@ -592,7 +614,7 @@ void vvp_fun_signal8::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit) if (needs_init_ || !bits8_.eeq(bit)) { bits8_ = bit; needs_init_ = false; - calculate_output_(ptr); + ptr.ptr()->send_vec8(bits8_); } break; @@ -630,7 +652,7 @@ void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, bits8_.set_bit(base+idx, bit.value(idx)); } needs_init_ = false; - calculate_output_(ptr); + ptr.ptr()->send_vec8(bits8_); break; case 1: // Continuous assign value @@ -639,7 +661,7 @@ void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, * strength aware. */ assert(0); break; - +#if 0 case 2: // Force value { vvp_vector2_t mask (vvp_vector2_t::FILL0, vwid); vvp_vector8_t vec (vvp_vector4_t(vwid, BIT4_Z),6,6); @@ -651,7 +673,7 @@ void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, calculate_output_(ptr); break; } - +#endif default: fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); assert(0); @@ -659,11 +681,6 @@ void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, } } -void vvp_fun_signal8::calculate_output_(vvp_net_ptr_t ptr) -{ - ptr.ptr()->send_vec8(bits8_); -} - void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net) { vvp_vector2_t mask (vvp_vector2_t::FILL1, bits8_.size()); @@ -691,7 +708,7 @@ void vvp_fun_signal8::release_pv(vvp_net_ptr_t ptr, bool net, if (net) { release_mask(mask); - calculate_output_(ptr); + ptr.ptr()->send_vec8(bits8_); } else { bits8_ = filtered_vec8(bits8_); release_mask(mask); @@ -870,17 +887,13 @@ void vvp_fun_force::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, vvp_fun_signal4*sig = dynamic_cast (dst->fil); assert(sig); - sig->force_vec4(bit, vvp_vector2_t(vvp_vector2_t::FILL1, sig->size())); + dst->force_vec4(coerce_to_width(bit, sig->size()), vvp_vector2_t(vvp_vector2_t::FILL1, sig->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(); - vvp_fun_signal_real*sig = dynamic_cast (dst->fil); - assert(sig); - - sig->force_real(bit, vvp_vector2_t(vvp_vector2_t::FILL1, 1)); + dst->force_real(bit, vvp_vector2_t(vvp_vector2_t::FILL1, 1)); } diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 72215fa85..7aa72a1d4 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -247,7 +247,7 @@ class vvp_fun_signal4 : public vvp_fun_signal_vec { public: // Enable filter force. - void force_vec4(const vvp_vector4_t&val, vvp_vector2_t mask); + void force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask); const vvp_vector4_t* filter_vec4(const vvp_vector4_t&val); // Test the value against the filter. vvp_bit4_t filtered_value(const vvp_vector4_t&val, unsigned idx) const; @@ -289,8 +289,6 @@ class vvp_fun_signal4_sa : public vvp_fun_signal4 { unsigned base, unsigned wid); private: - void calculate_output_(vvp_net_ptr_t ptr); - vvp_vector4_t bits4_; }; @@ -364,15 +362,13 @@ class vvp_fun_signal8 : public vvp_fun_signal_vec { public: // Enable filter force. - void force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask); + void force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask); const vvp_vector8_t* filter_vec8(const vvp_vector8_t&val); // Test the value against the filter. vvp_scalar_t filtered_value(const vvp_vector8_t&val, unsigned idx) const; const vvp_vector8_t& filtered_vec8(const vvp_vector8_t&val) const; private: - void calculate_output_(vvp_net_ptr_t ptr); - vvp_vector8_t bits8_; vvp_vector8_t force8_; mutable vvp_vector8_t filter8_; @@ -390,7 +386,7 @@ class vvp_fun_signal_real : public vvp_fun_signal_base { public: // Enable filter force. - void force_real(double val, vvp_vector2_t mask); + void force_fil_real(double val, vvp_vector2_t mask); bool filter_real(double&val); // Test the value against the filter. double filtered_real(double val) const; From 1940de0110853a028a3570f8424cdb64dad5a934 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 25 Jun 2009 20:43:09 -0700 Subject: [PATCH 15/54] Fix some merge errors. --- vvp/array.cc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index ec3f112f3..839f59eb7 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -1163,9 +1163,9 @@ void vvp_fun_arrayport_sa::check_word_change(unsigned long addr) if (addr != addr_) return; if (vpi_array_is_real(arr_)) { - net_->send_real(net_->out, array_get_word_r(arr_, addr_), 0); + net_->send_real(array_get_word_r(arr_, addr_), 0); } else { - net_->send_vec4(net_->out, array_get_word(arr_, addr_), 0); + net_->send_vec4(array_get_word(arr_, addr_), 0); } } @@ -1250,12 +1250,10 @@ 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_)) { - port.ptr()->send_real(port.ptr()->out, - array_get_word_r(arr_, *addr), + port.ptr()->send_real(array_get_word_r(arr_, *addr), context); } else { - port.ptr()->send_vec4(port.ptr()->out, - array_get_word(arr_, *addr), + port.ptr()->send_vec4(array_get_word(arr_, *addr), context); } break; @@ -1282,10 +1280,10 @@ void vvp_fun_arrayport_aa::check_word_change(unsigned long addr) return; if (vpi_array_is_real(arr_)) { - net_->send_real(net_->out, array_get_word_r(arr_, addr), + net_->send_real(array_get_word_r(arr_, addr), vthread_get_wt_context()); } else { - net_->send_vec4(net_->out, array_get_word(arr_, addr), + net_->send_vec4(array_get_word(arr_, addr), vthread_get_wt_context()); } } From 7df9d6076168f6923dac270dbd846389adabf017 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 25 Jun 2009 22:13:03 -0700 Subject: [PATCH 16/54] Collapse vvp_filter_wire_base into vvp_net_fil_t. The vvp_filter_wire_base class was not really used, and by collapsing into vvp_net_fil_t some casts are eliminated. --- vvp/vthread.cc | 29 ++++----- vvp/vvp_net.cc | 79 ++++++++++++++++++++++++ vvp/vvp_net.h | 79 +++++++++++++++++++++++- vvp/vvp_net_sig.cc | 97 +----------------------------- vvp/vvp_net_sig.h | 132 +---------------------------------------- vvp/vvp_vpi_callback.h | 63 ++++++++++++++++++++ 6 files changed, 235 insertions(+), 244 deletions(-) create mode 100644 vvp/vvp_vpi_callback.h diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 30a023a98..69e705d03 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2311,11 +2311,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_filter_wire_base*sig - = dynamic_cast(dst->fun); - assert(sig); - - sig->force_link(dst, src); + assert(dst->fil); + dst->fil->force_link(dst, src); return true; } @@ -3936,6 +3933,7 @@ bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp) 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; @@ -3943,14 +3941,14 @@ bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp) bool full_sig = base == 0 && width == sig->size(); // XXXX Can't really do this if this is a partial release? - sig->force_unlink(); + net->fil->force_unlink(); /* Do we release all or part of the net? */ vvp_net_ptr_t ptr (net, 0); if (full_sig) { - sig->release(ptr, true); + net->fil->release(ptr, true); } else { - sig->release_pv(ptr, true, base, width); + net->fil->release_pv(ptr, true, base, width); } return true; @@ -3965,6 +3963,7 @@ bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp) 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; @@ -3972,15 +3971,15 @@ bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp) bool full_sig = base == 0 && width == sig->size(); // XXXX Can't really do this if this is a partial release? - sig->force_unlink(); + net->fil->force_unlink(); // Send a command to this signal to unforce itself. /* Do we release all or part of the net? */ vvp_net_ptr_t ptr (net, 0); if (full_sig) { - sig->release(ptr, false); + net->fil->release(ptr, false); } else { - sig->release_pv(ptr, false, base, width); + net->fil->release_pv(ptr, false, base, width); } return true; @@ -3992,14 +3991,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); - - sig->force_unlink(); + assert(net->fil); + net->fil->force_unlink(); // Send a command to this signal to unforce itself. vvp_net_ptr_t ptr (net, 0); - sig->release(ptr, type==0); + net->fil->release(ptr, type==0); return true; } diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 42ea332cd..2ca0c67f9 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -194,12 +194,16 @@ 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); } const vvp_vector4_t* vvp_net_fil_t::filter_vec4(const vvp_vector4_t&val) @@ -222,6 +226,81 @@ bool vvp_net_fil_t::filter_long(long&) return true; } +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) { diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 5f47ad4e1..c00846ce4 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 @@ -1097,10 +1098,10 @@ class vvp_net_fun_t { * false. If false, then send_*() continues as usual. If false, output * propagation is stopped. * - * The filter object can be used to implement force/release, and also - * can be used to implement vpi net object. + * The filter object also provides an implementation hooks for + * force/release. */ -class vvp_net_fil_t { +class vvp_net_fil_t : public vvp_vpi_callback { public: vvp_net_fil_t(); @@ -1117,6 +1118,37 @@ class vvp_net_fil_t { // propagation is suppressed. The value may be edited by the filter. virtual bool filter_real(double&val); virtual bool filter_long(long&val); + + 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; + + // 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); + + 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; + + template const T*filter_mask_(const T&val, const T&force, T&buf); + template bool filter_mask_(T&val); + + 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 **** */ @@ -1147,6 +1179,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 @@ -1391,4 +1444,24 @@ inline void vvp_net_t::send_real(double val, vvp_context_t context) 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 index 3c1669eeb..2901e57f9 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -30,20 +30,9 @@ # include -vvp_filter_wire_base::vvp_filter_wire_base() +template const T*vvp_net_fil_t::filter_mask_(const T&val, const T&force, T&filter) { - force_propagate_ = false; - force_link_ = 0; -} - -vvp_filter_wire_base::~vvp_filter_wire_base() -{ - assert(force_link_ == 0); -} - -template const T*vvp_filter_wire_base::filter_mask_(const T&val, const T&force, T&filter) -{ - if (force_mask_.size()) { + if (!test_force_mask_is_zero()) { bool propagate_flag = force_propagate_; force_propagate_ = false; assert(val.size() == force_mask_.size()); @@ -70,52 +59,7 @@ template const T*vvp_filter_wire_base::filter_mask_(const T&val, const } } -/* - * 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_filter_wire_base::force_link(vvp_net_t*dst, vvp_net_t*src) -{ - assert(dst->fil == this); - - if (force_link_ == 0) { - force_link_ = new vvp_net_t; - // Use port[3] to hold the force destination. - force_link_->port[3] = vvp_net_ptr_t(dst, 0); - force_link_->port[2] = vvp_net_ptr_t(0,0); - force_link_->fun = new vvp_fun_force; - } - - 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_filter_wire_base::force_unlink(void) -{ - if (force_link_ == 0) return; - vvp_net_t*src = force_link_->port[2].ptr(); - if (src == 0) return; - - src->unlink(vvp_net_ptr_t(force_link_,0)); - force_link_->port[2] = vvp_net_ptr_t(0,0); -} - -template bool vvp_filter_wire_base::filter_mask_(T&val) +template bool vvp_net_fil_t::filter_mask_(T&val) { run_vpi_callbacks(); return true; @@ -136,11 +80,6 @@ bool vvp_fun_signal_real::filter_real(double&val) return filter_mask_(val); } -bool vvp_filter_wire_base::filter_long(long&val) -{ - return filter_mask_(val); -} - void vvp_fun_signal4::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) { force_mask(mask); @@ -255,36 +194,6 @@ double vvp_fun_signal_real::filtered_real(double val) const return force_real_; } -void vvp_filter_wire_base::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_filter_wire_base::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(); -} - /* **** vvp_fun_signal methods **** */ vvp_fun_signal_base::vvp_fun_signal_base() diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 7aa72a1d4..324ef655a 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -36,43 +36,6 @@ class ostream; using namespace std; -/* - * 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_; -}; - /* 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 @@ -128,78 +91,7 @@ class vvp_vpi_callback { */ -class vvp_filter_wire_base : public vvp_net_fil_t, public vvp_vpi_callback { - - public: - vvp_filter_wire_base(); - ~vvp_filter_wire_base(); - - // The filter_long is a placeholder here. This should be moved - // to a vvp_fun_signal_long when such a thing is implemented. - bool filter_long(long&val); - - public: - // Force/release work in the filter by setting the forced - // value using one of the force_* methods. This sets the - // forced value as a mask of the bits of the vector that are - // forced. The filter then automatically runs the filter on - // the outputs that pass through. You can also get at the - // filtering results using the filtered_* methods. The - // release_mask() method releases bits of the vector. - - 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; - - /* 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); - - private: - struct vvp_net_t*force_link_; - - 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; - - template const T*filter_mask_(const T&val, const T&force, T&buf); - template bool filter_mask_(T&val); - - private: - // Forced value - 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_; -}; - -inline bool vvp_filter_wire_base::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_filter_wire_base::test_force_mask_is_zero(void) const -{ - if (force_mask_.size() == 0) - return true; - if (force_mask_.is_zero()) - return true; - return false; -} - -class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_filter_wire_base { +class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_net_fil_t { public: vvp_fun_signal_base(); @@ -449,26 +341,4 @@ class vvp_fun_signal_real_aa : public vvp_fun_signal_real, public automatic_hook }; -/* - * The vvp_fun_force class objects are net functors that use their input - * to force the associated filter. They do not actually have an - * output, they instead drive the force_* methods of the net filter. - * - * 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); -}; - - #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 From ac78ae347b79b0b052c66ba4edc2f0770e26f343 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 28 Jun 2009 20:54:20 -0700 Subject: [PATCH 17/54] Make force_fil_* methods virtual and part of vvp_net_fil_t. These methods are type specific, but the code that invokes them get at them from pointers to filter objects, so it makes sense to make them abstract methods of the vvp_net_fil_t class. --- vvp/vvp_net.h | 7 +++++++ vvp/vvp_net_sig.cc | 36 ++++++++++++++++++++++++++++++++---- vvp/vvp_net_sig.h | 7 +++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index c00846ce4..500b4ef66 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1129,6 +1129,13 @@ class vvp_net_fil_t : public vvp_vpi_callback { void force_link(vvp_net_t*dst, vvp_net_t*src); void force_unlink(void); + + 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); diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 2901e57f9..c5314e160 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -96,15 +96,28 @@ void vvp_fun_signal4::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask } } +void vvp_fun_signal4::force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) +{ + assert(0); +} + +void vvp_fun_signal4::force_fil_real(double val, vvp_vector2_t mask) +{ + assert(0); +} + void vvp_net_t::force_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) { - vvp_fun_signal4*sig = dynamic_cast (fil); - assert(sig); - - sig->force_fil_vec4(val, mask); + assert(fil); + fil->force_fil_vec4(val, mask); send_vec4(val, 0); } +void vvp_fun_signal8::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) +{ + force_fil_vec8(vvp_vector8_t(val,6,6), mask); +} + void vvp_fun_signal8::force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) { force_mask(mask); @@ -120,6 +133,11 @@ void vvp_fun_signal8::force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask } } +void vvp_fun_signal8::force_fil_real(double val, vvp_vector2_t mask) +{ + assert(0); +} + void vvp_net_t::force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) { vvp_fun_signal8*sig = dynamic_cast (fil); @@ -129,6 +147,16 @@ void vvp_net_t::force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) send_vec8(val); } +void vvp_fun_signal_real::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) +{ + assert(0); +} + +void vvp_fun_signal_real::force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) +{ + assert(0); +} + void vvp_fun_signal_real::force_fil_real(double val, vvp_vector2_t mask) { force_mask(mask); diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 324ef655a..3c7a1455e 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -140,6 +140,8 @@ class vvp_fun_signal4 : public vvp_fun_signal_vec { public: // Enable filter force. 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); const vvp_vector4_t* filter_vec4(const vvp_vector4_t&val); // Test the value against the filter. vvp_bit4_t filtered_value(const vvp_vector4_t&val, unsigned idx) const; @@ -254,7 +256,9 @@ class vvp_fun_signal8 : public vvp_fun_signal_vec { public: // Enable filter force. + 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); const vvp_vector8_t* filter_vec8(const vvp_vector8_t&val); // Test the value against the filter. vvp_scalar_t filtered_value(const vvp_vector8_t&val, unsigned idx) const; @@ -278,7 +282,10 @@ class vvp_fun_signal_real : public vvp_fun_signal_base { public: // Enable filter force. + 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); + bool filter_real(double&val); // Test the value against the filter. double filtered_real(double val) const; From 6ef9243a10cd1453cce6e4eb4ef69408c1bef5ae Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 5 Jul 2009 16:27:14 -0700 Subject: [PATCH 18/54] vthread no longer accesses any signal methods. We want the entire force/release subsystem to only reference the vvp_net_t or vvp_net_fil_t objects in a net. This gives us the latitude to take wire implementations out of the vvp_net_fun classes. --- vvp/vthread.cc | 105 +++++++++++++-------------------------------- vvp/vvp_net.h | 1 + vvp/vvp_net_sig.cc | 10 +++-- vvp/vvp_net_sig.h | 2 + 4 files changed, 40 insertions(+), 78 deletions(-) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 69e705d03..2496f183f 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2338,14 +2338,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); - /* Send the force value to the signal on the node. */ - vvp_fun_signal4*sig = reinterpret_cast (net->fun); - assert(sig); + /* Send the force value to the filter on the node. */ - if (value.size() != sig->size()) - value = coerce_to_width(value, sig->size()); + assert(net->fil); + if (value.size() != net->fil->size()) + value = coerce_to_width(value, net->fil->size()); - net->force_vec4(value, vvp_vector2_t(vvp_vector2_t::FILL1, sig->size())); + net->force_vec4(value, vvp_vector2_t(vvp_vector2_t::FILL1, net->fil->size())); return true; } @@ -2367,6 +2366,8 @@ 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; @@ -2379,49 +2380,25 @@ bool of_FORCE_X0(vthread_t thr, vvp_code_t cp) index = 0; } - if (vvp_fun_signal4*sig = dynamic_cast (net->fun)) { + unsigned use_size = net->fil->size(); - if (index >= (long)sig->size()) - return true; - - if (index+wid > sig->size()) - wid = sig->size() - index; - - vvp_vector2_t mask(vvp_vector2_t::FILL0, sig->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(sig->size(), BIT4_Z); - value.set_vec(index, vector); - - net->force_vec4(value, mask); + if (index >= (long)use_size) return true; - } - if (vvp_fun_signal8*sig = dynamic_cast (net->fun)) { + if (index+wid > use_size) + wid = use_size - index; - if (index >= (long)sig->size()) - return true; + vvp_vector2_t mask(vvp_vector2_t::FILL0, use_size); + for (unsigned idx = 0 ; idx < wid ; idx += 1) + mask.set_bit(index+idx, 1); - if (index+wid > sig->size()) - wid = sig->size() - index; + 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_vector2_t mask(vvp_vector2_t::FILL0, sig->size()); - for (unsigned idx = 0 ; idx < wid ; idx += 1) - mask.set_bit(index+idx, 1); + net->force_vec4(value, mask); - vvp_vector4_t vec4 = vthread_bits_to_vector(thr, base, wid); - vvp_vector4_t val4(sig->size(), BIT4_Z); - val4.set_vec(index, vec4); - - net->force_vec8(vvp_vector8_t(val4,6,6), mask); - - return true; - } - - assert(0); return true; } @@ -3925,20 +3902,18 @@ 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->size()) return true; + if (base+width > net->fil->size()) width = net->fil->size() - base; - bool full_sig = base == 0 && width == sig->size(); + bool full_sig = base == 0 && width == net->fil->size(); // XXXX Can't really do this if this is a partial release? net->fil->force_unlink(); @@ -3946,43 +3921,23 @@ bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp) /* Do we release all or part of the net? */ vvp_net_ptr_t ptr (net, 0); if (full_sig) { - net->fil->release(ptr, true); + net->fil->release(ptr, net_flag); } else { - net->fil->release_pv(ptr, true, base, width); + net->fil->release_pv(ptr, net_flag, base, width); } 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); - assert(net->fil); - - if (base >= sig->size()) return true; - if (base+width > sig->size()) width = sig->size() - base; - - bool full_sig = base == 0 && width == sig->size(); - - // XXXX Can't really do this if this is a partial release? - net->fil->force_unlink(); - - // Send a command to this signal to unforce itself. - /* Do we release all or part of the net? */ - vvp_net_ptr_t ptr (net, 0); - if (full_sig) { - net->fil->release(ptr, false); - } else { - net->fil->release_pv(ptr, false, base, width); - } - - return true; + return do_release_vec(thr, cp, false); } /* The type is 1 for registers and 0 for everything else. */ diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 500b4ef66..e5acc925f 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1129,6 +1129,7 @@ class vvp_net_fil_t : public vvp_vpi_callback { void force_link(vvp_net_t*dst, vvp_net_t*src); void force_unlink(void); + virtual unsigned size() const =0; public: // Suport for force methods diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index c5314e160..758de51db 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -80,6 +80,11 @@ bool vvp_fun_signal_real::filter_real(double&val) return filter_mask_(val); } +unsigned vvp_fun_signal_real::size() const +{ + return 1; +} + void vvp_fun_signal4::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) { force_mask(mask); @@ -821,10 +826,9 @@ void vvp_fun_force::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, vvp_net_t*net = ptr.ptr(); vvp_net_t*dst = net->port[3].ptr(); - vvp_fun_signal4*sig = dynamic_cast (dst->fil); - assert(sig); + assert(dst->fil); - dst->force_vec4(coerce_to_width(bit, sig->size()), vvp_vector2_t(vvp_vector2_t::FILL1, sig->size())); + dst->force_vec4(coerce_to_width(bit, dst->fil->size()), vvp_vector2_t(vvp_vector2_t::FILL1, dst->fil->size())); } void vvp_fun_force::recv_real(vvp_net_ptr_t ptr, double bit, vvp_context_t) diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 3c7a1455e..acaf6d2eb 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -290,6 +290,8 @@ class vvp_fun_signal_real : public vvp_fun_signal_base { // Test the value against the filter. double filtered_real(double val) const; + virtual unsigned size() const; + private: double force_real_; }; From 8bbb7ff7dbca8fb62e17116505453df122341ebb Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 27 Jul 2009 21:42:04 -0700 Subject: [PATCH 19/54] Create the vvp_wire_base class to handle wires. Take wires out of the signals/variables and move them into a filter instead. This is a big shift, and finally starts us on the path to divide wires out of signals. --- vvp/array.cc | 4 +- vvp/vpi_callback.cc | 27 +++-- vvp/vpi_signal.cc | 42 ++++---- vvp/vthread.cc | 67 ++++++------ vvp/vvp_net.h | 2 +- vvp/vvp_net_sig.cc | 252 +++++++++++++++++++++++++++++++++++++------- vvp/vvp_net_sig.h | 145 ++++++++++++++++++------- vvp/words.cc | 48 ++++----- 8 files changed, 423 insertions(+), 164 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index 839f59eb7..24fe3d21c 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -870,9 +870,9 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) vpiHandle word = arr->nets[0]; 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->fun); assert(sig); - return vvp_vector4_t(sig->size(), BIT4_X); + return vvp_vector4_t(sig->value_size(), BIT4_X); } vpiHandle word = arr->nets[address]; diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 829a7a537..eb05dc8e3 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -157,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: @@ -577,7 +577,7 @@ void vvp_vpi_callback::run_vpi_callbacks() } } -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: @@ -595,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)); @@ -614,6 +614,11 @@ void vvp_fun_signal4::get_value(struct t_vpi_value*vp) } } +void vvp_fun_signal4::get_value(struct t_vpi_value*vp) +{ + get_signal_value(vp); +} + void vvp_fun_signal8::get_value(struct t_vpi_value*vp) { switch (vp->format) { @@ -688,3 +693,13 @@ void vvp_fun_signal_real::get_value(struct t_vpi_value*vp) vp->format); } } + +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) +{ + assert(0); +} diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 4ae87285e..a3c6ca6ff 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -134,13 +134,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 offset = wid - 1 + base; long end = base + (signed)wid; - 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 +154,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 +210,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 +270,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 +313,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 +322,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 +338,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 +351,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 +371,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 +398,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 +408,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 +452,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 +465,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 +659,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) { diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 2496f183f..31d246539 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -989,12 +989,12 @@ 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 + = reinterpret_cast (cp->net->fun); 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; @@ -1009,7 +1009,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; } @@ -1026,12 +1026,12 @@ 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 + = reinterpret_cast (cp->net->fun); 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; @@ -1046,7 +1046,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; } @@ -1062,12 +1062,12 @@ 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->fun); 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; @@ -1091,9 +1091,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); } @@ -1307,12 +1307,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->fun); if (index < 0 && (wid <= (unsigned)-index)) return true; - if (index >= (long)sig->size()) + if (index >= (long)sig->value_size()) return true; if (index < 0) { @@ -1320,13 +1320,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; } @@ -1738,7 +1738,7 @@ 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_fun_signal_vec*sig = dynamic_cast(net->fun); assert(sig); if (base >= sig->size()) return true; @@ -2341,10 +2341,10 @@ bool of_FORCE_V(vthread_t thr, vvp_code_t cp) /* Send the force value to the filter on the node. */ assert(net->fil); - if (value.size() != net->fil->size()) - value = coerce_to_width(value, net->fil->size()); + 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->size())); + net->force_vec4(value, vvp_vector2_t(vvp_vector2_t::FILL1, net->fil->filter_size())); return true; } @@ -2380,7 +2380,7 @@ bool of_FORCE_X0(vthread_t thr, vvp_code_t cp) index = 0; } - unsigned use_size = net->fil->size(); + unsigned use_size = net->fil->filter_size(); if (index >= (long)use_size) @@ -3055,13 +3055,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->fun); 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); @@ -3910,10 +3910,11 @@ static bool do_release_vec(vthread_t thr, vvp_code_t cp, bool net_flag) assert(net->fil); - if (base >= net->fil->size()) return true; - if (base+width > net->fil->size()) width = net->fil->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 == net->fil->size(); + bool full_sig = base == 0 && width == net->fil->filter_size(); // XXXX Can't really do this if this is a partial release? net->fil->force_unlink(); @@ -4049,7 +4050,7 @@ 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->fun); // If the entire part is below the beginning of the vector, // then we are done. @@ -4058,7 +4059,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 @@ -4071,8 +4072,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) { @@ -4083,7 +4084,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_net.h b/vvp/vvp_net.h index e5acc925f..e3943bf78 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1129,7 +1129,7 @@ class vvp_net_fil_t : public vvp_vpi_callback { void force_link(vvp_net_t*dst, vvp_net_t*src); void force_unlink(void); - virtual unsigned size() const =0; + virtual unsigned filter_size() const =0; public: // Suport for force methods diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 758de51db..ce993e194 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -65,6 +65,10 @@ template bool vvp_net_fil_t::filter_mask_(T&val) return true; } +vvp_signal_value::~vvp_signal_value() +{ +} + const vvp_vector4_t* vvp_fun_signal4::filter_vec4(const vvp_vector4_t&val) { return filter_mask_(val, force4_, filter4_); @@ -80,9 +84,14 @@ bool vvp_fun_signal_real::filter_real(double&val) return filter_mask_(val); } -unsigned vvp_fun_signal_real::size() const +unsigned vvp_fun_signal_real::filter_size() const { - return 1; + return size(); +} + +unsigned vvp_fun_signal4::filter_size() const +{ + return value_size(); } void vvp_fun_signal4::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) @@ -378,17 +387,11 @@ void vvp_fun_signal_base::deassign_pv(unsigned base, unsigned wid) void vvp_fun_signal4_sa::release(vvp_net_ptr_t ptr, bool net) { vvp_vector2_t mask (vvp_vector2_t::FILL1, bits4_.size()); + assert(!net); - if (net) { - // If releasing a net, then the output should revert to - // the un-forced value. - release_mask(mask); - ptr.ptr()->send_vec4(bits4_, 0); - } else { - // Variables keep their forced value after the release. - bits4_ = filtered_vec4(bits4_); - release_mask(mask); - } + // Variables keep their forced value after the release. + bits4_ = filtered_vec4(bits4_); + release_mask(mask); } void vvp_fun_signal4_sa::release_pv(vvp_net_ptr_t ptr, bool net, @@ -400,17 +403,11 @@ void vvp_fun_signal4_sa::release_pv(vvp_net_ptr_t ptr, bool net, for (unsigned idx = 0 ; idx < wid ; idx += 1) mask.set_bit(base+idx, 1); - if (net) { - release_mask(mask); - ptr.ptr()->send_vec4(bits4_,0); - } else { - bits4_ = filtered_vec4(bits4_); - release_mask(mask); - } - + bits4_ = filtered_vec4(bits4_); + release_mask(mask); } -unsigned vvp_fun_signal4_sa::size() const +unsigned vvp_fun_signal4_sa::value_size() const { return bits4_.size(); } @@ -509,7 +506,7 @@ void vvp_fun_signal4_aa::release_pv(vvp_net_ptr_t ptr, bool net, assert(0); } -unsigned vvp_fun_signal4_aa::size() const +unsigned vvp_fun_signal4_aa::value_size() const { return size_; } @@ -603,19 +600,7 @@ void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit, * strength aware. */ assert(0); break; -#if 0 - case 2: // Force value - { vvp_vector2_t mask (vvp_vector2_t::FILL0, vwid); - vvp_vector8_t vec (vvp_vector4_t(vwid, BIT4_Z),6,6); - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - mask.set_bit(base+idx, 1); - vec.set_bit(base+idx, bit.value(idx)); - } - force_vec8(vec, mask); - calculate_output_(ptr); - break; - } -#endif + default: fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); assert(0); @@ -657,7 +642,12 @@ void vvp_fun_signal8::release_pv(vvp_net_ptr_t ptr, bool net, } } -unsigned vvp_fun_signal8::size() const +unsigned vvp_fun_signal8::filter_size() const +{ + return value_size(); +} + +unsigned vvp_fun_signal8::value_size() const { return bits8_.size(); } @@ -828,7 +818,7 @@ void vvp_fun_force::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, vvp_net_t*dst = net->port[3].ptr(); assert(dst->fil); - dst->force_vec4(coerce_to_width(bit, dst->fil->size()), vvp_vector2_t(vvp_vector2_t::FILL1, dst->fil->size())); + 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) @@ -838,3 +828,191 @@ void vvp_fun_force::recv_real(vvp_net_ptr_t ptr, double bit, vvp_context_t) 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) +: width_(wid) +{ +} + +const vvp_vector4_t* vvp_wire_vec4::filter_vec4(const vvp_vector4_t&bit) +{ + return filter_mask_(bit, force4_, filter4_); +} + +const vvp_vector8_t* vvp_wire_vec4::filter_vec8(const vvp_vector8_t&bit) +{ + assert(0); + return 0; +} + +unsigned vvp_wire_vec4::filter_size() const +{ + return width_; +} + +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)); + } + } +} + +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) +{ + assert(net); + + // Wires revert to their unforced value after release. + vvp_vector2_t mask (vvp_vector2_t::FILL1, width_); + release_mask(mask); + ptr.ptr()->send_vec4(bits4_, 0); +} + +void vvp_wire_vec4::release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) +{ + assert(bits4_.size() >= base + wid); + assert(net); + + 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); + ptr.ptr()->send_vec4(bits4_,0); +} + +unsigned vvp_wire_vec4::value_size() const +{ + return width_; +} + +vvp_bit4_t vvp_wire_vec4::filtered_value_(const vvp_vector4_t&val, unsigned idx) const +{ + if (test_force_mask(idx)) + return force4_.value(idx); + else + return val.value(idx); +} + +vvp_bit4_t vvp_wire_vec4::value(unsigned idx) const +{ + return filtered_value_(bits4_, idx); +} + +vvp_scalar_t vvp_wire_vec4::scalar_value(unsigned idx) const +{ + assert(0); +} + +vvp_vector4_t vvp_wire_vec4::vec4_value() const +{ + assert(0); +} + +vvp_wire_vec8::vvp_wire_vec8(unsigned wid) +: width_(wid) +{ +} + +const vvp_vector4_t* vvp_wire_vec8::filter_vec4(const vvp_vector4_t&bit) +{ + assert(0); + return 0; +} + +const vvp_vector8_t* vvp_wire_vec8::filter_vec8(const vvp_vector8_t&bit) +{ + assert(0); + return 0; +} + +unsigned vvp_wire_vec8::filter_size() const +{ + return width_; +} + +void vvp_wire_vec8::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) +{ + assert(0); +} + +void vvp_wire_vec8::force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) +{ + assert(0); +} + +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) +{ + assert(net); + + // Wires revert to their unforced value after release. + vvp_vector2_t mask (vvp_vector2_t::FILL1, width_); + release_mask(mask); + ptr.ptr()->send_vec8(bits8_); +} + +void vvp_wire_vec8::release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) +{ + assert(width_ >= base + wid); + assert(net); + + vvp_vector2_t mask (vvp_vector2_t::FILL0, width_); + for (unsigned idx = 0 ; idx < wid ; idx += 1) + mask.set_bit(base+idx, 1); + + release_mask(mask); + ptr.ptr()->send_vec8(bits8_); +} + +unsigned vvp_wire_vec8::value_size() const +{ + return width_; +} + +vvp_bit4_t vvp_wire_vec8::value(unsigned idx) const +{ + assert(0); +} + +vvp_scalar_t vvp_wire_vec8::scalar_value(unsigned idx) const +{ + assert(0); +} + +vvp_vector4_t vvp_wire_vec8::vec4_value() const +{ + assert(0); +} diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index acaf6d2eb..d6f530671 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -62,32 +62,6 @@ using namespace std; * 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. */ @@ -117,17 +91,27 @@ class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_net_fil_t { }; /* - * This abstract class is a little more specific than the signal_base - * class, in that it adds vector access methods. + * Variables and wires can have their values accessed, so this base + * class offers the unified concept of an acessible value. */ -class vvp_fun_signal_vec : public vvp_fun_signal_base { - +class vvp_signal_value { public: - // For vector signal types, this returns the vector count. - virtual unsigned size() const =0; + 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 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 vvp_signal_value { + public: + unsigned size() const { return value_size(); } }; class vvp_fun_signal4 : public vvp_fun_signal_vec { @@ -146,6 +130,7 @@ class vvp_fun_signal4 : public vvp_fun_signal_vec { // Test the value against the filter. vvp_bit4_t filtered_value(const vvp_vector4_t&val, unsigned idx) const; const vvp_vector4_t& filtered_vec4(const vvp_vector4_t&val) const; + unsigned filter_size() const; private: vvp_vector4_t force4_; @@ -172,7 +157,7 @@ class vvp_fun_signal4_sa : public vvp_fun_signal4 { unsigned base, unsigned wid, unsigned vwid); // Get information about the vector value. - unsigned size() const; + 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; @@ -209,7 +194,7 @@ class vvp_fun_signal4_aa : public vvp_fun_signal4, public automatic_hooks_s { vvp_context_t); // Get information about the vector value. - unsigned size() const; + 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; @@ -241,7 +226,7 @@ class vvp_fun_signal8 : public vvp_fun_signal_vec { unsigned base, unsigned wid, unsigned vwid); // Get information about the vector value. - unsigned size() const; + 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; @@ -263,6 +248,7 @@ class vvp_fun_signal8 : public vvp_fun_signal_vec { // Test the value against the filter. vvp_scalar_t filtered_value(const vvp_vector8_t&val, unsigned idx) const; const vvp_vector8_t& filtered_vec8(const vvp_vector8_t&val) const; + unsigned filter_size() const; private: vvp_vector8_t bits8_; @@ -290,7 +276,8 @@ class vvp_fun_signal_real : public vvp_fun_signal_base { // Test the value against the filter. double filtered_real(double val) const; - virtual unsigned size() const; + unsigned size() const { return 1; } + virtual unsigned filter_size() const; private: double force_real_; @@ -350,4 +337,90 @@ class vvp_fun_signal_real_aa : public vvp_fun_signal_real, public automatic_hook }; +/* 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(); + + // The main filter behavior for this class + const vvp_vector4_t* filter_vec4(const vvp_vector4_t&bit) =0; + const vvp_vector8_t* filter_vec8(const vvp_vector8_t&val) =0; + +}; + +class vvp_wire_vec4 : public vvp_wire_base { + + public: + vvp_wire_vec4(unsigned wid, vvp_bit4_t init=BIT4_X); + + // 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. + const vvp_vector4_t* filter_vec4(const vvp_vector4_t&bit); + const vvp_vector8_t* filter_vec8(const vvp_vector8_t&val); + + // 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); + void release_pv(vvp_net_ptr_t ptr, bool net, unsigned base, unsigned wid); + + // 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_(const vvp_vector4_t&val, unsigned idx) const; + + private: + unsigned width_; + vvp_vector4_t bits4_; // The tracked driven value + vvp_vector4_t force4_; // the value being forced + vvp_vector4_t filter4_; // scratch space for filter_mask_ function. +}; + +class vvp_wire_vec8 : public vvp_wire_base { + + public: + vvp_wire_vec8(unsigned wid); + + // The main filter behavior for this class + const vvp_vector4_t* filter_vec4(const vvp_vector4_t&bit); + const vvp_vector8_t* filter_vec8(const vvp_vector8_t&val); + + // 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); + void release_pv(vvp_net_ptr_t ptr, bool net, unsigned base, unsigned wid); + + // 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: + unsigned width_; + vvp_vector8_t bits8_; +}; + #endif diff --git a/vvp/words.cc b/vvp/words.cc index f7d5173de..534ec7785 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -148,40 +148,36 @@ void compile_variablew(char*label, vvp_array_t array, /* * Here we handle .net records from the vvp source: * - *