Add .cast/int and update .cast/real.

This patch adds .cast/int and updates .cast/real to act as a local
(temporary) net and to support either a signed or unsigned input.
The vvp_vector4_t class not can convert an arbitrarily sized double
to a vector value. This removes the restriction of lround().

Also document the new statements.
This commit is contained in:
Cary R 2008-06-20 18:11:11 -07:00 committed by Stephen Williams
parent f60a6561bb
commit 27cdd27889
26 changed files with 341 additions and 73 deletions

View File

@ -302,6 +302,14 @@ void NetArrayDq::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetCastInt::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Cast to int. (NetCastInt): " <<
name() << " width=" << width() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetCastReal::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Cast to real (NetCastReal): " <<

View File

@ -113,14 +113,13 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
return;
}
/* If either lval or rid are real then both must be real. */
if ((lval->data_type() == IVL_VT_REAL ||
rid->data_type() == IVL_VT_REAL) &&
lval->data_type() != rid->data_type()) {
cerr << get_fileline() << ": sorry: Both the r-value and "
"the l-value must be real in this context." << endl;
des->errors += 1;
return;
/* Cast the right side when needed. */
if ((lval->data_type() == IVL_VT_REAL &&
rid->data_type() != IVL_VT_REAL)) {
rid = cast_to_real(des, scope, rid);
} else if ((lval->data_type() != IVL_VT_REAL &&
rid->data_type() == IVL_VT_REAL)) {
rid = cast_to_int(des, scope, rid, lval->vector_width());
}
ivl_assert(*this, rid);
@ -287,14 +286,13 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
assert(lval && rval);
assert(rval->pin_count() == 1);
/* If either lval or rval are real then both must be real. */
if ((lval->data_type() == IVL_VT_REAL ||
rval->data_type() == IVL_VT_REAL) &&
lval->data_type() != rval->data_type()) {
cerr << get_fileline() << ": sorry: Both the r-value and "
"the l-value must be real in this context." << endl;
des->errors += 1;
return;
/* Cast the right side when needed. */
if ((lval->data_type() == IVL_VT_REAL &&
rval->data_type() != IVL_VT_REAL)) {
rval = cast_to_real(des, scope, rval);
} else if ((lval->data_type() != IVL_VT_REAL &&
rval->data_type() == IVL_VT_REAL)) {
rval = cast_to_int(des, scope, rval, lval->vector_width());
}
/* If the r-value insists on being smaller then the l-value

View File

@ -72,6 +72,11 @@ bool NetCaseCmp::emit_node(struct target_t*tgt) const
return true;
}
bool NetCastInt::emit_node(struct target_t*tgt) const
{
return tgt->lpm_cast_int(this);
}
bool NetCastReal::emit_node(struct target_t*tgt) const
{
return tgt->lpm_cast_real(this);

View File

@ -254,6 +254,7 @@ typedef enum ivl_lpm_type_e {
IVL_LPM_ABS = 32,
IVL_LPM_ADD = 0,
IVL_LPM_ARRAY = 30,
IVL_LPM_CAST_INT = 34,
IVL_LPM_CAST_REAL = 33,
IVL_LPM_CONCAT = 16,
IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */

View File

@ -849,6 +849,15 @@ const NetScope* NetProcTop::scope() const
return scope_;
}
NetCastInt::NetCastInt(NetScope*scope, perm_string n, unsigned width)
: NetNode(scope, n, 2), width_(width)
{
pin(0).set_dir(Link::OUTPUT);
pin(0).set_name(perm_string::literal("O"), 0);
pin(1).set_dir(Link::INPUT);
pin(1).set_name(perm_string::literal("I"), 0);
}
NetCastReal::NetCastReal(NetScope*scope, perm_string n, bool signed_flag)
: NetNode(scope, n, 2), signed_flag_(signed_flag)
{

View File

@ -916,6 +916,24 @@ class NetArrayDq : public NetNode {
};
/*
* Convert an IVL_VT_REAL input to a logical value with the
* given width. The input is pin(1) and the output is pin(0).
*/
class NetCastInt : public NetNode {
public:
NetCastInt(NetScope*s, perm_string n, unsigned width);
unsigned width() const { return width_; }
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
unsigned width_;
};
/*
* Convert an input to IVL_VT_REAL. The input is pin(1), which can be
* any vector type (VT_BOOL or VT_LOGIC) and the output is pin(0),

View File

@ -76,6 +76,26 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val)
#endif
}
NetNet* cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid)
{
if (src->data_type() != IVL_VT_REAL)
return src;
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid);
tmp->data_type(IVL_VT_LOGIC);
tmp->set_line(*src);
tmp->local_flag(true);
NetCastInt*cast = new NetCastInt(scope, scope->local_symbol(), wid);
cast->set_line(*src);
des->add_node(cast);
connect(cast->pin(0), tmp->pin(0));
connect(cast->pin(1), src->pin(0));
return tmp;
}
NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
{
if (src->data_type() == IVL_VT_REAL)
@ -84,6 +104,7 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE);
tmp->data_type(IVL_VT_REAL);
tmp->set_line(*src);
tmp->local_flag(true);
NetCastReal*cast = new NetCastReal(scope, scope->local_symbol(), src->get_signed());
cast->set_line(*src);

View File

@ -68,6 +68,7 @@ extern NetNet*pad_to_width_signed(Design*des, NetNet*n, unsigned w);
* Generate the nodes necessary to cast an expression (a net) to a
* real value.
*/
extern NetNet*cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid);
extern NetNet*cast_to_real(Design*des, NetScope*scope, NetNet*src);
/*

View File

@ -886,6 +886,7 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
assert(net);
switch (net->type) {
case IVL_LPM_ABS:
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL:
assert(idx == 0);
return net->u_.arith.a;
@ -1029,6 +1030,7 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
switch (net->type) {
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL:
case IVL_LPM_CMP_GE:
case IVL_LPM_CMP_GT:
@ -1166,6 +1168,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
return net->u_.shift.signed_flag;
case IVL_LPM_CAST_INT:
case IVL_LPM_SIGN_EXT: // Sign extend is always signed.
return 1;
case IVL_LPM_SFUNC:

View File

@ -1550,6 +1550,38 @@ void dll_target::lpm_clshift(const NetCLShift*net)
scope_add_lpm(obj->scope, obj);
}
bool dll_target::lpm_cast_int(const NetCastInt*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_CAST_INT;
obj->name = net->name(); // NetCastInt names are permallocated
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
obj->width = net->width();
const Nexus*nex;
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->u_.arith.q = nex->t_cookie();
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->u_.arith.a = nex->t_cookie();
nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
make_lpm_delays_(obj, net);
scope_add_lpm(obj->scope, obj);
return true;
}
bool dll_target::lpm_cast_real(const NetCastReal*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;

View File

@ -76,6 +76,7 @@ struct dll_target : public target_t, public expr_scan_t {
void lpm_abs(const NetAbs*);
void lpm_add_sub(const NetAddSub*);
bool lpm_array_dq(const NetArrayDq*);
bool lpm_cast_int(const NetCastInt*);
bool lpm_cast_real(const NetCastReal*);
void lpm_clshift(const NetCLShift*);
void lpm_compare(const NetCompare*);

View File

@ -107,6 +107,13 @@ bool target_t::lpm_array_dq(const NetArrayDq*)
return false;
}
bool target_t::lpm_cast_int(const NetCastInt*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetCastInt." << endl;
return false;
}
bool target_t::lpm_cast_real(const NetCastReal*)
{
cerr << "target (" << typeid(*this).name() << "): "

View File

@ -72,6 +72,7 @@ struct target_t {
virtual void lpm_add_sub(const NetAddSub*);
virtual bool lpm_array_dq(const NetArrayDq*);
virtual void lpm_clshift(const NetCLShift*);
virtual bool lpm_cast_int(const NetCastInt*);
virtual bool lpm_cast_real(const NetCastReal*);
virtual void lpm_compare(const NetCompare*);
virtual void lpm_divide(const NetDivide*);

View File

@ -240,6 +240,31 @@ static void show_lpm_array(ivl_lpm_t net)
}
}
static void show_lpm_cast_int(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
fprintf(out, " LPM_CAST_INT %s: <width=%u>\n",
ivl_lpm_basename(net), width);
ivl_nexus_t q = ivl_lpm_q(net,0);
ivl_nexus_t a = ivl_lpm_data(net,0);
fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0)));
fprintf(out, " A: %s\n", ivl_nexus_name(ivl_lpm_data(net,0)));
if (type_of_nexus(q) == IVL_VT_REAL) {
fprintf(out, " ERROR: Data type of Q is %s, expecting !real\n",
data_type_string(type_of_nexus(q)));
stub_errors += 1;
}
if (type_of_nexus(a) != IVL_VT_REAL) {
fprintf(out, " ERROR: Data type of A is %s, expecting real\n",
data_type_string(type_of_nexus(a)));
stub_errors += 1;
}
}
static void show_lpm_cast_real(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
@ -827,6 +852,10 @@ static void show_lpm(ivl_lpm_t net)
show_lpm_array(net);
break;
case IVL_LPM_CAST_INT:
show_lpm_cast_int(net);
break;
case IVL_LPM_CAST_REAL:
show_lpm_cast_real(net);
break;

View File

@ -387,6 +387,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_ARRAY:
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL:
case IVL_LPM_CONCAT:
case IVL_LPM_CMP_EEQ:

View File

@ -1079,6 +1079,17 @@ static void draw_lpm_abs(ivl_lpm_t net)
net, dly, src_table[0]);
}
static void draw_lpm_cast_int(ivl_lpm_t net)
{
const char*src_table[1];
draw_lpm_data_inputs(net, 0, 1, src_table);
const char*dly = draw_lpm_output_delay(net);
fprintf(vvp_out, "L_%p%s .cast/int %u, %s;\n",
net, dly, ivl_lpm_width(net), src_table[0]);
}
static void draw_lpm_cast_real(ivl_lpm_t net)
{
const char*src_table[1];
@ -1086,8 +1097,11 @@ static void draw_lpm_cast_real(ivl_lpm_t net)
const char*dly = draw_lpm_output_delay(net);
fprintf(vvp_out, "L_%p%s .cast/real %s;\n",
net, dly, src_table[0]);
const char*is_signed = "";
if (ivl_lpm_signed(net)) is_signed = ".s";
fprintf(vvp_out, "L_%p%s .cast/real%s %s;\n",
net, dly, is_signed, src_table[0]);
}
static void draw_lpm_add(ivl_lpm_t net)
@ -1140,20 +1154,9 @@ static void draw_lpm_add(ivl_lpm_t net)
case IVL_LPM_POW:
if (dto == IVL_VT_REAL)
type = "pow.r";
else if (ivl_lpm_signed(net)) {
else if (ivl_lpm_signed(net))
type = "pow.s";
if (width > 8*sizeof(long)) {
fprintf(stderr, "%s:%u: sorry (vvp-tgt): Signed power "
#ifdef __MINGW32__ /* MinGW does not know about z. */
"result must be no more than %u bits.\n",
#else
"result must be no more than %zu bits.\n",
#endif
ivl_lpm_file(net), ivl_lpm_lineno(net),
8*sizeof(long));
exit(1);
}
} else
else
type = "pow";
break;
default:
@ -1655,6 +1658,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
draw_lpm_abs(net);
return;
case IVL_LPM_CAST_INT:
draw_lpm_cast_int(net);
return;
case IVL_LPM_CAST_REAL:
draw_lpm_cast_real(net);
return;

