mul
mul
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

mul multiplies two registers together. It reads source registers rs1 and rs2, multiplies their values, and writes the result into destination register rd — written mul rd, rs1, rs2, meaning rd = rs1 * rs2.

Multiplication is not part of the most basic RISC-V core. The instruction set is built in layers called extensions, and multiply and divide live in one named M. This simulator includes it (its full name, RV32IM, ends in M), so mul, div, and friends are available — but on a stripped-down processor they might not be, and the work would fall to software instead.

There is a subtlety about size. Multiplying two 32-bit numbers can produce a result needing up to 64 bits — far more than one register holds. mul keeps only the lower 32 bits of that result, which for everyday small values is the complete answer. (If you ever need the upper half, a separate instruction, mulh, provides it.) As with addition, the low 32 bits come out the same whether the inputs are treated as signed or unsigned, so one instruction covers both.

There is often a faster route when multiplying by a power of two — 2, 4, 8, 16, and so on. Shifting a number's bits left by 3 places multiplies it by 8, and shifting is cheaper than a full multiply (see slli). Compilers do this swap automatically. The example multiplies 6 by 7, leaving 42 in t2.

li t0, 6
li t1, 7
mul t2, t0, t1   # t2 = 42