Skip to content
Shane DeSeranno edited this page Nov 4, 2015 · 2 revisions

Go Home

Part 07 - Booting (Part 2)

Now that the memory is being mapped to specific devices, we can continue with the OpCode process. The next one we need to implement is actually pretty complicated.

CALL (0xCD 0x95 0x00)

 call nn        CD nn nn    24 ---- call to nn, SP=SP-2, (SP)=PC, PC=nn

This instruction does exactly what it says. We should make a method to push a ushort to the SP. This will decrement the SP by 2, and push the PC to the address the SP points to, then set the PC to the address you read. Later, we'll implement RET, which will do this action in reverse effectively "returning" from the function call. Don't forget PC should have been incremented to the next OpCode before you save it.

After this call runs, then the current PC value should be store in the HRAM and the SP should be 0xFFFC. The PC should be 0x0095.

LD C, A (0x4F)

This is the instruction that the CALL OpCode jumps to. It is quite easy and just loads the accumulator (A) into the C register. At this point A is 0xCE (the value pulled off the cartridge, which happens to be part of the Nintendo logo). So, after this runs, C will also be 0xCE.

LD B, e (0x06 0x04)

This is similar to other OpCodes. It loads the next byte (0x04) into the B register.

PUSH BC (0xC5)

This can make use of the push method we made earlier! It pushes the BC value (0x04CE) onto the stack.

RL C (0xCB 0x11)

The content of the C register is rotated left by 1 bit. The content of bit 7 is copied to the carry flag, and the previous content of the carry bit is copied to bit 0. This is a bit confusing, but C is currently 0xCE. In binary this is 1100 1110. If you shift everything left one bit, you get, 1 1001 1100. Don't forget make bit 1 equal to the carry flag (1 if set, 0 if unset), and also the 1 that rolled off the end must now go into the carry flag. After running this. The C register will be 0x9C and the carry flag will be set.

RLA (0x17)

The contents of A are rotated left 1 bit position through the Carry flag. The previous content of the carry flag copied to bit 0. This is pretty much identical to the previous OpCode. Remember that A is 0xCE. After running it should be 0x9D because the carry bit set and so bit 0 is set. The carry flag will still be set.

POP BC (0xC1)

This is the reverse of the PUSH command. The value we stored onto the stack (0x04CE) will be popped off the stack, and BC will be set to it. This means, after running this command, BC will be 0x04CE again.

RL C (0xCB 0x11)

We did this already!

RLA (0x17)

We did this already! My math may be flawed, but I THINK the A register should be 0x3B at this point.

DEC B (0x05)

Just decrement the B register by 1. It should be 0x03. Remember to be checking and setting flags as appropriate.

JR NZ, e (0x20 0xF5)

We did this already! Basically, it will loop, until B is 0x00. Then it will move to the next OpCode.

LDI (HL), A (0x22)

This is another one of those pesky re-mapped OpCodes.

0x22      LD   (nn),HL    LDI  (HL),A
ldi  (HL),A      22         8 ---- (HL)=A, HL=HL+1

This OpCode loads the A register to the address pointed to by the HL register and then increments HL by one. If I recall HL was 0x8010. After running this, the GPU should have set 0x8010 to whatever the end result for the A math was. And then HL should be incremented to 0x8011.

INC HL (0x23)

Just increment HL. It should now be 0x8012.

LDI (HL), A (0x22)

We did this already!

INC HL (0x23)

We did this already!

RET (0xC9)

This one allows us to get back to our original location before we made the CALL OpCode. To do this, it sets pops the value we stored earlier, when we made the call, off the stack and into the PC. That's all there is to it. The POP should have left the SP moved back to 0xFFFE and the PC should now be 0x002B.

CALL (0xCD 0x96 0x00)

We did this already, and it should push 0x002E onto the stack and jump the PC to 0x0096. This will literally run code we have already done until it gets back to 0x002E.

INC DE (0x13)

Does exactly what it seems like it should. Increment DE.

LD A,E (0x7B)

This loads the E register into the A register.

CP n (0xFE 0x34)

This compares the value in the A register to the next byte (0x34) and sets flags as documented in the PDF. In short, it is getting ready to do a loop, using E to store this value, until it has ran 0x34 times. At which point the next OpCode will not jump back!

JP NZ, n (0x20 0xF3)

We've done this already. This causes the code to loop back until we have looped 0x34 times. After that we move on. All of this code has been reading in bytes from the cartridge ROM that contains the Nintendo logo, and performing a variety of math functions on it. Basically, it is ensuring that the ROM contains the correct data.

LD DE, nn (0x11 0xD8 0x00)

Done it! Loads 0x00D8 into the DE register.

LD B, n (0x06 0x08)

I think we've done this too. Just loads 0x08 into the B register.

At this point, I think you get the idea. Right now, we are concentrating on all the OpCodes we need to perform a boot of the Gameboy. However, eventually, we will have to implement every possible OpCode available. This takes time, and is tedious, but the reward is so awesome! The first time you see your emulator do something on screen is indescribable!

I'm going to stop document each OpCode and instead, if we have issues, I'll document the complicated ones.

-The End-

Clone this wiki locally