CPU Emulation and locking to a specific clock speed

FlySwat picture FlySwat · Sep 22, 2008 · Viewed 11.9k times · Source

If you had read my other question, you'll know I've spent this weekend putting together a 6502 CPU emulator as a programming exercise.

The CPU emulator is mostly complete, and seems to be fairly accurate from my limited testing, however it is running incredibly fast, and I want to throttle it down to the actual clock speed of the machine.

My current test loop is this:

    // Just loop infinitely.
    while (1 == 1)
    {                
        CPU.ClockCyclesBeforeNext--;

        if (CPU.ClockCyclesBeforeNext <= 0)
        {
            // Find out how many clock cycles this instruction will take
            CPU.ClockCyclesBeforeNext = CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].CpuCycles;

            // Run the instruction
            CPU.ExecuteInstruction(CPU.Memory[CPU.PC]);

            // Debugging Info
            CPU.DumpDebug();
            Console.WriteLine(CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].ArgumentLength);

            // Move to next instruction
            CPU.PC += 1 + CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].ArgumentLength;                                        
        }
    }

As you can tell, each opcode takes a specific amount of time to complete, so I do not run the next instruction until I count down the CPU Cycle clock. This provides proper timing between opcodes, its just that the entire thing runs way to fast.

The targeted CPU speed is 1.79mhz, however I'd like whatever solution to the clock issue to keep the speed at 1.79mhz even as I add complexity, so I don't have to adjust it up.

Any ideas?

Answer

Jason Fritcher picture Jason Fritcher · May 6, 2009

I wrote a Z80 emulator many years ago, and to do cycle accurate execution, I divided the clock rate into a number of small blocks and had the core execute that many clock cycles. In my case, I tied it to the frame rate of the game system I was emulating. Each opcode knew how many cycles it took to execute and the core would keep running opcodes until the specified number of cycles had been executed. I had an outer run loop that would run the cpu core, and run other parts of the emulated system and then sleep until the start time of the next iteration.

EDIT: Adding example of run loop.

int execute_run_loop( int cycles )
{
    int n = 0;
    while( n < cycles )
    {
        /* Returns number of cycles executed */
        n += execute_next_opcode();
    }

    return n;
}

Hope this helps.