sub
sub
rd, rs1, rs2
rd = rs1 - rs2
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

sub is subtraction between registers. Like its partner add, it works on registers — the small numbered storage slots inside the processor, each holding one 32-bit number. It reads two of them and writes the result to a third.

The form is sub rd, rs1, rs2, meaning rd = rs1 - rs2. The first named register, rd, is the destination where the answer lands; rs1 and rs2 are the sources. Order matters here in a way it did not for addition, and it is a common beginner slip: sub t2, t0, t1 computes t0 minus t1, not the other way around. The left source is always the one being subtracted *from*.

To subtract you might expect an instruction called subi for subtracting a constant, but there is none — and that is intentional. The addi instruction (add a constant) accepts negative constants, so subtracting a fixed number is just adding its negative: addi t0, t0, -1 lowers t0 by one. The designers saved an instruction by letting one cover both directions.

A particularly useful pattern: RISC-V has a special register named zero that always holds the value 0. Subtracting a number from zero flips its sign — sub t0, zero, t1 puts the negative of t1 into t0. That trick is so common it has its own shorthand, the neg instruction. In the worked example, 10 minus 4 leaves 6 in t2; swap the two sources and you would get -6 instead, stored in the processor's scheme for negative numbers.

li t0, 10
li t1, 4
sub t2, t0, t1   # t2 = 6