views:

896

answers:

5

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?

+4  A: 

1.79 mhz means 1790000 Instructions per second, or ~0,55 microseconds per instruction. Sounds like a job for a high-precision timer, although i'm not sure how good they are for such small intervals. Maybe a queue that executed 20 instructions at a time every 11 microseconds?

Michael Stum
Good advice, but its actually 179,000 cycles per second. Since each instruction takes between 1 and 7 cycles to complete, the actual instructions per second time will vary.
FlySwat
True on the Instruction parts, i actually meant clock cycles. Just: Are you sure about the 179k cycles? Megahertz is a million hertz, and therefore i think it's 1.79 million cycles, unless there is something on the 6502 that causes 1 cycle to take 10 Hertz?
Michael Stum
it's been a long time since i've tried to implement a CPU emulator (i still want to write a GameBoy Emulator in Silverlight one day :D), but generally I think that a timer is the way to go, only the exact implementation I am no expert on.
Michael Stum
+3  A: 

I would use the clock cycles to calculate time and them sleep the difference in time. Of course, to do this, you need a high-resolution clock. They way you are doing it is going to spike the CPU in spinning loops.

Lou Franco
+4  A: 

Take a look at the original quicktime documentation for inspiration.

It was written a long time ago, when displaying video meant just swapping still frames at high enough speed, but the Apple guys decided they needed a full time-management framework. The design at first looks overengineered, but it let them deal with widely different speed requirements and keep them tightly synchronized.

you're fortunate that 6502 has deterministic time behaviour, the exact time each instruction takes is well documented; but it's not constant. some instructions take 2 cycles, other 3. Just like frames in QuickTime, a video doesn't have a 'frames per second' parameter, each frame tells how long it wants to be in screen.

Since modern CPU's are so non-deterministic, and multitasking OS's can even freeze for a few miliseconds (virtual memory!), you should keep a tab if you're behind schedule, or if you can take a few microseconds nap.

Javier
+2  A: 

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.

jkf
+1  A: 

As jfk says, the most common way to do this is tie the cpu speed to the vertical refresh of the (emulated) video output.

Pick a number of cycles to run per video frame. This will often be machine-specific but you can calculate it by something like :

cycles = clock speed in Hz / required frames-per-second

Then you also get to do a sleep until the video update is hit, at which point you start the next n cycles of CPU emulation.

If you're emulating something in particular then you just need to look up the fps rate and processor speed to get this approximately right.

EDIT: If you don't have any external timing requirements then it is normal for an emulator to just run as fast as it possibly can. Sometimes this is a desired effect and sometimes not :)

Legooolas