Skip to content

Commit

Permalink
Add signed bit based power to continuous assignments.
Browse files Browse the repository at this point in the history
This patch adds the power operator for signed bit based values
in a continuous assignment. It also fixes a few other power
expression width problems. The expression width is still not
calculated correctly, since the correct method can produce huge
possible bit widths. The result is currently limited to the width
of the native long. This is because lround() is used to convert
from a double to an integer. A check in the code generator protects
the runtime from this limitation.
  • Loading branch information
caryr authored and steveicarus committed Feb 12, 2008
1 parent f2ff25b commit 331faa2
Show file tree
Hide file tree
Showing 13 changed files with 98 additions and 36 deletions.
12 changes: 3 additions & 9 deletions elab_net.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1142,22 +1142,16 @@ NetNet* PEBinary::elaborate_net_pow_(Design*des, NetScope*scope,
// The power is signed if either its operands are signed.
bool arith_is_signed = lsig->get_signed() || rsig->get_signed();

/* For now we only support real values. */
if (lsig->data_type() != IVL_VT_REAL && arith_is_signed) {
cerr << get_fileline() << ": sorry: Signed bit based power (**) is "
<< "currently unsupported in continuous assignments." << endl;
des->errors += 1;
return 0;
}

unsigned rwidth = lwidth;
if (rwidth == 0) {
/* Reals are always 1 wide and lsig/rsig types match here. */
if (lsig->data_type() == IVL_VT_REAL) {
rwidth = 1;
lwidth = 1;
} else {
/* Nothing for now. Need integer value.*/
/* This is incorrect! a * (2^b - 1) is close. */
rwidth = lsig->vector_width() + rsig->vector_width();
lwidth = rwidth;
}
}

Expand Down
5 changes: 3 additions & 2 deletions net_expr.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2007 Stephen Williams ([email protected])
* Copyright (c) 2002-2008 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
Expand Down Expand Up @@ -258,7 +258,8 @@ NetEBPow::NetEBPow(char op, NetExpr*l, NetExpr*r)
: NetEBinary(op, l, r)
{
assert(op == 'p');
expr_width(l->expr_width());
/* This is incorrect! a * (2^b - 1) is close. */
expr_width(l->expr_width()+r->expr_width());
cast_signed(l->has_sign() || r->has_sign());
}

Expand Down
6 changes: 2 additions & 4 deletions set_width.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2007 Stephen Williams ([email protected])
* Copyright (c) 1999-2008 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
Expand Down Expand Up @@ -185,8 +185,7 @@ bool NetEBMult::set_width(unsigned w, bool)

bool NetEBPow::set_width(unsigned w, bool last_chance)
{
bool flag = left_->set_width(w, last_chance);
return flag;
return w == expr_width();
}

/*
Expand Down Expand Up @@ -445,4 +444,3 @@ bool NetEUReduce::set_width(unsigned w, bool)
{
return w == 1;
}

1 change: 1 addition & 0 deletions t-dll.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1777,6 +1777,7 @@ void dll_target::lpm_pow(const NetPow*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_POW;
FILE_NAME(obj, net);
obj->name = net->name();
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
Expand Down
13 changes: 10 additions & 3 deletions tgt-vvp/vvp_scope.c
Original file line number Diff line number Diff line change
Expand Up @@ -1708,9 +1708,16 @@ 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))
assert(0); /* No support for signed bit based signals. */
else
else if (ivl_lpm_signed(net)) {
type = "pow.s";
if (width > 8*sizeof(long)) {
fprintf(stderr, "%s:%u: sorry (vvp-tgt): Signed power "
"result must be no more than %d bits.\n",
ivl_lpm_file(net), ivl_lpm_lineno(net),
8*sizeof(long));
exit(1);
}
} else
type = "pow";
break;
default:
Expand Down
34 changes: 24 additions & 10 deletions vvp/arith.cc
Original file line number Diff line number Diff line change
Expand Up @@ -400,8 +400,8 @@ void vvp_arith_mult::wide(vvp_ipoint_t base, bool push)

// Power

vvp_arith_pow::vvp_arith_pow(unsigned wid)
: vvp_arith_(wid)
vvp_arith_pow::vvp_arith_pow(unsigned wid, bool signed_flag)
: vvp_arith_(wid), signed_flag_(signed_flag)
{
}

Expand All @@ -413,17 +413,31 @@ void vvp_arith_pow::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
{
dispatch_operand_(ptr, bit);

vvp_vector2_t a2 (op_a_);
vvp_vector2_t b2 (op_b_);
vvp_vector4_t res4;
if (signed_flag_) {
if (op_a_.has_xz() || op_b_.has_xz()) {
vvp_send_vec4(ptr.ptr()->out, x_val_);
return;
}

if (a2.is_NaN() || b2.is_NaN()) {
vvp_send_vec4(ptr.ptr()->out, x_val_);
return;
}
double ad, bd;
vector4_to_value(op_a_, ad, true);
vector4_to_value(op_b_, bd, true);

vvp_vector2_t result = pow(a2, b2);
res4 = double_to_vector4(pow(ad, bd), wid_);
} else {
vvp_vector2_t a2 (op_a_);
vvp_vector2_t b2 (op_b_);

if (a2.is_NaN() || b2.is_NaN()) {
vvp_send_vec4(ptr.ptr()->out, x_val_);
return;
}

vvp_vector2_t result = pow(a2, b2);
res4 = vector2_to_vector4(result, wid_);
}

vvp_vector4_t res4 = vector2_to_vector4(result, wid_);
vvp_send_vec4(ptr.ptr()->out, res4);
}

Expand Down
4 changes: 3 additions & 1 deletion vvp/arith.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,11 @@ class vvp_arith_mult : public vvp_arith_ {
class vvp_arith_pow : public vvp_arith_ {

public:
explicit vvp_arith_pow(unsigned wid);
explicit vvp_arith_pow(unsigned wid, bool signed_flag);
~vvp_arith_pow();
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit);
private:
bool signed_flag_;
};

class vvp_arith_sub : public vvp_arith_ {
Expand Down
19 changes: 15 additions & 4 deletions vvp/compile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -921,7 +921,10 @@ void compile_arith_div(char*label, long wid, bool signed_flag,
assert( wid > 0 );

if (argc != 2) {
fprintf(stderr, "%s; .arith/div has wrong number of symbols\n", label);
char *suffix = "";
if (signed_flag) suffix = ".s";
fprintf(stderr, "%s; .arith/div%s has wrong number of "
"symbols\n", label, suffix);
compile_errors += 1;
return;
}
Expand Down Expand Up @@ -998,18 +1001,26 @@ void compile_arith_mult_r(char*label, unsigned argc, struct symb_s*argv)
}


void compile_arith_pow(char*label, long wid,
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) {
fprintf(stderr, "%s .arith/pow has wrong number of symbols\n", label);
char *suffix = "";
if (signed_flag) suffix = ".s";
fprintf(stderr, "%s .arith/pow%s has wrong number of "
"symbols\n", label, suffix);
compile_errors += 1;
return;
}

vvp_arith_ *arith = new vvp_arith_pow(wid);
vvp_arith_ *arith = new vvp_arith_pow(wid, signed_flag);
make_arith(arith, label, argc, argv);
}

Expand Down
2 changes: 1 addition & 1 deletion vvp/compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ extern void compile_part_select_var(char*label, char*src,
* This is called by the parser to make the various arithmetic and
* comparison functors.
*/
extern void compile_arith_pow(char*label, long width,
extern void compile_arith_pow(char*label, long width, 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);
Expand Down
1 change: 1 addition & 0 deletions vvp/lexor.lex
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
".arith/mult.r" { return K_ARITH_MULT_R; }
".arith/pow" { return K_ARITH_POW; }
".arith/pow.r" { return K_ARITH_POW_R; }
".arith/pow.s" { return K_ARITH_POW_S; }
".arith/sub" { return K_ARITH_SUB; }
".arith/sub.r" { return K_ARITH_SUB_R; }
".arith/sum" { return K_ARITH_SUM; }
Expand Down
9 changes: 7 additions & 2 deletions vvp/parse.y
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ 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_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
%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_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
Expand Down Expand Up @@ -288,14 +288,19 @@ statement

| T_LABEL K_ARITH_POW T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5;
compile_arith_pow($1, $3, obj.cnt, obj.vect);
compile_arith_pow($1, $3, false, obj.cnt, obj.vect);
}

| T_LABEL K_ARITH_POW_R T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5;
compile_arith_pow_r($1, obj.cnt, obj.vect);
}

| T_LABEL K_ARITH_POW_S T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5;
compile_arith_pow($1, $3, true, obj.cnt, obj.vect);
}

| T_LABEL K_ARITH_SUB T_NUMBER ',' symbols ';'
{ struct symbv_s obj = $5;
compile_arith_sub($1, $3, obj.cnt, obj.vect);
Expand Down
26 changes: 26 additions & 0 deletions vvp/vvp_net.cc
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,32 @@ 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, unsigned long&val)
{
unsigned long res = 0;
Expand Down
2 changes: 2 additions & 0 deletions vvp/vvp_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ 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
Expand Down

0 comments on commit 331faa2

Please sign in to comment.