From 47d1d981d5e87160223860d3f5389efab8269171 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 5 Feb 2008 17:12:21 -0800 Subject: [PATCH 1/2] Mangle the scope for user functions in a continuous assignment. User functions called in a continuous assignment were not getting their scope mangled. This is needed to handle arrayed instances and possibly other things. --- tgt-vvp/vvp_scope.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index b2f73350e..c3bb31c98 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -2094,7 +2094,7 @@ static void draw_lpm_ufunc(ivl_lpm_t net) const char*dly = draw_lpm_output_delay(net); fprintf(vvp_out, "L_%p%s .ufunc TD_%s, %u", net, dly, - ivl_scope_name(def), + vvp_mangle_id(ivl_scope_name(def)), ivl_lpm_width(net)); /* Print all the net signals that connect to the input of the From 85229a6cdc3f0407d57d853f02d30fe6a3433023 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 5 Feb 2008 19:09:30 -0800 Subject: [PATCH 2/2] Add unsigned bit based power to continuous assignments. This patch adds the power operator for unsigned bit based values in a continuous assignment. It also refactors the power code for normal expressions and continuous assignments. --- elab_net.cc | 10 +++++----- tgt-vvp/vvp_scope.c | 4 +++- vvp/arith.cc | 31 ++++++++++++++++++++++++++++++ vvp/arith.h | 8 ++++++++ vvp/compile.cc | 16 +++++++++++++++ vvp/compile.h | 2 ++ vvp/lexor.lex | 1 + vvp/parse.y | 7 ++++++- vvp/vthread.cc | 47 +++++++-------------------------------------- vvp/vvp_net.cc | 27 ++++++++++++++++++++++++++ vvp/vvp_net.h | 2 ++ 11 files changed, 108 insertions(+), 47 deletions(-) diff --git a/elab_net.cc b/elab_net.cc index b2f639bcc..6ee8add8a 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1139,17 +1139,17 @@ NetNet* PEBinary::elaborate_net_pow_(Design*des, NetScope*scope, return 0; } + // 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) { - cerr << get_fileline() << ": sorry: Bit based power (**) is " + 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; } - // The power is signed if both its operands are signed. - bool arith_is_signed = lsig->get_signed() && rsig->get_signed(); - unsigned rwidth = lwidth; if (rwidth == 0) { /* Reals are always 1 wide and lsig/rsig types match here. */ diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index c3bb31c98..fbb4acf44 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1708,8 +1708,10 @@ 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 - assert(0); /* No support for bit based signals. */ + type = "pow"; break; default: assert(0); diff --git a/vvp/arith.cc b/vvp/arith.cc index 27d94720f..a984d68d6 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -397,6 +397,37 @@ void vvp_arith_mult::wide(vvp_ipoint_t base, bool push) } #endif + +// Power + +vvp_arith_pow::vvp_arith_pow(unsigned wid) +: vvp_arith_(wid) +{ +} + +vvp_arith_pow::~vvp_arith_pow() +{ +} + +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_); + + if (a2.is_NaN() || b2.is_NaN()) { + vvp_send_vec4(ptr.ptr()->out, x_val_); + return; + } + + vvp_vector2_t result = pow(a2, b2); + + vvp_vector4_t res4 = vector2_to_vector4(result, wid_); + vvp_send_vec4(ptr.ptr()->out, res4); +} + + // Addition vvp_arith_sum::vvp_arith_sum(unsigned wid) diff --git a/vvp/arith.h b/vvp/arith.h index 4579a923d..bd238edc3 100644 --- a/vvp/arith.h +++ b/vvp/arith.h @@ -159,6 +159,14 @@ class vvp_arith_mult : public vvp_arith_ { void wide_(vvp_net_ptr_t ptr); }; +class vvp_arith_pow : public vvp_arith_ { + + public: + explicit vvp_arith_pow(unsigned wid); + ~vvp_arith_pow(); + void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit); +}; + class vvp_arith_sub : public vvp_arith_ { public: diff --git a/vvp/compile.cc b/vvp/compile.cc index c2f56e18c..e7337d8bc 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -997,6 +997,22 @@ void compile_arith_mult_r(char*label, unsigned argc, struct symb_s*argv) make_arith(arith, label, argc, argv); } + +void compile_arith_pow(char*label, long wid, + unsigned argc, struct symb_s*argv) +{ + assert( wid > 0 ); + + if (argc != 2) { + fprintf(stderr, "%s .arith/pow has wrong number of symbols\n", label); + compile_errors += 1; + return; + } + + vvp_arith_ *arith = new vvp_arith_pow(wid); + make_arith(arith, label, argc, argv); +} + void compile_arith_pow_r(char*label, unsigned argc, struct symb_s*argv) { if (argc != 2) { diff --git a/vvp/compile.h b/vvp/compile.h index 44e82e4a7..92270a794 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -146,6 +146,8 @@ 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, + 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, diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 9af366a34..93641eb9d 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -94,6 +94,7 @@ ".arith/mod.r" { return K_ARITH_MOD_R; } ".arith/mult" { return K_ARITH_MULT; } ".arith/mult.r" { return K_ARITH_MULT_R; } +".arith/pow" { return K_ARITH_POW; } ".arith/pow.r" { return K_ARITH_POW_R; } ".arith/sub" { return K_ARITH_SUB; } ".arith/sub.r" { return K_ARITH_SUB_R; } diff --git a/vvp/parse.y b/vvp/parse.y index 6cdb62549..7fda09d4d 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -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_R +%token K_ARITH_SUM K_ARITH_SUM_R K_ARITH_POW K_ARITH_POW_R %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 @@ -286,6 +286,11 @@ statement compile_arith_mult_r($1, obj.cnt, obj.vect); } + | T_LABEL K_ARITH_POW T_NUMBER ',' symbols ';' + { struct symbv_s obj = $5; + compile_arith_pow($1, $3, 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); diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 3872683b8..1190b71bf 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -3172,33 +3172,6 @@ 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); @@ -3206,27 +3179,21 @@ bool of_POW(vthread_t thr, vvp_code_t cp) 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); + vvp_vector2_t xv2 = vvp_vector2_t(vthread_bits_to_vector(thr, idx, wid)); + vvp_vector2_t yv2 = vvp_vector2_t(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) + if (xv2.is_NaN() || yv2.is_NaN()) { + for (unsigned idx = 0 ; idx < wid ; 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); + xv2.trim(); + yv2.trim(); - - vvp_vector2_t result = calc_uspow(vvp_vector2_t(xval), - vvp_vector2_t(yval)); + vvp_vector2_t result = pow(xv2, yv2); /* If the result is too small zero pad it. */ if (result.size() < wid) { diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 35b10d2f0..2da64524a 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1094,6 +1094,33 @@ bool vvp_vector2_t::is_NaN() const return wid_ == 0; } +/* + * 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. + */ +vvp_vector2_t pow(const 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 * pow(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 = pow(x, y); + vvp_vector2_t res = z * z; + res.trim(); // To keep the size under control trim extra zeros. + return res; +} + static void multiply_long(unsigned long a, unsigned long b, unsigned long&low, unsigned long&high) { diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index ef4cee578..7f32ade93 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -328,6 +328,8 @@ extern vvp_vector2_t operator + (const vvp_vector2_t&, const vvp_vector2_t&); extern vvp_vector2_t operator * (const vvp_vector2_t&, const vvp_vector2_t&); extern vvp_vector2_t operator / (const vvp_vector2_t&, const vvp_vector2_t&); extern vvp_vector2_t operator % (const vvp_vector2_t&, const vvp_vector2_t&); + +vvp_vector2_t pow(const vvp_vector2_t&, vvp_vector2_t&); extern vvp_vector4_t vector2_to_vector4(const vvp_vector2_t&, unsigned wid); /* A c4string is of the form C4<...> where ... are bits. */ extern vvp_vector4_t c4string_to_vector4(const char*str);