I'm writing Gameboy emulator. My approach to writing an emulator here is simple - I load Dr. Mario rom into my emulator which then reads opcode after opcode. If there's opcode program doesn't know it stops executing and gives me opcode's hex number. I then check what instruction this opcode corresponds to (several opcodes may be for one instruction, just taking different registers for parameter) and I write function which implements what this instruction does. In the end I should have somewhere around 70-80 such functions (I think there are about 77 instructions, but I don't remember exact number) for over 250 opcodes. This way I should implement CPU emulation relatively quick.
I'm constantly checking my emulator work with No$gmb debugger. I look up if my emulator executes same opcodes and then jumps to the correct next opcode, so I know if my emulator will emulate Dr. Mario properly (at least in terms of CPU right now), just as No$gmb does it. And everything went smoothely so far, but I encountered situation where my emulator did not jump to the same opcode as No$gmb did. And that rather shouldn't happen, because both emulators should work the same way. Instruction I'm talking about is JR - it does a conditional jump (it checks if certain condition is true and then adds a signed byte value to program counter and jumps to location being the result of such addition). In this particular case instruction goes like this:
So basicaly it tells us "if zero flag is reset, jump to 01F0" (at least I think so). In hex it is:
And here's what I'm concerned about. 20 is opcode for this instruction and FC is this value emulator should add to program counter. But I don't get why there's FC in the second piece of code, but 01F0 in the first one? And what's more important to me, Dr. Mario on No$gmb actually jumps to 01F0, although on my emulator it doesn't. So there's something wrong I think. Both emulators should work the same way, so the game should jump to 01F0 on my emulator also. Instead it goes to next opcode in line (on 01F4 actually). That could mean that I have not implemented setting and resetting zero flag correctly, but I believe I did it correctly. But where does 01F0 come from? If FC is value that should be added to current value in program counter, which is 01F2, that should be 02EE, right? Even if it should concatanate both values using | operator the result would be different.
My current implementation for JR instruction is:
That's pretty simple. There are only 4 variations of this instruction (4 different opcodes) and each one just checks if certain flag is set or reset. So I could just compare certain bit in F register with either 1 or 0 and if values match then do the jump:
I think that's ok, but why do I get different results compared to No$gmb? And why is there 01F0 which doesn't make sense to me? Perhaps some more experienced programmer who did code emulators or coded his own GB emulator could help me here, because this problem means that my emulator could not work properly = could not run the game properly and running games properly is all what emulator should do.
I'm constantly checking my emulator work with No$gmb debugger. I look up if my emulator executes same opcodes and then jumps to the correct next opcode, so I know if my emulator will emulate Dr. Mario properly (at least in terms of CPU right now), just as No$gmb does it. And everything went smoothely so far, but I encountered situation where my emulator did not jump to the same opcode as No$gmb did. And that rather shouldn't happen, because both emulators should work the same way. Instruction I'm talking about is JR - it does a conditional jump (it checks if certain condition is true and then adds a signed byte value to program counter and jumps to location being the result of such addition). In this particular case instruction goes like this:
Code:
jr nz,01F0
So basicaly it tells us "if zero flag is reset, jump to 01F0" (at least I think so). In hex it is:
Code:
20 FC
And here's what I'm concerned about. 20 is opcode for this instruction and FC is this value emulator should add to program counter. But I don't get why there's FC in the second piece of code, but 01F0 in the first one? And what's more important to me, Dr. Mario on No$gmb actually jumps to 01F0, although on my emulator it doesn't. So there's something wrong I think. Both emulators should work the same way, so the game should jump to 01F0 on my emulator also. Instead it goes to next opcode in line (on 01F4 actually). That could mean that I have not implemented setting and resetting zero flag correctly, but I believe I did it correctly. But where does 01F0 come from? If FC is value that should be added to current value in program counter, which is 01F2, that should be 02EE, right? Even if it should concatanate both values using | operator the result would be different.
My current implementation for JR instruction is:
Code:
void JR(BYTE jump, int b, int val) {
if (checkbit(F, b, val)) {
pc = pc + jump;
no_incr = true;
}
else pc++;
printf("jr %02X\n", jump);
}
//...
bool checkbit(BYTE ®, int b, int val) {
return ((reg >> b) & 1 == val);
}
That's pretty simple. There are only 4 variations of this instruction (4 different opcodes) and each one just checks if certain flag is set or reset. So I could just compare certain bit in F register with either 1 or 0 and if values match then do the jump:
Code:
BYTE *opcode = &memory[pc];
switch (*opcode) {
case 0x20:
JR(opcode[1], 7, 0);
break;
}
I think that's ok, but why do I get different results compared to No$gmb? And why is there 01F0 which doesn't make sense to me? Perhaps some more experienced programmer who did code emulators or coded his own GB emulator could help me here, because this problem means that my emulator could not work properly = could not run the game properly and running games properly is all what emulator should do.