The Fetch Execute Loop

If you read any introduction to writing emulators, they all tell you to do the same thing. You write a loop that continually fetches instructions and executes them.

while true
{
    executeInstruction()
    instruction = fetchNextInstruction()
}

Notice that I put the fetch after the execute. Doing so makes certain aspects of the design cleaner such as coming in to the loop first time. you can prefill the first instruction with a pseudo instruction to do a reset. It also better reflects the way real microprocessors usually do things. They fetch the next instruction while still cleaning up after the last one.

CPUs need to be able to handle interrupts. I simulate this with a boolean variable (or variables, if the processor has more than one kind of interrupt) that can be set from the outside World. I would normally put this test just before the instruction fetch.

while true
{
    executeInstruction()
    if irqRaised
    {
        serviceInterrupt()
    }
    else
    {
        fetchNextInstruction()
    }
}

There are some subtleties here. Firstly, we need to talk about clock cycles. Most processors are driven by a clock, by which I mean a constant frequency square wave, not a wall clock. Often the same clock also drives some peripheral devices. If we were going for ultimate realism, we would model the clock and have the clock run the loop and call the CPU and all the other devices once per clock cycle to do what is inside of the loop above. However, this is likely to be too slow, so actually we generally put the loop in the CPU like above and have it also drive the other devices.

while true
{
    executeInstruction()
    if irqRaised
    {
        serviceInterrupt()
    }
    else
    {
        fetchNextInstruction()
    }
    clockExternalDevices()
}

Now comes a critical point, how many clock cycles are there per iteration? You might think one is logical. But, most instructions take more than one cycle. On the Z80, for example, the ld a,(hl) instruction takes seven clock cycles (note that, in Z80 parlance, what I call clock cycles here are called “t-states”). If you choose one cycle per iteration, you would have to break the instruction down into stages. This is not necessarily bad: it is, after all, how the real processor does its work, but there are complications. To do it properly, you have to try to break the instruction down into a hopefully realistic set of steps and you have to decide whether to handle interrupts after each step or at the end of the instruction (usually, the answer is the latter because many processors use the same convention). Also, you have performance issues because of the overhead of the loop.

An alternate scheme is to do one iteration per instruction. The external devices then need to know how many clock cycles have passed because you are not driving them on every hypothetical clock pulse.

while true
{
    let cycleCount = cyclesForCurrentInstruction()
    executeInstruction()
    if irqRaised
    {
        serviceInterrupt()
    }
    else
    {
        fetchNextInstruction()
    }
    clockExternalDevices(cycleCount)
}

You will not get absolute fidelity of timing with this scheme, but the coding will be easier and the emulator will have more apparent speed.

Finally, it is convenient to know how many cycles the processor has consumed. This is useful for timing – if you run the processor for a measured amount of time, you can calculate its apparent clock speed as cycles consumed/elapsed time. Also, you can tell the processor to run for a while and then stop. Typically, for a GUI program, I’ll let the processor run for a large number of cycles, let it stop, update the register display and start it again in a loop that terminates when the user presses the stop button. My final fetch execute loop is a variant on the following

func run(forCycles: Int)
{
    let maxCycles = cycleCount + forCycles
    while cycleCount < maxCycles
    {
        instructionCyles = cyclesForCurrentInstruction()
        cycleCount += instructionCycles
        executeInstruction()
        if irqRaised
        {
            serviceInterrupt()
        }
        else
        {
            fetchNextInstruction()
        }
        clockExternalDevices(instructionCycles)
    }
}

The next problem is memory access. We’ll talk about that next time.

One thought on “The Fetch Execute Loop

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.