目录 ← 首页
CS61C

RISC-V Arithmetic Instructions I: Arithmetic Operations

Learning Outcomes

  • Write assembly to perform arithmetic operations.
  • Write arithmetic instructions involving immediates.
  • Understand how pseudoinstructions and the zero register help balance a reduced instruction set with flexibility of operations.

add and sub Instructions

Generally, assembly instructions have a very rigid format. Consider arithmetic and logical instructions like addition (add), bitwise AND (and), etc., which operate on two registers and store the result in a third register. These instructions always follow the same rigid syntax shown in #fig-r-type-arithmetic:

Syntax template for an R-type instruction: opname rd rs1 rs2 with braces labeling operation, destination register, first source register, and second source register.

R-Type instructions (arithmetic and logical involving two source registers).

The fields are separated by spaces1, in order:

  • opname: The operation name
  • rd: The destination register, i.e., the operand to which we store the result of the operation.
  • rs1: The “source1” register, i.e., the first source operand for the operation.
  • rs2: The “source2” register, i.e., the second operand for the operation.

The full set of instructions that follow the format in #fig-r-type are located on the RISC-V green card. For now, we focus on two instructions in #tab-add-sub:

The addition command in assembly is simply add, which is easy to remember. The RV32I instruction

add x1, x2, x3

is equivalent to the C statement a = b + c; for 32-bit integers3 a, b, and c, where each variable corresponds to a value stored in a register. In #fig-rv32i-add, the variable a is in register x1, variable b is in register x2, and variable c is in x3.

Addition example pairing RISC-V add x1 x2 x3 with C a = b + c, with arrows from x1 to a, x2 to b, and x3 to c.

Addition instruction add in RISC-V and C.

Subtraction works almost the same way, using the operation sub. If you want to subtract the values in x4 and x5 and store the result in x3, you would write the below, which is equivalent to the C integer arithmetic statement d = e - f; (@fig-rv32i-sub).

sub x3, x4, x5

Subtraction example pairing RISC-V sub x4 x5 x6 with C d = e - f, with arrows linking destination and source registers to variables and a note that operand order matters.

Subtraction instruction sub in RISC-V and C.

RISC Arithmetic: Examples

As mentioned earlier, a single line of C may translate into several lines of RISC-V. Consider the C integer arithmetic statement:

a = b + c + d - e;

Suppose that variables a, b, c, d, and e mapped to registers x10, x1, x2, x3, and x4, respectively. We can use x10 as a running sum to compute the correct value of a after three instructions:

add x10  x1 x2   # a_temp = b + c
add x10 x10 x3   # a_temp = a_temp + d
sub x10 x10 x4   # a = a_temp - e

Immediates

Immediates are numerical constants in RISC-V. Immediates are called as such because their bit patterns are directly encoded into the machine instruction—thus their values are “immediately” available to the computer.

Immediates appear often in code; hence, they have separate instructions (@fig-i-type-arithmetic).

Syntax template for an I-type arithmetic or logical instruction: opname rd rs1 imm with braces labeling operation, destination, first source register, and immediate operand.

Arithmetic and Logical I-Type instructions involving one source register and one immediate.

Like before, fields are separated by spaces1, in order:

  • opname: The operation name
  • rd: The destination register, i.e., the operand to which we store the result of the operation.
  • rs1: The “source1” register, i.e., the first source operand for the operation.
  • imm: The immediate (numeric constant).

The full set of instructions that follow the format in #fig-i-type-arithmetic are located on the RISC-V green card.

addi instruction

Let’s discuss the Add Immediate instruction (@tab-addi).

The RV32I instruction

addi x3, x4, 10

is equivalent to the C statement f = g + 10;, where f and g are 32-bit integers (@fig-rv32i-addi).

Add-immediate example pairing RISC-V addi x3 x4 10 with C f = g + 10, with arrows from x3 to f and x4 to g and matching emphasis on constant 10.

Add immediate instruction in RISC-V and C.

::::{warning} No subi instruction!

Recall the “R” in RISC is Reduced. If an operation can be decomposed into equivalent or simpler operations, don’t include it in the ISA.

RISC-V Immediates are signed. There is therefore no “subtract immediate” instruction–there is just addi. The instruction

addi x3 x4 -10

is equivalent to the C statement f = g - 10; where f and g are 32-bit integers (@fig-rv32i-subi).

Subtraction via add-immediate example pairing RISC-V addi x3 x4 -10 with C f = g - 10, showing negative immediate as the subtracted constant.

Add immediate instruction in RISC-V and C with negative values.

Using x0 to reduce our instruction set

We have previously discussed the zero register x0. Hardwiring register x0 to the value zero proves extremely useful for reusing add and addi for very common C operations. Two toy examples are shown in #fig-rv32i-x0-mv and #fig-rv32i-x0-li:

Register-move idiom showing RISC-V add x3 x4 x0 equivalent to C f = g, with x0 highlighted as zero and arrows from x3 and x4 to f and g.

To assign the C integer variable f to the value of another integer variable g, we could use add with x0 as a source operand (though we don’t in practice4).

Load-immediate idiom showing RISC-V addi x3 x0 0xff equivalent to C f = 0xff, with an arrow from destination register x3 to variable f and x0 as the source register with zero value.

To assign the variable f to a numeric constant, use addi with x0 as the source register operand.

Pseudoinstructions

We have just seen several cases where common C statements translate into other instructions in our reduced instruction set architecture. While this is fine and dandy for designing architecture, compilers (and you, as a human assembly instruction-writer) will find it useful to use pseudoinstructions.

Pseudoinstructions are convenient instructions in RISC-V. Pseudoinstructions help compilers more directly translate higher-level language code into assembly instructions (really!), but by themselves they are not real instructions.

Consider two examples below (and see the full set in the RISC-V green card).

When assembling to machine instructions, the assembler replaces pseudoinstructions with their real instruction counterpart.

Footnotes

  1. Stylistically, assembly instructions can include commas. In RISC-V, commas are not needed. We stick to a space-only convention in this course. 2

  2. We won’t expect you to know Verilog in this course, but the syntax is useful. R[rs1] means the data in register rs1. 2

  3. You will see later that signed and unsigned addition and subtraction are implemented with the same hardware circuit. 2

  4. Why addi with immediate 0 and not add with x0 (as in #fig-rv32i-x0-mv)? See the ASM manual on GitHub. 2

  5. This description is incomplete given the range of imm in addi. See the green-card and a later section for the full translation of load immediates.

  6. We will see later how a “no-op” instruction can improve hardware performance (really).