View File

@ -84,7 +84,7 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8 *name_ext)
}
}
/* We can only have two argument. */
/* We can have a maximum of two arguments. */
if (vpi_scan(argv) != 0) {
char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:",

View File

@ -345,6 +345,24 @@ The .alias statements do not create new nodes, but instead create net
names that are aliases of an existing node. This handles special cases
where a net has different names, possibly in different scopes.
CAST STATEMENTS:
Sometimes nets need to be cast from a real valued net to a bit based
net or from a bit based net to a real valued net. These statements
are used to performa that operation:
<label> .case/int <width>, <symbol>;
<label> .case/real <symbol>;
<label> .case/real.s <symbol>;
For .case/int the output <label> is a bit based net that is <width>
bits wide. The input <symbol> is expected to put real values to
this functor.
For .case/real the output <label> is a real valued net. The input
<symbol> is expected to put bit based values and for .case/real.s
the bits will be interpreted as a signed value.
DELAY STATEMENTS:
Delay nodes are structural net delay nodes that carry and manage
@ -793,7 +811,7 @@ The &PV<> argument is a reference to part of a signal. The syntax is:
&PV '<' <symbol> , <base> , <width> '>'
&PV '<' <symbol> , <tbase> <twid> , <width> '>'
The <symbol> is the label for a signal, the <base> is the cannonical
The <symbol> is the label for a signal, the <base> is the canonical
starting bit of the part select and <width> is the number of bits in
the select. The second form retrieves the <base> from thread space
using <twid> bits starting at <tbase>.

View File

@ -90,6 +90,20 @@ void vvp_arith_abs::recv_real(vvp_net_ptr_t ptr, double bit)
vvp_send_real(ptr.ptr()->out, out);
}
vvp_arith_cast_int::vvp_arith_cast_int(unsigned wid)
: wid_(wid)
{
}
vvp_arith_cast_int::~vvp_arith_cast_int()
{
}
void vvp_arith_cast_int::recv_real(vvp_net_ptr_t ptr, double bit)
{
vvp_send_vec4(ptr.ptr()->out, vvp_vector4_t(wid_, bit));
}
vvp_arith_cast_real::vvp_arith_cast_real(bool signed_flag)
: signed_(signed_flag)
{
@ -475,7 +489,7 @@ void vvp_arith_pow::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
vector4_to_value(op_a_, ad, true);
vector4_to_value(op_b_, bd, true);
res4 = double_to_vector4(pow(ad, bd), wid_);
res4 = vvp_vector4_t(wid_, pow(ad, bd));
} else {
vvp_vector2_t a2 (op_a_);
vvp_vector2_t b2 (op_b_);

View File

@ -60,6 +60,17 @@ class vvp_arith_abs : public vvp_net_fun_t {
private:
};
class vvp_arith_cast_int : public vvp_net_fun_t {
public:
explicit vvp_arith_cast_int(unsigned wid);
~vvp_arith_cast_int();
void recv_real(vvp_net_ptr_t ptr, double bit);
private:
unsigned wid_;
};
class vvp_arith_cast_real : public vvp_net_fun_t {
public:
explicit vvp_arith_cast_real(bool signed_flag);

View File

@ -889,9 +889,26 @@ template <class T_> void make_arith(T_ *arith, char*label,
free(argv);
}
void compile_arith_cast_real(char*label, unsigned argc, struct symb_s*argv)
void compile_arith_cast_int(char*label, long width,
unsigned argc, struct symb_s*argv)
{
vvp_arith_cast_real*arith = new vvp_arith_cast_real(false);
vvp_arith_cast_int*arith = new vvp_arith_cast_int((unsigned) width);
vvp_net_t* ptr = new vvp_net_t;
ptr->fun = arith;
define_functor_symbol(label, ptr);
free(label);
assert(argc == 1);
inputs_connect(ptr, argc, argv);
free(argv);
}
void compile_arith_cast_real(char*label, bool signed_flag,
unsigned argc, struct symb_s*argv)
{
vvp_arith_cast_real*arith = new vvp_arith_cast_real(signed_flag);
vvp_net_t* ptr = new vvp_net_t;
ptr->fun = arith;
@ -1009,11 +1026,6 @@ void compile_arith_pow(char*label, long wid, bool signed_flag,
unsigned argc, struct symb_s*argv)
{
assert( wid > 0 );
/* For now we need to do a double to long cast, so the number
of bits is limited. This should be caught in the compiler. */
if (signed_flag) {
assert( wid <= (long)(8*sizeof(long)) );
}
if (argc != 2) {
const char *suffix = "";

View File

@ -151,8 +151,10 @@ extern void compile_arith_pow(char*label, long width, bool signed_flag,
unsigned argc, struct symb_s*argv);
extern void compile_arith_abs(char*label,
unsigned argc, struct symb_s*argv);
extern void compile_arith_cast_real(char*label,
unsigned argc, struct symb_s*argv);
extern void compile_arith_cast_int(char*label, long width,
unsigned argc, struct symb_s*argv);
extern void compile_arith_cast_real(char*label, bool signed_flag,
unsigned argc, struct symb_s*argv);
extern void compile_arith_div(char*label, long width, bool signed_flag,
unsigned argc, struct symb_s*argv);
extern void compile_arith_mod(char*label, long width,

View File

@ -107,7 +107,9 @@
".array/real" { return K_ARRAY_R; }
".array/s" { return K_ARRAY_S; }
".array/port" { return K_ARRAY_PORT; }
".cast/int" { return K_CAST_INT; }
".cast/real" { return K_CAST_REAL; }
".cast/real.s" { return K_CAST_REAL_S; }
".cmp/eeq" { return K_CMP_EEQ; }
".cmp/eq" { return K_CMP_EQ; }
".cmp/eq.r" { return K_CMP_EQ_R; }

View File

@ -71,7 +71,7 @@ static struct __vpiModPath*modpath_dst = 0;
%token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R
%token K_ARITH_SUM K_ARITH_SUM_R K_ARITH_POW K_ARITH_POW_R K_ARITH_POW_S
%token K_ARRAY K_ARRAY_I K_ARRAY_R K_ARRAY_S K_ARRAY_PORT
%token K_CAST_REAL
%token K_CAST_INT K_CAST_REAL K_CAST_REAL_S
%token K_CMP_EEQ K_CMP_EQ K_CMP_EQ_R K_CMP_NEE K_CMP_NE K_CMP_NE_R
%token K_CMP_GE K_CMP_GE_R K_CMP_GE_S K_CMP_GT K_CMP_GT_R K_CMP_GT_S
%token K_CONCAT K_DEBUG K_DELAY K_DFF
@ -253,9 +253,19 @@ statement
compile_arith_abs($1, obj.cnt, obj.vect);
}
| T_LABEL K_CAST_INT T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5;
compile_arith_cast_int($1, $3, obj.cnt, obj.vect);
}
| T_LABEL K_CAST_REAL symbols ';'
{ struct symbv_s obj = $3;
compile_arith_cast_real($1, obj.cnt, obj.vect);
compile_arith_cast_real($1, false, obj.cnt, obj.vect);
}
| T_LABEL K_CAST_REAL_S symbols ';'
{ struct symbv_s obj = $3;
compile_arith_cast_real($1, true, obj.cnt, obj.vect);
}
/* Arithmetic statements generate functor arrays of a given width

View File

@ -360,6 +360,87 @@ void vvp_vector4_t::allocate_words_(unsigned wid, unsigned long inita, unsigned
}
}
vvp_vector4_t::vvp_vector4_t(unsigned size, double val)
: size_(size)
{
bool is_neg = false;
double fraction;
int exponent;
/* We return 'bx for a NaN. */
if (val != val) {
allocate_words_(size, WORD_X_ABITS, WORD_X_BBITS);
return;
}
/* We return 'b1 for + or - infinity. */
if (val && (val == 0.5*val)) {
allocate_words_(size, WORD_1_ABITS, WORD_1_BBITS);
return;
}
/* Convert to a positive result. */
if (val < 0.0) {
is_neg = true;
val = -val;
}
allocate_words_(size, WORD_0_ABITS, WORD_0_BBITS);
/* Get the exponent and fractional part of the number. */
fraction = frexp(val, &exponent);
/* If the value is small enough just use lround(). */
if (exponent < BITS_PER_WORD-2) {
if (is_neg) this->invert(); // Invert the bits if negative.
long sval = lround(val);
if (is_neg) sval = -sval;
/* This requires that 0 and 1 have the same bbit value. */
if (size_ > BITS_PER_WORD) {
abits_ptr_[0] = sval;
} else {
abits_val_ = sval;
}
return;
}
unsigned nwords = (exponent-1) / BITS_PER_WORD;
unsigned my_words = (size_ + BITS_PER_WORD - 1) / BITS_PER_WORD - 1;
fraction = ldexp(fraction, (exponent-1) % BITS_PER_WORD + 1);
/* Skip any leading bits. */
for (int idx = (signed) nwords; idx > (signed) my_words; idx -=1) {
unsigned bits = (unsigned) fraction;
fraction = fraction - (double) bits;
fraction = ldexp(fraction, BITS_PER_WORD);
}
/* Convert the remaining bits as appropriate. */
if (my_words == 0) {
unsigned bits = (unsigned) fraction;
abits_val_ = bits;
fraction = fraction - (double) bits;
/* Round any fractional part up. */
if (fraction >= 0.5) *this += (int64_t) 1;
} else {
if (nwords < my_words) my_words = nwords;
for (int idx = (signed)my_words; idx >= 0; idx -= 1) {
unsigned bits = (unsigned) fraction;
abits_ptr_[idx] = bits;
fraction = fraction - (double) bits;
fraction = ldexp(fraction, BITS_PER_WORD);
}
/* Round any fractional part up. */
if (fraction >= ldexp(0.5, BITS_PER_WORD)) *this += (int64_t) 1;
}
/* Convert to a negative number if needed. */
if (is_neg) {
this->invert();
*this += (int64_t) 1;
}
}
vvp_vector4_t::vvp_vector4_t(const vvp_vector4_t&that,
unsigned adr, unsigned wid)
{
@ -1052,32 +1133,6 @@ ostream& operator<< (ostream&out, const vvp_vector4_t&that)
return out;
}
/* 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;
}
bool vector4_to_value(const vvp_vector4_t&vec, long&val, bool is_signed)
{
long res = 0;

View File

@ -127,6 +127,8 @@ class vvp_vector4_t {
public:
explicit vvp_vector4_t(unsigned size =0, vvp_bit4_t bits =BIT4_X);
explicit vvp_vector4_t(unsigned size, double val);
// Construct a vector4 from the subvalue of another vector4.
explicit vvp_vector4_t(const vvp_vector4_t&that,
unsigned adr, unsigned wid);
@ -175,6 +177,8 @@ class vvp_vector4_t {
private:
// Number of vvp_bit4_t bits that can be shoved into a word.
enum { BITS_PER_WORD = 8*sizeof(unsigned long) };
// The double value constructor requires that WORD_0_BBITS
// and WORD_1_BBITS have the same value!
#if SIZEOF_UNSIGNED_LONG == 8
enum { WORD_0_ABITS = 0x0000000000000000UL,
WORD_0_BBITS = 0x0000000000000000UL };
@ -370,8 +374,6 @@ extern vvp_bit4_t compare_gtge_signed(const vvp_vector4_t&a,
vvp_bit4_t val_if_equal);
template <class T> extern T coerce_to_width(const T&that, unsigned width);
extern vvp_vector4_t double_to_vector4(double val, unsigned wid);
/*
* These functions extract the value of the vector as a native type,
* if possible, and return true to indicate success. If the vector has