diff --git a/src/opmath.cpp b/src/opmath.cpp index bbc6e35c..4df50a1f 100644 --- a/src/opmath.cpp +++ b/src/opmath.cpp @@ -11,15 +11,16 @@ int32_t op_divide(int32_t dividend, int32_t divisor) { // Adjust division to floor toward negative infinity, // not truncate toward zero - return dividend / divisor - ((dividend % divisor < 0) != (divisor < 0)); + int32_t remainder = dividend % divisor; + return dividend / divisor - (remainder != 0 && (remainder < 0) != (divisor < 0)); } int32_t op_modulo(int32_t dividend, int32_t divisor) { - int32_t remainder = dividend % divisor; - // Adjust modulo to have the sign of the divisor, // not the sign of the dividend - return remainder + divisor * ((remainder < 0) != (divisor < 0)); + return static_cast( + dividend - static_cast(op_divide(dividend, divisor)) * divisor + ); } int32_t op_exponent(int32_t base, uint32_t power) { diff --git a/test/asm/div-negative.asm b/test/asm/div-negative.asm new file mode 100644 index 00000000..fc182707 --- /dev/null +++ b/test/asm/div-negative.asm @@ -0,0 +1,47 @@ +MACRO test + def num = \1 + def den = \2 + def quo = num / den + def rem = num % den + def rev = quo * den + rem + assert num == rev + println "{ 11d:num} (${08x:num}) / { 11d:den} (${08x:den}) = { 11d:quo} (${08x:quo}) R { 11d:rem} (${08x:rem})" +ENDM + +test $8000_0000, $8000_0000 +test $8000_0000, $c000_0000 +test $8000_0000, $f000_0000 +test $8000_0000, $f800_0000 +test $8000_0000, $ff00_0000 + +test $c000_0000, $8000_0000 +test $c000_0000, $c000_0000 +test $c000_0000, $f000_0000 +test $c000_0000, $f800_0000 +test $c000_0000, $ff00_0000 + +test $f800_0000, $8000_0000 +test $f800_0000, $c000_0000 +test $f800_0000, $f000_0000 +test $f800_0000, $f800_0000 +test $f800_0000, $ff00_0000 + +test $0000_0000, $8000_0000 +test $0000_0000, $c000_0000 +test $0000_0000, $f000_0000 +test $0000_0000, $f800_0000 +test $0000_0000, $ff00_0000 + +test $0080_0000, $ff80_0000 + +test $0300_0000, $fd00_0000 +test $0300_0000, $ff00_0000 +test $0300_0000, $ff80_0000 + +test $6000_0000, $fd00_0000 +test $6000_0000, $ff00_0000 +test $6000_0000, $ff80_0000 + +test $7f00_0000, $fd00_0000 +test $7f00_0000, $ff00_0000 +test $7f00_0000, $ff80_0000 diff --git a/test/asm/div-negative.out b/test/asm/div-negative.out new file mode 100644 index 00000000..64be3698 --- /dev/null +++ b/test/asm/div-negative.out @@ -0,0 +1,30 @@ +-2147483648 ($80000000) / -2147483648 ($80000000) = 1 ($00000001) R 0 ($00000000) +-2147483648 ($80000000) / -1073741824 ($c0000000) = 2 ($00000002) R 0 ($00000000) +-2147483648 ($80000000) / -268435456 ($f0000000) = 8 ($00000008) R 0 ($00000000) +-2147483648 ($80000000) / -134217728 ($f8000000) = 16 ($00000010) R 0 ($00000000) +-2147483648 ($80000000) / -16777216 ($ff000000) = 128 ($00000080) R 0 ($00000000) +-1073741824 ($c0000000) / -2147483648 ($80000000) = 0 ($00000000) R -1073741824 ($c0000000) +-1073741824 ($c0000000) / -1073741824 ($c0000000) = 1 ($00000001) R 0 ($00000000) +-1073741824 ($c0000000) / -268435456 ($f0000000) = 4 ($00000004) R 0 ($00000000) +-1073741824 ($c0000000) / -134217728 ($f8000000) = 8 ($00000008) R 0 ($00000000) +-1073741824 ($c0000000) / -16777216 ($ff000000) = 64 ($00000040) R 0 ($00000000) + -134217728 ($f8000000) / -2147483648 ($80000000) = 0 ($00000000) R -134217728 ($f8000000) + -134217728 ($f8000000) / -1073741824 ($c0000000) = 0 ($00000000) R -134217728 ($f8000000) + -134217728 ($f8000000) / -268435456 ($f0000000) = 0 ($00000000) R -134217728 ($f8000000) + -134217728 ($f8000000) / -134217728 ($f8000000) = 1 ($00000001) R 0 ($00000000) + -134217728 ($f8000000) / -16777216 ($ff000000) = 8 ($00000008) R 0 ($00000000) + 0 ($00000000) / -2147483648 ($80000000) = 0 ($00000000) R 0 ($00000000) + 0 ($00000000) / -1073741824 ($c0000000) = 0 ($00000000) R 0 ($00000000) + 0 ($00000000) / -268435456 ($f0000000) = 0 ($00000000) R 0 ($00000000) + 0 ($00000000) / -134217728 ($f8000000) = 0 ($00000000) R 0 ($00000000) + 0 ($00000000) / -16777216 ($ff000000) = 0 ($00000000) R 0 ($00000000) + 8388608 ($00800000) / -8388608 ($ff800000) = -1 ($ffffffff) R 0 ($00000000) + 50331648 ($03000000) / -50331648 ($fd000000) = -1 ($ffffffff) R 0 ($00000000) + 50331648 ($03000000) / -16777216 ($ff000000) = -3 ($fffffffd) R 0 ($00000000) + 50331648 ($03000000) / -8388608 ($ff800000) = -6 ($fffffffa) R 0 ($00000000) + 1610612736 ($60000000) / -50331648 ($fd000000) = -32 ($ffffffe0) R 0 ($00000000) + 1610612736 ($60000000) / -16777216 ($ff000000) = -96 ($ffffffa0) R 0 ($00000000) + 1610612736 ($60000000) / -8388608 ($ff800000) = -192 ($ffffff40) R 0 ($00000000) + 2130706432 ($7f000000) / -50331648 ($fd000000) = -43 ($ffffffd5) R -33554432 ($fe000000) + 2130706432 ($7f000000) / -16777216 ($ff000000) = -127 ($ffffff81) R 0 ($00000000) + 2130706432 ($7f000000) / -8388608 ($ff800000) = -254 ($ffffff02) R 0 ($00000000) diff --git a/test/link/patch-diagnostics.asm b/test/link/patch-diagnostics.asm index b11676b9..63960c7f 100644 --- a/test/link/patch-diagnostics.asm +++ b/test/link/patch-diagnostics.asm @@ -1,6 +1,7 @@ def fzero equs "startof(\"test\")" section "test", rom0 ld a, $8000_0000 / (fzero - 1) +ld a, $8000_0000 / (fzero - 2) ld a, 1 << (fzero - 1) ld a, 1 << (fzero + 32) ld a, (fzero - 1) >> 1 diff --git a/test/link/patch-diagnostics.out b/test/link/patch-diagnostics.out index 4e17c608..7183b51b 100644 --- a/test/link/patch-diagnostics.out +++ b/test/link/patch-diagnostics.out @@ -1,16 +1,18 @@ warning: Shifting right by large amount 32 [-Wshift-amount] + at patch-diagnostics.asm(11) +warning: Shifting right by negative amount -1 [-Wshift-amount] at patch-diagnostics.asm(10) -warning: Shifting right by negative amount -1 [-Wshift-amount] - at patch-diagnostics.asm(9) warning: Shifting right by large amount 32 [-Wshift-amount] - at patch-diagnostics.asm(8) + at patch-diagnostics.asm(9) warning: Shifting right by negative amount -1 [-Wshift-amount] - at patch-diagnostics.asm(7) + at patch-diagnostics.asm(8) warning: Shifting right negative value -1 [-Wshift] - at patch-diagnostics.asm(6) + at patch-diagnostics.asm(7) warning: Shifting left by large amount 32 [-Wshift-amount] - at patch-diagnostics.asm(5) + at patch-diagnostics.asm(6) warning: Shifting left by negative amount -1 [-Wshift-amount] + at patch-diagnostics.asm(5) +warning: Value $40000000 is not 8-bit [-Wtruncation] at patch-diagnostics.asm(4) warning: Division of -2147483648 by -1 yields -2147483648 [-Wdiv] at patch-diagnostics.asm(3)