Add unsigned bit based power support to normal expressions.

This patch adds bit based power support to normal expressions.
It also pushes the constant unsigned bit based calculation to
the runtime until the bit based method can be copied to the
compiler. Continuous assignments also need to use this type
of calculation.
This commit is contained in:
Cary R 2008-02-04 19:43:50 -08:00 committed by Stephen Williams
parent 1b410f0c7d
commit e82293c981
11 changed files with 97 additions and 14 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -185,12 +185,6 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
case 'p':
tmp = new NetEBPow(op_, lp, rp);
tmp->set_line(*this);
if (tmp->expr_type() == IVL_VT_LOGIC) {
cerr << get_fileline() << ": sorry: Power operator is not "
"currently supported on unsigned bit based values."
<< endl;
des->errors += 1;
}
break;
case '*':

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -979,7 +979,11 @@ NetExpr* NetEBPow::eval_tree(int prune_to_width)
verinum lval = lc->value();
verinum rval = rc->value();
return new NetEConst( pow(lval,rval) );
if (lc->has_sign() || rc->has_sign()) {
return new NetEConst( pow(lval,rval) );
} else {
return 0; // For now force this to the runtime.
}
}
@ -1634,4 +1638,3 @@ NetEConst* NetEUReduce::eval_tree(int prune_to_width)
return new NetEConst(verinum(res, 1));
}

View File

@ -1783,6 +1783,7 @@ void dll_target::lpm_pow(const NetPow*net)
assert(obj->scope);
unsigned wid = net->width_r();
obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
obj->width = wid;

View File

@ -1234,7 +1234,8 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
break;
case 'p':
assert(0);
fprintf(vvp_out, " %%pow%s %u, %u, %u;\n", sign_string,
lv.base, rv.base, wid);
break;
default:
@ -2394,4 +2395,3 @@ struct vector_info draw_eval_expr(ivl_expr_t exp, int stuff_ok_flag)
{
return draw_eval_expr_wid(exp, ivl_expr_width(exp), stuff_ok_flag);
}

View File

@ -1709,7 +1709,7 @@ static void draw_lpm_add(ivl_lpm_t net)
if (dto == IVL_VT_REAL)
type = "pow.r";
else
assert(0); /* Not supported for bit based signals, */
assert(0); /* No support for bit based signals. */
break;
default:
assert(0);

View File

@ -114,6 +114,7 @@ extern bool of_NOR(vthread_t thr, vvp_code_t code);
extern bool of_NORR(vthread_t thr, vvp_code_t code);
extern bool of_OR(vthread_t thr, vvp_code_t code);
extern bool of_ORR(vthread_t thr, vvp_code_t code);
extern bool of_POW(vthread_t thr, vvp_code_t code);
extern bool of_POW_WR(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);

View File

@ -161,6 +161,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%nor/r", of_NORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%or", of_OR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%or/r", of_ORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pow", of_POW, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pow/wr", of_POW_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%release/net",of_RELEASE_NET,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
{ "%release/reg",of_RELEASE_REG,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },

View File

@ -570,6 +570,12 @@ and the <dst> is a writable scalar. The <dst> gets the value of the
or of all the bits of the src vector.
* %pow <bit-l>, <bit-r>
This opcode raises <bit-l> (unsigned) to the power of <bit-r> (unsigned).
The result replaces the left operand.
* %pow/wr <bit-l>, <bit-r>
This opcode raises <bit-l> (real) to the power of <bit-r> (real). The

View File

@ -3172,6 +3172,77 @@ bool of_NOR(vthread_t thr, vvp_code_t cp)
return true;
}
/*
* Basic idea from "Introduction to Programming using SML" by
* Michael R. Hansen and Hans Rischel page 261 and "Seminumerical
* Algorithms, Third Edition" by Donald E. Knuth section 4.6.3.
*/
static vvp_vector2_t calc_uspow(vvp_vector2_t x, vvp_vector2_t y)
{
/* If we have a zero exponent just return a 1 bit wide 1. */
if (y == vvp_vector2_t(0L, 1)) {
return vvp_vector2_t(1L, 1);
}
/* Is the value odd? */
if (y.value(0) == 1) {
y.set_bit(0, 0); // A quick subtract by 1.
vvp_vector2_t res = x * calc_uspow(x, y);
res.trim(); // To keep the size under control trim extra zeros.
return res;
}
y >>= 1; // A fast divide by two. We know the LSB is zero.
vvp_vector2_t z = calc_uspow(x, y);
vvp_vector2_t res = z * z;
res.trim(); // To keep the size under control trim extra zeros.
return res;
}
bool of_POW(vthread_t thr, vvp_code_t cp)
{
assert(cp->bit_idx[0] >= 4);
unsigned idx = cp->bit_idx[0];
unsigned idy = cp->bit_idx[1];
unsigned wid = cp->number;
vvp_vector4_t xval = vthread_bits_to_vector(thr, idx, wid);
vvp_vector4_t yval = vthread_bits_to_vector(thr, idy, wid);
/* If we have an X or Z in the arguments return X. */
if (xval.has_xz() || yval.has_xz()) {
for (unsigned idx = 0 ; idx < cp->number ; idx += 1)
thr_put_bit(thr, cp->bit_idx[0]+idx, BIT4_X);
return true;
}
/* To make the result more manageable trim off the extra bits. */
unsigned min_x_wid = wid;
while (xval.value(min_x_wid-1) == BIT4_0 && min_x_wid > 0) min_x_wid -= 1;
xval.resize(min_x_wid);
unsigned min_y_wid = wid;
while (yval.value(min_y_wid-1) == BIT4_0 && min_y_wid > 0) min_y_wid -= 1;
yval.resize(min_y_wid);
vvp_vector2_t result = calc_uspow(vvp_vector2_t(xval),
vvp_vector2_t(yval));
/* If the result is too small zero pad it. */
if (result.size() < wid) {
for (unsigned idx = wid-1; idx >= result.size(); idx -= 1)
thr_put_bit(thr, cp->bit_idx[0]+idx, BIT4_0);
wid = result.size();
}
/* Copy only what we need of the result. */
for (unsigned idx = 0; idx < wid; idx += 1)
thr_put_bit(thr, cp->bit_idx[0]+idx,
result.value(idx) ? BIT4_1 : BIT4_0);
return true;
}
bool of_POW_WR(vthread_t thr, vvp_code_t cp)
{
double l = thr->words[cp->bit_idx[0]].w_real;

View File

@ -1050,6 +1050,11 @@ vvp_vector2_t::~vvp_vector2_t()
if (vec_) delete[]vec_;
}
void vvp_vector2_t::trim()
{
while (value(wid_-1) == 0 && wid_ > 1) wid_ -= 1;
}
unsigned vvp_vector2_t::size() const
{
return wid_;
@ -2473,4 +2478,3 @@ vvp_bit4_t compare_gtge_signed(const vvp_vector4_t&a,
else
return BIT4_0;
}

View File

@ -307,6 +307,8 @@ class vvp_vector2_t {
unsigned size() const;
int value(unsigned idx) const;
void set_bit(unsigned idx, int bit);
// Make the size just big enough to hold the first 1 bit.
void trim();
private:
enum { BITS_PER_WORD = 8 * sizeof(unsigned long) };