Implement atom2 types with vvp_vector2_t.

This reflects the SystemVerilog intent, and also washes away
the 'bx and 'bz values properly.
This commit is contained in:
Stephen Williams 2010-10-12 20:49:38 -07:00
parent 4643872fc6
commit 67000e46a8
6 changed files with 312 additions and 21 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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 <class T> prop_t filter_mask_(const T&val, const T&force, T&rep, unsigned addr);
// This template method is similar to the above, but works for
// native types that are not so expensive to edit in place.

View File

@ -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; idx<bits2_.size(); idx += 1)
res.set_bit(idx,value(idx));
release_mask(mask);
ptr.ptr()->fun->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; idx<wid; idx += 1)
res.set_bit(idx,value(base+idx));
release_mask(mask);
ptr.ptr()->fun->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)
{

View File

@ -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:

View File

@ -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;