addi
addi
rd, rs1, imm
rd = rs1 + imm
R
31–25funct7
24–20rs2
19–15rs1
14–12funct3
11–7rd
6–0opcode
I
31–20imm[11:0]
19–15rs1
14–12funct3
11–7rd
6–0opcode
S
31–25imm[11:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:0]
6–0opcode
B
31–25imm[12,10:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:1,11]
6–0opcode
U
31–12imm[31:12]
11–7rd
6–0opcode
J
31–12imm[20,10:1,11,19:12]
11–7rd
6–0opcode

addi means add immediate, and the key word is immediate. So far, adding has meant combining two registers. But often one of the numbers you want to add is a fixed constant known when you write the program — like adding 1 to a counter. An immediate is exactly that: a constant value written directly into the instruction itself, instead of being read from a register. addi adds such a constant to a register.

The form is addi rd, rs1, imm: take the value in source register rs1, add the constant imm, and store the result in destination register rd. So addi t0, t0, 1 reads t0, adds one, and writes it back — the assembly way of saying t0 = t0 + 1.

There is a size limit on the constant. The immediate must fit in 12 bits and is signed (it can be negative), giving a range from -2048 to 2047. The assembler refuses anything larger; for bigger constants you first load them into a register with li. Because the immediate can be negative, addi also handles subtraction of a constant — addi t0, t0, -1 counts down — which is why RISC-V never needed a separate subtract-immediate instruction.

addi is one of the most-used instructions in any program: bumping counters, stepping a pointer to the next item, and reserving scratch space on the stack are all addi. The example shows two directions at once — adding 1 to advance a counter, and adding -16 to set aside 16 bytes of working memory, the standard opening move of a function that needs room to work.

addi t0, t0, 1     # t0++
addi sp, sp, -16   # reserve 16 bytes of stack