From e82293c981aaf74a00d90cb4545040ae9b1ee5f8 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 4 Feb 2008 19:43:50 -0800 Subject: [PATCH] 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. --- elab_expr.cc | 8 +---- eval_tree.cc | 9 ++++-- t-dll.cc | 1 + tgt-vvp/eval_expr.c | 4 +-- tgt-vvp/vvp_scope.c | 2 +- vvp/codes.h | 1 + vvp/compile.cc | 1 + vvp/opcodes.txt | 6 ++++ vvp/vthread.cc | 71 +++++++++++++++++++++++++++++++++++++++++++++ vvp/vvp_net.cc | 6 +++- vvp/vvp_net.h | 2 ++ 11 files changed, 97 insertions(+), 14 deletions(-) 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) };