diff --git a/elab_expr.cc b/elab_expr.cc index f185b641f..e200e29eb 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -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 '*': diff --git a/eval_tree.cc b/eval_tree.cc index 28e7f32de..13926ea0f 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -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)); } - diff --git a/t-dll.cc b/t-dll.cc index 274da4966..958cbdc46 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -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; diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 0890e860f..70cc14c74 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -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); } - diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index c064b365f..b2f73350e 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -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); diff --git a/vvp/codes.h b/vvp/codes.h index 855b55d9d..26343bdc1 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -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); diff --git a/vvp/compile.cc b/vvp/compile.cc index 811f178f5..c2f56e18c 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -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} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index ec7791fd9..117e5c83b 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -570,6 +570,12 @@ and the is a writable scalar. The gets the value of the or of all the bits of the src vector. +* %pow , + +This opcode raises (unsigned) to the power of (unsigned). +The result replaces the left operand. + + * %pow/wr , This opcode raises (real) to the power of (real). The diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 82df48850..3872683b8 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -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; diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 4bce71c28..35b10d2f0 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -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; } - diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 2349df533..ef4cee578 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -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) };