The Fetch Decode Execute cycle
Understanding how the CPU works, registers and low-level programming.
There are some excellent simulations, such as the Little Man computer and SimCom. It is a lot of fun writing your own programs for these and you will begin to really understand how programming (the software) works with the CPU, RAM and the registers (the hardware).
Registers
A Von Neumann CPU (the type of CPU you get in nearly all personal computers) has a number of 'registers'. These are very fast memory circuits. You can think of each register as a box which holds a piece of data useful to the CPU. These pieces of data allow the CPU to quickly fetch and then execute instuctions from RAM, and also to write data to RAM. They hold important information information that enables instructions to be processed (fetched, then decoded, then executed). The registers you should know about include:
Program Counter (PC) - this holds the address of the next instruction to be fetched and executed.
Current Instruction Register (CIR) - this holds the current instruction being executed
Memory Address Register (MAR) - this holds the RAM address you want to read to or write from.
Memory Data Register (MDR) - this holds the data you have read from RAM or want to write to RAM.
Accumulators - these hold the data being worked on and the results of arithmetic and logical operations
Status Register - this holds information about the last operation e.g. whether the least sum done produced a negative result
Interrupt Register - this holds details about whether an interrupt has happened
The fetch-decode-execute (FDE) cycle
You want to run a program that you have on your hard disk. You double-click on it in your file manager. The loader program (part of the operating system) goes to the hard disk and copies it to a suitable place in the IAS. It adjusts any memory references in the program as appropriate and then loads the address of the first instruction of the program into the Program Counter (PC). It then signals to the CPU that it has done this. The CPU wants to run the program and gives control to the control unit. The control unit fetches the first instruction from the IAS. It then decodes it and executes it. Once executed, the cycle is reset and the control unit fetches, decodes and executes the next instruction in the program, then resets the cycle again. This process is repeated until the whole program has been ‘run’. At all stages in the FDE instruction, the CPU will need to use the registers. These are discussed in detail below.
The fetch part of the cycle
Every program has a start address. The start address is placed in the Program Counter (PC). The contents of Program Counter is copied to the Memory Address Register (MAR). The Control Unit goes to that address in memory and copies the bit pattern it finds there to the Memory Data Register (MDR), where it is then copied to the Current Instruction Register (CIR). While it is doing this, the PC is automatically incremented, so it is pointing to the memory address of the next instruction. The following describes what happens in the fetch part of the FDE cycle.
The registers are used in this way for the fetch part of EVERY instruction, regardless of what the instruction actually is.
Decoding an instruction
Once an instruction has been fetched, it needs to be decoded by the control unit. This simply means that the control unit works out what the instruction is and what signals it has to send out to the various parts of the CPU to make the instruction happen – to ‘execute’ it.
Executing an instruction
To execute an instruction, we need to use the registers again. How the registers are used depends on exactly what the instruction we want to execute is. Generally however, once we have fetched an instruction and have got it into the CIR, it is split into two parts:
- the actual instruction we want to execute
- the actual address of the data we want to use with the instruction.
Central to every operation that is fetched, decoded and executed is the Accumulator. You do any actual mathematical or logical operations in this register. That means that before you can work on any data, you must put it into the Accumulator first. This is straightforward. Simply put the operand of the instruction on the MAR and then move the contents of the MDR to the Accumulator. To store the Accumulator’s contents, simply put the address where you want to store the contents on the MAR and then move the Accumulator to the MDR. Also note ADD (x) instructions usually take the form of ‘ADD the contents of a location given by the operand x to the contents of the Accumulator and store the result in the Accumulator’. SUB (x) means ‘subtract the contents of the location given by x from whatever is in the Accumulator and store the result in the Accumulator’.
Suppose you wanted to add two numbers together, held in locations 2000 and 3000 and store the result in 4000. The instructions might be:
LOAD (2000) //This loads the contents of memory location 2000 into the accumulator.
ADD (3000) //This adds the contents of location 3000 to the accumulator, storing the result in the accumulator.
STORE (4000) //This instruction takes whatever is in the accumulator and stores it in location 4000.
The use of the registers can be summarised as follows:
-
- The PC or Program Counter. This holds the address of the next instruction in the Fetch-Decode-Execute cycle.
- The MAR or Memory Address Register. The contents of the PC are loaded into the MAR. This allows the PC to be incremented.
- The MDR or Memory Data Register. This register holds the bit pattern held in the address pointed to by the address in the MAR.
- The CIR or Current Instruction Register. This register holds a copy of the bit pattern in the MDR, thus freeing up the MDR.
- The Accumulator. All logical and arithmetic operations take place in the accumulator. Sometimes there is more than one accumulator and these might be referred to as accumulator A, accumulator B etc.
- The Interrupt Register. This holds information about what interrupts have happened. It will be checked after each Fetch-Decode-Execute cycle.
- The Status Register. This register gets updated after every ALU operation. It holds information about the result of the last operation that was carried out. It will tell you whether the last operation produced a carry bit, whether the result was zero, or negative, or there was an underflow, or an overflow, for example.
- The Input Register. This register is used to transfer information from an input device into the CPU.
- The Output Register. This register is used to transfer information from the CPU to an output device.
Dealing with a jump instruction
If an instruction is fetched and decoded and turns out to be a jump instruction, we can execute it in the following way:
IF the instruction turns out to be a CONDITIONAL JUMP instruction, THEN
The Status Register is examined.
If a jump is required, then the operand associated with the jump instruction is copied to the PC and the next fetch, decode, execute cycle is done. If a jump isn’t required, then the next fetch, decode, execute cycle is done anyway.
ELSE IF the instruction is an UNCONDITIONAL JUMP instruction, THEN
Copy the operand associated with the unconditional jump to the PC.
Do the next fetch, decode, execute cycle.
ENDIF
For example, the control unit fetched an instruction using the registers. It was decoded by the instruction decoder and found to be JMZ 4. JMZ means ‘jump to the address given in the operand if the result of the last instruction produced a negative result’. The operator is JMZ and the operand is 4. We carry it out as follows:
-
- Because this is a ‘conditional jump’ instruction, the Status Register is examined.
- The status register holds information about the last instruction that was done. It can be thought of as a byte, with 8 bits, each bit indicating a status – one bit would indicate if the last instruction done produced a carry, or an underflow, or an overflow, or if the result of the last instruction produced a negative number.
- The bit associated with negative numbers is examined.
- Assuming that the last instruction did indeed produce a negative result, this bit is found to be set.
- The control unit therefore loads the operand associated with JMZ into the PC (in other words 4 is loaded into the PC) and the current FDE cycle ends.
- This FDE cycle has now finished so the next instruction must be done. The address of the next instruction to do is held in the PC.
- The control unit goes to the address held in the PC and fetches it – it goes to memory address 4 and gets the instruction it finds there.
- The program has successfully branched off to a different part of the program (beginning at address 4) than it would have done. A jump to a subroutine has been achieved!
Von Neumann bottleneck
Whatever you do to improve performance, you cannot get away from the fact that instructions can only be done one at a time and can only be carried out sequentially. Both of these factors hold back the efficiency of the CPU. This is commonly referred to as the 'Von Neumann bottleneck'. You can provide a Von Neumann processor with more RAM, more cache or faster components but if real gains are to be made in CPU performance then a major review needs to take place of CPU design.