core bug in RSBS and RSCS instructions
I'm writing a GBA emulator for fun, and was testing my own core against VBA-M's
Â
I found a bug in the ARM mode RSBS and RSCS instructions, in that they set the flags wrongly. They are set wrongly according to the ARM architecture documentation, and I have tested VBA-M against real hardware (a nintendoDS in GBA mode), and have found the flags to be set differently.
Â
I'm using VBA-M 1.8.0.1138, compiled from the source available from the download page.
Â
for example:
Â
Code: Select all
mov r0, #0x80000000
mov r1, #0x00000001
rsb r0, r0, r1
Â
on real hardware, the result is 0x80000001 and flags should be 0x90000001f (N..V..)
in VBA-M, the result is 0x80000001 and flags are 0x8000001f (N.C...)
Â
the issue can be fixed with the following patch for VBA-M's C core:
Code: Select all
--- GBA-arm.cpp.old 2013-02-01 13:34:42.591850606 +0000
+++ GBA-arm.cpp 2013-02-01 14:01:38.395172242 +0000
@@ -951,9 +951,9 @@
#endif
#ifndef OP_RSB
#define OP_RSB \
- u32 lhs = reg[(opcode>>16)&15].I; \
- u32 rhs = value; \
- u32 res = rhs - lhs; \
+ u32 lhs = value; \
+ u32 rhs = reg[(opcode>>16)&15].I; \
+ u32 res = lhs - rhs; \
reg[dest].I = res;
#endif
#ifndef OP_RSBS
@@ -991,9 +991,9 @@
#endif
#ifndef OP_RSC
#define OP_RSC \
- u32 lhs = reg[(opcode>>16)&15].I; \
- u32 rhs = value; \
- u32 res = rhs - lhs - !((u32)C_FLAG); \
+ u32 lhs = value; \
+ u32 rhs = reg[(opcode>>16)&15].I; \
+ u32 res = lhs - rhs - !((u32)C_FLAG); \
reg[dest].I = res;
#endif
#ifndef OP_RSCS
Â
I have not tested the asm core, and haven't even bothered to read the source. When enabled, it will not compile on my machine, but it is possible that the bug is present there too.
Â
If anyone wants to test the issue themselves, here is the code I used. I will attach a pre-compiled ROM for testing too. [.gba files cannot be uploaded, perhaps for good reason - you will have to compile this yourself if you want to test it]
Â
main.c
Code: Select all
#include
#include
#include
#include
#define GET_BIT(x, b) ((x) & (1 << (b)))
u32 testFunc(u32 a, u32 b);
int main() {
u32 flags;
irqInit();
irqEnable(IRQ_VBLANK);
consoleInit(0, 4, 0, NULL, 0, 15);
BG_COLORS[0] = RGB5(0, 0, 0);
BG_COLORS[241] = RGB5(31, 31, 31);
REG_DISPCNT = MODE_0 | BG0_ON;
u32 v1 = 0x80000000;
u32 v2 = 0x00000001;
printf("test: rsbs %08x, %08x\n", v1, v2);
flags = testFunc(v1, v2);
printf("flags: %08x (", flags);
printf("%c", GET_BIT(flags, 31) ? 'N' : '.');
printf("%c", GET_BIT(flags, 30) ? 'Z' : '.');
printf("%c", GET_BIT(flags, 29) ? 'C' : '.');
printf("%c", GET_BIT(flags, 28) ? 'V' : '.');
printf("%c", GET_BIT(flags, 27) ? 'Q' : '.');
printf("%c", GET_BIT(flags, 5) ? 'T' : '.');
printf(")\n");
return 0;
}
Â
asm.s
Code: Select all
.arch armv4t
.section .iwram, "ax", %progbits @ use fast 32k RAM for ARM code
.align 2
.global testFunc
testFunc:
rsbs r0, r0, r1
mrs r0, cpsr
bx lr
Â
regards,