Finishing the CPU emulator

Given the information presented you should be able to get a long way. You're going to have to decide which way you want to go with the emulator - whether you want to do a full 8080 emulation, or just implement the instructions needed to play the game.

If you do a full emulation, you're going to need a few new tools in your toolbox. I'll cover that in the next section.

The other way to go is to emulate only the instructions used by the game. We'll continue to fill out the giant switch statement we made in the Emulator Shell section. You repeat a process like this until you don't get any unimplemented instructions:

  1. Run your emulator on the Space Invaders ROM

  2. The call to UnimplementedInstruction() will exit when an instruction isn't done

  3. Emulate that instruction

  4. Goto step 1

The first thing I did when I started to write my emulator was to add in the code from my disassembler. That way I could print out the instruction that was about to be executed:

   int Emulate8080Op(State8080* state)    
       unsigned char *opcode = &state->memory[state->pc];    
       Disassemble8080Op(state->memory, state->pc);    
       switch (*opcode)    
           case 0x00:   //NOP    
           /* ... */    
       /* print out processor state */    
       printf("\tC=%d,P=%d,S=%d,Z=%d\n", state->, state->cc.p,    
           state->cc.s, state->cc.z);    
       printf("\tA $%02x B $%02x C $%02x D $%02x E $%02x H $%02x L $%02x SP %04x\n",    
           state->a, state->b, state->c, state->d,    
           state->e, state->h, state->l, state->sp);    

I also added code at the end to print out all the registers and condition flags.

The good news is that you only have to do a subset of the 8080's opcodes to get about 50,000 instructions into the program. I'll even give you the list of opcodes you'll need to implement:

Opcode Instruction
0x01LXI B,D16
0x05DCR B
0x06MVI B,D8
0x09DAD B
0x0dDCR C
0x0eMVI C,D8
0x11LXI D,D16
0x13INX D
0x19DAD D
0x1aLDAX D
0x21LXI H,D16
0x23INX H
0x26MVI H,D8
0x29DAD H
0x31LXI SP,D16
0x32STA adr
0x36MVI M,D8
0x3aLDA adr
0x3eMVI A,D8
0x56MOV D,M
0x5eMOV E,M
0x66MOV H,M
0x6fMOV L,A
0x77MOV M,A
0x7aMOV A,D
0x7bMOV A,E
0x7cMOV A,H
0x7eMOV A,M
0xa7ANA A
0xafXRA A
0xc1POP B
0xc2JNZ adr
0xc3JMP adr
0xc5PUSH B
0xc6ADI D8
0xcdCALL adr
0xd1POP D
0xd3OUT D8
0xd5PUSH D
0xe1POP H
0xe5PUSH H
0xe6ANI D8
0xfeCPI D8

That's only 50 instructions, and 10 of those are moves which are trivial to implement.


I have some bad news. Your emulator is almost certainly not going to work right, and bugs in code like this are really hard to find. If you know which instruction is going bad (like a jump or call that goes off to nonsense code), you can try to fix it by inspecting your code.

Besides just staring at your code, the only other way to fix a problem is to compare your emulator against one that is known to work. You assume the other one is always right, and that any difference is a bug in your emulator. One approach would be to use my emulator. You could run them side by side manually. It would probably save time overall if you integrated my code into your project for a process like this:

  1. Create state for yours

  2. Create state for mine

  3. For next instruction

  4. Call yours with your state

  5. Call mine with my state

  6. Compare our two states

  7. error on any difference

  8. goto 3

Another way is to use this site manually. It is a Javascript 8080 emulator that even has the Space Invaders ROM built in. Here is a process for that:

  1. Restart the Space Invaders emulation by pushing the "Space Invaders" button

  2. Click the "Run 1" button to execute an instruction.

  3. Execute the next instruction on your emulator

  4. Compare the processor state to yours

  5. If the state matches, goto step 2

  6. If the state doesn't match, your emulation of this instruction is bad. Fix it, then restart from step 1.

I used this method in the beginning to debug my 8080 emulator. I'm not going to lie, this can be slow going. A lot of my problems turned out to be typos and copy-paste errors that were easy to fix once they were identified.

As you step through your code, a lot of the first 30000 instructions are spent in a loop around $1a5f. If you watch on the javascript emulator, you can see this code is copying data to the screen. I bet this code gets called a lot.

After the screen is drawn once, About 50,000 instructions in, the program gets stuck in this infinite loop:

   0ada LDA    $20c0    
   0add ANA    A    
   0ade JNZ    $0ada    

It is waiting for memory location $20c0 to get changed to zero. Since the code in this loop certainly isn't going to change $20c0, it must be a signal from somewhere else. It's time to talk about emulating the arcade machine hardware.

Before you move on to the next section, make sure your CPU emulator gets to this infinite loop.

View my source for reference

← Prev: more-about-binary-numbers   Next: full-8080-emulation →

Post questions or comments on Twitter @realemulator101, or if you find issues in the code, file them on the github repository.