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:
parent
f60a6561bb
commit
27cdd27889
|
|
@ -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): " <<
|
||||
|
|
|
|||
30
elaborate.cc
30
elaborate.cc
|
|
@ -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
|
||||
|
|
|
|||
5
emit.cc
5
emit.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 (===) */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
18
netlist.h
18
netlist.h
|
|
@ -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),
|
||||
|
|
|
|||
21
netmisc.cc
21
netmisc.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
32
t-dll.cc
32
t-dll.cc
|
|
@ -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;
|
||||
|
|
|
|||
1
t-dll.h
1
t-dll.h
|
|
@ -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*);
|
||||
|
|
|
|||
|
|
@ -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() << "): "
|
||||
|
|
|
|||
1
target.h
1
target.h
|
|
@ -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*);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:",
|
||||
|
|
|
|||
|
|
@ -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>.
|
||||
|
|
|
|||
16
vvp/arith.cc
16
vvp/arith.cc
|
|
@ -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_);
|
||||
|
|
|
|||
11
vvp/arith.h
11
vvp/arith.h
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 = "";
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
14
vvp/parse.y
14
vvp/parse.y
|
|
@ -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
|
||||
|
|
|
|||
107
vvp/vvp_net.cc
107
vvp/vvp_net.cc
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue