Handle the abs() function in net context.

In net context we have to create a node that does the abs() function
for us. Elaborate that node and handle it all the way down to vvp.
This commit is contained in:
Stephen Williams 2008-05-06 20:37:00 -07:00
parent e91243e1c6
commit 523de1b69c
9 changed files with 103 additions and 2 deletions

View File

@ -3491,6 +3491,18 @@ NetNet* PEUnary::elab_net_unary_real_(Design*des, NetScope*scope,
des->errors += 1;
break;
case 'm': // abs()
NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), 1);
tmp->set_line(*this);
tmp->rise_time(rise);
tmp->fall_time(fall);
tmp->decay_time(decay);
des->add_node(tmp);
connect(tmp->pin(0), sig->pin(0));
connect(tmp->pin(1), sub_sig->pin(0));
break;
case '-':
NetAddSub*sub = new NetAddSub(scope, scope->local_symbol(), 1);
sub->attribute(perm_string::literal("LPM_Direction"),

View File

@ -1323,7 +1323,7 @@ void dll_target::lpm_abs(const NetAbs*net)
obj->u_.arith.q = nex->t_cookie();
nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
nex = net->pin(0).nexus();
nex = net->pin(1).nexus();
assert(nex->t_cookie());
/* pin(1) is the input data. */

View File

@ -679,6 +679,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
if (lpm) switch (ivl_lpm_type(lpm)) {
case IVL_LPM_FF:
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_ARRAY:
case IVL_LPM_CONCAT:
@ -1693,6 +1694,17 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net)
return dly;
}
static void draw_lpm_abs(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 .abs %s;\n",
net, dly, src_table[0]);
}
static void draw_lpm_add(ivl_lpm_t net)
{
const char*src_table[2];
@ -2338,6 +2350,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
{
switch (ivl_lpm_type(net)) {
case IVL_LPM_ABS:
draw_lpm_abs(net);
return;
case IVL_LPM_ADD:
case IVL_LPM_SUB:
case IVL_LPM_MULT:

View File

@ -55,6 +55,41 @@ void vvp_arith_::dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit)
}
vvp_arith_abs::vvp_arith_abs()
{
}
vvp_arith_abs::~vvp_arith_abs()
{
}
void vvp_arith_abs::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
{
vvp_vector4_t out (bit.size(), BIT4_0);;
vvp_bit4_t cmp = compare_gtge_signed(bit, out, BIT4_1);
switch (cmp) {
case BIT4_1: // bit >= 0
out = bit;
break;
case BIT4_0: // bit < 0
out = ~bit;
out += 1;
break;
default: // There's an X.
out = vvp_vector4_t(bit.size(), BIT4_X);
break;
}
vvp_send_vec4(ptr.ptr()->out, out);
}
void vvp_arith_abs::recv_real(vvp_net_ptr_t ptr, double bit)
{
double out = fabs(bit);
vvp_send_real(ptr.ptr()->out, out);
}
// Division
vvp_arith_div::vvp_arith_div(unsigned wid, bool signed_flag)

View File

@ -49,6 +49,17 @@ class vvp_arith_ : public vvp_net_fun_t {
vvp_vector4_t x_val_;
};
class vvp_arith_abs : public vvp_net_fun_t {
public:
explicit vvp_arith_abs();
~vvp_arith_abs();
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit);
void recv_real(vvp_net_ptr_t ptr, double bit);
private:
};
class vvp_arith_div : public vvp_arith_ {
public:

View File

@ -941,6 +941,21 @@ template <class T_> void make_arith(T_ *arith, char*label,
free(argv);
}
void compile_arith_abs(char*label, unsigned argc, struct symb_s*argv)
{
vvp_arith_abs*arith = new vvp_arith_abs;
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_div(char*label, long wid, bool signed_flag,
unsigned argc, struct symb_s*argv)
{

View File

@ -149,6 +149,8 @@ extern void compile_part_select_var(char*label, char*src,
*/
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_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

@ -87,6 +87,7 @@
".alias" { return K_ALIAS; }
".alias/real" { return K_ALIAS_R; }
".alias/s" { return K_ALIAS_S; }
".abs" { return K_ARITH_ABS; }
".arith/div" { return K_ARITH_DIV; }
".arith/div.r" { return K_ARITH_DIV_R; }
".arith/div.s" { return K_ARITH_DIV_S; }

View File

@ -66,7 +66,8 @@ static struct __vpiModPath*modpath_dst = 0;
};
%token K_ALIAS K_ALIAS_S K_ALIAS_R
%token K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD K_ARITH_MOD_R
%token K_ARITH_ABS K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD
%token K_ARITH_MOD_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_ARRAY K_ARRAY_I K_ARRAY_R K_ARRAY_S K_ARRAY_PORT
@ -248,6 +249,14 @@ statement
symbols ';'
{ compile_concat($1, $4, $5, $6, $7, $10.cnt, $10.vect); }
/* The ABS statement is a special arithmetic node that takes 1
input. Re-use the symbols rule. */
| T_LABEL K_ARITH_ABS symbols ';'
{ struct symbv_s obj = $3;
compile_arith_abs($1, obj.cnt, obj.vect);
}
/* Arithmetic statements generate functor arrays of a given width
that take like size input vectors. */