diff --git a/CHANGES b/CHANGES index c67de2735..eb2da13e2 100644 --- a/CHANGES +++ b/CHANGES @@ -51,6 +51,7 @@ Misc: - PSP2: Add fit-to-height screen mode - GBA Video: Remove old slow path fallback - GBA Video: Optimize sprite drawing + - GBA BIOS: Use custom ArcTan, not relying on OS 0.4.1: (2016-07-11) Bugfixes: diff --git a/src/gba/bios.c b/src/gba/bios.c index c81c50596..dcb2cf42f 100644 --- a/src/gba/bios.c +++ b/src/gba/bios.c @@ -265,6 +265,52 @@ static void _Div(struct GBA* gba, int32_t num, int32_t denom) { } } +static int16_t _ArcTan(int16_t i) { + int32_t a = -((i * i) >> 14); + int32_t b = ((0xA9 * a) >> 14) + 0x390; + b = ((b * a) >> 14) + 0x91C; + b = ((b * a) >> 14) + 0xFB6; + b = ((b * a) >> 14) + 0x16AA; + b = ((b * a) >> 14) + 0x2081; + b = ((b * a) >> 14) + 0x3651; + b = ((b * a) >> 14) + 0xA2F9; + return (i * b) >> 16; +} + +static int16_t _ArcTan2(int16_t x, int16_t y) { + if (!y) { + if (x >= 0) { + return 0; + } + return 0x8000; + } + if (!x) { + if (y >= 0) { + return 0x4000; + } + return 0xC000; + } + if (y >= 0) { + if (x >= 0) { + if (x >= y) { + return _ArcTan((y << 14)/ x); + } + } else if (-x >= y) { + return _ArcTan((y << 14) / x) + 0x8000; + } + return 0x4000 - _ArcTan((x << 14) / y); + } else { + if (x <= 0) { + if (-x > -y) { + return _ArcTan((y << 14) / x) + 0x8000; + } + } else if (x >= -y) { + return _ArcTan((y << 14) / x) + 0x10000; + } + return 0xC000 - _ArcTan((x << 14 / y)); + } +} + void GBASwi16(struct ARMCore* cpu, int immediate) { struct GBA* gba = (struct GBA*) cpu->master; mLOG(GBA_BIOS, DEBUG, "SWI: %02X r0: %08X r1: %08X r2: %08X r3: %08X", @@ -303,8 +349,10 @@ void GBASwi16(struct ARMCore* cpu, int immediate) { case 0x8: cpu->gprs[0] = sqrt((uint32_t) cpu->gprs[0]); break; + case 0x9: + cpu->gprs[0] = _ArcTan(cpu->gprs[0]); case 0xA: - cpu->gprs[0] = (uint16_t) (atan2f(cpu->gprs[1] / 16384.f, cpu->gprs[0] / 16384.f) / (2 * M_PI) * 0x10001); + cpu->gprs[0] = _ArcTan2(cpu->gprs[0], cpu->gprs[1]); break; case 0xB: case 0xC: