Results 1 to 10 of 10

Thread: Gameboy - unsure about jr instruction

  1. #1
    The New Kid
    Join Date
    Oct 2016
    Posts
    6

    Default Gameboy - unsure about jr instruction

    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:

    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 &reg, 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.

  2. #2
    Member
    Join Date
    Oct 2004
    Location
    Land of Oz
    Posts
    600

    Default Re: Gameboy - unsure about jr instruction

    The program counter points to the next instruction before the current instruction is evaluated. FC is -4, so 1F4 - 4 = 1F0.

    You should do some learning about relative jumps before continuing with your emulator.

    The CPU used in the gameboy is a Z80 variant, and there's oodles of stuff available on the Z80.

  3. #3
    The New Kid
    Join Date
    Oct 2016
    Posts
    6

    Default Re: Gameboy - unsure about jr instruction

    OK, I was using only GBCPUman. I've read a little bit more about JR. This instruction can only jump 128 bytes ahead or behind. So if the given parameter is greater than 128, it is a signed value. Is that correct? But how should I calculate what exactly the value is? FC is 252 in decimal, should I do 256 - parameter to get the correct value (and substraction should only take place if parameter is greater than 128)?

  4. #4
    Controller Man ulaoulao's Avatar
    Join Date
    Dec 2005
    Location
    FL
    Posts
    3,391

    Default Re: Gameboy - unsure about jr instruction

    This instruction can only jump 128 bytes ahead or behind.
    rjmp limited to x bytes depending on CPU.
    jmp unlimited (I believe) but requires an extra clock.
    Last edited by ulaoulao; November 3rd, 2016 at 13:59.
    Original, the only way to play.

    Forums
    main page - Working controllers

  5. #5
    The New Kid
    Join Date
    Oct 2016
    Posts
    6

    Default Re: Gameboy - unsure about jr instruction

    I've been looking up my code and seems that I also have setting half-carry flag wrong. For instruction DEC n, half-carry flag should be set if there was no borrow from bit 4. Normally half-carry flag is set when there was a carry from bit 3 to bit 4, which is something like that:

    Code:
    	BYTE hc = ((val1 & 0xF) + (val2 & 0xF)) & 0x10;
    	if (hc == 0x10) setbit(F, 5); //set half-carry flag
    	else resetbit(F, 5); //reset hc flag
    But here situation is different and I can't get correct results. No$gmb shows me that after executing DEC B (decrease register B) half-carry flag should be set, but my emulator doesn't set it. So above code should set half carry flag in a different way, but I don't know what way.

    EDIT:

    I'm not sure if this is correct for this DEC n instruction, but perhaps setting half-carry flag should look like this?:
    Code:
    	BYTE hc = ((reg & 0xF) - (1 & 0xF)) & 0x10;
    	if (hc == 0x10) setbit(F, 5);
    Last edited by mentor93; November 3rd, 2016 at 15:06.

  6. #6
    The New Kid
    Join Date
    Oct 2016
    Posts
    6

    Default Re: Gameboy - unsure about jr instruction

    OK, thanks for your help, but I managed to solve both issues (half-carry flag and JR instruction).

  7. #7
    The New Kid
    Join Date
    Oct 2016
    Posts
    6

    Default Re: Gameboy - unsure about jr instruction

    Now I'm confused about RES instruction. It resets specified bit in one of the registers, but I don't get where do I get the specified bit from? Because everything that No$gmb debugger shows is:

    Code:
    CB 87        res 0,a
    I don't get where this 0 bit comes from. CB 87 is opcode for instruction RES b,A, so it's ok there's A register - I know why it is there. But why 0? There's no parameter after CB 87, so where does this 0 come from?

  8. #8
    Controller Man ulaoulao's Avatar
    Join Date
    Dec 2005
    Location
    FL
    Posts
    3,391

    Default Re: Gameboy - unsure about jr instruction

    Possible the explanation is in here.
    http://pastraiser.com/cpu/gameboy/gameboy_opcodes.html

    But from an ASM point of view the res reserves space in a data, possibly it's a free memory?
    Original, the only way to play.

    Forums
    main page - Working controllers

  9. #9
    Member
    Join Date
    Oct 2004
    Location
    Land of Oz
    Posts
    600

    Default Re: Gameboy - unsure about jr instruction

    The above link explains it all.
    CB 87 is RES 0,a while CB 8F is RES 1,a
    CB 80 is RES 0,b.
    So the opcode selects both the bit and the register. Further, other CB codes choose RES, SET or BIT.

    RES means to turn the specified bit to 0;
    SET means to turn the specified bit to 1;
    BIT means to return the status of the specified bit in the Z flag.
    Last edited by Robert; November 5th, 2016 at 05:54.

  10. #10
    The New Kid
    Join Date
    Oct 2016
    Posts
    6

    Default Re: Gameboy - unsure about jr instruction

    Thank you for all your answers. I managed to implement all opcodes and most of the games I checked can get into menu or intro, but only a few (Soccer, Robin Hood: Prince of Thieves, Wario Land and Double Dragon 2 are worth mention here) can get past menu. I revisioned my code already once and found several serious mistakes, but still my emulator doesn't really play any game. I probably need to revision code once more, but for now I don't get what did I do wrong. For emulating graphics, joypad, timers etc. I followed a tutorial at http://codeslinger.co.uk/ and I checked these modules several times already and no errors there. So it must be something in implentation of cpu instructions.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •