How Does a Microprocessor Run a Program?
How instructions are fetched, decoded and executed in a RISC processor
Once assembly code has been turned into machine code, it can be loaded into computer memory and executed. In this article, I will use the Calcutron-33 example code, but the basic of the operations are the same for any RISC-like microprocessor such as a RISC-V or Arm-based processor.
In this section, I will break down all the steps involved in executing a machine code instruction. The first step is to write an assembly code program. Here is an example of a simple program which loads the numbers 42 and 23 stored in memory, adds them to produce 65 and store the result in another memory location.
LOAD x1, first
LOAD x2, second
ADD x3, x1, x2
STOR x3, result
HLT
first:
DAT 42
second:
DAT 23
result:
DAT 0
This program must be converted to machine code before it can be loaded into memory and executed. If you have downloaded the Calcutron-33 source code you can find this example program under examples/memadder.ct33
. With the Calcutron-33 tools installed, you can use the cutron asm
command to produce machine code.
❯ cutron asm memadder.ct33
5105
5206
1312
7307
0000
0042
0023
0000
Every instruction is a 4-digit decimal number. When we load this program into the Calcutron-33 computer, the instructions will be arranged in order. Instruction 5105
will be placed at address 00
in memory. Instruction 5206
at address 01
. Instruction 1312
at address 02
and so on.
Running a program, simply means fetching one instruction at a time in order, decoding it and executing it. To keep track of what instruction to fetch, a microprocessor has a program counter (PC) which keeps track of the address, in memory, of the next instruction to fetch.
To help you better understand how a single instruction is executed, I am going to break down all the steps involved in executing the third instruction 1312
. It is an ADD
instruction.
Fetch Instruction
The big boss in a microprocessor (CPU) is the control unit (CU) show as a gray box at the bottom left of the diagram below. It orchestrates and coordinate all the actions. Let us use the gas pipes analogy. Every functional unit has several inputs and output. The control unit use its red control lines to open the valves on the program counter (PC) and main memory, so that the address, 02
, of the instruction to fetch flows from the program counter to the address selector on main memory.
The memory block has another output to send out the number at the selected address. The control unit opens the valve on this output and on the input to the instruction register. All other valves are closed so that the contents 1312
at address 02
only flows into the instruction register.
Decode Instruction
The control unit doesn't tell everybody what to do on its own accord. Its actions are controlled by the instructions it gets supplied. However, to figure out what to do next, it needs to decode the instruction stored in the instruction register (IR). The control unit toggles its control lines to the instruction register so that the instruction decoder can figure out what the instruction is telling the control unit to do.
When decoding instruction 1312
the control unit looks at the first digit 1
to determine that it needs to instruct the ALU to perform an addition. The last two digits 12
tells it to select register 1 and register 2 and send their values to the ALU.
Execute Instruction
Register x1 contains the number 42 which will be sent out on the first output port of the register file. Register x2, contains the number 23. This number gets sent on the second output port of the register file to the second input port on the ALU. The ALU has been set in addition mode by the control unit and adds the two numbers to produce 65, which is sent out on the output port of the ALU. The result is temporarily stored in a buffer. More correctly, we should have called this a latch. A latch is akin to a register. The reason we use the name latch is to clarify that we are only using it for temporary storage.
Write Back Result
The fifth step is called "write back". Wait, what was the fourth step? Normally, the fourth step involves memory operations, but the ADD
operation neither reads from nor write to memory, so nothing will be done in the fourth step. We skip along to the final fifth step instead.
The control unit has used the decoder to look at instruction 1312
and determined that register x3
is the destination register for the computation. Thus, the control unit will select the that register in the register file and open up the "valves" between the temporary write back buffer and the register file to transfer the result value 65 to register x3
.
This step concludes the execution of the ADD x3, x1, x2
instruction. Each instruction will go through five steps, but the actions performed on each step will vary slightly. The first two steps: Fetch and decode, will always be the same, though.
Instruction-Set Architecture
Every microprocessor has a what we call an instruction-set architecture (ISA). It is the programmer's view of the microprocessor. It involves not just the instructions a programmer can expect to be able to use, but all the registers available and how they can be used. x86-64, for instance, is the ISA used by both AMD and Intel to make microprocessors such as AMD Ryzen 7 or Intel Core i7. The processors have very different micro architectures but have the same ISA, which is what allows an AMD and Intel processor to run the same programs. Arm processors have a variety of ISAs. The latest ISA for 64-processors is called A64, as opposed to Arm's older 32-bit ISA called A32. RISC-V processors can be configured with different instruction-sets, as RISC-V is a modular architecture. The minimal 32-bit RISC-V instruction-set architecture is referred to as RV32I, while the 64-bit version is called RV32I.
Calcutron-33 has its own instruction-set architecture, which you should familiarize yourself with before we get into more details about how other instructions are executed.
Immediate Instructions
Instructions such as ADDI
, LODI
, LOAD
, STOR
, LSH
and RSH
have inputs which are immediate values rather than registers. We can use ADDI
as an example. With a normal add instruction such as ADD x4, x2, x1
we are only adding the numbers stored in registers. Compare with an instruction such as ADDI x3, 42
. The number 42 is what we call an immediate value. The number is encoded into the ADDI
instruction. If you assemble the instruction into machine code, you will get 2342
. The last two digits is the immediate value. You can check how individual instructions are assembled with the cutron dbg
command if you install Calcutron-33 tools. The asm
command can be used to assemble an individual instruction, as shown in the following Terminal screenshot.
Keep reading with a 7-day free trial
Subscribe to Erik Explores to keep reading this post and get 7 days of free access to the full post archives.