Function attributes should be placed in the function declaration, not definition.
61 lines
2.0 KiB
C++
61 lines
2.0 KiB
C++
#include "mtl/target.hpp"
|
|
|
|
#include "mtl/fixed.hpp"
|
|
|
|
TARGET_ARM_MODE
|
|
|
|
namespace mtl {
|
|
|
|
fixed fixed::operator/(fixed rhs) const {
|
|
int32_t raw_result;
|
|
asm(
|
|
// This division implementation has two methods it can use.
|
|
// The fastest uses a left shift followed by a single division. The value is shifted
|
|
// first to preserve the decimal part. Unfortunately, this means large numerators
|
|
// will cause the operation to overflow. In this case, a compatible method will be
|
|
// used. This method uses two divisions, one to calculate the integral quotient,
|
|
// and one to calculate the decimal part. Both these methods work for negative numbers as well.
|
|
".arm;"
|
|
"movs r1, %[d];" // Load numerator and denominator, and check if negative or zero
|
|
"beq 4f;"
|
|
"movs r0, %[n];"
|
|
"blt 1f;"
|
|
"tst r0, #0x7e000000;" // Check if the numerator is large enough to overflow
|
|
"bne 3f;"
|
|
"b 2f;"
|
|
"1:" // check_negative
|
|
"mvn r2, r0;" // Check if the numerator is large enough to overflow.
|
|
"tst r2, #0x7e000000;"
|
|
"bne 3f;"
|
|
"2:" // fast_div // Fast method
|
|
"lsl r0, #6;" // Shift first to avoid truncation
|
|
"swi #0x60000;" // GBA Div syscall
|
|
"mov %[res], r0;"
|
|
"b 5f;"
|
|
"3:" // compat_div // Compatible method
|
|
"swi #0x60000;" // Compute quotient and shift
|
|
"lsl r2, r0, #6;"
|
|
"mov r0, r1;" // Div syscall puts the modulus in r1, use it as the numerator
|
|
"lsr r1, %[d], #6;" // Load the denominator again, shifted right to calculate decimal part
|
|
"swi #0x60000;"
|
|
"mov %[res], r2;" // Calculate the final result
|
|
"add %[res], r0;"
|
|
"b 5f;"
|
|
"4:" // zero_div
|
|
"teq %[n], %[d];" // Set result to largest possible negative/positive value.
|
|
"movmi %[res], #0x80000000;"
|
|
"movpl %[res], #0x7FFFFFFF;"
|
|
"5:"
|
|
: [res] "=r" (raw_result)
|
|
: [n] "r" (x),
|
|
[d] "r" (rhs.x)
|
|
: "r0", "r1", "r2", "r3"
|
|
);
|
|
return from_raw(raw_result);
|
|
}
|
|
|
|
} // namespace mtl
|
|
|
|
TARGET_END_MODE
|
|
|