diff --git a/Documentation/developer/guide/vvp/opcodes.rst b/Documentation/developer/guide/vvp/opcodes.rst index dd7e6cffc..3303e8b50 100644 --- a/Documentation/developer/guide/vvp/opcodes.rst +++ b/Documentation/developer/guide/vvp/opcodes.rst @@ -812,6 +812,10 @@ result is pushed back on the vec4 stack. This opcode multiplies two real words together. +* %neg/wr + +This opcode negates the real value on top of the real stack. + * %nand Perform the bitwise NAND of two vec4 vectors, and push the result. Each diff --git a/ivtest/ivltests/real_unary_minus_inf.v b/ivtest/ivltests/real_unary_minus_inf.v new file mode 100644 index 000000000..543644d68 --- /dev/null +++ b/ivtest/ivltests/real_unary_minus_inf.v @@ -0,0 +1,31 @@ +// Check that unary real minus preserves infinities. + +module test; + + reg failed; + real inf; + real result; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %h, got %h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + inf = $bitstoreal(64'h7ff0000000000000); + + result = -inf; + `check($realtobits(result), 64'hfff0000000000000); + + result = -result; + `check($realtobits(result), 64'h7ff0000000000000); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/real_unary_minus_nan.v b/ivtest/ivltests/real_unary_minus_nan.v new file mode 100644 index 000000000..f9ea679aa --- /dev/null +++ b/ivtest/ivltests/real_unary_minus_nan.v @@ -0,0 +1,31 @@ +// Check that unary real minus preserves NaN bits. + +module test; + + reg failed; + real nan; + real result; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %h, got %h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + nan = $bitstoreal(64'h7ff8000000000001); + + result = -nan; + `check($realtobits(result), 64'hfff8000000000001); + + result = -result; + `check($realtobits(result), 64'h7ff8000000000001); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/real_unary_minus_zero.v b/ivtest/ivltests/real_unary_minus_zero.v new file mode 100644 index 000000000..1c92bc27d --- /dev/null +++ b/ivtest/ivltests/real_unary_minus_zero.v @@ -0,0 +1,31 @@ +// Check that unary real minus preserves the sign of zero. + +module test; + + reg failed; + real zero; + real result; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %h, got %h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + zero = 0.0; + + result = -zero; + `check($realtobits(result), 64'h8000000000000000); + + result = -result; + `check($realtobits(result), 64'h0000000000000000); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 7689bca81..9655c20df 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -214,6 +214,9 @@ pv_wr_fn_vec4 vvp_tests/pv_wr_fn_vec4.json queue_fail vvp_tests/queue_fail.json readmem-invalid vvp_tests/readmem-invalid.json real_negative_zero vvp_tests/real_negative_zero.json +real_unary_minus_inf vvp_tests/real_unary_minus_inf.json +real_unary_minus_nan vvp_tests/real_unary_minus_nan.json +real_unary_minus_zero vvp_tests/real_unary_minus_zero.json scaled_real vvp_tests/scaled_real.json scan-invalid vvp_tests/scan-invalid.json sdf_interconnect1 vvp_tests/sdf_interconnect1.json diff --git a/ivtest/vvp_tests/real_unary_minus_inf.json b/ivtest/vvp_tests/real_unary_minus_inf.json new file mode 100644 index 000000000..15f4203e7 --- /dev/null +++ b/ivtest/vvp_tests/real_unary_minus_inf.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "real_unary_minus_inf.v" +} diff --git a/ivtest/vvp_tests/real_unary_minus_nan.json b/ivtest/vvp_tests/real_unary_minus_nan.json new file mode 100644 index 000000000..4dde327de --- /dev/null +++ b/ivtest/vvp_tests/real_unary_minus_nan.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "real_unary_minus_nan.v" +} diff --git a/ivtest/vvp_tests/real_unary_minus_zero.json b/ivtest/vvp_tests/real_unary_minus_zero.json new file mode 100644 index 000000000..27bf853c9 --- /dev/null +++ b/ivtest/vvp_tests/real_unary_minus_zero.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "real_unary_minus_zero.v" +} diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index 0c685624f..1a996b814 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -453,9 +453,8 @@ static void draw_unary_real(ivl_expr_t expr) } if (ivl_expr_opcode(expr) == '-') { - fprintf(vvp_out, " %%pushi/real 0, 0; load 0.0\n"); draw_eval_real(sube); - fprintf(vvp_out, " %%sub/wr;\n"); + fprintf(vvp_out, " %%neg/wr;\n"); return; } diff --git a/vvp/codes.h b/vvp/codes.h index 94a4f26b5..00594e1f0 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -164,6 +164,7 @@ extern bool of_MOD_WR(vthread_t thr, vvp_code_t code); extern bool of_MUL(vthread_t thr, vvp_code_t code); extern bool of_MULI(vthread_t thr, vvp_code_t code); extern bool of_MUL_WR(vthread_t thr, vvp_code_t code); +extern bool of_NEG_WR(vthread_t thr, vvp_code_t code); extern bool of_NAND(vthread_t thr, vvp_code_t code); extern bool of_NANDR(vthread_t thr, vvp_code_t code); extern bool of_NEW_COBJ(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index d41c19d72..fa5391717 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -219,6 +219,7 @@ static const struct opcode_table_s opcode_table[] = { { "%muli", of_MULI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%nand", of_NAND, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%nand/r", of_NANDR, 0, {OA_NONE, OA_NONE, OA_NONE} }, + { "%neg/wr", of_NEG_WR, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%new/cobj", of_NEW_COBJ, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} }, { "%new/darray",of_NEW_DARRAY,2, {OA_BIT1, OA_STRING,OA_NONE} }, { "%noop", of_NOOP, 0, {OA_NONE, OA_NONE, OA_NONE} }, diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 98cd41a99..2b171111f 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -4288,6 +4288,15 @@ bool of_MOD_WR(vthread_t thr, vvp_code_t) return true; } +/* + * %neg/wr + */ +bool of_NEG_WR(vthread_t thr, vvp_code_t) +{ + thr->poke_real(0, -thr->peek_real(0)); + return true; +} + /* * %pad/s */