diff --git a/vvp/codes.h b/vvp/codes.h index 0e634a95b..eff9a2b14 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -135,6 +135,7 @@ 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_S(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 167c8d94a..fa569d90e 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -178,6 +178,7 @@ const static struct opcode_table_s opcode_table[] = { { "%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/s", of_POW_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%pow/wr", of_POW_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index c9419c405..db3de0c4e 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -653,10 +653,14 @@ and the is a writable scalar. The gets the value of the or of all the bits of the src vector. -* %pow , +* %pow , , +* %pow/s , , -This opcode raises (unsigned) to the power of (unsigned). -The result replaces the left operand. +The %pow opcode raises (unsigned) to the power of +(unsigned) giving an exact integer result. The %pow/s opcode does +the same for signed values, except it uses the double pow() function +to calculate the result so may not produce exact results. The result +replaces the left operand. * %pow/wr , diff --git a/vvp/vthread.cc b/vvp/vthread.cc index ddeda1c11..250a43d7f 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -3838,6 +3838,36 @@ bool of_POW(vthread_t thr, vvp_code_t cp) return true; } +bool of_POW_S(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 xv = vthread_bits_to_vector(thr, idx, wid); + vvp_vector4_t yv = vthread_bits_to_vector(thr, idy, wid); + + /* If we have an X or Z in the arguments return X. */ + if (xv.has_xz() || yv.has_xz()) { + for (unsigned jdx = 0 ; jdx < wid ; jdx += 1) + thr_put_bit(thr, cp->bit_idx[0]+jdx, BIT4_X); + return true; + } + + /* Calculate the result using the double pow() function. */ + double xd, yd; + vector4_to_value(xv, xd, true); + vector4_to_value(yv, yd, true); + vvp_vector4_t res = vvp_vector4_t(wid, pow(xd, yd)); + + /* Copy the result. */ + for (unsigned jdx = 0; jdx < wid; jdx += 1) + thr_put_bit(thr, cp->bit_idx[0]+jdx, res.value(jdx)); + + return true; +} + bool of_POW_WR(vthread_t thr, vvp_code_t cp) { double l = thr->words[cp->bit_idx[0]].w_real;