2004-12-11 03:31:25 +01:00
|
|
|
/*
|
2008-01-13 03:22:46 +01:00
|
|
|
* Copyright (c) 2004-2008 Stephen Williams (steve@icarus.com)
|
2004-12-11 03:31:25 +01:00
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
|
|
|
|
|
2005-04-13 08:34:20 +02:00
|
|
|
# include "config.h"
|
2004-12-11 03:31:25 +01:00
|
|
|
# include "vvp_net.h"
|
2005-04-03 07:45:51 +02:00
|
|
|
# include "schedule.h"
|
2007-12-02 17:47:06 +01:00
|
|
|
# include "statistics.h"
|
2004-12-11 03:31:25 +01:00
|
|
|
# include <stdio.h>
|
2008-01-05 00:23:47 +01:00
|
|
|
# include <cstring>
|
|
|
|
|
# include <cstdlib>
|
2005-04-13 08:34:20 +02:00
|
|
|
# include <iostream>
|
2004-12-11 03:31:25 +01:00
|
|
|
# include <typeinfo>
|
2005-06-27 23:13:14 +02:00
|
|
|
# include <limits.h>
|
2006-12-09 20:06:53 +01:00
|
|
|
# include <math.h>
|
2004-12-11 03:31:25 +01:00
|
|
|
# include <assert.h>
|
|
|
|
|
|
|
|
|
|
/* *** BIT operations *** */
|
|
|
|
|
vvp_bit4_t add_with_carry(vvp_bit4_t a, vvp_bit4_t b, vvp_bit4_t&c)
|
|
|
|
|
{
|
2005-02-03 05:55:13 +01:00
|
|
|
if (bit4_is_xz(a) || bit4_is_xz(b) || bit4_is_xz(c)) {
|
2004-12-11 03:31:25 +01:00
|
|
|
c = BIT4_X;
|
|
|
|
|
return BIT4_X;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-03 05:55:13 +01:00
|
|
|
// NOTE: This relies on the facts that XZ values have been
|
|
|
|
|
// weeded out, and that BIT4_1 is 1 and BIT4_0 is 0.
|
|
|
|
|
int sum = (int)a + (int)b + (int)c;
|
2004-12-11 03:31:25 +01:00
|
|
|
|
|
|
|
|
switch (sum) {
|
|
|
|
|
case 0:
|
2008-04-21 06:36:53 +02:00
|
|
|
// c must already be 0.
|
2004-12-11 03:31:25 +01:00
|
|
|
return BIT4_0;
|
|
|
|
|
case 1:
|
|
|
|
|
c = BIT4_0;
|
|
|
|
|
return BIT4_1;
|
|
|
|
|
case 2:
|
|
|
|
|
c = BIT4_1;
|
|
|
|
|
return BIT4_0;
|
|
|
|
|
case 3:
|
|
|
|
|
c = BIT4_1;
|
|
|
|
|
return BIT4_1;
|
|
|
|
|
default:
|
2007-08-23 00:15:32 +02:00
|
|
|
fprintf(stderr, "Incorrect result %d.\n", sum);
|
2004-12-11 03:31:25 +01:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-03 05:55:13 +01:00
|
|
|
vvp_bit4_t operator ^ (vvp_bit4_t a, vvp_bit4_t b)
|
|
|
|
|
{
|
|
|
|
|
if (bit4_is_xz(a))
|
|
|
|
|
return BIT4_X;
|
|
|
|
|
if (bit4_is_xz(b))
|
|
|
|
|
return BIT4_X;
|
|
|
|
|
if (a == BIT4_0)
|
|
|
|
|
return b;
|
|
|
|
|
if (b == BIT4_0)
|
|
|
|
|
return a;
|
|
|
|
|
return BIT4_0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-13 08:34:20 +02:00
|
|
|
ostream& operator<<(ostream&out, vvp_bit4_t bit)
|
|
|
|
|
{
|
|
|
|
|
switch (bit) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
out << "0";
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
out << "1";
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_X:
|
|
|
|
|
out << "X";
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_Z:
|
|
|
|
|
out << "Z";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
out << "?";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-02 07:13:22 +01:00
|
|
|
typedef unsigned short edge_t;
|
|
|
|
|
|
|
|
|
|
inline edge_t VVP_EDGE(vvp_bit4_t from, vvp_bit4_t to)
|
|
|
|
|
{
|
|
|
|
|
return 1 << ((from << 2) | to);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const edge_t vvp_edge_posedge
|
|
|
|
|
= VVP_EDGE(BIT4_0,BIT4_1)
|
|
|
|
|
| VVP_EDGE(BIT4_0,BIT4_X)
|
|
|
|
|
| VVP_EDGE(BIT4_0,BIT4_Z)
|
|
|
|
|
| VVP_EDGE(BIT4_X,BIT4_1)
|
|
|
|
|
| VVP_EDGE(BIT4_Z,BIT4_1)
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
const edge_t vvp_edge_negedge
|
|
|
|
|
= VVP_EDGE(BIT4_1,BIT4_0)
|
|
|
|
|
| VVP_EDGE(BIT4_1,BIT4_X)
|
|
|
|
|
| VVP_EDGE(BIT4_1,BIT4_Z)
|
|
|
|
|
| VVP_EDGE(BIT4_X,BIT4_0)
|
|
|
|
|
| VVP_EDGE(BIT4_Z,BIT4_0)
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
int edge(vvp_bit4_t from, vvp_bit4_t to)
|
|
|
|
|
{
|
|
|
|
|
edge_t mask = VVP_EDGE(from, to);
|
|
|
|
|
if (mask & vvp_edge_posedge)
|
|
|
|
|
return 1;
|
|
|
|
|
if (mask & vvp_edge_negedge)
|
|
|
|
|
return -1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-31 07:00:06 +01:00
|
|
|
void vvp_send_vec8(vvp_net_ptr_t ptr, vvp_vector8_t val)
|
|
|
|
|
{
|
|
|
|
|
while (struct vvp_net_t*cur = ptr.ptr()) {
|
|
|
|
|
vvp_net_ptr_t next = cur->port[ptr.port()];
|
|
|
|
|
|
|
|
|
|
if (cur->fun)
|
|
|
|
|
cur->fun->recv_vec8(ptr, val);
|
|
|
|
|
|
|
|
|
|
ptr = next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
void vvp_send_real(vvp_net_ptr_t ptr, double val)
|
|
|
|
|
{
|
|
|
|
|
while (struct vvp_net_t*cur = ptr.ptr()) {
|
|
|
|
|
vvp_net_ptr_t next = cur->port[ptr.port()];
|
|
|
|
|
|
|
|
|
|
if (cur->fun)
|
|
|
|
|
cur->fun->recv_real(ptr, val);
|
|
|
|
|
|
|
|
|
|
ptr = next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vvp_send_long(vvp_net_ptr_t ptr, long val)
|
|
|
|
|
{
|
|
|
|
|
while (struct vvp_net_t*cur = ptr.ptr()) {
|
|
|
|
|
vvp_net_ptr_t next = cur->port[ptr.port()];
|
|
|
|
|
|
|
|
|
|
if (cur->fun)
|
|
|
|
|
cur->fun->recv_long(ptr, val);
|
|
|
|
|
|
|
|
|
|
ptr = next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-12 00:04:00 +01:00
|
|
|
void vvp_send_long_pv(vvp_net_ptr_t ptr, long val,
|
|
|
|
|
unsigned base, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
while (struct vvp_net_t*cur = ptr.ptr()) {
|
|
|
|
|
vvp_net_ptr_t next = cur->port[ptr.port()];
|
|
|
|
|
|
|
|
|
|
if (cur->fun)
|
|
|
|
|
cur->fun->recv_long_pv(ptr, val, base, wid);
|
|
|
|
|
|
|
|
|
|
ptr = next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-13 03:22:46 +01:00
|
|
|
void vvp_vector4_t::copy_bits(const vvp_vector4_t&that)
|
|
|
|
|
{
|
|
|
|
|
|
2008-05-23 23:30:32 +02:00
|
|
|
if (size_ == that.size_) {
|
|
|
|
|
if (size_ > BITS_PER_WORD) {
|
|
|
|
|
unsigned words = (size_+BITS_PER_WORD-1) / BITS_PER_WORD;
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
|
|
|
|
abits_ptr_[idx] = that.abits_ptr_[idx];
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
|
|
|
|
bbits_ptr_[idx] = that.bbits_ptr_[idx];
|
|
|
|
|
} else {
|
|
|
|
|
abits_val_ = that.abits_val_;
|
|
|
|
|
bbits_val_ = that.bbits_val_;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now we know that the sizes of this and that are definitely
|
|
|
|
|
different. We can use that in code below. In any case, we
|
|
|
|
|
need to copy only the smaller of the sizes. */
|
|
|
|
|
|
|
|
|
|
/* If source and destination are both short, then mask/copy
|
|
|
|
|
the bit values. */
|
|
|
|
|
if (size_ <= BITS_PER_WORD && that.size_ <= BITS_PER_WORD) {
|
|
|
|
|
unsigned bits_to_copy = (that.size_ < size_) ? that.size_ : size_;
|
|
|
|
|
unsigned long mask = (1UL << bits_to_copy) - 1UL;
|
|
|
|
|
abits_val_ &= ~mask;
|
|
|
|
|
bbits_val_ &= ~mask;
|
|
|
|
|
abits_val_ |= that.abits_val_&mask;
|
|
|
|
|
bbits_val_ |= that.bbits_val_&mask;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now we know that either source or destination are long. If
|
|
|
|
|
the destination is short, then mask/copy from the low word
|
|
|
|
|
of the long source. */
|
|
|
|
|
if (size_ <= BITS_PER_WORD) {
|
|
|
|
|
abits_val_ = that.abits_ptr_[0];
|
|
|
|
|
bbits_val_ = that.bbits_ptr_[0];
|
|
|
|
|
if (size_ < BITS_PER_WORD) {
|
|
|
|
|
unsigned long mask = (1UL << size_) - 1UL;
|
|
|
|
|
abits_val_ &= mask;
|
|
|
|
|
bbits_val_ &= mask;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now we know that the destination must be long. If the
|
|
|
|
|
source is short, then mask/copy from its value. */
|
|
|
|
|
if (that.size_ <= BITS_PER_WORD) {
|
|
|
|
|
unsigned long mask;
|
|
|
|
|
if (that.size_ < BITS_PER_WORD) {
|
|
|
|
|
mask = (1UL << that.size_) - 1UL;
|
|
|
|
|
abits_ptr_[0] &= ~mask;
|
|
|
|
|
bbits_ptr_[0] &= ~mask;
|
|
|
|
|
} else {
|
|
|
|
|
mask = -1UL;
|
|
|
|
|
}
|
|
|
|
|
abits_ptr_[0] |= that.abits_val_&mask;
|
|
|
|
|
bbits_ptr_[0] |= that.bbits_val_&mask;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finally, we know that source and destination are long. copy
|
|
|
|
|
words until we get to the last. */
|
|
|
|
|
unsigned bits_to_copy = (that.size_ < size_) ? that.size_ : size_;
|
|
|
|
|
unsigned word = 0;
|
|
|
|
|
while (bits_to_copy >= BITS_PER_WORD) {
|
|
|
|
|
abits_ptr_[word] = that.abits_ptr_[word];
|
|
|
|
|
bbits_ptr_[word] = that.bbits_ptr_[word];
|
|
|
|
|
bits_to_copy -= BITS_PER_WORD;
|
|
|
|
|
word += 1;
|
|
|
|
|
}
|
|
|
|
|
if (bits_to_copy > 0) {
|
|
|
|
|
unsigned long mask = (1UL << bits_to_copy) - 1UL;
|
|
|
|
|
abits_ptr_[word] &= ~mask;
|
|
|
|
|
bbits_ptr_[word] &= ~mask;
|
|
|
|
|
abits_ptr_[word] |= that.abits_ptr_[word] & mask;
|
|
|
|
|
bbits_ptr_[word] |= that.bbits_ptr_[word] & mask;
|
|
|
|
|
}
|
2008-01-13 03:22:46 +01:00
|
|
|
}
|
|
|
|
|
|
2005-06-20 03:28:14 +02:00
|
|
|
void vvp_vector4_t::copy_from_(const vvp_vector4_t&that)
|
2004-12-11 03:31:25 +01:00
|
|
|
{
|
|
|
|
|
size_ = that.size_;
|
2005-06-20 03:28:14 +02:00
|
|
|
if (size_ > BITS_PER_WORD) {
|
|
|
|
|
unsigned words = (size_+BITS_PER_WORD-1) / BITS_PER_WORD;
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_ = new unsigned long[2*words];
|
|
|
|
|
bbits_ptr_ = abits_ptr_ + words;
|
2004-12-11 03:31:25 +01:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_[idx] = that.abits_ptr_[idx];
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
|
|
|
|
bbits_ptr_[idx] = that.bbits_ptr_[idx];
|
2004-12-11 03:31:25 +01:00
|
|
|
|
|
|
|
|
} else {
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_val_ = that.abits_val_;
|
|
|
|
|
bbits_val_ = that.bbits_val_;
|
2004-12-11 03:31:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-21 01:30:27 +02:00
|
|
|
void vvp_vector4_t::allocate_words_(unsigned wid, unsigned long inita, unsigned long initb)
|
2004-12-11 03:31:25 +01:00
|
|
|
{
|
2005-06-20 03:28:14 +02:00
|
|
|
if (size_ > BITS_PER_WORD) {
|
|
|
|
|
unsigned cnt = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD;
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_ = new unsigned long[2*cnt];
|
|
|
|
|
bbits_ptr_ = abits_ptr_ + cnt;
|
|
|
|
|
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
|
|
|
|
abits_ptr_[idx] = inita;
|
2004-12-11 03:31:25 +01:00
|
|
|
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
2008-04-21 01:30:27 +02:00
|
|
|
bbits_ptr_[idx] = initb;
|
2004-12-11 03:31:25 +01:00
|
|
|
|
|
|
|
|
} else {
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_val_ = inita;
|
|
|
|
|
bbits_val_ = initb;
|
2004-12-11 03:31:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
vvp_vector4_t::vvp_vector4_t(const vvp_vector4_t&that,
|
|
|
|
|
unsigned adr, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
size_ = wid;
|
|
|
|
|
assert((adr + wid) <= that.size_);
|
|
|
|
|
|
2008-04-21 01:30:27 +02:00
|
|
|
allocate_words_(wid, WORD_X_ABITS, WORD_X_BBITS);
|
2005-08-27 04:34:42 +02:00
|
|
|
|
|
|
|
|
if (wid > BITS_PER_WORD) {
|
|
|
|
|
/* In this case, the subvector and the source vector are
|
|
|
|
|
long. Do the transfer reasonably efficiently. */
|
|
|
|
|
unsigned ptr = adr / BITS_PER_WORD;
|
2008-04-21 01:30:27 +02:00
|
|
|
unsigned long off = adr % BITS_PER_WORD;
|
|
|
|
|
unsigned long noff = BITS_PER_WORD - off;
|
|
|
|
|
unsigned long lmask = (1UL << off) - 1UL;
|
2005-08-27 04:34:42 +02:00
|
|
|
unsigned trans = 0;
|
|
|
|
|
unsigned dst = 0;
|
|
|
|
|
while (trans < wid) {
|
|
|
|
|
// The low bits of the result.
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_[dst] = (that.abits_ptr_[ptr] & ~lmask) >> off;
|
|
|
|
|
bbits_ptr_[dst] = (that.bbits_ptr_[ptr] & ~lmask) >> off;
|
2005-08-27 04:34:42 +02:00
|
|
|
trans += noff;
|
|
|
|
|
|
|
|
|
|
if (trans >= wid)
|
|
|
|
|
break;
|
|
|
|
|
|
2005-08-30 02:49:42 +02:00
|
|
|
ptr += 1;
|
|
|
|
|
|
2005-08-29 06:46:52 +02:00
|
|
|
// The high bits of the result. Skip this if the
|
|
|
|
|
// source and destination are perfectly aligned.
|
|
|
|
|
if (noff != BITS_PER_WORD) {
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_[dst] |= (that.abits_ptr_[ptr]&lmask) << noff;
|
|
|
|
|
bbits_ptr_[dst] |= (that.bbits_ptr_[ptr]&lmask) << noff;
|
2005-08-29 06:46:52 +02:00
|
|
|
trans += off;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
dst += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-23 23:30:32 +02:00
|
|
|
} else if (that.size_ > BITS_PER_WORD) {
|
|
|
|
|
/* In this case, the subvector fits in a single word,
|
|
|
|
|
but the source is large. */
|
|
|
|
|
unsigned ptr = adr / BITS_PER_WORD;
|
|
|
|
|
unsigned long off = adr % BITS_PER_WORD;
|
|
|
|
|
unsigned trans = BITS_PER_WORD - off;
|
|
|
|
|
if (trans > wid)
|
|
|
|
|
trans = wid;
|
|
|
|
|
|
|
|
|
|
if (trans == BITS_PER_WORD) {
|
|
|
|
|
// Very special case: Copy exactly 1 perfectly
|
|
|
|
|
// aligned word.
|
|
|
|
|
abits_val_ = that.abits_ptr_[ptr];
|
|
|
|
|
bbits_val_ = that.bbits_ptr_[ptr];
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// lmask is the low bits of the destination,
|
|
|
|
|
// masked into the source.
|
|
|
|
|
unsigned long lmask = (1UL<<trans) - 1UL;
|
|
|
|
|
lmask <<= off;
|
|
|
|
|
|
|
|
|
|
// The low bits of the result.
|
|
|
|
|
abits_val_ = (that.abits_ptr_[ptr] & lmask) >> off;
|
|
|
|
|
bbits_val_ = (that.bbits_ptr_[ptr] & lmask) >> off;
|
|
|
|
|
|
|
|
|
|
if (trans < wid) {
|
|
|
|
|
// If there are more bits, then get them
|
|
|
|
|
// from the bottom of the next word of the
|
|
|
|
|
// source.
|
|
|
|
|
unsigned long hmask = (1UL << (wid-trans)) - 1UL;
|
|
|
|
|
|
|
|
|
|
// The high bits of the result.
|
|
|
|
|
abits_val_ |= (that.abits_ptr_[ptr+1]&hmask) << trans;
|
|
|
|
|
bbits_val_ |= (that.bbits_ptr_[ptr+1]&hmask) << trans;
|
|
|
|
|
}
|
2005-08-27 04:34:42 +02:00
|
|
|
}
|
2008-05-23 23:30:32 +02:00
|
|
|
|
|
|
|
|
} else if (size_ == BITS_PER_WORD) {
|
|
|
|
|
/* We know that source and destination are short. If the
|
|
|
|
|
destination is a full word, then we know the copy is
|
|
|
|
|
aligned and complete. */
|
|
|
|
|
abits_val_ = that.abits_val_;
|
|
|
|
|
bbits_val_ = that.bbits_val_;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* Finally, the source and destination vectors are both
|
|
|
|
|
short, so there is a single mask/shift/copy. */
|
|
|
|
|
unsigned long mask = (1UL << size_) - 1UL;
|
|
|
|
|
mask <<= adr;
|
|
|
|
|
|
|
|
|
|
abits_val_ = (that.abits_val_ & mask) >> adr;
|
|
|
|
|
bbits_val_ = (that.bbits_val_ & mask) >> adr;
|
2005-08-27 04:34:42 +02:00
|
|
|
}
|
2008-04-21 01:30:27 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Change the size of the vvp_vector4_t vector to the new size. Copy
|
|
|
|
|
* the old values, as many as well fit, into the new vector.
|
|
|
|
|
*/
|
|
|
|
|
void vvp_vector4_t::resize(unsigned newsize)
|
|
|
|
|
{
|
|
|
|
|
if (size_ == newsize)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
unsigned cnt = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
if (newsize > BITS_PER_WORD) {
|
|
|
|
|
unsigned newcnt = (newsize + BITS_PER_WORD - 1) / BITS_PER_WORD;
|
2008-04-21 01:30:27 +02:00
|
|
|
unsigned long*newbits = new unsigned long[2*newcnt];
|
2005-08-27 04:34:42 +02:00
|
|
|
|
|
|
|
|
if (cnt > 1) {
|
|
|
|
|
unsigned trans = cnt;
|
|
|
|
|
if (trans > newcnt)
|
|
|
|
|
trans = newcnt;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < trans ; idx += 1)
|
2008-04-21 01:30:27 +02:00
|
|
|
newbits[idx] = abits_ptr_[idx];
|
|
|
|
|
for (unsigned idx = 0 ; idx < trans ; idx += 1)
|
|
|
|
|
newbits[newcnt+idx] = bbits_ptr_[idx];
|
2005-08-27 04:34:42 +02:00
|
|
|
|
2008-04-21 01:30:27 +02:00
|
|
|
delete[]abits_ptr_;
|
2005-08-27 04:34:42 +02:00
|
|
|
|
|
|
|
|
} else {
|
2008-04-21 01:30:27 +02:00
|
|
|
newbits[0] = abits_val_;
|
|
|
|
|
newbits[newcnt] = bbits_val_;
|
2005-08-27 04:34:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = cnt ; idx < newcnt ; idx += 1)
|
2008-04-21 01:30:27 +02:00
|
|
|
newbits[idx] = WORD_X_ABITS;
|
|
|
|
|
for (unsigned idx = cnt ; idx < newcnt ; idx += 1)
|
|
|
|
|
newbits[newcnt+idx] = WORD_X_BBITS;
|
2005-08-27 04:34:42 +02:00
|
|
|
|
|
|
|
|
size_ = newsize;
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_ = newbits;
|
|
|
|
|
bbits_ptr_ = newbits + newcnt;
|
2005-08-27 04:34:42 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
if (cnt > 1) {
|
2008-04-21 01:30:27 +02:00
|
|
|
unsigned long newvala = abits_ptr_[0];
|
|
|
|
|
unsigned long newvalb = bbits_ptr_[0];
|
|
|
|
|
delete[]abits_ptr_;
|
|
|
|
|
abits_val_ = newvala;
|
|
|
|
|
bbits_val_ = newvalb;
|
2005-08-27 04:34:42 +02:00
|
|
|
}
|
2005-10-04 06:41:07 +02:00
|
|
|
|
|
|
|
|
size_ = newsize;
|
2005-08-27 04:34:42 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned long* vvp_vector4_t::subarray(unsigned adr, unsigned wid) const
|
|
|
|
|
{
|
|
|
|
|
const unsigned BIT2_PER_WORD = 8*sizeof(unsigned long);
|
|
|
|
|
unsigned awid = (wid + BIT2_PER_WORD - 1) / (BIT2_PER_WORD);
|
|
|
|
|
unsigned long*val = new unsigned long[awid];
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < awid ; idx += 1)
|
|
|
|
|
val[idx] = 0;
|
|
|
|
|
|
|
|
|
|
if (size_ <= BITS_PER_WORD) {
|
|
|
|
|
/* Handle the special case that the array is small. The
|
2008-04-21 01:30:27 +02:00
|
|
|
entire value of the vector4 is within the xbits_val_
|
2005-08-27 04:34:42 +02:00
|
|
|
so we know that the result is a single word, the
|
|
|
|
|
source is a single word, and we just have to loop
|
|
|
|
|
through that word. */
|
2008-04-21 01:30:27 +02:00
|
|
|
unsigned long atmp = abits_val_ >> adr;
|
|
|
|
|
unsigned long btmp = bbits_val_ >> adr;
|
2008-04-23 02:31:08 +02:00
|
|
|
if (wid < BIT2_PER_WORD) {
|
|
|
|
|
atmp &= (1UL << wid) - 1;
|
|
|
|
|
btmp &= (1UL << wid) - 1;
|
|
|
|
|
}
|
2008-04-21 01:30:27 +02:00
|
|
|
if (btmp) goto x_out;
|
2005-08-27 04:34:42 +02:00
|
|
|
|
2008-04-21 01:30:27 +02:00
|
|
|
val[0] = atmp;
|
2005-08-27 04:34:42 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
2008-04-21 01:30:27 +02:00
|
|
|
unsigned val_ptr = 0;
|
|
|
|
|
unsigned val_off = 0;
|
|
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
/* Get the first word we are scanning. We may in fact be
|
|
|
|
|
somewhere in the middle of that word. */
|
2008-04-21 01:30:27 +02:00
|
|
|
while (wid > 0) {
|
|
|
|
|
unsigned long atmp = abits_ptr_[adr/BITS_PER_WORD];
|
|
|
|
|
unsigned long btmp = bbits_ptr_[adr/BITS_PER_WORD];
|
|
|
|
|
unsigned long off = adr%BITS_PER_WORD;
|
|
|
|
|
atmp >>= off;
|
|
|
|
|
btmp >>= off;
|
|
|
|
|
|
|
|
|
|
unsigned long trans = BITS_PER_WORD - off;
|
2008-04-23 02:31:08 +02:00
|
|
|
if (trans > (BIT2_PER_WORD - val_off))
|
|
|
|
|
trans = BIT2_PER_WORD - val_off;
|
2008-04-21 01:30:27 +02:00
|
|
|
if (wid < trans)
|
|
|
|
|
trans = wid;
|
2008-04-23 02:31:08 +02:00
|
|
|
if (trans < BIT2_PER_WORD) {
|
|
|
|
|
atmp &= (1UL << trans) - 1;
|
|
|
|
|
btmp &= (1UL << trans) - 1;
|
|
|
|
|
}
|
2008-04-21 01:30:27 +02:00
|
|
|
if (btmp) goto x_out;
|
|
|
|
|
|
|
|
|
|
val[val_ptr] |= atmp << val_off;
|
|
|
|
|
adr += trans;
|
|
|
|
|
wid -= trans;
|
|
|
|
|
val_off += trans;
|
2008-04-23 02:31:08 +02:00
|
|
|
if (val_off == BIT2_PER_WORD) {
|
2007-12-03 04:00:12 +01:00
|
|
|
val_ptr += 1;
|
2008-04-21 01:30:27 +02:00
|
|
|
val_off = 0;
|
2007-12-03 04:00:12 +01:00
|
|
|
}
|
2005-08-27 04:34:42 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return val;
|
|
|
|
|
|
|
|
|
|
x_out:
|
|
|
|
|
delete[]val;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-23 22:50:05 +02:00
|
|
|
void vvp_vector4_t::setarray(unsigned adr, unsigned wid, const unsigned long*val)
|
|
|
|
|
{
|
|
|
|
|
assert(adr+wid <= size_);
|
|
|
|
|
|
|
|
|
|
const unsigned BIT2_PER_WORD = 8*sizeof(unsigned long);
|
|
|
|
|
|
|
|
|
|
if (size_ <= BITS_PER_WORD) {
|
|
|
|
|
// We know here that both the source and the target are
|
|
|
|
|
// within a single word. Write the bits into the
|
|
|
|
|
// abits_val_ directly.
|
|
|
|
|
|
|
|
|
|
assert(BIT2_PER_WORD <= BITS_PER_WORD);
|
|
|
|
|
unsigned long lmask = (1UL << adr) - 1UL;
|
|
|
|
|
unsigned long hmask = ((adr+wid) < BITS_PER_WORD)
|
|
|
|
|
? -1UL << (adr+wid)
|
|
|
|
|
: 0;
|
|
|
|
|
unsigned long mask = ~(hmask | lmask);
|
|
|
|
|
|
|
|
|
|
abits_val_ &= ~mask;
|
|
|
|
|
bbits_val_ &= ~mask;
|
|
|
|
|
|
|
|
|
|
abits_val_ |= mask & (val[0] << adr);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// The general case, there are multiple words of
|
|
|
|
|
// destination, and possibly multiple words of source
|
|
|
|
|
// data. Shift and mask as we go.
|
|
|
|
|
unsigned off = adr % BITS_PER_WORD;
|
|
|
|
|
unsigned ptr = adr / BITS_PER_WORD;
|
|
|
|
|
unsigned val_off = 0;
|
|
|
|
|
unsigned val_ptr = 0;
|
|
|
|
|
while (wid > 0) {
|
|
|
|
|
unsigned trans = wid;
|
|
|
|
|
if (trans > (BIT2_PER_WORD-val_off))
|
|
|
|
|
trans = BIT2_PER_WORD-val_off;
|
|
|
|
|
if (trans > (BITS_PER_WORD-off))
|
|
|
|
|
trans = BITS_PER_WORD-off;
|
|
|
|
|
|
|
|
|
|
unsigned long lmask = (1UL << off) - 1UL;
|
|
|
|
|
unsigned long hmask = ((off+trans) < BITS_PER_WORD)
|
|
|
|
|
? -1UL << (off+trans)
|
|
|
|
|
: 0;
|
|
|
|
|
unsigned long mask = ~(hmask | lmask);
|
|
|
|
|
|
|
|
|
|
abits_ptr_[ptr] &= ~mask;
|
|
|
|
|
bbits_ptr_[ptr] &= ~mask;
|
|
|
|
|
if (val_off >= off)
|
|
|
|
|
abits_ptr_[ptr] |= mask & (val[val_ptr] >> (val_off-off));
|
|
|
|
|
else
|
|
|
|
|
abits_ptr_[ptr] |= mask & (val[val_ptr] << (off-val_off));
|
|
|
|
|
|
|
|
|
|
wid -= trans;
|
|
|
|
|
val_off += trans;
|
|
|
|
|
if (val_off == BIT2_PER_WORD) {
|
|
|
|
|
val_off = 0;
|
|
|
|
|
val_ptr += 1;
|
|
|
|
|
}
|
|
|
|
|
off += trans;
|
|
|
|
|
if (off == BITS_PER_WORD) {
|
|
|
|
|
off = 0;
|
|
|
|
|
ptr += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-30 02:49:42 +02:00
|
|
|
/*
|
|
|
|
|
* Set the bits of that vector, which must be a subset of this vector,
|
|
|
|
|
* into the addressed part of this vector. Use bit masking and word
|
|
|
|
|
* copies to go as fast as reasonably possible.
|
|
|
|
|
*/
|
2005-08-27 04:34:42 +02:00
|
|
|
void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that)
|
|
|
|
|
{
|
|
|
|
|
assert(adr+that.size_ <= size_);
|
|
|
|
|
|
|
|
|
|
if (size_ <= BITS_PER_WORD) {
|
|
|
|
|
|
|
|
|
|
/* The destination vector (me!) is within a bits_val_
|
|
|
|
|
word, so the subvector is certainly within a
|
|
|
|
|
bits_val_ word. Therefore, the entire operation is a
|
|
|
|
|
matter of writing the bits of that into the addressed
|
|
|
|
|
bits of this. The mask below is calculated to be 1
|
|
|
|
|
for all the bits that are to come from that. Do the
|
|
|
|
|
job by some shifting, masking and OR. */
|
|
|
|
|
|
2008-04-21 01:30:27 +02:00
|
|
|
unsigned long lmask = (1UL << adr) - 1;
|
2005-08-30 02:49:42 +02:00
|
|
|
unsigned long hmask;
|
|
|
|
|
unsigned long hshift = adr+that.size_;
|
|
|
|
|
if (hshift >= BITS_PER_WORD)
|
|
|
|
|
hmask = -1UL;
|
|
|
|
|
else
|
2008-04-21 01:30:27 +02:00
|
|
|
hmask = (1UL << (adr+that.size_)) - 1;
|
2005-08-27 04:34:42 +02:00
|
|
|
unsigned long mask = hmask & ~lmask;
|
|
|
|
|
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_val_ =
|
|
|
|
|
(abits_val_ & ~mask)
|
|
|
|
|
| ((that.abits_val_<<adr) & mask);
|
|
|
|
|
bbits_val_ =
|
|
|
|
|
(bbits_val_ & ~mask)
|
|
|
|
|
| ((that.bbits_val_<<adr) & mask);
|
2005-08-27 04:34:42 +02:00
|
|
|
|
|
|
|
|
} else if (that.size_ <= BITS_PER_WORD) {
|
|
|
|
|
|
2007-03-22 17:08:14 +01:00
|
|
|
/* This vector is more than a word, but that vector is
|
2005-08-30 02:49:42 +02:00
|
|
|
still small. Write into the destination, possibly
|
2008-04-21 01:30:27 +02:00
|
|
|
spanning two destination words, depending on whether
|
2005-08-30 02:49:42 +02:00
|
|
|
the source vector spans a word transition. */
|
2005-08-27 04:34:42 +02:00
|
|
|
unsigned long dptr = adr / BITS_PER_WORD;
|
|
|
|
|
unsigned long doff = adr % BITS_PER_WORD;
|
|
|
|
|
|
2008-04-21 01:30:27 +02:00
|
|
|
unsigned long lmask = (1UL << doff) - 1;
|
2005-08-29 06:46:52 +02:00
|
|
|
unsigned long hshift = doff+that.size_;
|
|
|
|
|
unsigned long hmask;
|
|
|
|
|
if (hshift >= BITS_PER_WORD)
|
|
|
|
|
hmask = -1UL;
|
|
|
|
|
else
|
2008-04-21 01:30:27 +02:00
|
|
|
hmask = (1UL << hshift) - 1UL;
|
2005-08-29 06:46:52 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
unsigned long mask = hmask & ~lmask;
|
|
|
|
|
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_[dptr] =
|
|
|
|
|
(abits_ptr_[dptr] & ~mask)
|
|
|
|
|
| ((that.abits_val_ << doff) & mask);
|
|
|
|
|
bbits_ptr_[dptr] =
|
|
|
|
|
(bbits_ptr_[dptr] & ~mask)
|
|
|
|
|
| ((that.bbits_val_ << doff) & mask);
|
2005-08-27 04:34:42 +02:00
|
|
|
|
2005-08-29 06:46:52 +02:00
|
|
|
if ((doff + that.size_) > BITS_PER_WORD) {
|
2005-08-27 04:34:42 +02:00
|
|
|
unsigned tail = doff + that.size_ - BITS_PER_WORD;
|
2008-04-21 01:30:27 +02:00
|
|
|
mask = (1UL << tail) - 1;
|
2005-08-27 04:34:42 +02:00
|
|
|
|
|
|
|
|
dptr += 1;
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_[dptr] =
|
|
|
|
|
(abits_ptr_[dptr] & ~mask)
|
|
|
|
|
| ((that.abits_val_ >> (that.size_-tail)) & mask);
|
|
|
|
|
bbits_ptr_[dptr] =
|
|
|
|
|
(bbits_ptr_[dptr] & ~mask)
|
|
|
|
|
| ((that.bbits_val_ >> (that.size_-tail)) & mask);
|
2005-08-27 04:34:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (adr%BITS_PER_WORD == 0) {
|
|
|
|
|
|
|
|
|
|
/* In this case, both vectors are long, but the
|
|
|
|
|
destination is neatly aligned. That means all but the
|
|
|
|
|
last word can be simply copied with no masking. */
|
|
|
|
|
|
|
|
|
|
unsigned remain = that.size_;
|
|
|
|
|
unsigned sptr = 0;
|
|
|
|
|
unsigned dptr = adr / BITS_PER_WORD;
|
|
|
|
|
while (remain >= BITS_PER_WORD) {
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_[dptr] = that.abits_ptr_[sptr];
|
|
|
|
|
bbits_ptr_[dptr] = that.bbits_ptr_[sptr];
|
|
|
|
|
dptr += 1;
|
|
|
|
|
sptr += 1;
|
2005-08-27 04:34:42 +02:00
|
|
|
remain -= BITS_PER_WORD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (remain > 0) {
|
2008-04-21 01:30:27 +02:00
|
|
|
unsigned long mask = (1UL << remain) - 1;
|
|
|
|
|
abits_ptr_[dptr] =
|
|
|
|
|
(abits_ptr_[dptr] & ~mask)
|
|
|
|
|
| (that.abits_ptr_[sptr] & mask);
|
|
|
|
|
bbits_ptr_[dptr] =
|
|
|
|
|
(bbits_ptr_[dptr] & ~mask)
|
|
|
|
|
| (that.bbits_ptr_[sptr] & mask);
|
2005-08-27 04:34:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* We know that there are two long vectors, and we know
|
|
|
|
|
that the destination is definitely NOT aligned. */
|
2005-08-30 02:49:42 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
unsigned remain = that.size_;
|
|
|
|
|
unsigned sptr = 0;
|
|
|
|
|
unsigned dptr = adr / BITS_PER_WORD;
|
|
|
|
|
unsigned doff = adr % BITS_PER_WORD;
|
2008-04-21 01:30:27 +02:00
|
|
|
unsigned long lmask = (1UL << doff) - 1;
|
2005-08-27 04:34:42 +02:00
|
|
|
unsigned ndoff = BITS_PER_WORD - doff;
|
|
|
|
|
while (remain >= BITS_PER_WORD) {
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_[dptr] =
|
|
|
|
|
(abits_ptr_[dptr] & lmask)
|
|
|
|
|
| ((that.abits_ptr_[sptr] << doff) & ~lmask);
|
|
|
|
|
bbits_ptr_[dptr] =
|
|
|
|
|
(bbits_ptr_[dptr] & lmask)
|
|
|
|
|
| ((that.bbits_ptr_[sptr] << doff) & ~lmask);
|
2005-08-27 04:34:42 +02:00
|
|
|
dptr += 1;
|
|
|
|
|
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_[dptr] =
|
|
|
|
|
(abits_ptr_[dptr] & ~lmask)
|
|
|
|
|
| ((that.abits_ptr_[sptr] >> ndoff) & lmask);
|
|
|
|
|
bbits_ptr_[dptr] =
|
|
|
|
|
(bbits_ptr_[dptr] & ~lmask)
|
|
|
|
|
| ((that.bbits_ptr_[sptr] >> ndoff) & lmask);
|
2005-08-27 04:34:42 +02:00
|
|
|
|
|
|
|
|
remain -= BITS_PER_WORD;
|
|
|
|
|
sptr += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-16 01:00:22 +01:00
|
|
|
if (remain > 0) {
|
|
|
|
|
unsigned long hshift = doff+remain;
|
|
|
|
|
unsigned long hmask;
|
|
|
|
|
if (hshift >= BITS_PER_WORD)
|
|
|
|
|
hmask = -1UL;
|
|
|
|
|
else
|
2008-04-21 01:30:27 +02:00
|
|
|
hmask = (1UL << (doff+remain)) - 1;
|
2005-08-30 02:49:42 +02:00
|
|
|
|
2008-02-16 01:00:22 +01:00
|
|
|
unsigned long mask = hmask & ~lmask;
|
2005-08-27 04:34:42 +02:00
|
|
|
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask)
|
|
|
|
|
| ((that.abits_ptr_[sptr] << doff) & mask);
|
|
|
|
|
bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask)
|
|
|
|
|
| ((that.bbits_ptr_[sptr] << doff) & mask);
|
2005-08-27 04:34:42 +02:00
|
|
|
|
2008-02-16 01:00:22 +01:00
|
|
|
if ((doff + remain) > BITS_PER_WORD) {
|
|
|
|
|
unsigned tail = doff + remain - BITS_PER_WORD;
|
|
|
|
|
if (tail >= BITS_PER_WORD)
|
|
|
|
|
mask = -1UL;
|
|
|
|
|
else
|
2008-04-21 01:30:27 +02:00
|
|
|
mask = (1UL << tail) - 1;
|
2005-08-27 04:34:42 +02:00
|
|
|
|
2008-02-16 01:00:22 +01:00
|
|
|
dptr += 1;
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) |
|
|
|
|
|
((that.abits_ptr_[sptr] >> (remain-tail))&mask);
|
|
|
|
|
bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) |
|
|
|
|
|
((that.bbits_ptr_[sptr] >> (remain-tail))&mask);
|
2008-02-16 01:00:22 +01:00
|
|
|
}
|
2005-08-27 04:34:42 +02:00
|
|
|
}
|
|
|
|
|
}
|
2008-04-21 01:30:27 +02:00
|
|
|
|
2005-08-27 04:34:42 +02:00
|
|
|
}
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2005-04-25 06:42:17 +02:00
|
|
|
bool vvp_vector4_t::eeq(const vvp_vector4_t&that) const
|
|
|
|
|
{
|
|
|
|
|
if (size_ != that.size_)
|
|
|
|
|
return false;
|
|
|
|
|
|
2005-08-29 06:46:52 +02:00
|
|
|
if (size_ < BITS_PER_WORD) {
|
2008-04-21 01:30:27 +02:00
|
|
|
unsigned long mask = (1UL << size_) - 1;
|
|
|
|
|
return (abits_val_&mask) == (that.abits_val_&mask)
|
|
|
|
|
&& (bbits_val_&mask) == (that.bbits_val_&mask);
|
2005-08-27 05:28:16 +02:00
|
|
|
}
|
2005-04-25 06:42:17 +02:00
|
|
|
|
2005-08-29 06:46:52 +02:00
|
|
|
if (size_ == BITS_PER_WORD) {
|
2008-04-21 01:30:27 +02:00
|
|
|
return (abits_val_ == that.abits_val_)
|
|
|
|
|
&& (bbits_val_ == that.bbits_val_);
|
2005-08-29 06:46:52 +02:00
|
|
|
}
|
|
|
|
|
|
2005-08-27 05:28:16 +02:00
|
|
|
unsigned words = size_ / BITS_PER_WORD;
|
2005-04-25 06:42:17 +02:00
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1) {
|
2008-04-21 01:30:27 +02:00
|
|
|
if (abits_ptr_[idx] != that.abits_ptr_[idx])
|
|
|
|
|
return false;
|
|
|
|
|
if (bbits_ptr_[idx] != that.bbits_ptr_[idx])
|
2005-04-25 06:42:17 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-27 05:28:16 +02:00
|
|
|
unsigned long mask = size_%BITS_PER_WORD;
|
|
|
|
|
if (mask > 0) {
|
2008-04-21 01:30:27 +02:00
|
|
|
mask = (1UL << mask) - 1;
|
|
|
|
|
return (abits_ptr_[words]&mask) == (that.abits_ptr_[words]&mask)
|
|
|
|
|
&& (bbits_ptr_[words]&mask) == (that.bbits_ptr_[words]&mask);
|
2005-08-27 05:28:16 +02:00
|
|
|
}
|
|
|
|
|
|
2005-04-25 06:42:17 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-05 04:15:15 +01:00
|
|
|
bool vvp_vector4_t::has_xz() const
|
|
|
|
|
{
|
|
|
|
|
if (size_ < BITS_PER_WORD) {
|
2008-04-21 01:30:27 +02:00
|
|
|
unsigned long mask = -1UL >> (BITS_PER_WORD - size_);
|
|
|
|
|
return bbits_val_&mask;
|
2007-12-05 04:15:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (size_ == BITS_PER_WORD) {
|
2008-04-21 01:30:27 +02:00
|
|
|
return bbits_val_;
|
2007-12-05 04:15:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned words = size_ / BITS_PER_WORD;
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1) {
|
2008-04-21 01:30:27 +02:00
|
|
|
if (bbits_ptr_[idx])
|
2007-12-05 04:15:15 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned long mask = size_%BITS_PER_WORD;
|
|
|
|
|
if (mask > 0) {
|
2008-04-21 01:30:27 +02:00
|
|
|
mask = -1UL >> (BITS_PER_WORD - mask);
|
|
|
|
|
return bbits_ptr_[words]&mask;
|
2007-12-05 04:15:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2005-06-22 00:48:23 +02:00
|
|
|
|
|
|
|
|
void vvp_vector4_t::change_z2x()
|
|
|
|
|
{
|
2008-04-21 01:30:27 +02:00
|
|
|
// This method relies on the fact that both BIT4_X and BIT4_Z
|
|
|
|
|
// have the bbit set in the vector4 encoding, and also that
|
|
|
|
|
// the BIT4_X has abit set in the vector4 encoding. By simply
|
|
|
|
|
// or-ing the bbit into the abit, BIT4_X and BIT4_Z both
|
|
|
|
|
// become BIT4_X.
|
2005-06-22 00:48:23 +02:00
|
|
|
|
|
|
|
|
if (size_ <= BITS_PER_WORD) {
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_val_ |= bbits_val_;
|
2005-06-22 00:48:23 +02:00
|
|
|
} else {
|
|
|
|
|
unsigned words = (size_+BITS_PER_WORD-1) / BITS_PER_WORD;
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
2008-04-21 01:30:27 +02:00
|
|
|
abits_ptr_[idx] |= bbits_ptr_[idx];
|
2005-06-22 00:48:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-29 18:52:06 +01:00
|
|
|
char* vvp_vector4_t::as_string(char*buf, size_t buf_len)
|
|
|
|
|
{
|
|
|
|
|
char*res = buf;
|
|
|
|
|
*buf++ = 'C';
|
|
|
|
|
*buf++ = '4';
|
|
|
|
|
*buf++ = '<';
|
|
|
|
|
buf_len -= 3;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < size() && buf_len >= 2 ; idx += 1) {
|
|
|
|
|
switch (value(size()-idx-1)) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
*buf++ = '0';
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
*buf++ = '1';
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_X:
|
|
|
|
|
*buf++ = 'x';
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_Z:
|
|
|
|
|
*buf++ = 'z';
|
|
|
|
|
}
|
|
|
|
|
buf_len -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*buf++ = '>';
|
|
|
|
|
*buf++ = 0;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-24 02:52:43 +02:00
|
|
|
void vvp_vector4_t::invert()
|
|
|
|
|
{
|
|
|
|
|
if (size_ <= BITS_PER_WORD) {
|
|
|
|
|
unsigned long mask = (size_<BITS_PER_WORD)? (1UL<<size_)-1UL : -1UL;
|
|
|
|
|
abits_val_ = mask & ~abits_val_;
|
|
|
|
|
abits_val_ |= bbits_val_;
|
|
|
|
|
} else {
|
|
|
|
|
unsigned remaining = size_;
|
|
|
|
|
unsigned idx = 0;
|
|
|
|
|
while (remaining >= BITS_PER_WORD) {
|
|
|
|
|
abits_ptr_[idx] = ~abits_ptr_[idx];
|
|
|
|
|
abits_ptr_[idx] |= bbits_ptr_[idx];
|
|
|
|
|
idx += 1;
|
|
|
|
|
remaining -= BITS_PER_WORD;
|
|
|
|
|
}
|
|
|
|
|
if (remaining > 0) {
|
|
|
|
|
unsigned long mask = (1UL<<remaining) - 1UL;
|
|
|
|
|
abits_ptr_[idx] = mask & ~abits_ptr_[idx];
|
|
|
|
|
abits_ptr_[idx] |= bbits_ptr_[idx];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t& vvp_vector4_t::operator &= (const vvp_vector4_t&that)
|
|
|
|
|
{
|
|
|
|
|
// Make sure that all Z bits are turned into X bits.
|
|
|
|
|
change_z2x();
|
|
|
|
|
|
|
|
|
|
// This is sneaky. The truth table is:
|
|
|
|
|
// 00 01 11
|
|
|
|
|
// 00 00 00 00
|
|
|
|
|
// 01 00 01 11
|
|
|
|
|
// 11 00 11 11
|
|
|
|
|
if (size_ <= BITS_PER_WORD) {
|
|
|
|
|
// Each tmp bit is true if that is 1, X or Z.
|
|
|
|
|
unsigned long tmp = that.abits_val_ | that.bbits_val_;
|
|
|
|
|
abits_val_ &= that.abits_val_;
|
|
|
|
|
bbits_val_ = (bbits_val_ & tmp) | (abits_val_&that.bbits_val_);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
unsigned words = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD;
|
|
|
|
|
for (unsigned idx = 0; idx < words ; idx += 1) {
|
|
|
|
|
unsigned long tmp = that.abits_ptr_[idx]|that.bbits_ptr_[idx];
|
|
|
|
|
abits_ptr_[idx] &= that.abits_ptr_[idx];
|
|
|
|
|
bbits_ptr_[idx] = (bbits_ptr_[idx]&tmp) | (abits_ptr_[idx]&that.bbits_ptr_[idx]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t& vvp_vector4_t::operator |= (const vvp_vector4_t&that)
|
|
|
|
|
{
|
|
|
|
|
// Make sure that all Z bits are turned into X bits.
|
|
|
|
|
change_z2x();
|
|
|
|
|
|
|
|
|
|
// This is sneaky.
|
|
|
|
|
// The OR is 1 if either operand is 1.
|
|
|
|
|
// The OR is 0 if both operants are 0.
|
|
|
|
|
// Otherwise, the AND is X. The truth table is:
|
|
|
|
|
//
|
|
|
|
|
// 00 01 11
|
|
|
|
|
// 00 00 01 11
|
|
|
|
|
// 01 01 01 01
|
|
|
|
|
// 11 11 01 11
|
|
|
|
|
if (size_ <= BITS_PER_WORD) {
|
|
|
|
|
// Each tmp bit is true if that is 1, X or Z.
|
|
|
|
|
unsigned long tmp1 = abits_val_ | bbits_val_;
|
|
|
|
|
unsigned long tmp2 = that.abits_val_ | that.bbits_val_;
|
|
|
|
|
bbits_val_ = (bbits_val_& ~(that.abits_val_^that.bbits_val_))
|
|
|
|
|
| (that.bbits_val_& ~abits_val_);
|
|
|
|
|
abits_val_ = tmp1 | tmp2;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
unsigned words = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD;
|
|
|
|
|
for (unsigned idx = 0; idx < words ; idx += 1) {
|
|
|
|
|
unsigned long tmp1 = abits_ptr_[idx] | bbits_ptr_[idx];
|
|
|
|
|
unsigned long tmp2 = that.abits_ptr_[idx] | that.bbits_ptr_[idx];
|
|
|
|
|
bbits_ptr_[idx] = (bbits_ptr_[idx]& ~(that.abits_ptr_[idx]^that.bbits_ptr_[idx]))
|
|
|
|
|
| (that.bbits_ptr_[idx]& ~abits_ptr_[idx]);
|
|
|
|
|
abits_ptr_[idx] = tmp1 | tmp2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-05 04:15:15 +01:00
|
|
|
/*
|
|
|
|
|
* Add an integer to the vvp_vector4_t in place, bit by bit so that
|
|
|
|
|
* there is no size limitations.
|
|
|
|
|
*/
|
|
|
|
|
vvp_vector4_t& vvp_vector4_t::operator += (int64_t that)
|
|
|
|
|
{
|
|
|
|
|
vvp_bit4_t carry = BIT4_0;
|
|
|
|
|
unsigned idx;
|
|
|
|
|
|
|
|
|
|
if (has_xz()) {
|
|
|
|
|
vvp_vector4_t xxx (size(), BIT4_X);
|
|
|
|
|
*this = xxx;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < size() ; idx += 1) {
|
|
|
|
|
if (that == 0 && carry==BIT4_0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
vvp_bit4_t that_bit = (that&1)? BIT4_1 : BIT4_0;
|
|
|
|
|
that >>= 1;
|
|
|
|
|
|
|
|
|
|
if (that_bit==BIT4_0 && carry==BIT4_0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
vvp_bit4_t bit = value(idx);
|
|
|
|
|
bit = add_with_carry(bit, that_bit, carry);
|
|
|
|
|
|
|
|
|
|
set_bit(idx, bit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-17 22:54:56 +02:00
|
|
|
ostream& operator<< (ostream&out, const vvp_vector4_t&that)
|
2005-05-07 05:14:50 +02:00
|
|
|
{
|
|
|
|
|
out << that.size() << "'b";
|
|
|
|
|
for (unsigned idx = 0 ; idx < that.size() ; idx += 1)
|
|
|
|
|
out << that.value(that.size()-idx-1);
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-09 02:32:57 +01:00
|
|
|
/* The width is guaranteed to not be larger than a long.
|
|
|
|
|
* If the double is outside the integer range (+/-) the
|
|
|
|
|
* largest/smallest integer value is returned. */
|
|
|
|
|
vvp_vector4_t double_to_vector4(double val, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
long span = 1l << (wid-1);
|
|
|
|
|
double dmin = -1l * span;
|
|
|
|
|
double dmax = span - 1l;
|
|
|
|
|
|
|
|
|
|
if (val > dmax) val = dmax;
|
|
|
|
|
if (val < dmin) val = dmin;
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t res (wid);
|
|
|
|
|
long bits = lround(val);
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
|
|
|
|
vvp_bit4_t bit = BIT4_0;
|
|
|
|
|
|
|
|
|
|
if (bits & 1L) bit = BIT4_1;
|
|
|
|
|
|
|
|
|
|
res.set_bit(idx, bit);
|
|
|
|
|
bits >>= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-28 06:34:25 +01:00
|
|
|
bool vector4_to_value(const vvp_vector4_t&vec, unsigned long&val)
|
|
|
|
|
{
|
|
|
|
|
unsigned long res = 0;
|
|
|
|
|
unsigned long msk = 1;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) {
|
|
|
|
|
switch (vec.value(idx)) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
res |= msk;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msk <<= 1UL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val = res;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2006-12-09 20:06:53 +01:00
|
|
|
bool vector4_to_value(const vvp_vector4_t&vec, double&val, bool signed_flag)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (vec.size() == 0) {
|
|
|
|
|
val = 0.0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-12 04:36:58 +02:00
|
|
|
bool flag = true;
|
|
|
|
|
|
2006-12-09 20:06:53 +01:00
|
|
|
if (vec.value(vec.size()-1) != BIT4_1) {
|
|
|
|
|
signed_flag = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double res = 0.0;
|
|
|
|
|
if (signed_flag) {
|
|
|
|
|
vvp_bit4_t carry = BIT4_1;
|
2007-03-07 01:38:15 +01:00
|
|
|
for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) {
|
2006-12-09 20:06:53 +01:00
|
|
|
vvp_bit4_t a = ~vec.value(idx);
|
|
|
|
|
vvp_bit4_t x = add_with_carry(a, BIT4_0, carry);
|
|
|
|
|
switch (x) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
2007-03-07 04:55:42 +01:00
|
|
|
res += pow(2.0, (int)idx);
|
2006-12-09 20:06:53 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2007-06-12 04:36:58 +02:00
|
|
|
flag = false;
|
2006-12-09 20:06:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res *= -1.0;
|
|
|
|
|
} else {
|
2007-03-07 01:38:15 +01:00
|
|
|
for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) {
|
2006-12-09 20:06:53 +01:00
|
|
|
switch (vec.value(idx)) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
2007-03-07 04:55:42 +01:00
|
|
|
res += pow(2.0, (int)idx);
|
2006-12-09 20:06:53 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2007-06-12 04:36:58 +02:00
|
|
|
flag = false;
|
2006-12-09 20:06:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
val = res;
|
2007-06-12 04:36:58 +02:00
|
|
|
return flag;
|
2006-12-09 20:06:53 +01:00
|
|
|
}
|
|
|
|
|
|
2005-11-25 18:55:26 +01:00
|
|
|
template <class T> T coerce_to_width(const T&that, unsigned width)
|
|
|
|
|
{
|
|
|
|
|
if (that.size() == width)
|
|
|
|
|
return that;
|
|
|
|
|
|
|
|
|
|
assert(that.size() > width);
|
|
|
|
|
T res (width);
|
|
|
|
|
for (unsigned idx = 0 ; idx < width ; idx += 1)
|
|
|
|
|
res.set_bit(idx, that.value(idx));
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2005-06-13 02:54:04 +02:00
|
|
|
|
2005-02-04 06:13:02 +01:00
|
|
|
vvp_vector2_t::vvp_vector2_t()
|
|
|
|
|
{
|
|
|
|
|
vec_ = 0;
|
|
|
|
|
wid_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector2_t::vvp_vector2_t(unsigned long v, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
wid_ = wid;
|
|
|
|
|
const unsigned bits_per_word = 8 * sizeof(vec_[0]);
|
|
|
|
|
const unsigned words = (wid_ + bits_per_word-1) / bits_per_word;
|
|
|
|
|
|
|
|
|
|
vec_ = new unsigned long[words];
|
2006-01-03 07:19:31 +01:00
|
|
|
vec_[0] = v;
|
|
|
|
|
for (unsigned idx = 1 ; idx < words ; idx += 1)
|
2005-02-04 06:13:02 +01:00
|
|
|
vec_[idx] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-26 18:16:05 +01:00
|
|
|
vvp_vector2_t::vvp_vector2_t(vvp_vector2_t::fill_t fill, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
wid_ = wid;
|
|
|
|
|
const unsigned bits_per_word = 8 * sizeof(vec_[0]);
|
|
|
|
|
const unsigned words = (wid_ + bits_per_word-1) / bits_per_word;
|
|
|
|
|
|
|
|
|
|
vec_ = new unsigned long[words];
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
|
|
|
|
vec_[idx] = fill? -1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 06:13:02 +01:00
|
|
|
vvp_vector2_t::vvp_vector2_t(const vvp_vector4_t&that)
|
|
|
|
|
{
|
|
|
|
|
wid_ = that.size();
|
2005-11-10 14:27:16 +01:00
|
|
|
const unsigned words = (that.size() + BITS_PER_WORD-1) / BITS_PER_WORD;
|
2005-02-04 06:13:02 +01:00
|
|
|
|
|
|
|
|
if (words == 0) {
|
|
|
|
|
vec_ = 0;
|
|
|
|
|
wid_ = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vec_ = new unsigned long[words];
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
|
|
|
|
vec_[idx] = 0;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < that.size() ; idx += 1) {
|
2005-11-10 14:27:16 +01:00
|
|
|
unsigned addr = idx / BITS_PER_WORD;
|
|
|
|
|
unsigned shift = idx % BITS_PER_WORD;
|
2005-02-04 06:13:02 +01:00
|
|
|
|
|
|
|
|
switch (that.value(idx)) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
2005-06-27 23:13:14 +02:00
|
|
|
vec_[addr] |= 1UL << shift;
|
2005-02-04 06:13:02 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
delete[]vec_;
|
|
|
|
|
vec_ = 0;
|
|
|
|
|
wid_ = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
void vvp_vector2_t::copy_from_that_(const vvp_vector2_t&that)
|
2005-02-04 06:13:02 +01:00
|
|
|
{
|
2005-11-10 14:27:16 +01:00
|
|
|
wid_ = that.wid_;
|
|
|
|
|
const unsigned words = (wid_ + BITS_PER_WORD-1) / BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
if (words == 0) {
|
|
|
|
|
vec_ = 0;
|
|
|
|
|
wid_ = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vec_ = new unsigned long[words];
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
|
|
|
|
vec_[idx] = that.vec_[idx];
|
2005-02-04 06:13:02 +01:00
|
|
|
}
|
|
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
vvp_vector2_t::vvp_vector2_t(const vvp_vector2_t&that)
|
2005-02-04 06:13:02 +01:00
|
|
|
{
|
2005-11-10 14:27:16 +01:00
|
|
|
copy_from_that_(that);
|
2005-02-04 06:13:02 +01:00
|
|
|
}
|
|
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
vvp_vector2_t::vvp_vector2_t(const vvp_vector2_t&that, unsigned newsize)
|
2005-02-04 06:13:02 +01:00
|
|
|
{
|
2005-11-10 14:27:16 +01:00
|
|
|
wid_ = newsize;
|
|
|
|
|
if (newsize == 0) {
|
|
|
|
|
vec_ = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2005-02-04 06:13:02 +01:00
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
const unsigned words = (wid_ + BITS_PER_WORD-1) / BITS_PER_WORD;
|
|
|
|
|
const unsigned twords = (that.wid_ + BITS_PER_WORD-1) / BITS_PER_WORD;
|
2005-02-04 06:13:02 +01:00
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
vec_ = new unsigned long[words];
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1) {
|
|
|
|
|
if (idx < twords)
|
|
|
|
|
vec_[idx] = that.vec_[idx];
|
|
|
|
|
else
|
|
|
|
|
vec_[idx] = 0;
|
|
|
|
|
}
|
2005-02-04 06:13:02 +01:00
|
|
|
}
|
|
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
vvp_vector2_t& vvp_vector2_t::operator= (const vvp_vector2_t&that)
|
2005-02-04 06:13:02 +01:00
|
|
|
{
|
2005-11-10 14:27:16 +01:00
|
|
|
if (this == &that)
|
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
|
|
if (vec_) {
|
|
|
|
|
delete[]vec_;
|
|
|
|
|
vec_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
copy_from_that_(that);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector2_t& vvp_vector2_t::operator <<= (unsigned int shift)
|
|
|
|
|
{
|
|
|
|
|
if (wid_ == 0)
|
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
|
|
const unsigned words = (wid_ + BITS_PER_WORD-1) / BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
// Number of words to shift
|
|
|
|
|
const unsigned wshift = shift / BITS_PER_WORD;
|
|
|
|
|
// bits to shift within each word.
|
|
|
|
|
const unsigned long oshift = shift % BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
// If shifting the entire value away, then return zeros.
|
|
|
|
|
if (wshift >= words) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
|
|
|
|
vec_[idx] = 0;
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Do the word shift first.
|
|
|
|
|
if (wshift > 0) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < words-wshift ; idx += 1) {
|
|
|
|
|
unsigned sel = words - idx - 1;
|
|
|
|
|
vec_[sel] = vec_[sel-wshift];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < wshift ; idx += 1)
|
|
|
|
|
vec_[idx] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Do the fine shift.
|
|
|
|
|
if (oshift != 0) {
|
|
|
|
|
unsigned long pad = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1) {
|
|
|
|
|
unsigned long next_pad = vec_[idx] >> (BITS_PER_WORD-oshift);
|
|
|
|
|
vec_[idx] = (vec_[idx] << oshift) | pad;
|
|
|
|
|
pad = next_pad;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cleanup the tail bits.
|
|
|
|
|
unsigned long mask = -1UL >> (BITS_PER_WORD - wid_%BITS_PER_WORD);
|
|
|
|
|
vec_[words-1] &= mask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector2_t& vvp_vector2_t::operator >>= (unsigned shift)
|
|
|
|
|
{
|
|
|
|
|
if (wid_ == 0)
|
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
|
|
const unsigned words = (wid_ + BITS_PER_WORD-1) / BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
// Number of words to shift
|
|
|
|
|
const unsigned wshift = shift / BITS_PER_WORD;
|
|
|
|
|
// bits to shift within each word.
|
|
|
|
|
const unsigned long oshift = shift % BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
// If shifting the entire value away, then return zeros.
|
|
|
|
|
if (wshift >= words) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1)
|
|
|
|
|
vec_[idx] = 0;
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wshift > 0) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < words-wshift ; idx += 1)
|
|
|
|
|
vec_[idx] = vec_[idx+wshift];
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = words-wshift ; idx < words ; idx += 1)
|
|
|
|
|
vec_[idx] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (oshift > 0) {
|
|
|
|
|
unsigned long pad = 0;
|
|
|
|
|
for (unsigned idx = words ; idx > 0 ; idx -= 1) {
|
|
|
|
|
unsigned long new_pad = vec_[idx-1] <<(BITS_PER_WORD-oshift);
|
|
|
|
|
vec_[idx-1] = pad | (vec_[idx-1] >> oshift);
|
|
|
|
|
pad = new_pad;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cleanup the tail bits.
|
|
|
|
|
unsigned long mask = -1UL >> (BITS_PER_WORD - wid_%BITS_PER_WORD);
|
|
|
|
|
vec_[words-1] &= mask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *this;
|
2005-02-04 06:13:02 +01:00
|
|
|
}
|
|
|
|
|
|
2005-06-27 23:13:14 +02:00
|
|
|
static unsigned long add_carry(unsigned long a, unsigned long b,
|
|
|
|
|
unsigned long&carry)
|
|
|
|
|
{
|
|
|
|
|
unsigned long out = carry;
|
|
|
|
|
carry = 0;
|
|
|
|
|
|
|
|
|
|
if ((ULONG_MAX - out) < a)
|
|
|
|
|
carry += 1;
|
|
|
|
|
out += a;
|
|
|
|
|
|
|
|
|
|
if ((ULONG_MAX - out) < b)
|
|
|
|
|
carry += 1;
|
|
|
|
|
out += b;
|
|
|
|
|
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
vvp_vector2_t& vvp_vector2_t::operator += (const vvp_vector2_t&that)
|
|
|
|
|
{
|
|
|
|
|
assert(wid_ == that.wid_);
|
|
|
|
|
if (wid_ == 0)
|
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
|
|
const unsigned words = (wid_ + BITS_PER_WORD-1) / BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
unsigned long carry = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1) {
|
|
|
|
|
vec_[idx] = add_carry(vec_[idx], that.vec_[idx], carry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Cleanup the tail bits.
|
|
|
|
|
unsigned long mask = -1UL >> (BITS_PER_WORD - wid_%BITS_PER_WORD);
|
|
|
|
|
vec_[words-1] &= mask;
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector2_t& vvp_vector2_t::operator -= (const vvp_vector2_t&that)
|
|
|
|
|
{
|
|
|
|
|
assert(wid_ == that.wid_);
|
|
|
|
|
if (wid_ == 0)
|
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
|
|
const unsigned words = (wid_ + BITS_PER_WORD-1) / BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
unsigned long carry = 1;
|
|
|
|
|
for (unsigned idx = 0 ; idx < words ; idx += 1) {
|
|
|
|
|
vec_[idx] = add_carry(vec_[idx], ~that.vec_[idx], carry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector2_t::~vvp_vector2_t()
|
|
|
|
|
{
|
|
|
|
|
if (vec_) delete[]vec_;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-05 04:43:50 +01:00
|
|
|
void vvp_vector2_t::trim()
|
|
|
|
|
{
|
|
|
|
|
while (value(wid_-1) == 0 && wid_ > 1) wid_ -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
int vvp_vector2_t::value(unsigned idx) const
|
|
|
|
|
{
|
|
|
|
|
if (idx >= wid_)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
const unsigned bits_per_word = 8 * sizeof(vec_[0]);
|
|
|
|
|
unsigned addr = idx/bits_per_word;
|
|
|
|
|
unsigned mask = idx%bits_per_word;
|
|
|
|
|
|
|
|
|
|
if (vec_[addr] & (1UL<<mask))
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-26 18:16:05 +01:00
|
|
|
void vvp_vector2_t::set_bit(unsigned idx, int bit)
|
|
|
|
|
{
|
|
|
|
|
assert(idx < wid_);
|
|
|
|
|
|
|
|
|
|
const unsigned bits_per_word = 8 * sizeof(vec_[0]);
|
|
|
|
|
unsigned addr = idx/bits_per_word;
|
|
|
|
|
unsigned long mask = idx%bits_per_word;
|
|
|
|
|
|
|
|
|
|
if (bit)
|
|
|
|
|
vec_[addr] |= 1UL << mask;
|
|
|
|
|
else
|
|
|
|
|
vec_[addr] &= ~(1UL << mask);
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
bool vvp_vector2_t::is_NaN() const
|
|
|
|
|
{
|
|
|
|
|
return wid_ == 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-10 03:56:42 +02:00
|
|
|
bool vvp_vector2_t::is_zero() const
|
|
|
|
|
{
|
|
|
|
|
const unsigned words = (wid_ + BITS_PER_WORD-1) / BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0; idx < words; idx += 1) {
|
|
|
|
|
if (vec_[idx] == 0) continue;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-06 04:09:30 +01:00
|
|
|
/*
|
|
|
|
|
* Basic idea from "Introduction to Programming using SML" by
|
|
|
|
|
* Michael R. Hansen and Hans Rischel page 261 and "Seminumerical
|
|
|
|
|
* Algorithms, Third Edition" by Donald E. Knuth section 4.6.3.
|
|
|
|
|
*/
|
|
|
|
|
vvp_vector2_t pow(const vvp_vector2_t&x, vvp_vector2_t&y)
|
|
|
|
|
{
|
|
|
|
|
/* If we have a zero exponent just return a 1 bit wide 1. */
|
|
|
|
|
if (y == vvp_vector2_t(0L, 1)) {
|
|
|
|
|
return vvp_vector2_t(1L, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Is the value odd? */
|
|
|
|
|
if (y.value(0) == 1) {
|
|
|
|
|
y.set_bit(0, 0); // A quick subtract by 1.
|
|
|
|
|
vvp_vector2_t res = x * pow(x, y);
|
|
|
|
|
res.trim(); // To keep the size under control trim extra zeros.
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
y >>= 1; // A fast divide by two. We know the LSB is zero.
|
|
|
|
|
vvp_vector2_t z = pow(x, y);
|
|
|
|
|
vvp_vector2_t res = z * z;
|
|
|
|
|
res.trim(); // To keep the size under control trim extra zeros.
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-27 23:13:14 +02:00
|
|
|
static void multiply_long(unsigned long a, unsigned long b,
|
|
|
|
|
unsigned long&low, unsigned long&high)
|
|
|
|
|
{
|
|
|
|
|
assert(sizeof(unsigned long) %2 == 0);
|
|
|
|
|
|
|
|
|
|
const unsigned long word_mask = (1UL << 4UL*sizeof(a)) - 1UL;
|
|
|
|
|
unsigned long tmpa;
|
|
|
|
|
unsigned long tmpb;
|
|
|
|
|
unsigned long res[4];
|
|
|
|
|
|
|
|
|
|
tmpa = a & word_mask;
|
|
|
|
|
tmpb = b & word_mask;
|
|
|
|
|
res[0] = tmpa * tmpb;
|
|
|
|
|
res[1] = res[0] >> 4UL*sizeof(unsigned long);
|
|
|
|
|
res[0] &= word_mask;
|
|
|
|
|
|
|
|
|
|
tmpa = (a >> 4UL*sizeof(unsigned long)) & word_mask;
|
|
|
|
|
tmpb = b & word_mask;
|
|
|
|
|
res[1] += tmpa * tmpb;
|
|
|
|
|
res[2] = res[1] >> 4UL*sizeof(unsigned long);
|
|
|
|
|
res[1] &= word_mask;
|
|
|
|
|
|
|
|
|
|
tmpa = a & word_mask;
|
|
|
|
|
tmpb = (b >> 4UL*sizeof(unsigned long)) & word_mask;
|
|
|
|
|
res[1] += tmpa * tmpb;
|
|
|
|
|
res[2] += res[1] >> 4UL*sizeof(unsigned long);
|
|
|
|
|
res[3] = res[2] >> 4UL*sizeof(unsigned long);
|
|
|
|
|
res[1] &= word_mask;
|
|
|
|
|
res[2] &= word_mask;
|
|
|
|
|
|
|
|
|
|
tmpa = (a >> 4UL*sizeof(unsigned long)) & word_mask;
|
|
|
|
|
tmpb = (b >> 4UL*sizeof(unsigned long)) & word_mask;
|
|
|
|
|
res[2] += tmpa * tmpb;
|
|
|
|
|
res[3] += res[2] >> 4UL*sizeof(unsigned long);
|
|
|
|
|
res[2] &= word_mask;
|
|
|
|
|
|
|
|
|
|
high = (res[3] << 4UL*sizeof(unsigned long)) | res[2];
|
|
|
|
|
low = (res[1] << 4UL*sizeof(unsigned long)) | res[0];
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 06:13:02 +01:00
|
|
|
/*
|
|
|
|
|
* Multiplication of two vector2 vectors returns a product as wide as
|
|
|
|
|
* the sum of the widths of the input vectors.
|
|
|
|
|
*/
|
|
|
|
|
vvp_vector2_t operator * (const vvp_vector2_t&a, const vvp_vector2_t&b)
|
|
|
|
|
{
|
|
|
|
|
const unsigned bits_per_word = 8 * sizeof(a.vec_[0]);
|
|
|
|
|
vvp_vector2_t r (0, a.size() + b.size());
|
|
|
|
|
|
|
|
|
|
unsigned awords = (a.wid_ + bits_per_word - 1) / bits_per_word;
|
|
|
|
|
unsigned bwords = (b.wid_ + bits_per_word - 1) / bits_per_word;
|
|
|
|
|
unsigned rwords = (r.wid_ + bits_per_word - 1) / bits_per_word;
|
|
|
|
|
|
|
|
|
|
for (unsigned bdx = 0 ; bdx < bwords ; bdx += 1) {
|
2005-06-27 23:13:14 +02:00
|
|
|
unsigned long tmpb = b.vec_[bdx];
|
2005-02-04 06:13:02 +01:00
|
|
|
if (tmpb == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for (unsigned adx = 0 ; adx < awords ; adx += 1) {
|
2005-06-27 23:13:14 +02:00
|
|
|
unsigned long tmpa = a.vec_[adx];
|
|
|
|
|
if (tmpa == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
unsigned long low, hig;
|
|
|
|
|
multiply_long(tmpa, tmpb, low, hig);
|
2005-02-04 06:13:02 +01:00
|
|
|
|
2005-06-27 23:13:14 +02:00
|
|
|
unsigned long carry = 0;
|
2005-02-04 06:13:02 +01:00
|
|
|
for (unsigned sdx = 0
|
2005-06-27 23:13:14 +02:00
|
|
|
; (adx+bdx+sdx) < rwords
|
2005-02-04 06:13:02 +01:00
|
|
|
; sdx += 1) {
|
2005-06-27 23:13:14 +02:00
|
|
|
|
|
|
|
|
r.vec_[adx+bdx+sdx] = add_carry(r.vec_[adx+bdx+sdx],
|
|
|
|
|
low, carry);
|
|
|
|
|
low = hig;
|
|
|
|
|
hig = 0;
|
2005-02-04 06:13:02 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
static void div_mod (vvp_vector2_t dividend, vvp_vector2_t divisor,
|
|
|
|
|
vvp_vector2_t"ient, vvp_vector2_t&remainder)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
quotient = vvp_vector2_t(0, dividend.size());
|
|
|
|
|
|
2007-11-01 17:52:20 +01:00
|
|
|
if (divisor == quotient) {
|
|
|
|
|
cerr << "ERROR: division by zero, exiting." << endl;
|
|
|
|
|
exit(255);
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
if (dividend < divisor) {
|
|
|
|
|
remainder = dividend;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector2_t mask (1, dividend.size());
|
|
|
|
|
|
2007-04-15 04:07:24 +02:00
|
|
|
// Make the dividend 1 bit larger to prevent overflow of
|
|
|
|
|
// divtmp in startup.
|
|
|
|
|
dividend = vvp_vector2_t(dividend, dividend.size()+1);
|
2005-11-10 14:27:16 +01:00
|
|
|
vvp_vector2_t divtmp (divisor, dividend.size());
|
|
|
|
|
|
|
|
|
|
while (divtmp < dividend) {
|
|
|
|
|
divtmp <<= 1;
|
|
|
|
|
mask <<= 1;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-01 17:52:20 +01:00
|
|
|
while (dividend >= divisor) {
|
2005-11-10 14:27:16 +01:00
|
|
|
if (divtmp <= dividend) {
|
|
|
|
|
dividend -= divtmp;
|
|
|
|
|
quotient += mask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
divtmp >>= 1;
|
|
|
|
|
mask >>= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
remainder = dividend;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector2_t operator / (const vvp_vector2_t÷nd,
|
|
|
|
|
const vvp_vector2_t&divisor)
|
|
|
|
|
{
|
|
|
|
|
vvp_vector2_t quot, rem;
|
|
|
|
|
div_mod(dividend, divisor, quot, rem);
|
|
|
|
|
return quot;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector2_t operator % (const vvp_vector2_t÷nd,
|
|
|
|
|
const vvp_vector2_t&divisor)
|
|
|
|
|
{
|
|
|
|
|
vvp_vector2_t quot, rem;
|
|
|
|
|
div_mod(dividend, divisor, quot, rem);
|
|
|
|
|
return rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator > (const vvp_vector2_t&a, const vvp_vector2_t&b)
|
|
|
|
|
{
|
|
|
|
|
const unsigned awords = (a.wid_ + vvp_vector2_t::BITS_PER_WORD-1) / vvp_vector2_t::BITS_PER_WORD;
|
|
|
|
|
const unsigned bwords = (b.wid_ + vvp_vector2_t::BITS_PER_WORD-1) / vvp_vector2_t::BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
const unsigned words = awords > bwords? awords : bwords;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = words ; idx > 0 ; idx -= 1) {
|
|
|
|
|
unsigned long aw = (idx <= awords)? a.vec_[idx-1] : 0;
|
|
|
|
|
unsigned long bw = (idx <= bwords)? b.vec_[idx-1] : 0;
|
|
|
|
|
|
|
|
|
|
if (aw > bw)
|
|
|
|
|
return true;
|
|
|
|
|
if (aw < bw)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the above loop finishes, then the vectors are equal.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-01 17:52:20 +01:00
|
|
|
bool operator >= (const vvp_vector2_t&a, const vvp_vector2_t&b)
|
|
|
|
|
{
|
|
|
|
|
const unsigned awords = (a.wid_ + vvp_vector2_t::BITS_PER_WORD-1) / vvp_vector2_t::BITS_PER_WORD;
|
|
|
|
|
const unsigned bwords = (b.wid_ + vvp_vector2_t::BITS_PER_WORD-1) / vvp_vector2_t::BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
const unsigned words = awords > bwords? awords : bwords;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = words ; idx > 0 ; idx -= 1) {
|
|
|
|
|
unsigned long aw = (idx <= awords)? a.vec_[idx-1] : 0;
|
|
|
|
|
unsigned long bw = (idx <= bwords)? b.vec_[idx-1] : 0;
|
|
|
|
|
|
|
|
|
|
if (aw > bw)
|
|
|
|
|
return true;
|
|
|
|
|
if (aw < bw)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the above loop finishes, then the vectors are equal.
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
bool operator < (const vvp_vector2_t&a, const vvp_vector2_t&b)
|
|
|
|
|
{
|
|
|
|
|
const unsigned awords = (a.wid_ + vvp_vector2_t::BITS_PER_WORD-1) / vvp_vector2_t::BITS_PER_WORD;
|
|
|
|
|
const unsigned bwords = (b.wid_ + vvp_vector2_t::BITS_PER_WORD-1) / vvp_vector2_t::BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
unsigned words = awords;
|
|
|
|
|
if (bwords > words)
|
|
|
|
|
words = bwords;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = words ; idx > 0 ; idx -= 1) {
|
|
|
|
|
unsigned long aw = (idx <= awords)? a.vec_[idx-1] : 0;
|
|
|
|
|
unsigned long bw = (idx <= bwords)? b.vec_[idx-1] : 0;
|
|
|
|
|
|
|
|
|
|
if (aw < bw)
|
|
|
|
|
return true;
|
|
|
|
|
if (aw > bw)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the above loop finishes, then the vectors are equal.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator <= (const vvp_vector2_t&a, const vvp_vector2_t&b)
|
|
|
|
|
{
|
|
|
|
|
// XXXX For now, only support equal width vectors.
|
|
|
|
|
assert(a.wid_ == b.wid_);
|
|
|
|
|
|
|
|
|
|
const unsigned awords = (a.wid_ + vvp_vector2_t::BITS_PER_WORD-1) / vvp_vector2_t::BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = awords ; idx > 0 ; idx -= 1) {
|
|
|
|
|
if (a.vec_[idx-1] < b.vec_[idx-1])
|
|
|
|
|
return true;
|
|
|
|
|
if (a.vec_[idx-1] > b.vec_[idx-1])
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the above loop finishes, then the vectors are equal.
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-01 17:52:20 +01:00
|
|
|
bool operator == (const vvp_vector2_t&a, const vvp_vector2_t&b)
|
|
|
|
|
{
|
|
|
|
|
const unsigned awords = (a.wid_ + vvp_vector2_t::BITS_PER_WORD-1) / vvp_vector2_t::BITS_PER_WORD;
|
|
|
|
|
const unsigned bwords = (b.wid_ + vvp_vector2_t::BITS_PER_WORD-1) / vvp_vector2_t::BITS_PER_WORD;
|
|
|
|
|
|
|
|
|
|
const unsigned words = awords > bwords? awords : bwords;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = words ; idx > 0 ; idx -= 1) {
|
|
|
|
|
unsigned long aw = (idx <= awords)? a.vec_[idx-1] : 0;
|
|
|
|
|
unsigned long bw = (idx <= bwords)? b.vec_[idx-1] : 0;
|
|
|
|
|
|
|
|
|
|
if (aw > bw)
|
|
|
|
|
return false;
|
|
|
|
|
if (aw < bw)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the above loop finishes, then the vectors are equal.
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-02-04 06:13:02 +01:00
|
|
|
vvp_vector4_t vector2_to_vector4(const vvp_vector2_t&that, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
vvp_vector4_t res (wid);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < res.size() ; idx += 1) {
|
|
|
|
|
vvp_bit4_t bit = BIT4_0;
|
|
|
|
|
|
|
|
|
|
if (that.value(idx))
|
|
|
|
|
bit = BIT4_1;
|
|
|
|
|
|
|
|
|
|
res.set_bit(idx, bit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2006-03-08 06:29:42 +01:00
|
|
|
vvp_vector4_t c4string_to_vector4(const char*str)
|
|
|
|
|
{
|
|
|
|
|
assert((str[0]=='C') && (str[1]=='4') && (str[2]=='<'));
|
|
|
|
|
|
|
|
|
|
str += 3;
|
2006-03-15 20:15:34 +01:00
|
|
|
const char*tp = str + strspn(str,"01xz");
|
2006-03-08 06:29:42 +01:00
|
|
|
assert(tp[0] == '>');
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t tmp (tp-str);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < tmp.size() ; idx += 1) {
|
|
|
|
|
vvp_bit4_t bit;
|
|
|
|
|
switch (str[idx]) {
|
|
|
|
|
case '0':
|
|
|
|
|
bit = BIT4_0;
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
bit = BIT4_1;
|
|
|
|
|
break;
|
|
|
|
|
case 'x':
|
|
|
|
|
bit = BIT4_X;
|
|
|
|
|
break;
|
|
|
|
|
case 'z':
|
|
|
|
|
bit = BIT4_Z;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2007-08-23 00:15:32 +02:00
|
|
|
fprintf(stderr, "Unsupported bit value %c(%d).\n", str[idx],
|
|
|
|
|
str[idx]);
|
2006-03-08 06:29:42 +01:00
|
|
|
assert(0);
|
|
|
|
|
bit = BIT4_0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
tmp.set_bit(tmp.size()-idx-1, bit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-10 14:27:16 +01:00
|
|
|
ostream& operator<< (ostream&out, const vvp_vector2_t&that)
|
|
|
|
|
{
|
|
|
|
|
if (that.is_NaN()) {
|
|
|
|
|
out << "NaN";
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
out << vector2_to_vector4(that, that.size());
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-31 07:00:06 +01:00
|
|
|
vvp_vector8_t::vvp_vector8_t(const vvp_vector8_t&that)
|
|
|
|
|
{
|
|
|
|
|
size_ = that.size_;
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
bits_ = new vvp_scalar_t[size_];
|
2004-12-31 07:00:06 +01:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < size_ ; idx += 1)
|
|
|
|
|
bits_[idx] = that.bits_[idx];
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_vector8_t::vvp_vector8_t(unsigned size)
|
|
|
|
|
: size_(size)
|
|
|
|
|
{
|
|
|
|
|
if (size_ == 0) {
|
|
|
|
|
bits_ = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
bits_ = new vvp_scalar_t[size_];
|
2004-12-11 03:31:25 +01:00
|
|
|
}
|
|
|
|
|
|
2004-12-31 07:00:06 +01:00
|
|
|
vvp_vector8_t::vvp_vector8_t(const vvp_vector4_t&that, unsigned str)
|
|
|
|
|
: size_(that.size())
|
|
|
|
|
{
|
|
|
|
|
if (size_ == 0) {
|
|
|
|
|
bits_ = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
bits_ = new vvp_scalar_t[size_];
|
2004-12-31 07:00:06 +01:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < size_ ; idx += 1)
|
2005-03-12 05:27:42 +01:00
|
|
|
bits_[idx] = vvp_scalar_t (that.value(idx), str);
|
2004-12-31 07:00:06 +01:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-13 08:34:20 +02:00
|
|
|
vvp_vector8_t::vvp_vector8_t(const vvp_vector4_t&that,
|
|
|
|
|
unsigned str0, unsigned str1)
|
|
|
|
|
: size_(that.size())
|
|
|
|
|
{
|
|
|
|
|
if (size_ == 0) {
|
|
|
|
|
bits_ = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bits_ = new vvp_scalar_t[size_];
|
|
|
|
|
for (unsigned idx = 0 ; idx < size_ ; idx += 1)
|
|
|
|
|
bits_[idx] = vvp_scalar_t (that.value(idx), str0, str1);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-31 07:00:06 +01:00
|
|
|
vvp_vector8_t& vvp_vector8_t::operator= (const vvp_vector8_t&that)
|
|
|
|
|
{
|
|
|
|
|
if (size_ != that.size_) {
|
|
|
|
|
if (size_ > 0)
|
|
|
|
|
delete[]bits_;
|
|
|
|
|
size_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (that.size_ == 0) {
|
|
|
|
|
assert(size_ == 0);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (size_ == 0) {
|
|
|
|
|
size_ = that.size_;
|
2005-03-12 05:27:42 +01:00
|
|
|
bits_ = new vvp_scalar_t[size_];
|
2004-12-31 07:00:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < size_ ; idx += 1)
|
|
|
|
|
bits_[idx] = that.bits_[idx];
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-15 02:47:15 +02:00
|
|
|
bool vvp_vector8_t::eeq(const vvp_vector8_t&that) const
|
|
|
|
|
{
|
|
|
|
|
if (size_ != that.size_)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (size_ == 0)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < size_ ; idx += 1) {
|
|
|
|
|
if (! bits_[idx] .eeq( that.bits_[idx] ))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-13 08:34:20 +02:00
|
|
|
ostream& operator<<(ostream&out, const vvp_vector8_t&that)
|
2005-02-12 07:13:22 +01:00
|
|
|
{
|
2005-04-13 08:34:20 +02:00
|
|
|
out << "C8<";
|
|
|
|
|
for (unsigned idx = 0 ; idx < that.size() ; idx += 1)
|
|
|
|
|
out << that.value(that.size()-idx-1);
|
2005-02-12 07:13:22 +01:00
|
|
|
|
2005-04-13 08:34:20 +02:00
|
|
|
out << ">";
|
|
|
|
|
return out;
|
2005-02-12 07:13:22 +01:00
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_net_fun_t::vvp_net_fun_t()
|
|
|
|
|
{
|
2007-12-02 17:47:06 +01:00
|
|
|
count_functors += 1;
|
2004-12-11 03:31:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_net_fun_t::~vvp_net_fun_t()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-22 02:04:48 +02:00
|
|
|
void vvp_net_fun_t::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&)
|
2004-12-11 03:31:25 +01:00
|
|
|
{
|
|
|
|
|
fprintf(stderr, "internal error: %s: recv_vec4 not implemented\n",
|
|
|
|
|
typeid(*this).name());
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2007-07-23 06:52:28 +02:00
|
|
|
void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t, const vvp_vector4_t&bits,
|
|
|
|
|
unsigned base, unsigned wid, unsigned vwid)
|
2005-01-09 21:11:15 +01:00
|
|
|
{
|
2007-07-23 06:52:28 +02:00
|
|
|
cerr << "internal error: " << typeid(*this).name() << ": "
|
|
|
|
|
<< "recv_vect_pv(" << bits << ", " << base
|
|
|
|
|
<< ", " << wid << ", " << vwid << ") not implemented" << endl;
|
2005-01-09 21:11:15 +01:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-09 07:30:38 +02:00
|
|
|
void vvp_net_fun_t::recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit)
|
2004-12-11 03:31:25 +01:00
|
|
|
{
|
2005-04-09 07:30:38 +02:00
|
|
|
recv_vec4(port, reduce4(bit));
|
2004-12-11 03:31:25 +01:00
|
|
|
}
|
|
|
|
|
|
2006-07-08 23:48:00 +02:00
|
|
|
void vvp_net_fun_t::recv_real(vvp_net_ptr_t, double bit)
|
2004-12-11 03:31:25 +01:00
|
|
|
{
|
2006-07-08 23:48:00 +02:00
|
|
|
fprintf(stderr, "internal error: %s: recv_real(%f) not implemented\n",
|
|
|
|
|
typeid(*this).name(), bit);
|
2004-12-11 03:31:25 +01:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vvp_net_fun_t::recv_long(vvp_net_ptr_t, long)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "internal error: %s: recv_long not implemented\n",
|
|
|
|
|
typeid(*this).name());
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-12 00:04:00 +01:00
|
|
|
void vvp_net_fun_t::recv_long_pv(vvp_net_ptr_t, long, unsigned, unsigned)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "internal error: %s: recv_long_pv not implemented\n",
|
|
|
|
|
typeid(*this).name());
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-13 08:34:20 +02:00
|
|
|
/* **** vvp_fun_drive methods **** */
|
|
|
|
|
|
|
|
|
|
vvp_fun_drive::vvp_fun_drive(vvp_bit4_t init, unsigned str0, unsigned str1)
|
|
|
|
|
{
|
|
|
|
|
assert(str0 < 8);
|
|
|
|
|
assert(str1 < 8);
|
|
|
|
|
|
|
|
|
|
drive0_ = str0;
|
|
|
|
|
drive1_ = str1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_fun_drive::~vvp_fun_drive()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-22 02:04:48 +02:00
|
|
|
void vvp_fun_drive::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
2005-04-13 08:34:20 +02:00
|
|
|
{
|
|
|
|
|
assert(port.port() == 0);
|
|
|
|
|
vvp_send_vec8(port.ptr()->out, vvp_vector8_t(bit, drive0_, drive1_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/* **** vvp_fun_signal methods **** */
|
|
|
|
|
|
2005-07-06 06:29:25 +02:00
|
|
|
vvp_fun_signal_base::vvp_fun_signal_base()
|
2004-12-11 03:31:25 +01:00
|
|
|
{
|
2005-07-06 06:29:25 +02:00
|
|
|
needs_init_ = true;
|
2004-12-11 03:31:25 +01:00
|
|
|
continuous_assign_active_ = false;
|
2005-07-06 06:29:25 +02:00
|
|
|
force_link = 0;
|
2007-02-05 02:08:10 +01:00
|
|
|
cassign_link = 0;
|
2007-12-02 17:47:06 +01:00
|
|
|
count_functors_sig += 1;
|
2005-07-06 06:29:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vvp_fun_signal_base::deassign()
|
|
|
|
|
{
|
|
|
|
|
continuous_assign_active_ = false;
|
2008-04-10 03:56:42 +02:00
|
|
|
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();
|
|
|
|
|
}
|
2005-07-06 06:29:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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:
|
2007-09-21 02:20:48 +02:00
|
|
|
fprintf(stderr, "Unsupported command %ld.\n", bit);
|
2005-07-06 06:29:25 +02:00
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2007-08-23 00:15:32 +02:00
|
|
|
default: // Other ports are errors.
|
|
|
|
|
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
|
2005-07-06 06:29:25 +02:00
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-12 00:04:00 +01:00
|
|
|
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
|
2008-04-10 03:56:42 +02:00
|
|
|
deassign_pv(base, wid);
|
2008-03-12 00:04:00 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-29 01:56:01 +02:00
|
|
|
vvp_fun_signal::vvp_fun_signal(unsigned wid, vvp_bit4_t init)
|
|
|
|
|
: bits4_(wid, init)
|
2005-07-06 06:29:25 +02:00
|
|
|
{
|
2004-12-11 03:31:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Nets simply reflect their input to their output.
|
2005-04-25 06:42:17 +02:00
|
|
|
*
|
|
|
|
|
* 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
|
2008-01-29 21:19:59 +01:00
|
|
|
* propagate if the value changes. Eliminating duplicate propagations
|
2005-04-25 06:42:17 +02:00
|
|
|
* 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.
|
2005-04-28 06:59:53 +02:00
|
|
|
*/
|
2005-06-22 02:04:48 +02:00
|
|
|
void vvp_fun_signal::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
2004-12-11 03:31:25 +01:00
|
|
|
{
|
|
|
|
|
switch (ptr.port()) {
|
|
|
|
|
case 0: // Normal input (feed from net, or set from process)
|
2008-04-10 03:56:42 +02:00
|
|
|
/* 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) {
|
2005-04-25 06:42:17 +02:00
|
|
|
if (needs_init_ || !bits4_.eeq(bit)) {
|
|
|
|
|
bits4_ = bit;
|
|
|
|
|
needs_init_ = false;
|
2005-11-26 18:16:05 +01:00
|
|
|
calculate_output_(ptr);
|
2005-04-25 06:42:17 +02:00
|
|
|
}
|
2008-04-10 03:56:42 +02:00
|
|
|
} 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);
|
|
|
|
|
}
|
2004-12-11 03:31:25 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: // Continuous assign value
|
2005-11-25 18:55:26 +01:00
|
|
|
bits4_ = bit;
|
2008-04-10 03:56:42 +02:00
|
|
|
assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size());
|
2005-11-26 18:16:05 +01:00
|
|
|
calculate_output_(ptr);
|
2004-12-11 03:31:25 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2: // Force value
|
2005-06-13 02:54:04 +02:00
|
|
|
|
|
|
|
|
// Force from a node may not have been sized completely
|
|
|
|
|
// by the source, so coerce the size here.
|
|
|
|
|
if (bit.size() != size())
|
2005-06-22 02:04:48 +02:00
|
|
|
force_ = coerce_to_width(bit, size());
|
|
|
|
|
else
|
|
|
|
|
force_ = bit;
|
2005-06-13 02:54:04 +02:00
|
|
|
|
2005-11-26 18:16:05 +01:00
|
|
|
force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size());
|
|
|
|
|
calculate_output_(ptr);
|
2004-12-11 03:31:25 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2007-08-23 00:15:32 +02:00
|
|
|
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
|
2004-12-11 03:31:25 +01:00
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-22 20:30:12 +02:00
|
|
|
void vvp_fun_signal::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
|
2005-02-14 02:50:23 +01:00
|
|
|
unsigned base, unsigned wid, unsigned vwid)
|
|
|
|
|
{
|
|
|
|
|
assert(bit.size() == wid);
|
|
|
|
|
assert(bits4_.size() == vwid);
|
|
|
|
|
|
|
|
|
|
switch (ptr.port()) {
|
|
|
|
|
case 0: // Normal input
|
2008-04-10 03:56:42 +02:00
|
|
|
if (assign_mask_.size() == 0) {
|
2005-02-14 02:50:23 +01:00
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
2008-04-10 03:56:42 +02:00
|
|
|
if (base+idx >= bits4_.size()) break;
|
2005-02-14 02:50:23 +01:00
|
|
|
bits4_.set_bit(base+idx, bit.value(idx));
|
|
|
|
|
}
|
2005-04-25 06:42:17 +02:00
|
|
|
needs_init_ = false;
|
2005-11-26 18:16:05 +01:00
|
|
|
calculate_output_(ptr);
|
2008-04-10 03:56:42 +02:00
|
|
|
} 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);
|
2005-02-14 02:50:23 +01:00
|
|
|
}
|
2008-04-10 03:56:42 +02:00
|
|
|
calculate_output_(ptr);
|
2005-02-14 02:50:23 +01:00
|
|
|
break;
|
|
|
|
|
|
2005-11-26 18:16:05 +01:00
|
|
|
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;
|
|
|
|
|
|
2005-02-14 02:50:23 +01:00
|
|
|
default:
|
2007-08-23 00:15:32 +02:00
|
|
|
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
|
2005-02-14 02:50:23 +01:00
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-26 18:16:05 +01:00
|
|
|
void vvp_fun_signal::calculate_output_(vvp_net_ptr_t ptr)
|
|
|
|
|
{
|
|
|
|
|
if (force_mask_.size()) {
|
|
|
|
|
assert(bits4_.size() == force_mask_.size());
|
|
|
|
|
assert(bits4_.size() == force_.size());
|
|
|
|
|
vvp_vector4_t bits (bits4_);
|
|
|
|
|
for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) {
|
|
|
|
|
if (force_mask_.value(idx))
|
|
|
|
|
bits.set_bit(idx, force_.value(idx));
|
|
|
|
|
}
|
|
|
|
|
vvp_send_vec4(ptr.ptr()->out, bits);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
vvp_send_vec4(ptr.ptr()->out, bits4_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
run_vpi_callbacks();
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-31 07:00:06 +01:00
|
|
|
void vvp_fun_signal::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
|
|
|
|
|
{
|
2005-11-25 18:55:26 +01:00
|
|
|
recv_vec4(ptr, reduce4(bit));
|
2004-12-31 07:00:06 +01:00
|
|
|
}
|
|
|
|
|
|
2005-11-25 18:55:26 +01:00
|
|
|
|
2004-12-15 18:16:08 +01:00
|
|
|
void vvp_fun_signal::release(vvp_net_ptr_t ptr, bool net)
|
|
|
|
|
{
|
2005-11-26 18:16:05 +01:00
|
|
|
force_mask_ = vvp_vector2_t();
|
2004-12-15 18:16:08 +01:00
|
|
|
if (net) {
|
2005-01-01 03:12:34 +01:00
|
|
|
vvp_send_vec4(ptr.ptr()->out, bits4_);
|
2004-12-15 18:16:08 +01:00
|
|
|
run_vpi_callbacks();
|
|
|
|
|
} else {
|
2005-01-01 03:12:34 +01:00
|
|
|
bits4_ = force_;
|
2004-12-15 18:16:08 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-12 00:04:00 +01:00
|
|
|
void vvp_fun_signal::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));
|
|
|
|
|
}
|
2008-04-10 03:56:42 +02:00
|
|
|
if (force_mask_.is_zero()) force_mask_ = vvp_vector2_t();
|
2008-03-12 00:04:00 +01:00
|
|
|
|
|
|
|
|
if (net) calculate_output_(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-22 01:58:22 +01:00
|
|
|
unsigned vvp_fun_signal::size() const
|
|
|
|
|
{
|
2005-11-26 18:16:05 +01:00
|
|
|
if (force_mask_.size())
|
2005-01-22 01:58:22 +01:00
|
|
|
return force_.size();
|
|
|
|
|
else
|
|
|
|
|
return bits4_.size();
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_bit4_t vvp_fun_signal::value(unsigned idx) const
|
|
|
|
|
{
|
2005-11-26 18:16:05 +01:00
|
|
|
if (force_mask_.size() && force_mask_.value(idx))
|
2004-12-15 18:16:08 +01:00
|
|
|
return force_.value(idx);
|
|
|
|
|
else
|
2005-01-01 03:12:34 +01:00
|
|
|
return bits4_.value(idx);
|
2004-12-11 03:31:25 +01:00
|
|
|
}
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
vvp_scalar_t vvp_fun_signal::scalar_value(unsigned idx) const
|
|
|
|
|
{
|
2005-11-26 18:16:05 +01:00
|
|
|
if (force_mask_.size() && force_mask_.value(idx))
|
2005-03-12 05:27:42 +01:00
|
|
|
return vvp_scalar_t(force_.value(idx), 6, 6);
|
|
|
|
|
else
|
|
|
|
|
return vvp_scalar_t(bits4_.value(idx), 6, 6);
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-18 03:56:03 +01:00
|
|
|
vvp_vector4_t vvp_fun_signal::vec4_value() const
|
|
|
|
|
{
|
2005-11-26 18:16:05 +01:00
|
|
|
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 {
|
2005-03-18 03:56:03 +01:00
|
|
|
return bits4_;
|
2005-11-26 18:16:05 +01:00
|
|
|
}
|
2005-03-18 03:56:03 +01:00
|
|
|
}
|
|
|
|
|
|
2005-11-25 18:55:26 +01:00
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
recv_vec8(ptr, bit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vvp_fun_signal8::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
|
|
|
|
|
{
|
|
|
|
|
switch (ptr.port()) {
|
|
|
|
|
case 0: // Normal input (feed from net, or set from process)
|
2008-04-10 03:56:42 +02:00
|
|
|
if (needs_init_ || !bits8_.eeq(bit)) {
|
|
|
|
|
bits8_ = bit;
|
|
|
|
|
needs_init_ = false;
|
|
|
|
|
calculate_output_(ptr);
|
2005-11-25 18:55:26 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: // Continuous assign value
|
2008-04-10 03:56:42 +02:00
|
|
|
/* This is a procedural continuous assign and it can
|
|
|
|
|
* only be used on a register and a register is never
|
|
|
|
|
* strength aware. */
|
|
|
|
|
assert(0);
|
2005-11-25 18:55:26 +01:00
|
|
|
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;
|
|
|
|
|
|
2005-11-26 18:16:05 +01:00
|
|
|
force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size());
|
2006-11-22 07:10:05 +01:00
|
|
|
calculate_output_(ptr);
|
2005-11-25 18:55:26 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2007-08-23 00:15:32 +02:00
|
|
|
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
|
2005-11-25 18:55:26 +01:00
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-10 03:56:42 +02:00
|
|
|
void vvp_fun_signal8::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
|
|
|
|
|
unsigned base, unsigned wid, unsigned vwid)
|
|
|
|
|
{
|
|
|
|
|
recv_vec8_pv(ptr, bit, base, wid, vwid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, 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));
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-11-22 07:10:05 +01:00
|
|
|
void vvp_fun_signal8::calculate_output_(vvp_net_ptr_t ptr)
|
|
|
|
|
{
|
|
|
|
|
if (force_mask_.size()) {
|
|
|
|
|
assert(bits8_.size() == force_mask_.size());
|
|
|
|
|
assert(bits8_.size() == force_.size());
|
|
|
|
|
vvp_vector8_t bits (bits8_);
|
|
|
|
|
for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) {
|
|
|
|
|
if (force_mask_.value(idx))
|
|
|
|
|
bits.set_bit(idx, force_.value(idx));
|
|
|
|
|
}
|
|
|
|
|
vvp_send_vec8(ptr.ptr()->out, bits);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
vvp_send_vec8(ptr.ptr()->out, bits8_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
run_vpi_callbacks();
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-25 18:55:26 +01:00
|
|
|
void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net)
|
|
|
|
|
{
|
2005-11-26 18:16:05 +01:00
|
|
|
force_mask_ = vvp_vector2_t();
|
2005-11-25 18:55:26 +01:00
|
|
|
if (net) {
|
|
|
|
|
vvp_send_vec8(ptr.ptr()->out, bits8_);
|
|
|
|
|
run_vpi_callbacks();
|
|
|
|
|
} else {
|
|
|
|
|
bits8_ = force_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-12 00:04:00 +01:00
|
|
|
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));
|
|
|
|
|
}
|
2008-04-10 03:56:42 +02:00
|
|
|
if (force_mask_.is_zero()) force_mask_ = vvp_vector2_t();
|
2008-03-12 00:04:00 +01:00
|
|
|
|
|
|
|
|
if (net) calculate_output_(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-25 18:55:26 +01:00
|
|
|
unsigned vvp_fun_signal8::size() const
|
|
|
|
|
{
|
2005-11-26 18:16:05 +01:00
|
|
|
if (force_mask_.size())
|
2005-11-25 18:55:26 +01:00
|
|
|
return force_.size();
|
|
|
|
|
else
|
|
|
|
|
return bits8_.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_bit4_t vvp_fun_signal8::value(unsigned idx) const
|
|
|
|
|
{
|
2005-11-26 18:16:05 +01:00
|
|
|
if (force_mask_.size() && force_mask_.value(idx))
|
2005-11-25 18:55:26 +01:00
|
|
|
return force_.value(idx).value();
|
|
|
|
|
else
|
|
|
|
|
return bits8_.value(idx).value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t vvp_fun_signal8::vec4_value() const
|
|
|
|
|
{
|
2008-04-10 03:56:42 +02:00
|
|
|
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
|
2005-11-25 18:55:26 +01:00
|
|
|
return reduce4(bits8_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_scalar_t vvp_fun_signal8::scalar_value(unsigned idx) const
|
|
|
|
|
{
|
2005-11-26 18:16:05 +01:00
|
|
|
if (force_mask_.size() && force_mask_.value(idx))
|
2005-11-25 18:55:26 +01:00
|
|
|
return force_.value(idx);
|
|
|
|
|
else
|
|
|
|
|
return bits8_.value(idx);
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-06 06:29:25 +02:00
|
|
|
vvp_fun_signal_real::vvp_fun_signal_real()
|
|
|
|
|
{
|
2008-02-15 23:10:53 +01:00
|
|
|
bits_ = 0.0;
|
2005-07-06 06:29:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double vvp_fun_signal_real::real_value() const
|
|
|
|
|
{
|
2005-11-26 18:16:05 +01:00
|
|
|
if (force_mask_.size())
|
2005-07-06 06:29:25 +02:00
|
|
|
return force_;
|
|
|
|
|
else
|
|
|
|
|
return bits_;
|
|
|
|
|
}
|
|
|
|
|
|
2007-07-14 03:42:35 +02:00
|
|
|
/*
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-06 06:29:25 +02:00
|
|
|
void vvp_fun_signal_real::recv_real(vvp_net_ptr_t ptr, double bit)
|
|
|
|
|
{
|
|
|
|
|
switch (ptr.port()) {
|
|
|
|
|
case 0:
|
|
|
|
|
if (!continuous_assign_active_) {
|
2007-07-14 03:42:35 +02:00
|
|
|
if (needs_init_ || !bits_equal(bits_,bit)) {
|
2005-07-06 06:29:25 +02:00
|
|
|
bits_ = bit;
|
|
|
|
|
needs_init_ = false;
|
|
|
|
|
vvp_send_real(ptr.ptr()->out, bit);
|
|
|
|
|
run_vpi_callbacks();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: // Continuous assign value
|
|
|
|
|
continuous_assign_active_ = true;
|
|
|
|
|
bits_ = bit;
|
|
|
|
|
vvp_send_real(ptr.ptr()->out, bit);
|
|
|
|
|
run_vpi_callbacks();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2: // Force value
|
2005-11-26 18:16:05 +01:00
|
|
|
force_mask_ = vvp_vector2_t(1, 1);
|
2005-07-06 06:29:25 +02:00
|
|
|
force_ = bit;
|
|
|
|
|
vvp_send_real(ptr.ptr()->out, bit);
|
|
|
|
|
run_vpi_callbacks();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2007-08-23 00:15:32 +02:00
|
|
|
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
|
2005-07-06 06:29:25 +02:00
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vvp_fun_signal_real::release(vvp_net_ptr_t ptr, bool net)
|
|
|
|
|
{
|
2005-11-26 18:16:05 +01:00
|
|
|
force_mask_ = vvp_vector2_t();
|
2005-07-06 06:29:25 +02:00
|
|
|
if (net) {
|
|
|
|
|
vvp_send_real(ptr.ptr()->out, bits_);
|
|
|
|
|
run_vpi_callbacks();
|
|
|
|
|
} else {
|
|
|
|
|
bits_ = force_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-12 00:04:00 +01:00
|
|
|
void vvp_fun_signal_real::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);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-01 08:02:45 +02:00
|
|
|
/* **** vvp_wide_fun_* methods **** */
|
|
|
|
|
|
|
|
|
|
vvp_wide_fun_core::vvp_wide_fun_core(vvp_net_t*net, unsigned nports)
|
|
|
|
|
{
|
|
|
|
|
ptr_ = net;
|
|
|
|
|
nports_ = nports;
|
2006-06-18 06:15:50 +02:00
|
|
|
port_values_ = 0;
|
|
|
|
|
port_rvalues_ = 0;
|
2005-04-01 08:02:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_wide_fun_core::~vvp_wide_fun_core()
|
|
|
|
|
{
|
2006-06-18 06:15:50 +02:00
|
|
|
if (port_values_) delete[]port_values_;
|
|
|
|
|
if (port_rvalues_) delete[]port_rvalues_;
|
2005-04-01 08:02:45 +02:00
|
|
|
}
|
|
|
|
|
|
2005-04-03 07:45:51 +02:00
|
|
|
void vvp_wide_fun_core::propagate_vec4(const vvp_vector4_t&bit,
|
|
|
|
|
vvp_time64_t delay)
|
2005-04-01 08:02:45 +02:00
|
|
|
{
|
2005-04-03 07:45:51 +02:00
|
|
|
if (delay)
|
|
|
|
|
schedule_assign_vector(ptr_->out, bit, delay);
|
2005-04-01 08:02:45 +02:00
|
|
|
else
|
|
|
|
|
vvp_send_vec4(ptr_->out, bit);
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-29 03:57:55 +01:00
|
|
|
void vvp_wide_fun_core::propagate_real(double bit,
|
|
|
|
|
vvp_time64_t delay)
|
|
|
|
|
{
|
|
|
|
|
if (delay) {
|
|
|
|
|
// schedule_assign_vector(ptr_->out, bit, delay);
|
|
|
|
|
assert(0); // Need a real-value version of assign_vector.
|
|
|
|
|
} else {
|
|
|
|
|
vvp_send_real(ptr_->out, bit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-01 08:02:45 +02:00
|
|
|
|
|
|
|
|
unsigned vvp_wide_fun_core::port_count() const
|
|
|
|
|
{
|
|
|
|
|
return nports_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t& vvp_wide_fun_core::value(unsigned idx)
|
|
|
|
|
{
|
|
|
|
|
assert(idx < nports_);
|
2006-06-18 06:15:50 +02:00
|
|
|
assert(port_values_);
|
2005-04-01 08:02:45 +02:00
|
|
|
return port_values_[idx];
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-18 06:15:50 +02:00
|
|
|
double vvp_wide_fun_core::value_r(unsigned idx)
|
|
|
|
|
{
|
|
|
|
|
assert(idx < nports_);
|
|
|
|
|
return port_rvalues_? port_rvalues_[idx] : 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vvp_wide_fun_core::recv_real_from_inputs(unsigned p)
|
|
|
|
|
{
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-01 08:02:45 +02:00
|
|
|
void vvp_wide_fun_core::dispatch_vec4_from_input_(unsigned port,
|
|
|
|
|
vvp_vector4_t bit)
|
|
|
|
|
{
|
|
|
|
|
assert(port < nports_);
|
2006-06-18 06:15:50 +02:00
|
|
|
if (port_values_ == 0) port_values_ = new vvp_vector4_t [nports_];
|
2005-04-01 08:02:45 +02:00
|
|
|
port_values_[port] = bit;
|
|
|
|
|
recv_vec4_from_inputs(port);
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-18 06:15:50 +02:00
|
|
|
void vvp_wide_fun_core::dispatch_real_from_input_(unsigned port,
|
|
|
|
|
double bit)
|
|
|
|
|
{
|
|
|
|
|
assert(port < nports_);
|
|
|
|
|
if (port_rvalues_ == 0) port_rvalues_ = new double[nports_];
|
|
|
|
|
port_rvalues_[port] = bit;
|
|
|
|
|
recv_real_from_inputs(port);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-01 08:02:45 +02:00
|
|
|
vvp_wide_fun_t::vvp_wide_fun_t(vvp_wide_fun_core*c, unsigned base)
|
|
|
|
|
: core_(c), port_base_(base)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_wide_fun_t::~vvp_wide_fun_t()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-22 02:04:48 +02:00
|
|
|
void vvp_wide_fun_t::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
2005-04-01 08:02:45 +02:00
|
|
|
{
|
|
|
|
|
unsigned pidx = port_base_ + port.port();
|
|
|
|
|
core_->dispatch_vec4_from_input_(pidx, bit);
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-18 06:15:50 +02:00
|
|
|
void vvp_wide_fun_t::recv_real(vvp_net_ptr_t port, double bit)
|
|
|
|
|
{
|
|
|
|
|
unsigned pidx = port_base_ + port.port();
|
|
|
|
|
core_->dispatch_real_from_input_(pidx, bit);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-01 08:02:45 +02:00
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
/* **** vvp_scalar_t methods **** */
|
2004-12-11 03:31:25 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* DRIVE STRENGTHS:
|
|
|
|
|
*
|
|
|
|
|
* The normal functor is not aware of strengths. It generates strength
|
|
|
|
|
* simply by virtue of having strength specifications. The drive
|
|
|
|
|
* strength specification includes a drive0 and drive1 strength, each
|
|
|
|
|
* with 8 possible values (that can be represented in 3 bits) as given
|
|
|
|
|
* in this table:
|
|
|
|
|
*
|
|
|
|
|
* HiZ = 0,
|
|
|
|
|
* SMALL = 1,
|
|
|
|
|
* MEDIUM = 2,
|
|
|
|
|
* WEAK = 3,
|
|
|
|
|
* LARGE = 4,
|
|
|
|
|
* PULL = 5,
|
|
|
|
|
* STRONG = 6,
|
|
|
|
|
* SUPPLY = 7
|
|
|
|
|
*
|
2005-03-12 05:27:42 +01:00
|
|
|
* The vvp_scalar_t value, however, is a combination of value and
|
2004-12-11 03:31:25 +01:00
|
|
|
* strength, used in strength-aware contexts.
|
|
|
|
|
*
|
|
|
|
|
* OUTPUT STRENGTHS:
|
|
|
|
|
*
|
|
|
|
|
* The strength-aware values are specified as an 8 bit value, that is
|
|
|
|
|
* two 4 bit numbers. The value is encoded with two drive strengths (0-7)
|
|
|
|
|
* and two drive values (0 or 1). Each nibble contains three bits of
|
|
|
|
|
* strength and one bit of value, like so: VSSS. The high nibble has
|
|
|
|
|
* the strength-value closest to supply1, and the low nibble has the
|
|
|
|
|
* strength-value closest to supply0.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* A signal value is unambiguous if the top 4 bits and the bottom 4
|
|
|
|
|
* bits are identical. This means that the VSSSvsss bits of the 8bit
|
|
|
|
|
* value have V==v and SSS==sss.
|
|
|
|
|
*/
|
|
|
|
|
# define UNAMBIG(v) (((v) & 0x0f) == (((v) >> 4) & 0x0f))
|
|
|
|
|
|
2005-02-10 05:54:41 +01:00
|
|
|
#if 0
|
2004-12-11 03:31:25 +01:00
|
|
|
# define STREN1(v) ( ((v)&0x80)? ((v)&0xf0) : (0x70 - ((v)&0xf0)) )
|
|
|
|
|
# define STREN0(v) ( ((v)&0x08)? ((v)&0x0f) : (0x07 - ((v)&0x0f)) )
|
2005-02-10 05:54:41 +01:00
|
|
|
#else
|
2005-02-12 07:13:22 +01:00
|
|
|
# define STREN1(v) (((v)&0x70) >> 4)
|
|
|
|
|
# define STREN0(v) ((v)&0x07)
|
2005-02-10 05:54:41 +01:00
|
|
|
#endif
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
vvp_scalar_t::vvp_scalar_t(vvp_bit4_t val, unsigned str0, unsigned str1)
|
2005-02-07 23:42:42 +01:00
|
|
|
{
|
|
|
|
|
assert(str0 <= 7);
|
|
|
|
|
assert(str1 <= 7);
|
|
|
|
|
|
2005-06-22 00:48:23 +02:00
|
|
|
if (str0 == 0 && str1 == 0) {
|
|
|
|
|
value_ = 0x00;
|
|
|
|
|
} else switch (val) {
|
2005-02-07 23:42:42 +01:00
|
|
|
case BIT4_0:
|
|
|
|
|
value_ = str0 | (str0<<4);
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
value_ = str1 | (str1<<4) | 0x88;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_X:
|
|
|
|
|
value_ = str0 | (str1<<4) | 0x80;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_Z:
|
|
|
|
|
value_ = 0x00;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
vvp_bit4_t vvp_scalar_t::value() const
|
2004-12-31 07:00:06 +01:00
|
|
|
{
|
|
|
|
|
if (value_ == 0) {
|
|
|
|
|
return BIT4_Z;
|
|
|
|
|
|
|
|
|
|
} else switch (value_ & 0x88) {
|
|
|
|
|
case 0x00:
|
|
|
|
|
return BIT4_0;
|
|
|
|
|
case 0x88:
|
|
|
|
|
return BIT4_1;
|
|
|
|
|
default:
|
|
|
|
|
return BIT4_X;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
unsigned vvp_scalar_t::strength0() const
|
|
|
|
|
{
|
|
|
|
|
return STREN0(value_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned vvp_scalar_t::strength1() const
|
|
|
|
|
{
|
|
|
|
|
return STREN1(value_);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-13 08:34:20 +02:00
|
|
|
ostream& operator <<(ostream&out, vvp_scalar_t a)
|
2005-02-12 07:13:22 +01:00
|
|
|
{
|
2005-04-13 08:34:20 +02:00
|
|
|
out << a.strength0() << a.strength1();
|
|
|
|
|
switch (a.value()) {
|
2005-02-12 07:13:22 +01:00
|
|
|
case BIT4_0:
|
2005-04-13 08:34:20 +02:00
|
|
|
out << "0";
|
2005-02-12 07:13:22 +01:00
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
2005-04-13 08:34:20 +02:00
|
|
|
out << "1";
|
2005-02-12 07:13:22 +01:00
|
|
|
break;
|
|
|
|
|
case BIT4_X:
|
2005-04-13 08:34:20 +02:00
|
|
|
out << "X";
|
2005-02-12 07:13:22 +01:00
|
|
|
break;
|
|
|
|
|
case BIT4_Z:
|
2005-04-13 08:34:20 +02:00
|
|
|
out << "Z";
|
2005-02-12 07:13:22 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2005-04-13 08:34:20 +02:00
|
|
|
return out;
|
2005-02-12 07:13:22 +01:00
|
|
|
}
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
vvp_scalar_t resolve(vvp_scalar_t a, vvp_scalar_t b)
|
2004-12-11 03:31:25 +01:00
|
|
|
{
|
|
|
|
|
// If the value is 0, that is the same as HiZ. In that case,
|
|
|
|
|
// resolution is simply a matter of returning the *other* value.
|
|
|
|
|
if (a.value_ == 0)
|
|
|
|
|
return b;
|
|
|
|
|
if (b.value_ == 0)
|
|
|
|
|
return a;
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
vvp_scalar_t res = a;
|
2004-12-11 03:31:25 +01:00
|
|
|
|
|
|
|
|
if (UNAMBIG(a.value_) && UNAMBIG(b.value_)) {
|
|
|
|
|
|
|
|
|
|
/* If both signals are unambiguous, simply choose
|
|
|
|
|
the stronger. If they have the same strength
|
|
|
|
|
but different values, then this becomes
|
|
|
|
|
ambiguous. */
|
|
|
|
|
|
|
|
|
|
if (a.value_ == b.value_) {
|
|
|
|
|
|
|
|
|
|
/* values are equal. do nothing. */
|
|
|
|
|
|
|
|
|
|
} else if ((b.value_&0x07) > (res.value_&0x07)) {
|
|
|
|
|
|
|
|
|
|
/* New value is stronger. Take it. */
|
|
|
|
|
res.value_ = b.value_;
|
|
|
|
|
|
|
|
|
|
} else if ((b.value_&0x77) == (res.value_&0x77)) {
|
|
|
|
|
|
|
|
|
|
/* Strengths are the same. Make value ambiguous. */
|
|
|
|
|
res.value_ = (res.value_&0x70) | (b.value_&0x07) | 0x80;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Must be res is the stronger one. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (UNAMBIG(res.value_)) {
|
|
|
|
|
unsigned tmp = 0;
|
|
|
|
|
|
|
|
|
|
if ((res.value_&0x70) > (b.value_&0x70))
|
|
|
|
|
tmp |= res.value_&0xf0;
|
|
|
|
|
else
|
|
|
|
|
tmp |= b.value_&0xf0;
|
|
|
|
|
|
|
|
|
|
if ((res.value_&0x07) > (b.value_&0x07))
|
|
|
|
|
tmp |= res.value_&0x0f;
|
|
|
|
|
else
|
|
|
|
|
tmp |= b.value_&0x0f;
|
|
|
|
|
|
|
|
|
|
res.value_ = tmp;
|
|
|
|
|
|
|
|
|
|
} else if (UNAMBIG(b.value_)) {
|
|
|
|
|
|
|
|
|
|
/* If one of the signals is unambiguous, then it
|
|
|
|
|
will sweep up the weaker parts of the ambiguous
|
|
|
|
|
signal. The result may be ambiguous, or maybe not. */
|
|
|
|
|
|
|
|
|
|
unsigned tmp = 0;
|
|
|
|
|
|
|
|
|
|
if ((b.value_&0x70) > (res.value_&0x70))
|
|
|
|
|
tmp |= b.value_&0xf0;
|
|
|
|
|
else
|
|
|
|
|
tmp |= res.value_&0xf0;
|
|
|
|
|
|
|
|
|
|
if ((b.value_&0x07) > (res.value_&0x07))
|
|
|
|
|
tmp |= b.value_&0x0f;
|
|
|
|
|
else
|
|
|
|
|
tmp |= res.value_&0x0f;
|
|
|
|
|
|
|
|
|
|
res.value_ = tmp;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* If both signals are ambiguous, then the result
|
|
|
|
|
has an even wider ambiguity. */
|
|
|
|
|
|
|
|
|
|
unsigned tmp = 0;
|
2005-03-12 05:27:42 +01:00
|
|
|
int sv1a = a.value_&0x80 ? STREN1(a.value_) : - STREN1(a.value_);
|
|
|
|
|
int sv0a = a.value_&0x08 ? STREN0(a.value_) : - STREN0(a.value_);
|
|
|
|
|
int sv1b = b.value_&0x80 ? STREN1(b.value_) : - STREN1(b.value_);
|
|
|
|
|
int sv0b = b.value_&0x08 ? STREN0(b.value_) : - STREN0(b.value_);
|
|
|
|
|
|
|
|
|
|
int sv1 = sv1a;
|
|
|
|
|
int sv0 = sv0a;
|
|
|
|
|
|
|
|
|
|
if (sv0a > sv1)
|
|
|
|
|
sv1 = sv0a;
|
|
|
|
|
if (sv1b > sv1)
|
|
|
|
|
sv1 = sv1b;
|
|
|
|
|
if (sv0b > sv1)
|
|
|
|
|
sv1 = sv0b;
|
|
|
|
|
|
|
|
|
|
if (sv1a < sv0)
|
|
|
|
|
sv0 = sv1a;
|
|
|
|
|
if (sv1b < sv0)
|
|
|
|
|
sv0 = sv1b;
|
|
|
|
|
if (sv0b < sv0)
|
|
|
|
|
sv0 = sv0b;
|
|
|
|
|
|
|
|
|
|
if (sv1 > 0) {
|
|
|
|
|
tmp |= 0x80;
|
|
|
|
|
tmp |= sv1 << 4;
|
|
|
|
|
} else {
|
2007-09-25 02:02:47 +02:00
|
|
|
/* Set the MSB when both arguments MSBs are set. This
|
|
|
|
|
can only happen if both one strengths are zero. */
|
|
|
|
|
tmp |= (a.value_&b.value_)&0x80;
|
2005-03-12 05:27:42 +01:00
|
|
|
tmp |= (-sv1) << 4;
|
|
|
|
|
}
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
if (sv0 > 0) {
|
|
|
|
|
tmp |= 0x08;
|
|
|
|
|
tmp |= sv0;
|
|
|
|
|
} else {
|
|
|
|
|
tmp |= (-sv0);
|
|
|
|
|
}
|
2004-12-11 03:31:25 +01:00
|
|
|
|
|
|
|
|
res.value_ = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Canonicalize the HiZ value. */
|
|
|
|
|
if ((res.value_&0x77) == 0)
|
|
|
|
|
res.value_ = 0;
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-31 07:00:06 +01:00
|
|
|
vvp_vector8_t resolve(const vvp_vector8_t&a, const vvp_vector8_t&b)
|
|
|
|
|
{
|
|
|
|
|
assert(a.size() == b.size());
|
|
|
|
|
|
|
|
|
|
vvp_vector8_t out (a.size());
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < out.size() ; idx += 1) {
|
|
|
|
|
out.set_bit(idx, resolve(a.value(idx), b.value(idx)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-12 17:13:37 +02:00
|
|
|
vvp_vector8_t resistive_reduction(const vvp_vector8_t&that)
|
|
|
|
|
{
|
|
|
|
|
static unsigned rstr[8] = {
|
|
|
|
|
0, /* Hi-Z --> Hi-Z */
|
|
|
|
|
1, /* Small capacitance --> Small capacitance */
|
|
|
|
|
1, /* Medium capacitance --> Small capacitance */
|
|
|
|
|
2, /* Weak drive --> Medium capacitance */
|
|
|
|
|
2, /* Large capacitance --> Medium capacitance */
|
|
|
|
|
3, /* Pull drive --> Weak drive */
|
|
|
|
|
5, /* Strong drive --> Pull drive */
|
|
|
|
|
5 /* Supply drive --> Pull drive */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
vvp_vector8_t res (that.size());
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < res.size() ; idx += 1) {
|
|
|
|
|
vvp_scalar_t bit = that.value(idx);
|
|
|
|
|
bit = vvp_scalar_t(bit.value(),
|
|
|
|
|
rstr[bit.strength0()],
|
|
|
|
|
rstr[bit.strength1()]);
|
|
|
|
|
res.set_bit(idx, bit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-31 07:00:06 +01:00
|
|
|
vvp_vector4_t reduce4(const vvp_vector8_t&that)
|
|
|
|
|
{
|
|
|
|
|
vvp_vector4_t out (that.size());
|
|
|
|
|
for (unsigned idx = 0 ; idx < out.size() ; idx += 1)
|
|
|
|
|
out.set_bit(idx, that.value(idx).value());
|
|
|
|
|
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-16 05:19:08 +01:00
|
|
|
vvp_bit4_t compare_gtge(const vvp_vector4_t&lef, const vvp_vector4_t&rig,
|
|
|
|
|
vvp_bit4_t out_if_equal)
|
|
|
|
|
{
|
|
|
|
|
unsigned min_size = lef.size();
|
|
|
|
|
if (rig.size() < min_size)
|
|
|
|
|
min_size = rig.size();
|
|
|
|
|
|
|
|
|
|
// If one of the inputs is nil, treat is as all X values, and
|
|
|
|
|
// that makes the result BIT4_X.
|
|
|
|
|
if (min_size == 0)
|
|
|
|
|
return BIT4_X;
|
|
|
|
|
|
|
|
|
|
// As per the IEEE1364 definition of >, >=, < and <=, if there
|
|
|
|
|
// are any X or Z values in either of the operand vectors,
|
|
|
|
|
// then the result of the compare is BIT4_X.
|
|
|
|
|
|
|
|
|
|
// Check for X/Z in the left operand
|
2008-04-24 01:50:22 +02:00
|
|
|
if (lef.has_xz())
|
|
|
|
|
return BIT4_X;
|
2005-01-16 05:19:08 +01:00
|
|
|
|
|
|
|
|
// Check for X/Z in the right operand
|
2008-04-24 20:05:11 +02:00
|
|
|
if (rig.has_xz())
|
2008-04-24 01:50:22 +02:00
|
|
|
return BIT4_X;
|
2005-01-16 05:19:08 +01:00
|
|
|
|
|
|
|
|
for (unsigned idx = lef.size() ; idx > rig.size() ; idx -= 1) {
|
|
|
|
|
if (lef.value(idx-1) == BIT4_1)
|
|
|
|
|
return BIT4_1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = rig.size() ; idx > lef.size() ; idx -= 1) {
|
|
|
|
|
if (rig.value(idx-1) == BIT4_1)
|
|
|
|
|
return BIT4_0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = min_size ; idx > 0 ; idx -= 1) {
|
|
|
|
|
vvp_bit4_t lv = lef.value(idx-1);
|
|
|
|
|
vvp_bit4_t rv = rig.value(idx-1);
|
|
|
|
|
|
|
|
|
|
if (lv == rv)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (lv == BIT4_1)
|
|
|
|
|
return BIT4_1;
|
|
|
|
|
else
|
|
|
|
|
return BIT4_0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return out_if_equal;
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-22 18:36:15 +01:00
|
|
|
vvp_bit4_t compare_gtge_signed(const vvp_vector4_t&a,
|
|
|
|
|
const vvp_vector4_t&b,
|
|
|
|
|
vvp_bit4_t out_if_equal)
|
|
|
|
|
{
|
|
|
|
|
assert(a.size() == b.size());
|
|
|
|
|
|
|
|
|
|
unsigned sign_idx = a.size()-1;
|
|
|
|
|
vvp_bit4_t a_sign = a.value(sign_idx);
|
|
|
|
|
vvp_bit4_t b_sign = b.value(sign_idx);
|
|
|
|
|
|
2008-04-24 01:50:22 +02:00
|
|
|
if (bit4_is_xz(a_sign))
|
2005-01-22 18:36:15 +01:00
|
|
|
return BIT4_X;
|
2008-04-24 01:50:22 +02:00
|
|
|
if (bit4_is_xz(b_sign))
|
2005-01-22 18:36:15 +01:00
|
|
|
return BIT4_X;
|
|
|
|
|
|
|
|
|
|
if (a_sign == b_sign)
|
|
|
|
|
return compare_gtge(a, b, out_if_equal);
|
|
|
|
|
|
2008-04-24 01:50:22 +02:00
|
|
|
if (a.has_xz())
|
|
|
|
|
return BIT4_X;
|
2005-01-22 18:36:15 +01:00
|
|
|
|
2008-04-24 01:50:22 +02:00
|
|
|
if (b.has_xz())
|
|
|
|
|
return BIT4_X;
|
2005-01-22 18:36:15 +01:00
|
|
|
|
|
|
|
|
if(a_sign == BIT4_0)
|
|
|
|
|
return BIT4_1;
|
|
|
|
|
else
|
|
|
|
|
return BIT4_0;
|
|
|
|
|
}
|