The Data Path

The Data Path

In the last chapter we got to know the RISC-V instruction set and wrote a first program. Now it is about the hardware: how does a CPU have to be built, so that it can execute these instructions? For this we combine the building blocks from the previous chapters - ALU, registers and memory - into a data path.

A minimal implementation

The minimal working subset of a RISC-V implementation contains the following instructions:

  • the arithmetic-logical instructions add, sub, and and or [R-type]

  • the memory instructions load word (lw) and store word (sw) [I-type and S-type]

  • the conditional branch instruction branch if equal (beq) [B-type]

We will see how the chosen instruction set architecture affects key performance aspects such as clock rate and cycles per instruction (CPI). We will also see that the different instruction types only differ in the later phases of execution.

For every instruction the first two steps are identical:

  1. The program counter (PC) holds the address of the current instruction. This address is sent to the instruction memory, which returns the instruction.

  2. One or two registers are read from the register file; the register numbers are contained in the fields of the instruction. lw and addi read only one register (rs1), all other instructions in our subset read two (rs1 and rs2).

The next steps depend on the instruction type, but still use the same resources. R-type instructions use the ALU to compute the result, memory instructions use it to compute the address, and branch instructions use it for the equality test. Only after the ALU do the different instruction types really differ.

cpu structure

This abstract schematic does not explain all cases yet, however: for example, it does not show how the ALU knows which operation to perform, or when the register file is written. For that we need an extended schematic that also shows the control.

cpu structure with control

The execution phases for the different instruction types

We start with the five classic phases of a RISC processor and show what happens in each phase for typical instructions:

Instruction fetch (IF) → Decode and register read (ID) → Execute (EX) → Memory access (MEM) → Write back (WB)

TypeInstructionFetch (IF)Decode (ID)Execute (EX)Memory access (MEM)Write back (WB)

Register

add, sub, and, or

fetch instruction, compute PC + 4

decode instruction, read rs1 and rs2

ALU computes rs1 op rs2

–

write result to rd

Load

lw

fetch instruction, compute PC + 4

decode instruction, read rs1

ALU computes address rs1 + offset

read word from data memory

write loaded word to rd

Store

sw

fetch instruction, compute PC + 4

decode instruction, read rs1 and rs2

ALU computes address rs1 + offset

write rs2 to data memory

–

Branch

beq

fetch instruction, compute PC + 4

decode instruction, read rs1 and rs2

ALU compares rs1 and rs2; second adder computes target PC + offset

–

PC = target if equal, otherwise PC + 4

So in the fetch phase, every instruction initially only computes PC + 4. Whether a branch is taken instead is only known for beq after the ALU has compared the two registers. A multiplexer then selects between PC + 4 and the branch target as the new value of the program counter.

In our first, simple implementation all five phases are completed within a single clock cycle (single-cycle processor). Splitting execution into phases still helps understanding – and it is the foundation of pipelining, where several instructions are processed in different phases at the same time.

The instruction part

To explain a CPU on this abstract level, we need a few more concepts. An instruction is stored in memory and is accessible under a specific address. An address in RISC-V (in its 32-bit variant RV32) is a 32-bit value pointing to a specific byte in memory. The program counter (PC) is a register that holds the address of the current instruction in instruction memory. The program counter is connected to the first adder, which adds the constant 4 to it: an instruction is 32 bits = 4 bytes long, so the next instruction is located 4 addresses further on.

cpu instruction part

If the instruction is a branch instruction, a second adder adds the offset contained in the instruction to the program counter. This is how jumps are created: if the branch condition is met, this result is loaded into the program counter instead of PC + 4.

cpu instruction path

The data part

The data path shows elements we are already familiar with: the ALU and the two memory blocks – the register file on the left and the data memory on the right. The first input of the ALU is connected to the first read port of the register file (rs1). The second input receives either the value of the second read port (rs2) or a constant from the instruction, such as the offset for lw and sw. Depending on the instruction, the ALU result is used as the value for the register file or as the address for data memory; for lw, the value read from data memory is written back to the register file.

cpu data path

The control part

So far, the control part is the most black-boxed element in our schematics. We already know how multiplexers work, and we can already see the feedback path through which a branch affects the program counter. What is still open is the central question: how do the multiplexers, the ALU, the register file and the data memory know what to do for a particular instruction? The answer is the control unit, which derives the appropriate control signals from the instruction’s opcode.

cpu structure with control

How the control unit works is shown in the next chapter: The Control Unit. There we also trace our example program clock cycle by clock cycle through the CPU.