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); 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 void NetCastReal::dump_node(ostream&o, unsigned ind) const
{ {
o << setw(ind) << "" << "Cast to real (NetCastReal): " << o << setw(ind) << "" << "Cast to real (NetCastReal): " <<

View File

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

View File

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

View File

@ -849,6 +849,15 @@ const NetScope* NetProcTop::scope() const
return scope_; 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) NetCastReal::NetCastReal(NetScope*scope, perm_string n, bool signed_flag)
: NetNode(scope, n, 2), signed_flag_(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 * 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), * 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 #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) NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
{ {
if (src->data_type() == IVL_VT_REAL) 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); NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE);
tmp->data_type(IVL_VT_REAL); tmp->data_type(IVL_VT_REAL);
tmp->set_line(*src); tmp->set_line(*src);
tmp->local_flag(true);
NetCastReal*cast = new NetCastReal(scope, scope->local_symbol(), src->get_signed()); NetCastReal*cast = new NetCastReal(scope, scope->local_symbol(), src->get_signed());
cast->set_line(*src); 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 * Generate the nodes necessary to cast an expression (a net) to a
* real value. * 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); 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); assert(net);
switch (net->type) { switch (net->type) {
case IVL_LPM_ABS: case IVL_LPM_ABS:
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL: case IVL_LPM_CAST_REAL:
assert(idx == 0); assert(idx == 0);
return net->u_.arith.a; 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) { switch (net->type) {
case IVL_LPM_ABS: case IVL_LPM_ABS:
case IVL_LPM_ADD: case IVL_LPM_ADD:
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL: case IVL_LPM_CAST_REAL:
case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GE:
case IVL_LPM_CMP_GT: 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_SHIFTL:
case IVL_LPM_SHIFTR: case IVL_LPM_SHIFTR:
return net->u_.shift.signed_flag; return net->u_.shift.signed_flag;
case IVL_LPM_CAST_INT:
case IVL_LPM_SIGN_EXT: // Sign extend is always signed. case IVL_LPM_SIGN_EXT: // Sign extend is always signed.
return 1; return 1;
case IVL_LPM_SFUNC: case IVL_LPM_SFUNC:

View File

@ -1550,6 +1550,38 @@ void dll_target::lpm_clshift(const NetCLShift*net)
scope_add_lpm(obj->scope, obj); 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) bool dll_target::lpm_cast_real(const NetCastReal*net)
{ {
ivl_lpm_t obj = new struct ivl_lpm_s; 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_abs(const NetAbs*);
void lpm_add_sub(const NetAddSub*); void lpm_add_sub(const NetAddSub*);
bool lpm_array_dq(const NetArrayDq*); bool lpm_array_dq(const NetArrayDq*);
bool lpm_cast_int(const NetCastInt*);
bool lpm_cast_real(const NetCastReal*); bool lpm_cast_real(const NetCastReal*);
void lpm_clshift(const NetCLShift*); void lpm_clshift(const NetCLShift*);
void lpm_compare(const NetCompare*); void lpm_compare(const NetCompare*);

View File

@ -107,6 +107,13 @@ bool target_t::lpm_array_dq(const NetArrayDq*)
return false; 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*) bool target_t::lpm_cast_real(const NetCastReal*)
{ {
cerr << "target (" << typeid(*this).name() << "): " cerr << "target (" << typeid(*this).name() << "): "

View File

@ -72,6 +72,7 @@ struct target_t {
virtual void lpm_add_sub(const NetAddSub*); virtual void lpm_add_sub(const NetAddSub*);
virtual bool lpm_array_dq(const NetArrayDq*); virtual bool lpm_array_dq(const NetArrayDq*);
virtual void lpm_clshift(const NetCLShift*); virtual void lpm_clshift(const NetCLShift*);
virtual bool lpm_cast_int(const NetCastInt*);
virtual bool lpm_cast_real(const NetCastReal*); virtual bool lpm_cast_real(const NetCastReal*);
virtual void lpm_compare(const NetCompare*); virtual void lpm_compare(const NetCompare*);
virtual void lpm_divide(const NetDivide*); 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) static void show_lpm_cast_real(ivl_lpm_t net)
{ {
unsigned width = ivl_lpm_width(net); unsigned width = ivl_lpm_width(net);
@ -827,6 +852,10 @@ static void show_lpm(ivl_lpm_t net)
show_lpm_array(net); show_lpm_array(net);
break; break;
case IVL_LPM_CAST_INT:
show_lpm_cast_int(net);
break;
case IVL_LPM_CAST_REAL: case IVL_LPM_CAST_REAL:
show_lpm_cast_real(net); show_lpm_cast_real(net);
break; 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_ABS:
case IVL_LPM_ADD: case IVL_LPM_ADD:
case IVL_LPM_ARRAY: case IVL_LPM_ARRAY:
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL: case IVL_LPM_CAST_REAL:
case IVL_LPM_CONCAT: case IVL_LPM_CONCAT:
case IVL_LPM_CMP_EEQ: 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]); 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) static void draw_lpm_cast_real(ivl_lpm_t net)
{ {
const char*src_table[1]; 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); const char*dly = draw_lpm_output_delay(net);
fprintf(vvp_out, "L_%p%s .cast/real %s;\n", const char*is_signed = "";
net, dly, src_table[0]); 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) 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: case IVL_LPM_POW:
if (dto == IVL_VT_REAL) if (dto == IVL_VT_REAL)
type = "pow.r"; type = "pow.r";
else if (ivl_lpm_signed(net)) { else if (ivl_lpm_signed(net))
type = "pow.s"; type = "pow.s";
if (width > 8*sizeof(long)) { else
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
type = "pow"; type = "pow";
break; break;
default: default:
@ -1655,6 +1658,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
draw_lpm_abs(net); draw_lpm_abs(net);
return; return;
case IVL_LPM_CAST_INT:
draw_lpm_cast_int(net);
return;
case IVL_LPM_CAST_REAL: case IVL_LPM_CAST_REAL:
draw_lpm_cast_real(net); draw_lpm_cast_real(net);
return; 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) { if (vpi_scan(argv) != 0) {
char msg [64]; char msg [64];
snprintf(msg, 64, "ERROR: %s line %d:", 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 names that are aliases of an existing node. This handles special cases
where a net has different names, possibly in different scopes. 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 STATEMENTS:
Delay nodes are structural net delay nodes that carry and manage 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> , <base> , <width> '>'
&PV '<' <symbol> , <tbase> <twid> , <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 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 the select. The second form retrieves the <base> from thread space
using <twid> bits starting at <tbase>. 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_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) vvp_arith_cast_real::vvp_arith_cast_real(bool signed_flag)
: signed_(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_a_, ad, true);
vector4_to_value(op_b_, bd, 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 { } else {
vvp_vector2_t a2 (op_a_); vvp_vector2_t a2 (op_a_);
vvp_vector2_t b2 (op_b_); vvp_vector2_t b2 (op_b_);

View File

@ -60,6 +60,17 @@ class vvp_arith_abs : public vvp_net_fun_t {
private: 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 { class vvp_arith_cast_real : public vvp_net_fun_t {
public: public:
explicit vvp_arith_cast_real(bool signed_flag); 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); 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; vvp_net_t* ptr = new vvp_net_t;
ptr->fun = arith; ptr->fun = arith;
@ -1009,11 +1026,6 @@ void compile_arith_pow(char*label, long wid, bool signed_flag,
unsigned argc, struct symb_s*argv) unsigned argc, struct symb_s*argv)
{ {
assert( wid > 0 ); 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) { if (argc != 2) {
const char *suffix = ""; 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); unsigned argc, struct symb_s*argv);
extern void compile_arith_abs(char*label, extern void compile_arith_abs(char*label,
unsigned argc, struct symb_s*argv); unsigned argc, struct symb_s*argv);
extern void compile_arith_cast_real(char*label, extern void compile_arith_cast_int(char*label, long width,
unsigned argc, struct symb_s*argv); 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, extern void compile_arith_div(char*label, long width, bool signed_flag,
unsigned argc, struct symb_s*argv); unsigned argc, struct symb_s*argv);
extern void compile_arith_mod(char*label, long width, extern void compile_arith_mod(char*label, long width,

View File

@ -107,7 +107,9 @@
".array/real" { return K_ARRAY_R; } ".array/real" { return K_ARRAY_R; }
".array/s" { return K_ARRAY_S; } ".array/s" { return K_ARRAY_S; }
".array/port" { return K_ARRAY_PORT; } ".array/port" { return K_ARRAY_PORT; }
".cast/int" { return K_CAST_INT; }
".cast/real" { return K_CAST_REAL; } ".cast/real" { return K_CAST_REAL; }
".cast/real.s" { return K_CAST_REAL_S; }
".cmp/eeq" { return K_CMP_EEQ; } ".cmp/eeq" { return K_CMP_EEQ; }
".cmp/eq" { return K_CMP_EQ; } ".cmp/eq" { return K_CMP_EQ; }
".cmp/eq.r" { return K_CMP_EQ_R; } ".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_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_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_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_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_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 %token K_CONCAT K_DEBUG K_DELAY K_DFF
@ -253,9 +253,19 @@ statement
compile_arith_abs($1, obj.cnt, obj.vect); 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 ';' | T_LABEL K_CAST_REAL symbols ';'
{ struct symbv_s obj = $3; { 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 /* 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, vvp_vector4_t::vvp_vector4_t(const vvp_vector4_t&that,
unsigned adr, unsigned wid) unsigned adr, unsigned wid)
{ {
@ -1052,32 +1133,6 @@ ostream& operator<< (ostream&out, const vvp_vector4_t&that)
return out; 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) bool vector4_to_value(const vvp_vector4_t&vec, long&val, bool is_signed)
{ {
long res = 0; long res = 0;

View File

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