In this post, we will understand how a CPU executes instructions on a high level by illustrating the instruction cycle using a step-by-step example. We also cover interrupts and how they affect the instruction cycle.
A CPU executes instructions using a cycle of steps known as the instruction cycle.
What is an Instruction Cycle?
The instruction cycle consists of three steps to fetch, decode, and execute instructions. It is, therefore, also known as the fetch-decode-execute cycle.
The fetch operation retrieves the instruction from memory and moves it to the CPU.
The decode operation unpacks the instruction so that the CPU can understand what to do.
The execute operation carries out the instruction.
Sometimes the cycle is described as consisting only of the fetch and the execute operation. This cycle is repeated continuously as long as the computer is running. If it stops, the computer has either been turned off, or it has crashed.
In the blog post on the von Neumann Architecture, we established that the CPU consists of a control unit for processing the instructions sent to the CPU, the arithmetic logic unit for performing the operations specified in the instructions, and registers for storing instructions and data that are immediately required by the CPU.
The fetch-decode-execute cycle makes use of these components in addition to the memory unit. In the fetch step of the cycle, the instructions are retrieved from the memory unit (RAM) and stored in the registers on the CPU. Next, the control unit decodes the instructions, which are then executed by the arithmetic and logic unit. The results of the instruction execution are sent back to RAM for storage, and the next instruction cycle begins.
What is CPU Clock Speed?
The number of instruction cycles a CPU can execute is stated as clock speed and measured in Hertz. If a CPU has a clock speed of 2 700 000 000 Hertz or 2.7 GHz, it executes 2.7 billion instruction cycles per second.
The Fetch Decode Execute Cycle Step By Step
In the following section, we will walk through the operations performed during the instruction cycle. Recall that a CPU has several different registers
The instruction cycle begins with the fetch operation. The program counter keeps track of the next instruction to be processed. A fetch operation starts by loading the memory address of the next instruction into the program counter. In the next step, the processor transfers the address from the program counter to the memory address register and subsequently loads the data stored at that memory location into the memory data register. The program counter is automatically incremented to the next memory location unless the current instruction explicitly points to a different memory location for the next instruction.
Let’s see how that works in practice using a concrete example:
The program counter initially points to the memory address 001
The memory address 001 is loaded into the memory address register by the processor
The processor next retrieves the instruction stored at memory address 001 and loads it into the memory data register.
Since the data contains the instruction “Get 203”, it is forwarded to the instruction register.
The program counter is incremented by 1, pointing to 002
The instruction in the instruction register is forwarded to the control unit.
What is an Execute Cycle?
After the fetch operation, the instruction cycle continues with the decode and execute portions. During the fetch stage, the control unit has been supplied with the instruction. It now needs to decode the instruction so that the processor can understand what to do next. In our example, I’ve supplied the instruction in plain English, such as “Get 203” which tells the processor to get the piece of data stored at memory location 203. In memory, the instruction is supplied in binary. For example, in a 16-bit memory, the first 4 bits may encode the operation to be performed, while the remaining bits specify the address from which to load the data. Lastly, the processor will execute the instruction supplied. So if the instruction is to get some other piece of data, the “execute” action will consist of retrieving the data from the supplied memory address and storing it in the appropriate register. If the instruction specifies a calculation such as adding two numbers, the execution of the calculation will be handed off to the arithmetic and logic unit (ALU)
Let’s continue with our concrete example:
The Control Unit decodes the instruction and tells the processor to go to memory address 203 and fetch the piece of information stored there.
The address 203, is stored in the memory address register.
The data, the number 4, is stored in the memory data register.
Since the data is a number that will be necessary for a future operation and not another instruction, the number is stored in the accumulator.
This concludes the first fetch-decode-execute cycle. The processor starts the next cycle by fetching the next instruction stored in the program counter. The fetching process is the same as in the previous cycle. This time, the instructions tell the processor to add the number stored at memory location 204 to the number currently stored in the accumulator.
After fetching the instruction, the processor retrieves the number stored at memory address 204 and places it in the accumulator while the previously stored number is forwarded to the arithmetic and logic unit (ALU).
Then, the number 3 is also forwarded to the arithmetic and logic unit, where the addition specified in the instruction is performed. Finally, the result is returned to the accumulator, where it will sit until the next instruction is executed.
In this example, we’ve used two instruction cycles to perform the addition. But modern processors may also load several pieces of data and perform calculations in one cycle.
What is an Interrupt in Computer Organization and Architecture?
As the term implies, an interrupt is a mechanism by which the normal course of actions of the processor is interrupted. This may be necessary for a variety of reasons, such as hardware failure or waiting for an I/O operation to complete.
Interrupts are part of a broader class of events known as exceptions. Exceptions essentially handle cases when the CPU encounters conditions that interfere with normal processing.
The main utility of interrupts lies in their ability to improve efficiency. Performing I/O operations is usually orders of magnitude slower than normal processing. If the computer had to communicate with an external device attached via USB, such as a flash drive, without the use of interrupts, the processor would have to wait until the i/O operation completes. The processor would spend thousands of instruction cycles just polling the peripheral device, asking if it was done processing without doing any useful work.
To make processing more efficient, the processor can receive an interrupt signal from the I/O device enabling it to work on something that is unrelated to the I/O operation while that operation is in progress.
Once the I/O device is done with its operations and requires communication with the processor, it sends an interrupt request signal to the processor. The processor then interrupts the execution of its current program and services the I/O device. This is achieved via a special device known as the interrupt handler. When the processor is finished with the I/O processing, it returns to the original process.
What happens during an Interrupt?
Once an Interrupt signal arrives, the processor has to perform a series of steps to handle the interrupt and continue processing:
The CPU needs to save the current context as it exists in the registers to memory. Some processor architectures push the context onto a stack and then pop it off the stack. That way, they can restore the previous context in reverse order.
Secondly, the CPU needs to retrieve the instructions of the interrupt handler from memory. The interrupt handler is basically a set of instructions stored in memory. Each type of interrupt has its own associated set of instructions.
The CPU executes the instructions specified by the interrupt handler
After concluding the operations specified by the interrupt handler, the CPU needs to restore the context of its previous operations by loading the associated instructions and data into the registers
The CPU continues the previous flow of operations.
To include the handling of interrupts into the instruction cycle, an additional interrupt cycle is included.
If multiple interrupts occur, there are essentially two options.
If an interrupt is currently being handled and a second interrupt occurs, the processor can push the second and all subsequent interrupts onto a stack and execute them in reverse sequential order. This has the disadvantage that we cannot prioritize interrupts. If an I/O device that causes a notoriously long interrupt, like a printer, is currently executing, all other interrupts would have to wait.
Alternatively, interrupts can be associated with priorities. If an interrupt with a higher priority were to occur while a lower priority interrupt is being handled, the lower priority interrupt would itself be interrupted. The processor then would handle the higher-priority interrupt first before turning back to the lower-priority one. Naturally, the second approach engenders more complexity but is usually more efficient.
Types of Interrupts
So far, we have focused on interrupts as caused by I/O devices. In fact, there are several reasons for a processor to interrupt its course of action leading to different types of interrupt handlers.
Failure of Hardware
A computer relies on electricity. If there is a power outage or something overheats, the processor needs to be able to handle that case when the underlying hardware fails. The hardware failure handler also kicks in when there is an inconsistency in memory access. For example, if a piece of data is different in memory when it is accessed from when it was stored, it may cause system crashes.
Interrupts may be generated by the processor on a regular basis to perform updates or other functions that may be necessary.
If an error occurs during the execution of a program, the program itself can trigger an interrupt. If you are a programmer, you probably have run into buffer overflow errors or other errors generated when executing your program. These errors are triggered when your program attempts to do something that the processor cannot or will not handle. In that case, the processor will generate an interrupt or an exception. In fact, good programmers anticipate potential modes of failure and handle these through exceptions in their code.
The controller of an I/O device can trigger interrupts as described previously. They either start a new interrupt by requesting service from the processor, signal normal completion of an I/O process, or indicate an error condition.