Thursday, 9 October 2008

Come back z80 ...

No, not really.  Many moons ago I wrote Gameboy emulator with a cut-down z80 CPU.  Although I never got as far as handling sound, everything else worked quite nicely.  I wrote it in C++ with the CPU core written in x86 assembler.  Thinking back now it seems an order of magnitude simpler than emulating a 68000 in Java.

The painful thing with the 68000 is that the instructions are complex.  Decoding the machine code isn't as simple or straight forward as something like a z80.  The 68000's instructions are all 16-bit words and decoding these is somewhat long winded.

The goal is to quickly identify each instruction so that it can be emulated as fast as possible without wasting precious time trying to determine which action to perform.  I also want to use the same determination algorithm for both the emulator and the disassembler.

I've settled on a scheme of using the 10 most significant bits of an instruction for identification.  This covers the majority of the instruction set and allows me to determine the size of the operation in most case (byte/word/long).  There are however a few special cases where more of the instruction needs to be used for qualification.

I want my core loop clean and envisage something like this simplified pseudo code:

while(running)
short opcode = readMemWord(reg_pc)
Instruction i = Instructions.get(opcode & 0xFFC0)
i.execute(opcode)
end while

I don't really want the mother of all switch statements in there, so I will use a hash collection of some sort, keyed against the 10 most significant bits of the opcode paired with an instance of the class that implements that particular instruction.  This allows me to write a class to handle each instruction and specialise it to handle different operation sizes too.

To facilitate this, I have an Instruction interface that these classes all implement that looks like this:

public interface Instruction
{
  public int execute(int opcode);
  public DecodedInstruction disassemble(int address, int opcode);
}

The disassembler will work in exactly the same way, except calling disassemble instead of execute.

The disassembler is about half done now.  Back to it.

2 comments:

Eight-Bit Guru said...

Sounds good. I like the hashtable idea - for large instruction set domains, it's got to be better than a thousand lines of CASE statements. ;)

thomas said...

The hashtable idea sounds pretty good! I've been thinking for a while about 68K emulation in a higher language, and most of the C approaches that I've seen look pretty clumsy when converted to something different.