Handle non-real operands to real division.
This handles the general case of a non-real operand to a real-valued division. This can turn up if only 1 operand of a divide is real. In this case the division as a whole is real and the other operand must be cast to real. This method creates an extra node, but it should be a very compact node and this node does no evaluation tricks so in the run time should be no more expensive then folding the cast into the .arith/div.r itself.
This commit is contained in:
parent
f6edd098a9
commit
37723698dc
|
|
@ -302,6 +302,14 @@ void NetArrayDq::dump_node(ostream&o, unsigned ind) const
|
|||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetCastReal::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Cast to real (NetCastReal): " <<
|
||||
name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetCLShift::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Combinatorial shift (NetCLShift): " <<
|
||||
|
|
|
|||
10
elab_net.cc
10
elab_net.cc
|
|
@ -716,6 +716,16 @@ NetNet* PEBinary::elaborate_net_div_(Design*des, NetScope*scope,
|
|||
|
||||
unsigned rwidth = lwidth;
|
||||
|
||||
// If either operand is IVL_VT_REAL, then cast the other to
|
||||
// IVL_VT_REAL so that the division can become IVL_VT_REAL.
|
||||
|
||||
if (lsig->data_type()==IVL_VT_REAL || rsig->data_type()==IVL_VT_REAL) {
|
||||
if (lsig->data_type() != IVL_VT_REAL)
|
||||
lsig = cast_to_real(des, scope, lsig);
|
||||
if (rsig->data_type() != IVL_VT_REAL)
|
||||
rsig = cast_to_real(des, scope, rsig);
|
||||
}
|
||||
|
||||
if (rwidth == 0) {
|
||||
rwidth = lsig->vector_width();
|
||||
if (rsig->vector_width() > rwidth)
|
||||
|
|
|
|||
5
emit.cc
5
emit.cc
|
|
@ -72,6 +72,11 @@ bool NetCaseCmp::emit_node(struct target_t*tgt) const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool NetCastReal::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->lpm_cast_real(this);
|
||||
}
|
||||
|
||||
bool NetCLShift::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_clshift(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_REAL = 33,
|
||||
IVL_LPM_CONCAT = 16,
|
||||
IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */
|
||||
IVL_LPM_CMP_EQ = 10,
|
||||
|
|
|
|||
|
|
@ -849,6 +849,15 @@ const NetScope* NetProcTop::scope() const
|
|||
return scope_;
|
||||
}
|
||||
|
||||
NetCastReal::NetCastReal(NetScope*scope, perm_string n, bool signed_flag)
|
||||
: NetNode(scope, n, 2), signed_flag_(signed_flag)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
NetConcat::NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt)
|
||||
: NetNode(scope, n, cnt+1), width_(wid)
|
||||
{
|
||||
|
|
|
|||
20
netlist.h
20
netlist.h
|
|
@ -916,6 +916,26 @@ class NetArrayDq : public NetNode {
|
|||
|
||||
};
|
||||
|
||||
/*
|
||||
* 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),
|
||||
* which is IVL_VT_REAL. The conversion interprets the input as an
|
||||
* unsigned value unless the signed_flag is true.
|
||||
*/
|
||||
class NetCastReal : public NetNode {
|
||||
|
||||
public:
|
||||
NetCastReal(NetScope*s, perm_string n, bool signed_flag);
|
||||
|
||||
bool signed_flag() const { return signed_flag_; }
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual bool emit_node(struct target_t*) const;
|
||||
|
||||
private:
|
||||
bool signed_flag_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This type represents the LPM_CLSHIFT device.
|
||||
*/
|
||||
|
|
|
|||
19
netmisc.cc
19
netmisc.cc
|
|
@ -76,6 +76,25 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val)
|
|||
#endif
|
||||
}
|
||||
|
||||
NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
|
||||
{
|
||||
if (src->data_type() == IVL_VT_REAL)
|
||||
return src;
|
||||
|
||||
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE);
|
||||
tmp->data_type(IVL_VT_REAL);
|
||||
tmp->set_line(*src);
|
||||
|
||||
NetCastReal*cast = new NetCastReal(scope, scope->local_symbol(), src->get_signed());
|
||||
cast->set_line(*src);
|
||||
des->add_node(cast);
|
||||
|
||||
connect(cast->pin(0), tmp->pin(0));
|
||||
connect(cast->pin(1), src->pin(0));
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a signed constant to an existing expression. Generate a new
|
||||
* NetEBAdd node that has the input expression and an expression made
|
||||
|
|
|
|||
|
|
@ -64,6 +64,12 @@ extern NetNet*pad_to_width(Design*des, NetNet*n, unsigned w);
|
|||
|
||||
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_real(Design*des, NetScope*scope, NetNet*src);
|
||||
|
||||
/*
|
||||
* Take the input expression and return a variation that assures that
|
||||
* the expression is 1-bit wide and logical. This reflects the needs
|
||||
|
|
|
|||
16
t-dll-api.cc
16
t-dll-api.cc
|
|
@ -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_REAL:
|
||||
assert(idx == 0);
|
||||
return net->u_.arith.a;
|
||||
|
||||
|
|
@ -1028,20 +1029,18 @@ 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_DIVIDE:
|
||||
case IVL_LPM_MOD:
|
||||
case IVL_LPM_MULT:
|
||||
case IVL_LPM_POW:
|
||||
case IVL_LPM_SUB:
|
||||
assert(idx == 0);
|
||||
return net->u_.arith.q;
|
||||
|
||||
case IVL_LPM_CAST_REAL:
|
||||
case IVL_LPM_CMP_GE:
|
||||
case IVL_LPM_CMP_GT:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
case IVL_LPM_CMP_NE:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_NEE:
|
||||
case IVL_LPM_DIVIDE:
|
||||
case IVL_LPM_MOD:
|
||||
case IVL_LPM_MULT:
|
||||
case IVL_LPM_POW:
|
||||
case IVL_LPM_SUB:
|
||||
assert(idx == 0);
|
||||
return net->u_.arith.q;
|
||||
|
||||
|
|
@ -1144,6 +1143,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
|
|||
return 0;
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_CAST_REAL:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
case IVL_LPM_CMP_GE:
|
||||
|
|
|
|||
33
t-dll.cc
33
t-dll.cc
|
|
@ -1550,6 +1550,39 @@ void dll_target::lpm_clshift(const NetCLShift*net)
|
|||
scope_add_lpm(obj->scope, obj);
|
||||
}
|
||||
|
||||
bool dll_target::lpm_cast_real(const NetCastReal*net)
|
||||
{
|
||||
ivl_lpm_t obj = new struct ivl_lpm_s;
|
||||
obj->type = IVL_LPM_CAST_REAL;
|
||||
obj->name = net->name(); // NetCastReal names are permallocated
|
||||
assert(net->scope());
|
||||
obj->scope = find_scope(des_, net->scope());
|
||||
assert(obj->scope);
|
||||
|
||||
obj->width = 0;
|
||||
obj->u_.arith.signed_flag = net->signed_flag()? 1 : 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make out of the NetCompare object an ivl_lpm_s object. The
|
||||
* comparators in ivl_target do not support < or <=, but they can be
|
||||
|
|
|
|||
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_real(const NetCastReal*);
|
||||
void lpm_clshift(const NetCLShift*);
|
||||
void lpm_compare(const NetCompare*);
|
||||
void lpm_divide(const NetDivide*);
|
||||
|
|
|
|||
|
|
@ -107,6 +107,13 @@ bool target_t::lpm_array_dq(const NetArrayDq*)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool target_t::lpm_cast_real(const NetCastReal*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetCastReal." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::lpm_clshift(const NetCLShift*)
|
||||
{
|
||||
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_real(const NetCastReal*);
|
||||
virtual void lpm_compare(const NetCompare*);
|
||||
virtual void lpm_divide(const NetDivide*);
|
||||
virtual void lpm_modulo(const NetModulo*);
|
||||
|
|
|
|||
|
|
@ -240,6 +240,31 @@ static void show_lpm_array(ivl_lpm_t net)
|
|||
}
|
||||
}
|
||||
|
||||
static void show_lpm_cast_real(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
|
||||
fprintf(out, " LPM_CAST_REAL %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_divide(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
|
|
@ -802,6 +827,10 @@ static void show_lpm(ivl_lpm_t net)
|
|||
show_lpm_array(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_CAST_REAL:
|
||||
show_lpm_cast_real(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_DIVIDE:
|
||||
show_lpm_divide(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_REAL:
|
||||
case IVL_LPM_CONCAT:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
|
|
|
|||
|
|
@ -1079,6 +1079,17 @@ static void draw_lpm_abs(ivl_lpm_t net)
|
|||
net, dly, src_table[0]);
|
||||
}
|
||||
|
||||
static void draw_lpm_cast_real(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/real %s;\n",
|
||||
net, dly, src_table[0]);
|
||||
}
|
||||
|
||||
static void draw_lpm_add(ivl_lpm_t net)
|
||||
{
|
||||
const char*src_table[2];
|
||||
|
|
@ -1644,6 +1655,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
|
|||
draw_lpm_abs(net);
|
||||
return;
|
||||
|
||||
case IVL_LPM_CAST_REAL:
|
||||
draw_lpm_cast_real(net);
|
||||
return;
|
||||
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_SUB:
|
||||
case IVL_LPM_MULT:
|
||||
|
|
|
|||
16
vvp/arith.cc
16
vvp/arith.cc
|
|
@ -90,6 +90,22 @@ void vvp_arith_abs::recv_real(vvp_net_ptr_t ptr, double bit)
|
|||
vvp_send_real(ptr.ptr()->out, out);
|
||||
}
|
||||
|
||||
vvp_arith_cast_real::vvp_arith_cast_real(bool signed_flag)
|
||||
: signed_(signed_flag)
|
||||
{
|
||||
}
|
||||
|
||||
vvp_arith_cast_real::~vvp_arith_cast_real()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_arith_cast_real::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
||||
{
|
||||
double val;
|
||||
vector4_to_value(bit, val, signed_);
|
||||
vvp_send_real(ptr.ptr()->out, val);
|
||||
}
|
||||
|
||||
// Division
|
||||
|
||||
vvp_arith_div::vvp_arith_div(unsigned wid, bool signed_flag)
|
||||
|
|
|
|||
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_real : public vvp_net_fun_t {
|
||||
public:
|
||||
explicit vvp_arith_cast_real(bool signed_flag);
|
||||
~vvp_arith_cast_real();
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit);
|
||||
|
||||
private:
|
||||
bool signed_;
|
||||
};
|
||||
|
||||
class vvp_arith_div : public vvp_arith_ {
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -889,6 +889,21 @@ 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)
|
||||
{
|
||||
vvp_arith_cast_real*arith = new vvp_arith_cast_real(false);
|
||||
|
||||
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_abs(char*label, unsigned argc, struct symb_s*argv)
|
||||
{
|
||||
vvp_arith_abs*arith = new vvp_arith_abs;
|
||||
|
|
|
|||
|
|
@ -151,6 +151,8 @@ 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_div(char*label, long width, bool signed_flag,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
extern void compile_arith_mod(char*label, long width,
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@
|
|||
".array/real" { return K_ARRAY_R; }
|
||||
".array/s" { return K_ARRAY_S; }
|
||||
".array/port" { return K_ARRAY_PORT; }
|
||||
".cast/real" { return K_CAST_REAL; }
|
||||
".cmp/eeq" { return K_CMP_EEQ; }
|
||||
".cmp/eq" { return K_CMP_EQ; }
|
||||
".cmp/eq.r" { return K_CMP_EQ_R; }
|
||||
|
|
|
|||
|
|
@ -71,6 +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_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
|
||||
|
|
@ -252,6 +253,11 @@ statement
|
|||
compile_arith_abs($1, obj.cnt, obj.vect);
|
||||
}
|
||||
|
||||
| T_LABEL K_CAST_REAL symbols ';'
|
||||
{ struct symbv_s obj = $3;
|
||||
compile_arith_cast_real($1, obj.cnt, obj.vect);
|
||||
}
|
||||
|
||||
/* Arithmetic statements generate functor arrays of a given width
|
||||
that take like size input vectors. */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue