diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index ecfd75163..87ddb10a3 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -702,6 +702,11 @@ void vvp_wire_real::get_signal_value(struct t_vpi_value*vp) real_signal_value(vp, real_value()); } +void vvp_wire_vec2::get_value(struct t_vpi_value*val) +{ + get_signal_value(val); +} + void vvp_wire_vec4::get_value(struct t_vpi_value*val) { get_signal_value(val); diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 8bd6338e7..7d57673ae 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1940,7 +1940,24 @@ vvp_vector2_t::vvp_vector2_t(vvp_vector2_t::fill_t fill, unsigned wid) vec_[idx] = fill? -1 : 0; } -vvp_vector2_t::vvp_vector2_t(const vvp_vector4_t&that) +vvp_vector2_t::vvp_vector2_t(const vvp_vector2_t&that, unsigned base, unsigned wid) +{ + wid_ = wid; + const unsigned words = (wid_ + BITS_PER_WORD-1) / BITS_PER_WORD; + + vec_ = new unsigned long[words]; + + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + int bit = that.value(base+idx); + if (bit == 0) + continue; + unsigned word = idx / BITS_PER_WORD; + unsigned long mask = 1UL << (idx % BITS_PER_WORD); + vec_[word] |= mask; + } +} + +void vvp_vector2_t::copy_from_that_(const vvp_vector4_t&that) { wid_ = that.size(); const unsigned words = (that.size() + BITS_PER_WORD-1) / BITS_PER_WORD; @@ -1961,15 +1978,12 @@ vvp_vector2_t::vvp_vector2_t(const vvp_vector4_t&that) switch (that.value(idx)) { case BIT4_0: + case BIT4_X: + case BIT4_Z: break; case BIT4_1: vec_[addr] |= 1UL << shift; break; - default: - delete[]vec_; - vec_ = 0; - wid_ = 0; - return; } } } @@ -1990,11 +2004,6 @@ void vvp_vector2_t::copy_from_that_(const vvp_vector2_t&that) vec_[idx] = that.vec_[idx]; } -vvp_vector2_t::vvp_vector2_t(const vvp_vector2_t&that) -{ - copy_from_that_(that); -} - vvp_vector2_t::vvp_vector2_t(const vvp_vector2_t&that, unsigned newsize) { wid_ = newsize; @@ -2027,6 +2036,14 @@ vvp_vector2_t& vvp_vector2_t::operator= (const vvp_vector2_t&that) return *this; } +vvp_vector2_t& vvp_vector2_t::operator= (const vvp_vector4_t&that) +{ + delete[]vec_; + vec_ = 0; + copy_from_that_(that); + return *this; +} + vvp_vector2_t& vvp_vector2_t::operator <<= (unsigned int shift) { if (wid_ == 0) @@ -2191,11 +2208,6 @@ vvp_vector2_t& vvp_vector2_t::operator -= (const vvp_vector2_t&that) return *this; } -vvp_vector2_t::~vvp_vector2_t() -{ - delete[] vec_; -} - void vvp_vector2_t::trim() { while (value(wid_-1) == 0 && wid_ > 1) wid_ -= 1; @@ -2239,6 +2251,14 @@ void vvp_vector2_t::set_bit(unsigned idx, int bit) vec_[addr] &= ~(1UL << mask); } +void vvp_vector2_t::set_vec(unsigned adr, const vvp_vector2_t&that) +{ + assert((adr + that.wid_) <= wid_); + + for (unsigned idx = 0 ; idx < that.wid_ ; idx += 1) + set_bit(adr+idx, that.value(idx)); +} + bool vvp_vector2_t::is_NaN() const { return wid_ == 0; @@ -2650,6 +2670,24 @@ vvp_vector8_t::vvp_vector8_t(const vvp_vector4_t&that, } } +vvp_vector8_t::vvp_vector8_t(const vvp_vector2_t&that, + unsigned str0, unsigned str1) +: size_(that.size()) +{ + if (size_ == 0) + return; + + if (size_ <= sizeof val_) { + ptr_ = 0; + for (unsigned idx = 0 ; idx < size_ ; idx += 1) + val_[idx] = vvp_scalar_t(that.value(idx)? BIT4_1:BIT4_0, str0, str1).raw(); + } else { + ptr_ = new unsigned char[size_]; + for (unsigned idx = 0 ; idx < size_ ; idx += 1) + ptr_[idx] = vvp_scalar_t(that.value(idx)? BIT4_1:BIT4_0, str0, str1).raw(); + } +} + const vvp_vector8_t vvp_vector8_t::nil; vvp_vector8_t& vvp_vector8_t::operator= (const vvp_vector8_t&that) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 6fb218c93..93e489684 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -41,6 +41,10 @@ using namespace std; /* Data types */ class vvp_scalar_t; +class vvp_vector2_t; +class vvp_vector4_t; +class vvp_vector8_t; + /* Basic netlist types. */ class vvp_net_t; class vvp_net_fun_t; @@ -606,9 +610,10 @@ class vvp_vector2_t { vvp_vector2_t(); vvp_vector2_t(const vvp_vector2_t&); vvp_vector2_t(const vvp_vector2_t&, unsigned newsize); + vvp_vector2_t(const vvp_vector2_t&, unsigned base, unsigned wid); // Make a vvp_vector2_t from a vvp_vector4_t. If there are X // or Z bits, then the result becomes a NaN value. - explicit vvp_vector2_t(const vvp_vector4_t&that); + vvp_vector2_t(const vvp_vector4_t&that); // Make from a native long and a specified width. vvp_vector2_t(unsigned long val, unsigned wid); // Make with the width, and filled with 1 or 0 bits. @@ -622,11 +627,19 @@ class vvp_vector2_t { vvp_vector2_t&operator >>= (unsigned shift); vvp_vector2_t&operator = (const vvp_vector2_t&); + // Assign a vec4 to a vec2, using Verilog rules for converting + // XZ values to 0. + vvp_vector2_t&operator = (const vvp_vector4_t&); + bool is_NaN() const; bool is_zero() const; unsigned size() const; int value(unsigned idx) const; + vvp_bit4_t value4(unsigned idx) const; + // Get the vector2 subvector starting at the address + vvp_vector2_t subvalue(unsigned idx, unsigned size) const; void set_bit(unsigned idx, int bit); + void set_vec(unsigned idx, const vvp_vector2_t&that); // Make the size just big enough to hold the first 1 bit. void trim(); // Trim off extra 1 bit since this is representing a negative value. @@ -640,6 +653,7 @@ class vvp_vector2_t { private: void copy_from_that_(const vvp_vector2_t&that); + void copy_from_that_(const vvp_vector4_t&that); }; extern bool operator > (const vvp_vector2_t&, const vvp_vector2_t&); @@ -666,12 +680,40 @@ extern double crstring_to_double(const char*str); extern ostream& operator<< (ostream&, const vvp_vector2_t&); +inline vvp_vector2_t::vvp_vector2_t(const vvp_vector2_t&that) +{ + copy_from_that_(that); +} + +inline vvp_vector2_t::vvp_vector2_t(const vvp_vector4_t&that) +{ + copy_from_that_(that); +} + +inline vvp_vector2_t::~vvp_vector2_t() +{ + delete[] vec_; +} + /* Inline some of the vector2_t methods. */ inline unsigned vvp_vector2_t::size() const { return wid_; } +inline vvp_bit4_t vvp_vector2_t::value4(unsigned idx) const +{ + if (value(idx)) + return BIT4_1; + else + return BIT4_0; +} + +inline vvp_vector2_t vvp_vector2_t::subvalue(unsigned base, unsigned wid) const +{ + return vvp_vector2_t(*this, base, wid); +} + /* * This class represents a scalar value with strength. These are * heavier then the simple vvp_bit4_t, but more information is @@ -809,6 +851,9 @@ class vvp_vector8_t { explicit vvp_vector8_t(const vvp_vector4_t&that, unsigned str0, unsigned str1); + explicit vvp_vector8_t(const vvp_vector2_t&that, + unsigned str0, + unsigned str1); ~vvp_vector8_t(); @@ -1219,7 +1264,9 @@ class vvp_net_fil_t : public vvp_vpi_callback { // the val through the force mask. The force value is the // currently forced value, and the buf is a value that this // method will use to hold a filtered value, if needed. This - // method returns a pointer to val or buf. + // method returns the replacement value into the "rep" + // argument and returns a code indicating whether any changes + // were made. template prop_t filter_mask_(const T&val, const T&force, T&rep, unsigned addr); // This template method is similar to the above, but works for // native types that are not so expensive to edit in place. diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index fc366599f..4c170e67b 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -600,6 +600,168 @@ vvp_wire_base::~vvp_wire_base() { } +vvp_wire_vec2::vvp_wire_vec2(unsigned wid) +: bits2_(0, wid) +{ + needs_init_ = true; +} + +vvp_net_fil_t::prop_t vvp_wire_vec2::filter_vec4(const vvp_vector4_t&bit, vvp_vector4_t&rep, + unsigned base, unsigned vwid) +{ + // Special case! the input bit is 0 wid. Interpret this as a + // vector of 0 to match the width of the bits2_ vector. + // FIXME! This is a hack to work around some buggy gate + // implementations! This should be removed! + if (base==0 && vwid==0) { + vvp_vector2_t tmp (0, bits2_.size()); + if (bits2_ == tmp && !needs_init_) return STOP; + bits2_ = tmp; + needs_init_ = false; + return filter_mask_(vector2_to_vector4(bits2_, bits2_.size()), + vector2_to_vector4(force2_, bits2_.size()), rep, 0); + } + + if (vwid != bits2_.size()) { + cerr << "Internal error: Input vector expected width=" + << bits2_.size() << ", got " + << "bit=" << bit << ", base=" << base << ", vwid=" << vwid + << endl; + } + assert(bits2_.size() == vwid); + + vvp_vector2_t bit2 = bit; + + // Keep track of the value being driven from this net, even if + // it is not ultimately what survives the force filter. + if (base==0 && bit2.size()==vwid) { + if (bits2_ == bit2 && !needs_init_) return STOP; + bits2_ = bit2; + } else { + bits2_.set_vec(base, bit2); + } + + needs_init_ = false; + return filter_mask_(vector2_to_vector4(bits2_, bits2_.size()), + vector2_to_vector4(force2_, bits2_.size()), rep, 0); +} + +vvp_net_fil_t::prop_t vvp_wire_vec2::filter_vec8(const vvp_vector8_t&bit, vvp_vector8_t&rep, unsigned base, unsigned vwid) +{ + assert(bits2_.size() == bit.size()); + bits2_ = reduce4(bit); + return filter_mask_(bit, vvp_vector8_t(force2_,6,6), rep, 0); +} + +unsigned vvp_wire_vec2::filter_size() const +{ + return bits2_.size(); +} + +void vvp_wire_vec2::force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask) +{ + force_mask(mask); + + if (force2_.size() == 0) { + force2_ = val; + } else { + for (unsigned idx = 0; idx < mask.size() ; idx += 1) { + if (mask.value(idx) == 0) + continue; + + force2_.set_bit(idx, val.value(idx)); + } + } + run_vpi_callbacks(); +} + +void vvp_wire_vec2::force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask) +{ + assert(0); +} + +void vvp_wire_vec2::force_fil_real(double val, vvp_vector2_t mask) +{ + assert(0); +} + +void vvp_wire_vec2::release(vvp_net_ptr_t ptr, bool net_flag) +{ + vvp_vector2_t mask (vvp_vector2_t::FILL1, bits2_.size()); + if (net_flag) { + // Wires revert to their unforced value after release. + release_mask(mask); + needs_init_ = ! (force2_ == bits2_); + ptr.ptr()->send_vec4(vector2_to_vector4(bits2_, bits2_.size()), 0); + run_vpi_callbacks(); + } else { + // Variables keep the current value. + vvp_vector4_t res (bits2_.size()); + for (unsigned idx=0; idxfun->recv_vec4(ptr, res, 0); + } +} + +void vvp_wire_vec2::release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag) +{ + assert(bits2_.size() >= base + wid); + + vvp_vector2_t mask (vvp_vector2_t::FILL0, bits2_.size()); + for (unsigned idx = 0 ; idx < wid ; idx += 1) + mask.set_bit(base+idx, 1); + + if (net_flag) { + // Wires revert to their unforced value after release. + release_mask(mask); + needs_init_ = ! (force2_.subvalue(base,wid) == bits2_.subvalue(base,wid)); + ptr.ptr()->send_vec4_pv(vector2_to_vector4(bits2_.subvalue(base,wid),wid), + base, wid, bits2_.size(), 0); + run_vpi_callbacks(); + } else { + // Variables keep the current value. + vvp_vector4_t res (wid); + for (unsigned idx=0; idxfun->recv_vec4_pv(ptr, res, base, wid, bits2_.size(), 0); + } +} + +unsigned vvp_wire_vec2::value_size() const +{ + return bits2_.size(); +} + +vvp_bit4_t vvp_wire_vec2::filtered_value_(unsigned idx) const +{ + if (test_force_mask(idx)) + return force2_.value4(idx); + else + return bits2_.value4(idx); +} + +vvp_bit4_t vvp_wire_vec2::value(unsigned idx) const +{ + return filtered_value_(idx); +} + +vvp_scalar_t vvp_wire_vec2::scalar_value(unsigned idx) const +{ + return vvp_scalar_t(value(idx),6,6); +} + +void vvp_wire_vec2::vec4_value(vvp_vector4_t&val) const +{ + val = vector2_to_vector4(bits2_, bits2_.size()); + if (test_force_mask_is_zero()) + return; + + for (unsigned idx = 0 ; idx < bits2_.size() ; idx += 1) + val.set_bit(idx, filtered_value_(idx)); +} + vvp_wire_vec4::vvp_wire_vec4(unsigned wid, vvp_bit4_t init) : bits4_(wid, init) { diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 6914b76e3..216491f94 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -274,6 +274,45 @@ class vvp_wire_base : public vvp_net_fil_t, public vvp_signal_value { ~vvp_wire_base(); }; +class vvp_wire_vec2 : public vvp_wire_base { + + public: + vvp_wire_vec2(unsigned wid); + + // The main filter behavior for this class. These methods take + // the value that the node is driven to, and applies the force + // filters. In wires, this also saves the driven value, so + // that when a force is released, we can revert to the driven value. + prop_t filter_vec4(const vvp_vector4_t&bit, vvp_vector4_t&rep, + unsigned base, unsigned vwid); + prop_t filter_vec8(const vvp_vector8_t&val, vvp_vector8_t&rep, + unsigned base, unsigned vwid); + + // Abstract methods from vvp_vpi_callback + void get_value(struct t_vpi_value*value); + // Abstract methods from vvp_net_fit_t + unsigned filter_size() const; + void force_fil_vec4(const vvp_vector4_t&val, vvp_vector2_t mask); + void force_fil_vec8(const vvp_vector8_t&val, vvp_vector2_t mask); + void force_fil_real(double val, vvp_vector2_t mask); + void release(vvp_net_ptr_t ptr, bool net_flag); + void release_pv(vvp_net_ptr_t ptr, unsigned base, unsigned wid, bool net_flag); + + // Implementation of vvp_signal_value methods + unsigned value_size() const; + vvp_bit4_t value(unsigned idx) const; + vvp_scalar_t scalar_value(unsigned idx) const; + void vec4_value(vvp_vector4_t&) const; + + private: + vvp_bit4_t filtered_value_(unsigned idx) const; + + private: + bool needs_init_; + vvp_vector2_t bits2_; // The tracked driven value + vvp_vector2_t force2_; // the value being forced +}; + class vvp_wire_vec4 : public vvp_wire_base { public: diff --git a/vvp/words.cc b/vvp/words.cc index 4b58e2226..9f5b414af 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -251,15 +251,15 @@ static void do_compile_net(vvp_net_t*node, vvp_array_t array, if (vsig == 0) { switch (vpi_type_code) { + case vpiIntVar: + vsig = new vvp_wire_vec2(wid); + break; case vpiLogicVar: vsig = new vvp_wire_vec4(wid,BIT4_Z); break; case -vpiLogicVar: vsig = new vvp_wire_vec8(wid); break; - case vpiIntVar: - vsig = new vvp_wire_vec4(wid,BIT4_Z); - break; } assert(vsig); node->fil = vsig;