RISC-V Complete Documentation

Instructions

add reg, reg, reg

Addition: set t1 to (t2 plus t3)

add t1,t2,t3

add.uw reg, reg, reg

Add unsigned word : Set t1 to the low 32 bits of t2, zero extended, plus t3. Adds an unsigned 32 bit index to a 64 bit base without a separate zero extension (64bit)

add.uw t1,t2,t3

addi reg, reg, [imm / %lo(id)]

Addition immediate: set t1 to (t2 plus signed 12-bit immediate)

addi t1,t2,-100

Load Lower Address : Set t1 to t2 + lower 12-bit label's address

addi t1,t2,%lo(label)

addiw reg, reg, imm

Addition immediate: set t1 to (t2 plus signed 12-bit immediate) using only the lower 32 bits (64bit)

addiw t1,t2,-100

addw reg, reg, reg

Addition: set t1 to (t2 plus t3) using only the lower 32 bits (64bit)

addw t1,t2,t3

amoadd.d reg, reg, (reg)

Atomic add : Set t1 to the double word at the address in t3, and store that value plus t2 there. Useful for a shared counter that several agents increment (64bit)

amoadd.d t1, t2, (t3)

amoadd.w reg, reg, (reg)

Atomic add : Set t1 to the word at the address in t3, and store that value plus t2 there. Useful for a shared counter that several agents increment

amoadd.w t1, t2, (t3)

amoand.d reg, reg, (reg)

Atomic and : Set t1 to the double word at the address in t3, and store the bitwise AND of that value and t2 there. Clears a bit mask in shared memory (64bit)

amoand.d t1, t2, (t3)

amoand.w reg, reg, (reg)

Atomic and : Set t1 to the word at the address in t3, and store the bitwise AND of that value and t2 there. Clears a bit mask in shared memory

amoand.w t1, t2, (t3)

amomax.d reg, reg, (reg)

Atomic maximum (signed) : Set t1 to the double word at the address in t3, and store the larger of that value and t2 there, comparing as signed (64bit)

amomax.d t1, t2, (t3)

amomax.w reg, reg, (reg)

Atomic maximum (signed) : Set t1 to the word at the address in t3, and store the larger of that value and t2 there, comparing as signed

amomax.w t1, t2, (t3)

amomaxu.d reg, reg, (reg)

Atomic maximum (unsigned) : Set t1 to the double word at the address in t3, and store the larger of that value and t2 there, comparing as unsigned (64bit)

amomaxu.d t1, t2, (t3)

amomaxu.w reg, reg, (reg)

Atomic maximum (unsigned) : Set t1 to the word at the address in t3, and store the larger of that value and t2 there, comparing as unsigned

amomaxu.w t1, t2, (t3)

amomin.d reg, reg, (reg)

Atomic minimum (signed) : Set t1 to the double word at the address in t3, and store the smaller of that value and t2 there, comparing as signed (64bit)

amomin.d t1, t2, (t3)

amomin.w reg, reg, (reg)

Atomic minimum (signed) : Set t1 to the word at the address in t3, and store the smaller of that value and t2 there, comparing as signed

amomin.w t1, t2, (t3)

amominu.d reg, reg, (reg)

Atomic minimum (unsigned) : Set t1 to the double word at the address in t3, and store the smaller of that value and t2 there, comparing as unsigned (64bit)

amominu.d t1, t2, (t3)

amominu.w reg, reg, (reg)

Atomic minimum (unsigned) : Set t1 to the word at the address in t3, and store the smaller of that value and t2 there, comparing as unsigned

amominu.w t1, t2, (t3)

amoor.d reg, reg, (reg)

Atomic or : Set t1 to the double word at the address in t3, and store the bitwise OR of that value and t2 there. Sets a bit mask in shared memory (64bit)

amoor.d t1, t2, (t3)

amoor.w reg, reg, (reg)

Atomic or : Set t1 to the word at the address in t3, and store the bitwise OR of that value and t2 there. Sets a bit mask in shared memory

amoor.w t1, t2, (t3)

amoswap.d reg, reg, (reg)

Atomic swap : Set t1 to the double word at the address in t3, and store t2 there. The exchange is indivisible, which makes this the natural way to implement a spinlock (64bit)

amoswap.d t1, t2, (t3)

amoswap.w reg, reg, (reg)

Atomic swap : Set t1 to the word at the address in t3, and store t2 there. The exchange is indivisible, which makes this the natural way to implement a spinlock

amoswap.w t1, t2, (t3)

amoxor.d reg, reg, (reg)

Atomic xor : Set t1 to the double word at the address in t3, and store the bitwise XOR of that value and t2 there (64bit)

amoxor.d t1, t2, (t3)

amoxor.w reg, reg, (reg)

Atomic xor : Set t1 to the word at the address in t3, and store the bitwise XOR of that value and t2 there

amoxor.w t1, t2, (t3)

and reg, reg, reg

Bitwise AND : Set t1 to bitwise AND of t2 and t3

and t1,t2,t3

andi reg, reg, imm

Bitwise AND immediate : Set t1 to bitwise AND of t2 and sign-extended 12-bit immediate

andi t1,t2,-100

andn reg, reg, reg

AND with inverted operand : Set t1 to the bitwise AND of t2 and the bitwise NOT of t3. Clears in t2 every bit that is set in t3

andn t1,t2,t3

auipc reg, imm

Add upper immediate to pc: set t1 to (pc plus an upper 20-bit immediate)

auipc t1,100000

b id

Branch : Branch to statement at label unconditionally

b label

bclr reg, reg, reg

Clear bit : Set t1 to t2 with the single bit numbered by the low bits of t3 cleared

bclr t1,t2,t3

bclri reg, reg, imm

Clear bit by immediate : Set t1 to t2 with the single bit numbered by the immediate cleared

bclri t1,t2,33

beq reg, reg, id

Branch if equal : Branch to statement at label's address if t1 and t2 are equal

beq t1,t2,label

beqz reg, id

Branch if EQual Zero : Branch to statement at label if t1 == 0

beqz t1,label

bext reg, reg, reg

Extract bit : Set t1 to the single bit of t2 numbered by the low bits of t3, as 0 or 1

bext t1,t2,t3

bexti reg, reg, imm

Extract bit by immediate : Set t1 to the single bit of t2 numbered by the immediate, as 0 or 1

bexti t1,t2,33

bge reg, reg, id

Branch if greater than or equal: Branch to statement at label's address if t1 is greater than or equal to t2

bge t1,t2,label

bgeu reg, reg, id

Branch if greater than or equal to (unsigned): Branch to statement at label's address if t1 is greater than or equal to t2 (with an unsigned interpretation)

bgeu t1,t2,label

bgez reg, id

Branch if Greater than or Equal to Zero : Branch to statement at label if t1 >= 0

bgez t1,label

bgt reg, reg, id

Branch if Greater Than : Branch to statement at label if t1 > t2

bgt t1,t2,label

bgtu reg, reg, id

Branch if Greater Than Unsigned: Branch to statement at label if t1 > t2 (unsigned compare)

bgtu t1,t2,label

bgtz reg, id

Branch if Greater Than Zero: Branch to statement at label if t1 > 0

bgtz t1,label

binv reg, reg, reg

Invert bit : Set t1 to t2 with the single bit numbered by the low bits of t3 flipped

binv t1,t2,t3

binvi reg, reg, imm

Invert bit by immediate : Set t1 to t2 with the single bit numbered by the immediate flipped

binvi t1,t2,33

ble reg, reg, id

Branch if Less or Equal : Branch to statement at label if t1 <= t2

ble t1,t2,label

bleu reg, reg, id

Branch if Less or Equal Unsigned : Branch to statement at label if t1 <= t2 (unsigned compare)

bleu t1,t2,label

blez reg, id

Branch if Less than or Equal to Zero : Branch to statement at label if t1 <= 0

blez t1,label

blt reg, reg, id

Branch if less than: Branch to statement at label's address if t1 is less than t2

blt t1,t2,label

bltu reg, reg, id

Branch if less than (unsigned): Branch to statement at label's address if t1 is less than t2 (with an unsigned interpretation)

bltu t1,t2,label

bltz reg, id

Branch if Less Than Zero : Branch to statement at label if t1 < 0

bltz t1,label

bne reg, reg, id

Branch if not equal : Branch to statement at label's address if t1 and t2 are not equal

bne t1,t2,label

bnez reg, id

Branch if Not Equal Zero : Branch to statement at label if t1 != 0

bnez t1,label

bset reg, reg, reg

Set bit : Set t1 to t2 with the single bit numbered by the low bits of t3 set

bset t1,t2,t3

bseti reg, reg, imm

Set bit by immediate : Set t1 to t2 with the single bit numbered by the immediate set

bseti t1,t2,33

call id

CALL: call a far-away subroutine

call label

clz reg, reg

Count leading zeros : Set t1 to the number of 0 bits above the most significant 1 bit of t2, which is the full register width when t2 is zero

clz t1,t2

clzw reg, reg

Count leading zeros (32 bit) : Set t1 to the number of 0 bits above the most significant 1 bit of the low 32 bits of t2, which is 32 when they are zero (64bit)

clzw t1,t2

cpop reg, reg

Count set bits : Set t1 to the number of 1 bits in t2, also known as the population count

cpop t1,t2

cpopw reg, reg

Count set bits (32 bit) : Set t1 to the number of 1 bits in the low 32 bits of t2 (64bit)

cpopw t1,t2

csrc reg, csr

Clear bits in control and status register

csrc t1, fcsr

csrci csr, imm

Clear bits in control and status register

csrci fcsr, 100

csrr reg, csr

Read control and status register

csrr t1, fcsr

csrrc reg, csr, reg

Atomic Read/Clear CSR: read from the CSR into t0 and clear bits of the CSR according to t1

csrrc t0, fcsr, t1

csrrci reg, csr, imm

Atomic Read/Clear CSR Immediate: read from the CSR into t0 and clear bits of the CSR according to a constant

csrrci t0, fcsr, 10

csrrs reg, csr, reg

Atomic Read/Set CSR: read from the CSR into t0 and logical or t1 into the CSR

csrrs t0, fcsr, t1

csrrsi reg, csr, imm

Atomic Read/Set CSR Immediate: read from the CSR into t0 and logical or a constant into the CSR

csrrsi t0, fcsr, 10

csrrw reg, csr, reg

Atomic Read/Write CSR: read from the CSR into t0 and write t1 into the CSR

csrrw t0, fcsr, t1

csrrwi reg, csr, imm

Atomic Read/Write CSR Immediate: read from the CSR into t0 and write a constant into the CSR

csrrwi t0, fcsr, 10

csrs reg, csr

Set bits in control and status register

csrs t1, fcsr

csrsi csr, imm

Set bits in control and status register

csrsi fcsr, 100

csrw reg, csr

Write control and status register

csrw t1, fcsr

csrwi csr, imm

Write control and status register

csrwi fcsr, 100

ctz reg, reg

Count trailing zeros : Set t1 to the number of 0 bits below the least significant 1 bit of t2, which is the full register width when t2 is zero

ctz t1,t2

ctzw reg, reg

Count trailing zeros (32 bit) : Set t1 to the number of 0 bits below the least significant 1 bit of the low 32 bits of t2, which is 32 when they are zero (64bit)

ctzw t1,t2

div reg, reg, reg

Division: set t1 to the result of t2/t3

div t1,t2,t3

divu reg, reg, reg

Division: set t1 to the result of t2/t3 using unsigned division

divu t1,t2,t3

divuw reg, reg, reg

Division: set t1 to the result of t2/t3 using unsigned division limited to 32 bits (64bit)

divuw t1,t2,t3

divw reg, reg, reg

Division: set t1 to the result of t2/t3 using only the lower 32 bits (64bit)

divw t1,t2,t3

ebreak

Pause execution

ebreak

ecall

Issue a system call : Execute the system call specified by value in a7

ecall

fabs.d freg, freg

Set f1 to the absolute value of f2 (64 bit)

fabs.d f1, f2

fabs.s freg, freg

Set f1 to the absolute value of f2

fabs.s f1, f2

fadd.d freg, freg, freg, rounding

Floating ADD (64 bit): assigns f1 to f2 + f3

fadd.d f1, f2, f3, dyn fadd.d f1, f2, f3

fadd.s freg, freg, freg, rounding

Floating ADD: assigns f1 to f2 + f3

fadd.s f1, f2, f3, dyn fadd.s f1, f2, f3

fclass.d reg, freg

Classify a floating point number (64 bit)

fclass.d t1, f1

fclass.s reg, freg

Classify a floating point number

fclass.s t1, f1

fcvt.d.l freg, reg, rounding

Convert double from long: Assigns the value of t1 to f1 (64bit)

fcvt.d.l f1, t1, dyn

Convert double from signed 64 bit integer: Assigns the value of t1 to f1 (64bit)

fcvt.d.l f1, t1

fcvt.d.lu freg, reg, rounding

Convert double from unsigned long: Assigns the value of t1 to f1 (64bit)

fcvt.d.lu f1, t1, dyn

Convert double from unsigned 64 bit integer: Assigns the value of t1 to f1 (64bit)

fcvt.d.lu f1, t1

fcvt.d.s freg, freg, rounding

Convert a float to a double: Assigned the value of f2 to f1

fcvt.d.s f1, f2, dyn

Convert float to double: Assigned the value of f2 to f1

fcvt.d.s f1, f2

fcvt.d.w freg, reg, rounding

Convert double from integer: Assigns the value of t1 to f1

fcvt.d.w f1, t1, dyn

Convert double from signed integer: Assigns the value of t1 to f1

fcvt.d.w f1, t1

fcvt.d.wu freg, reg, rounding

Convert double from unsigned integer: Assigns the value of t1 to f1

fcvt.d.wu f1, t1, dyn fcvt.d.wu f1, t1

fcvt.l.d reg, freg, rounding

Convert 64 bit integer from double: Assigns the value of f1 (rounded) to t1 (64bit)

fcvt.l.d t1, f1, dyn

Convert signed 64 bit integer from double: Assigns the value of f1 (rounded) to t1 (64bit)

fcvt.l.d t1, f1

fcvt.l.s reg, freg, rounding

Convert 64 bit integer from float: Assigns the value of f1 (rounded) to t1 (64bit)

fcvt.l.s t1, f1, dyn

Convert signed 64 bit integer from float: Assigns the value of f1 (rounded) to t1 (64bit)

fcvt.l.s t1, f1

fcvt.lu.d reg, freg, rounding

Convert unsigned 64 bit integer from double: Assigns the value of f1 (rounded) to t1 (64bit)

fcvt.lu.d t1, f1, dyn fcvt.lu.d t1, f1

fcvt.lu.s reg, freg, rounding

Convert unsigned 64 bit integer from float: Assigns the value of f1 (rounded) to t1 (64bit)

fcvt.lu.s t1, f1, dyn fcvt.lu.s t1, f1

fcvt.s.d freg, freg, rounding

Convert a double to a float: Assigned the value of f2 to f1

fcvt.s.d f1, f2, dyn

Convert double to float: Assigned the value of f2 to f1

fcvt.s.d f1, f2

fcvt.s.l freg, reg, rounding

Convert float from long: Assigns the value of t1 to f1 (64bit)

fcvt.s.l f1, t1, dyn

Convert float from signed 64 bit integer: Assigns the value of t1 to f1 (64bit)

fcvt.s.l f1, t1

fcvt.s.lu freg, reg, rounding

Convert float from unsigned long: Assigns the value of t1 to f1 (64bit)

fcvt.s.lu f1, t1, dyn

Convert float from unsigned 64 bit integer: Assigns the value of t1 to f1 (64bit)

fcvt.s.lu f1, t1

fcvt.s.w freg, reg, rounding

Convert float from integer: Assigns the value of t1 to f1

fcvt.s.w f1, t1, dyn

Convert float from signed integer: Assigns the value of t1 to f1

fcvt.s.w f1, t1

fcvt.s.wu freg, reg, rounding

Convert float from unsigned integer: Assigns the value of t1 to f1

fcvt.s.wu f1, t1, dyn fcvt.s.wu f1, t1

fcvt.w.d reg, freg, rounding

Convert integer from double: Assigns the value of f1 (rounded) to t1

fcvt.w.d t1, f1, dyn

Convert signed integer from double: Assigns the value of f1 (rounded) to t1

fcvt.w.d t1, f1

fcvt.w.s reg, freg, rounding

Convert integer from float: Assigns the value of f1 (rounded) to t1

fcvt.w.s t1, f1, dyn

Convert signed integer from float: Assigns the value of f1 (rounded) to t1

fcvt.w.s t1, f1

fcvt.wu.d reg, freg, rounding

Convert unsinged integer from double: Assigns the value of f1 (rounded) to t1

fcvt.wu.d t1, f1, dyn

Convert unsigned integer from double: Assigns the value of f1 (rounded) to t1

fcvt.wu.d t1, f1

fcvt.wu.s reg, freg, rounding

Convert unsinged integer from float: Assigns the value of f1 (rounded) to t1

fcvt.wu.s t1, f1, dyn

Convert unsigned integer from float: Assigns the value of f1 (rounded) to t1

fcvt.wu.s t1, f1

fdiv.d freg, freg, freg, rounding

Floating DIVide (64 bit): assigns f1 to f2 / f3

fdiv.d f1, f2, f3, dyn fdiv.d f1, f2, f3

fdiv.s freg, freg, freg, rounding

Floating DIVide: assigns f1 to f2 / f3

fdiv.s f1, f2, f3, dyn fdiv.s f1, f2, f3

fence imm, imm

Ensure that IO and memory accesses before the fence happen before the following IO and memory accesses as viewed by a different thread

fence 1, 1

fence.i

Ensure that stores to instruction memory are visible to instruction fetches

fence.i

feq.d reg, freg, freg

Floating EQuals (64 bit): if f1 = f2, set t1 to 1, else set t1 to 0

feq.d t1, f1, f2

feq.s reg, freg, freg

Floating EQuals: if f1 = f2, set t1 to 1, else set t1 to 0

feq.s t1, f1, f2

fge.d reg, freg, freg

Floating Greater Than or Equal (64 bit): if f2 >= f3, set t1 to 1, else set t1 to 0

fge.d t1, f2, f3

fge.s reg, freg, freg

Floating Greater Than or Equal: if f2 >= f3, set t1 to 1, else set t1 to 0

fge.s t1, f2, f3

fgt.d reg, freg, freg

Floating Greater Than (64 bit): if f2 > f3, set t1 to 1, else set t1 to 0

fgt.d t1, f2, f3

fgt.s reg, freg, freg

Floating Greater Than: if f2 > f3, set t1 to 1, else set t1 to 0

fgt.s t1, f2, f3

fld freg, [imm(reg) / (reg) / imm / id / %lo(id)], [reg / (reg)]

Load a double from memory

fld f1, -100(t1)

Load Word: Set f1 to 64-bit value from effective memory word address

fld f1,(t2) fld f1,-100

Load Word: Set f1 to 64-bit value from effective memory word address using t3 as a temporary

fld f1,10000000,t3 fld f1,label, t3

Load from Address

fld f1,%lo(label)(t2)

fle.d reg, freg, freg

Floating Less than or Equals (64 bit): if f1 <= f2, set t1 to 1, else set t1 to 0

fle.d t1, f1, f2

fle.s reg, freg, freg

Floating Less than or Equals: if f1 <= f2, set t1 to 1, else set t1 to 0

fle.s t1, f1, f2

flt.d reg, freg, freg

Floating Less Than (64 bit): if f1 < f2, set t1 to 1, else set t1 to 0

flt.d t1, f1, f2

flt.s reg, freg, freg

Floating Less Than: if f1 < f2, set t1 to 1, else set t1 to 0

flt.s t1, f1, f2

flw freg, [imm(reg) / (reg) / imm / id / %lo(id)], [reg / (reg)]

Load a float from memory

flw f1, -100(t1)

Load Word Coprocessor 1 : Set f1 to 32-bit value from effective memory word address

flw f1,(t2) flw f1,-100

Load Word Coprocessor 1 : Set f1 to 32-bit value from effective memory word address using t3 as a temporary

flw f1,10000000,t3 flw f1,label, t3

Load from Address

flw f1,%lo(label)(t2)

fmadd.d freg, freg, freg, freg, rounding

Fused Multiply Add (64 bit): Assigns f2*f3+f4 to f1

fmadd.d f1, f2, f3, f4, dyn fmadd.d f1, f2, f3, f4

fmadd.s freg, freg, freg, freg, rounding

Fused Multiply Add: Assigns f2*f3+f4 to f1

fmadd.s f1, f2, f3, f4, dyn fmadd.s f1, f2, f3, f4

fmax.d freg, freg, freg

Floating MAXimum (64 bit): assigns f1 to the larger of f1 and f3

fmax.d f1, f2, f3

fmax.s freg, freg, freg

Floating MAXimum: assigns f1 to the larger of f1 and f3

fmax.s f1, f2, f3

fmin.d freg, freg, freg

Floating MINimum (64 bit): assigns f1 to the smaller of f1 and f3

fmin.d f1, f2, f3

fmin.s freg, freg, freg

Floating MINimum: assigns f1 to the smaller of f1 and f3

fmin.s f1, f2, f3

fmsub.d freg, freg, freg, freg, rounding

Fused Multiply Subatract: Assigns f2*f3-f4 to f1

fmsub.d f1, f2, f3, f4, dyn

Fused Multiply Subatract (64 bit): Assigns f2*f3-f4 to f1

fmsub.d f1, f2, f3, f4

fmsub.s freg, freg, freg, freg, rounding

Fused Multiply Subatract: Assigns f2*f3-f4 to f1

fmsub.s f1, f2, f3, f4, dyn fmsub.s f1, f2, f3, f4

fmul.d freg, freg, freg, rounding

Floating MULtiply (64 bit): assigns f1 to f2 * f3

fmul.d f1, f2, f3, dyn fmul.d f1, f2, f3

fmul.s freg, freg, freg, rounding

Floating MULtiply: assigns f1 to f2 * f3

fmul.s f1, f2, f3, dyn fmul.s f1, f2, f3

fmv.d freg, freg

Move the value of f2 to f1 (64 bit)

fmv.d f1, f2

fmv.d.x freg, reg

Move float: move bits representing a double from an 64 bit integer register (64bit)

fmv.d.x f1, t1

fmv.s freg, freg

Move the value of f2 to f1

fmv.s f1, f2

fmv.s.x freg, reg

Move float: move bits representing a float from an integer register

fmv.s.x f1, t1

fmv.w.x freg, reg

Move float (New mnemonic): move bits representing a float from an integer register

fmv.w.x f1, t1

fmv.x.d reg, freg

Move double: move bits representing a double to an 64 bit integer register (64bit)

fmv.x.d t1, f1

fmv.x.s reg, freg

Move float: move bits representing a float to an integer register

fmv.x.s t1, f1

fmv.x.w reg, freg

Move float (New mnemonic): move bits representing a float to an integer register

fmv.x.w t1, f1

fneg.d freg, freg

Set f1 to the negation of f2 (64 bit)

fneg.d f1, f2

fneg.s freg, freg

Set f1 to the negation of f2

fneg.s f1, f2

fnmadd.d freg, freg, freg, freg, rounding

Fused Negate Multiply Add (64 bit): Assigns -(f2*f3+f4) to f1

fnmadd.d f1, f2, f3, f4, dyn fnmadd.d f1, f2, f3, f4

fnmadd.s freg, freg, freg, freg, rounding

Fused Negate Multiply Add: Assigns -(f2*f3+f4) to f1

fnmadd.s f1, f2, f3, f4, dyn fnmadd.s f1, f2, f3, f4

fnmsub.d freg, freg, freg, freg, rounding

Fused Negated Multiply Subatract: Assigns -(f2*f3-f4) to f1

fnmsub.d f1, f2, f3, f4, dyn

Fused Negated Multiply Subatract (64 bit): Assigns -(f2*f3-f4) to f1

fnmsub.d f1, f2, f3, f4

fnmsub.s freg, freg, freg, freg, rounding

Fused Negated Multiply Subatract: Assigns -(f2*f3-f4) to f1

fnmsub.s f1, f2, f3, f4, dyn fnmsub.s f1, f2, f3, f4

frcsr reg

Read FP control/status register

frcsr t1

frflags reg

Read FP exception flags

frflags t1

frrm reg

Read FP rounding mode

frrm t1

frsr reg

Alias for frcsr t1

frsr t1

fscsr reg, reg

Swap FP control/status register

fscsr t1, t2

Write FP control/status register

fscsr t1

fsd freg, [imm(reg) / (reg) / imm / id / %lo(id)], [reg / (reg)]

Store a double to memory

fsd f1, -100(t1)

Store Word: Store 64-bit value from f1 to effective memory word address

fsd f1,(t2) fsd f1,-100

Store Word: Store 64-bit value from f1 to effective memory word address using t3 as a temporary

fsd f1,10000000,t3 fsd f1,label, t3

Store to Address

fsd f1,%lo(label)(t2)

fsflags reg, reg

Swap FP exception flags

fsflags t1, t2

Write FP exception flags

fsflags t1

fsgnj.d freg, freg, freg

Floating point sign injection (64 bit): replace the sign bit of f2 with the sign bit of f3 and assign it to f1

fsgnj.d f1, f2, f3

fsgnj.s freg, freg, freg

Floating point sign injection: replace the sign bit of f2 with the sign bit of f3 and assign it to f1

fsgnj.s f1, f2, f3

fsgnjn.d freg, freg, freg

Floating point sign injection (inverted 64 bit): replace the sign bit of f2 with the opposite of sign bit of f3 and assign it to f1

fsgnjn.d f1, f2, f3

fsgnjn.s freg, freg, freg

Floating point sign injection (inverted): replace the sign bit of f2 with the opposite of sign bit of f3 and assign it to f1

fsgnjn.s f1, f2, f3

fsgnjx.d freg, freg, freg

Floating point sign injection (xor 64 bit): xor the sign bit of f2 with the sign bit of f3 and assign it to f1

fsgnjx.d f1, f2, f3

fsgnjx.s freg, freg, freg

Floating point sign injection (xor): xor the sign bit of f2 with the sign bit of f3 and assign it to f1

fsgnjx.s f1, f2, f3

fsqrt.d freg, freg, rounding

Floating SQuare RooT (64 bit): Assigns f1 to the square root of f2

fsqrt.d f1, f2, dyn fsqrt.d f1, f2

fsqrt.s freg, freg, rounding

Floating SQuare RooT: Assigns f1 to the square root of f2

fsqrt.s f1, f2, dyn fsqrt.s f1, f2

fsrm reg, reg

Swap FP rounding mode

fsrm t1, t2

Write FP rounding mode

fsrm t1

fssr reg, reg

Alias for fscsr t1, t2

fssr t1, t2

Alias for fscsr t1

fssr t1

fsub.d freg, freg, freg, rounding

Floating SUBtract (64 bit): assigns f1 to f2 - f3

fsub.d f1, f2, f3, dyn fsub.d f1, f2, f3

fsub.s freg, freg, freg, rounding

Floating SUBtract: assigns f1 to f2 - f3

fsub.s f1, f2, f3, dyn fsub.s f1, f2, f3

fsw freg, [imm(reg) / (reg) / imm / id / %lo(id)], [reg / (reg)]

Store a float to memory

fsw f1, -100(t1)

Store Word Coprocessor 1 : Store 32-bit value from f1 to effective memory word address

fsw f1,(t2) fsw f1,-100

Store Word Coprocessor 1 : Store 32-bit value from f1 to effective memory word address using t3 as a temporary

fsw f1,10000000,t3 fsw f1,label, t3

Store to Address

fsw f1,%lo(label)(t2)

j id

Jump : Jump to statement at label

j label

jal [reg / id], id

Jump and link : Set t1 to Program Counter (return address) then jump to statement at target address

jal t1, target

Jump And Link: Jump to statement at label and set the return address to ra

jal label

jalr reg, [reg / imm / imm(reg)], imm

Jump and link register: Set t1 to Program Counter (return address) then jump to statement at t2 + immediate

jalr t1, t2, -100

Jump And Link Register: Jump to address in t0 and set the return address to ra

jalr t0 jalr t0, -100

Jump And Link Register: Jump to address in t1 and set the return address to t0

jalr t0,-100(t1)

jr reg, imm

Jump Register: Jump to address in t0

jr t0 jr t0, -100

la reg, id

Load Address : Set t1 to label's address

la t1,label

lb reg, [imm(reg) / (reg) / imm / id / %lo(id)], (reg)

Set t1 to sign-extended 8-bit value from effective memory byte address

lb t1, -100(t2)

Load Byte : Set t1 to sign-extended 8-bit value from effective memory byte address

lb t1,(t2)

Load Byte : Set $1 to sign-extended 8-bit value from effective memory byte address

lb t1,-100

Load Byte : Set $t1 to sign-extended 8-bit value from effective memory byte address

lb t1,10000000 lb t1,label

Load from Address

lb t1,%lo(label)(t2)

lbu reg, [imm(reg) / (reg) / imm / id / %lo(id)], (reg)

Set t1 to zero-extended 8-bit value from effective memory byte address

lbu t1, -100(t2)

Load Byte Unsigned : Set $t1 to zero-extended 8-bit value from effective memory byte address

lbu t1,(t2) lbu t1,-100

Load Byte Unsigned : Set t1 to zero-extended 8-bit value from effective memory byte address

lbu t1,10000000 lbu t1,label

Load from Address

lbu t1,%lo(label)(t2)

ld reg, [imm(reg) / (reg) / imm / id / %lo(id)], (reg)

Set t1 to contents of effective memory double word address (64bit)

ld t1, -100(t2)

Load Double word : Set t1 to contents of effective memory word address (64bit)

ld t1,(t2) ld t1,-100 ld t1,10000000

Load Double word : Set t1 to contents of memory word at label's address (64bit)

ld t1,label

Load from Address (64bit)

ld t1,%lo(label)(t2)

lh reg, [imm(reg) / (reg) / imm / id / %lo(id)], (reg)

Set t1 to sign-extended 16-bit value from effective memory halfword address

lh t1, -100(t2)

Load Halfword : Set t1 to sign-extended 16-bit value from effective memory halfword address

lh t1,(t2) lh t1,-100 lh t1,10000000 lh t1,label

Load from Address

lh t1,%lo(label)(t2)

lhu reg, [imm(reg) / (reg) / imm / id / %lo(id)], (reg)

Set t1 to zero-extended 16-bit value from effective memory halfword address

lhu t1, -100(t2)

Load Halfword Unsigned : Set t1 to zero-extended 16-bit value from effective memory halfword address

lhu t1,(t2) lhu t1,-100 lhu t1,10000000 lhu t1,label

Load from Address

lhu t1,%lo(label)(t2)

li reg, imm

Load Immediate : Set t1 to 12-bit immediate (sign-extended)

li t1,-100

Load Immediate : Set t1 to 32-bit immediate

li t1,10000000

Load Immediate : Set t1 to 12-bit immediate (sign-extended) (64bit)

li t1,-100

Load Immediate : Set t1 to 32-bit immediate (sign-extended) (64bit)

li t1,10000000

Load Immediate : Set t1 to 64-bit immediate (64bit)

li t1,1000000000000000

lr.d reg, (reg)

Load reserved (double word) : Set t1 to the double word at the address in t2 and reserve that address. Pair with sc.d to build an atomic read-modify-write that can be retried (64bit)

lr.d t1, (t2)

lr.w reg, (reg)

Load reserved (word) : Set t1 to the word at the address in t2 and reserve that address. Pair with sc.w to build an atomic read-modify-write that can be retried

lr.w t1, (t2)

lui reg, [imm / %hi(id)]

Load upper immediate: set t1 to 20-bit followed by 12 0s

lui t1,100000

Load Upper Address : Set t1 to upper 20-bit label's address

lui t1,%hi(label)

lw reg, [imm(reg) / (reg) / imm / id / %lo(id)], (reg)

Set t1 to contents of effective memory word address

lw t1, -100(t2)

Load Word : Set t1 to contents of effective memory word address

lw t1,(t2) lw t1,-100 lw t1,10000000

Load Word : Set t1 to contents of memory word at label's address

lw t1,label

Load from Address

lw t1,%lo(label)(t2)

lwu reg, [imm(reg) / %lo(id)], (reg)

Set t1 to contents of effective memory word address without sign-extension (64bit)

lwu t1, -100(t2)

Load from Address (64bit)

lwu t1,%lo(label)(t2)

max reg, reg, reg

Maximum (signed) : Set t1 to the larger of t2 and t3, comparing as signed. Branch free, unlike the usual blt and move

max t1,t2,t3

maxu reg, reg, reg

Maximum (unsigned) : Set t1 to the larger of t2 and t3, comparing as unsigned

maxu t1,t2,t3

min reg, reg, reg

Minimum (signed) : Set t1 to the smaller of t2 and t3, comparing as signed. Branch free, unlike the usual blt and move

min t1,t2,t3

minu reg, reg, reg

Minimum (unsigned) : Set t1 to the smaller of t2 and t3, comparing as unsigned

minu t1,t2,t3

mul reg, reg, reg

Multiplication: set t1 to the lower 32 bits of t2*t3

mul t1,t2,t3

mulh reg, reg, reg

Multiplication: set t1 to the upper 32 bits of t2*t3 using signed multiplication

mulh t1,t2,t3

mulhsu reg, reg, reg

Multiplication: set t1 to the upper 32 bits of t2*t3 where t2 is signed and t3 is unsigned

mulhsu t1,t2,t3

mulhu reg, reg, reg

Multiplication: set t1 to the upper 32 bits of t2*t3 using unsigned multiplication

mulhu t1,t2,t3

mulw reg, reg, reg

Multiplication: set t1 to the lower 32 bits of t2*t3 using only the lower 32 bits of the input (64bit)

mulw t1,t2,t3

mv reg, reg

MoVe : Set t1 to contents of t2

mv t1,t2

neg reg, reg

NEGate : Set t1 to negation of t2

neg t1,t2

negw reg, reg

NEGate Word: Set t1 to negation of t2 (only lower 32 bits) (64bit)

negw t1, t2

nop

NO OPeration

nop

not reg, reg

Bitwise NOT (bit inversion)

not t1,t2

or reg, reg, reg

Bitwise OR : Set t1 to bitwise OR of t2 and t3

or t1,t2,t3

orc.b reg, reg

Bitwise OR combine within bytes : Set every byte of t1 to 0xFF when the matching byte of t2 has any bit set, and to 0 otherwise. Used to find a zero byte inside a word

orc.b t1,t2

ori reg, reg, imm

Bitwise OR immediate : Set t1 to bitwise OR of t2 and sign-extended 12-bit immediate

ori t1,t2,-100

orn reg, reg, reg

OR with inverted operand : Set t1 to the bitwise OR of t2 and the bitwise NOT of t3

orn t1,t2,t3

rdcycle reg

Read from cycle

rdcycle t1

rdcycleh reg

Read from cycleh

rdcycleh t1

rdinstret reg

Read from instret

rdinstret t1

rdinstreth reg

Read from instreth

rdinstreth t1

rdtime reg

Read from time

rdtime t1

rdtimeh reg

Read from timeh

rdtimeh t1

rem reg, reg, reg

Remainder: set t1 to the remainder of t2/t3

rem t1,t2,t3

remu reg, reg, reg

Remainder: set t1 to the remainder of t2/t3 using unsigned division

remu t1,t2,t3

remuw reg, reg, reg

Remainder: set t1 to the remainder of t2/t3 using unsigned division limited to 32 bits (64bit)

remuw t1,t2,t3

remw reg, reg, reg

Remainder: set t1 to the remainder of t2/t3 using only the lower 32 bits (64bit)

remw t1,t2,t3

ret

Return: return from a subroutine

ret

rev8 reg, reg

Reverse bytes : Set t1 to t2 with its bytes in the opposite order, converting between little and big endian

rev8 t1,t2

rol reg, reg, reg

Rotate left : Set t1 to t2 rotated left by the low bits of t3, so bits shifted off the top re-enter at the bottom

rol t1,t2,t3

rolw reg, reg, reg

Rotate left (32 bit) : Set t1 to the low 32 bits of t2 rotated left by the low 5 bits of t3, sign extended (64bit)

rolw t1,t2,t3

ror reg, reg, reg

Rotate right : Set t1 to t2 rotated right by the low bits of t3, so bits shifted off the bottom re-enter at the top

ror t1,t2,t3

rori reg, reg, imm

Rotate right by immediate : Set t1 to t2 rotated right by the immediate, so bits shifted off the bottom re-enter at the top

rori t1,t2,33

roriw reg, reg, imm

Rotate right by immediate (32 bit) : Set t1 to the low 32 bits of t2 rotated right by the immediate, sign extended (64bit)

roriw t1,t2,10

rorw reg, reg, reg

Rotate right (32 bit) : Set t1 to the low 32 bits of t2 rotated right by the low 5 bits of t3, sign extended (64bit)

rorw t1,t2,t3

sb reg, [imm(reg) / (reg) / imm / id / %lo(id)], [reg / (reg)]

Store byte : Store the low-order 8 bits of t1 into the effective memory byte address

sb t1, -100(t2)

Store Byte : Store the low-order 8 bits of t1 into the effective memory byte address

sb t1,(t2)

Store Byte : Store the low-order 8 bits of $t1 into the effective memory byte address

sb t1,-100 sb t1,10000000,t2 sb t1,label,t2

Store to Address

sb t1,%lo(label)(t2)

sc.d reg, reg, (reg)

Store conditional (double word) : Store t2 as a double word at the address in t3 only if that address is still reserved by an lr.d, then set t1 to 0 on success or 1 on failure. Always branch on t1 and retry from the lr.d when it fails (64bit)

sc.d t1, t2, (t3)

sc.w reg, reg, (reg)

Store conditional (word) : Store t2 as a word at the address in t3 only if that address is still reserved by an lr.w, then set t1 to 0 on success or 1 on failure. Always branch on t1 and retry from the lr.w when it fails

sc.w t1, t2, (t3)

sd reg, [imm(reg) / %lo(id)], (reg)

Store double word : Store contents of t1 into effective memory double word address (64bit)

sd t1, -100(t2)

Store to Address (64bit)

sd t1,%lo(label)(t2)

seqz reg, reg

Set EQual to Zero : if t2 == 0 then set t1 to 1 else 0

seqz t1,t2

sext.b reg, reg

Sign extend byte : Set t1 to the low byte of t2 sign extended to the full register width

sext.b t1,t2

sext.h reg, reg

Sign extend half word : Set t1 to the low 16 bits of t2 sign extended to the full register width

sext.h t1,t2

sext.w reg, reg

Sign EXTend Word: extract the low 32-bits from t2 and sign extend it into t1 (64bit)

sext.w t1, t2

sgt reg, reg, reg

Set Greater Than : if t2 greater than t3 then set t1 to 1 else 0

sgt t1,t2,t3

sgtu reg, reg, reg

Set Greater Than Unsigned : if t2 greater than t3 (unsigned compare) then set t1 to 1 else 0

sgtu t1,t2,t3

sgtz reg, reg

Set Greater Than Zero : if t2 > 0 then set t1 to 1 else 0

sgtz t1,t2

sh reg, [imm(reg) / (reg) / imm / id / %lo(id)], [reg / (reg)]

Store halfword : Store the low-order 16 bits of t1 into the effective memory halfword address

sh t1, -100(t2)

Store Halfword : Store the low-order 16 bits of $1 into the effective memory halfword address

sh t1,(t2)

Store Halfword : Store the low-order 16 bits of $t1 into the effective memory halfword address

sh t1,-100

Store Halfword : Store the low-order 16 bits of t1 into the effective memory halfword address using t2 as a temporary

sh t1,10000000,t2 sh t1,label,t2

Store to Address

sh t1,%lo(label)(t2)

sh1add reg, reg, reg

Shift left by 1 and add : Set t1 to (t2 << 1) + t3. One instruction for stepping a pointer through an array of 2 byte elements

sh1add t1,t2,t3

sh1add.uw reg, reg, reg

Shift unsigned word left by 1 and add : Set t1 to (zero extended low 32 bits of t2 << 1) + t3 (64bit)

sh1add.uw t1,t2,t3

sh2add reg, reg, reg

Shift left by 2 and add : Set t1 to (t2 << 2) + t3. One instruction for indexing an array of words

sh2add t1,t2,t3

sh2add.uw reg, reg, reg

Shift unsigned word left by 2 and add : Set t1 to (zero extended low 32 bits of t2 << 2) + t3 (64bit)

sh2add.uw t1,t2,t3

sh3add reg, reg, reg

Shift left by 3 and add : Set t1 to (t2 << 3) + t3. One instruction for indexing an array of double words

sh3add t1,t2,t3

sh3add.uw reg, reg, reg

Shift unsigned word left by 3 and add : Set t1 to (zero extended low 32 bits of t2 << 3) + t3 (64bit)

sh3add.uw t1,t2,t3

sll reg, reg, reg

Shift left logical: Set t1 to result of shifting t2 left by number of bits specified by value in low-order 5 bits of t3

sll t1,t2,t3

slli reg, reg, imm

Shift left logical : Set t1 to result of shifting t2 left by number of bits specified by immediate (64bit)

slli t1,t2,33

slli.uw reg, reg, imm

Shift unsigned word left by immediate : Set t1 to the low 32 bits of t2, zero extended, shifted left by the immediate. Scales an unsigned 32 bit index without a separate zero extension (64bit)

slli.uw t1,t2,10

slliw reg, reg, imm

Shift left logical (32 bit): Set t1 to result of shifting t2 left by number of bits specified by immediate (64bit)

slliw t1,t2,10

sllw reg, reg, reg

Shift left logical (32 bit): Set t1 to result of shifting t2 left by number of bits specified by value in low-order 5 bits of t3 (64bit)

sllw t1,t2,t3

slt reg, reg, reg

Set less than : If t2 is less than t3, then set t1 to 1 else set t1 to 0

slt t1,t2,t3

slti reg, reg, imm

Set less than immediate : If t2 is less than sign-extended 12-bit immediate, then set t1 to 1 else set t1 to 0

slti t1,t2,-100

sltiu reg, reg, imm

Set less than immediate unsigned : If t2 is less than sign-extended 16-bit immediate using unsigned comparison, then set t1 to 1 else set t1 to 0

sltiu t1,t2,-100

sltu reg, reg, reg

Set less than : If t2 is less than t3 using unsigned comparision, then set t1 to 1 else set t1 to 0

sltu t1,t2,t3

sltz reg, reg

Set Less Than Zero : if t2 < 0 then set t1 to 1 else 0

sltz t1,t2

snez reg, reg

Set Not Equal to Zero : if t2 != 0 then set t1 to 1 else 0

snez t1,t2

sra reg, reg, reg

Shift right arithmetic: Set t1 to result of sign-extended shifting t2 right by number of bits specified by value in low-order 5 bits of t3

sra t1,t2,t3

srai reg, reg, imm

Shift right arithmetic : Set t1 to result of sign-extended shifting t2 right by number of bits specified by immediate (64bit)

srai t1,t2,33

sraiw reg, reg, imm

Shift right arithmetic (32 bit): Set t1 to result of sign-extended shifting t2 right by number of bits specified by immediate (64bit)

sraiw t1,t2,10

sraw reg, reg, reg

Shift left logical (32 bit): Set t1 to result of shifting t2 left by number of bits specified by value in low-order 5 bits of t3 (64bit)

sraw t1,t2,t3

srl reg, reg, reg

Shift right logical: Set t1 to result of shifting t2 right by number of bits specified by value in low-order 5 bits of t3

srl t1,t2,t3

srli reg, reg, imm

Shift right logical : Set t1 to result of shifting t2 right by number of bits specified by immediate (64bit)

srli t1,t2,33

srliw reg, reg, imm

Shift right logical (32 bit): Set t1 to result of shifting t2 right by number of bits specified by immediate (64bit)

srliw t1,t2,10

srlw reg, reg, reg

Shift left logical (32 bit): Set t1 to result of shifting t2 left by number of bits specified by value in low-order 5 bits of t3 (64bit)

srlw t1,t2,t3

sub reg, reg, reg

Subtraction: set t1 to (t2 minus t3)

sub t1,t2,t3

subw reg, reg, reg

Subtraction: set t1 to (t2 minus t3) using only the lower 32 bits (64bit)

subw t1,t2,t3

sw reg, [imm(reg) / (reg) / imm / id / %lo(id)], [reg / (reg)]

Store word : Store contents of t1 into effective memory word address

sw t1, -100(t2)

Store Word : Store t1 contents into effective memory word address

sw t1,(t2)

Store Word : Store $t1 contents into effective memory word address

sw t1,-100

Store Word : Store $t1 contents into effective memory word address using t2 as a temporary

sw t1,10000000,t2

Store Word : Store $t1 contents into memory word at label's address using t2 as a temporary

sw t1,label,t2

Store to Address

sw t1,%lo(label)(t2)

tail id

TAIL call: tail call (call without saving return address)a far-away subroutine

tail label

uret

Return from handling an interrupt or exception (to uepc)

uret

wfi

Wait for Interrupt

wfi

xnor reg, reg, reg

Exclusive NOR : Set t1 to the bitwise NOT of the XOR of t2 and t3, so a bit is set wherever t2 and t3 agree

xnor t1,t2,t3

xor reg, reg, reg

Bitwise XOR : Set t1 to bitwise XOR of t2 and t3

xor t1,t2,t3

xori reg, reg, imm

Bitwise XOR immediate : Set t1 to bitwise XOR of t2 and sign-extended 12-bit immediate

xori t1,t2,-100

zext.b reg, reg

Zero EXTend Byte: extract the low byte into t1

zext.b t1, t2

Zero EXTend Byte: extract the low byte into t1 (64bit)

zext.b t1, t2

zext.h reg, reg

Zero extend half word : Set t1 to the low 16 bits of t2 with the rest of the register cleared

zext.h t1,t2

zext.w reg, reg

Zero EXTend Word: extract the low 32-bits from t2 into t1 (64bit)

zext.w t1, t2

Directives

RISC-V directives are used to define the structure of the program. They are not instructions that are executed by the CPU, but rather instructions that are used by the assembler to define the structure of the program.

.data

Subsequent items stored in Data segment at next available address

.text

Subsequent items (instructions) stored in Text segment at next available address

.word

Store the listed value(s) as 32 bit words on word boundary

.dword

Store the listed value(s) as 64 bit double-word on word boundary

.ascii

Store the string in the Data segment but do not add null terminator

.asciz

Store the string in the Data segment and add null terminator

.string

Alias for .asciz

.byte

Store the listed value(s) as 8 bit bytes

.align

Align next data item on specified byte boundary (0=byte, 1=half, 2=word, 3=double)

.half

Store the listed value(s) as 16 bit halfwords on halfword boundary

.space

Reserve the next specified number of bytes in Data segment

.double

Store the listed value(s) as double precision floating point

.float

Store the listed value(s) as single precision floating point

.extern

Declare the listed label and byte length to be a global data field

.globl

Declare the listed label(s) as global to enable referencing from other files

.global

Declare the listed label(s) as global to enable referencing from other files

.eqv

Substitute second operand for first. First operand is symbol, second operand is expression (like #define)

.macro

Begin macro definition. See .end_macro

.end_macro

End macro definition. See .macro

.include

Insert the contents of the specified file. Put filename in quotes.

.section

Allows specifying sections without .text or .data directives. Included for gcc comparability

.bss

Subsequent items stored in the Data segment, which starts out zeroed

.sbss

Alias for .bss

.zero

Reserve the next specified number of bytes, which read as zero. Alias for .space

.comm

Reserve the given number of bytes for a global symbol, the way a C compiler declares an uninitialized global variable. Takes a symbol, a size in bytes and an optional alignment

.lcomm

Reserve the given number of bytes for a symbol local to this file, the way a C compiler declares an uninitialized static variable

.p2align

Align next data item on a 2^n byte boundary. Alias for .align

.balign

Align next data item on the given byte boundary, written directly rather than as a power of two

.2byte

Alias for .half

.4byte

Alias for .word

.8byte

Alias for .dword

Syscalls

RISC-V syscalls are used to make requests to the operating system. They are not instructions that are executed by the CPU, but rather instructions that are used by the simulator to make requests to the operating system.

Each syscall has a unique code that is used to identify it. You must put the syscall code inside the the a7 register before calling the ecall instruction.

As an example:

# Load the integer 42 into register a0, which is
# the register that will be printed by the syscall
li a0, 42

# Set the syscall code for printing an integer
li a7, 1
ecall

1 - Print integer

Arguments

a0
integer to print

2 - Print float

Arguments

f12
float to print

3 - Print double

Arguments

f12
double to print

4 - Print string

Arguments

a0
address of null-terminated string to print

5 - Read integer

Result

v0
contains integer read

6 - Read float

Result

f0
contains float read

7 - Read double

Result

f0
contains double read

8 - Read string

Service 8 - Follows semantics of UNIX 'fgets'. For specified length n, string can be no longer than n-1. If less than that, adds newline to end. In either case, then pads with null byte If n = 1, input is ignored and null byte placed at buffer address. If n < 1, input is ignored and nothing is written to the buffer.

Arguments

a0
address of input buffer
a1
maximum number of characters to read

9 - Sbrk (allocate heap memory)

Result

v0
contains address of allocated memory

Arguments

a0
number of bytes to allocate

10 - Exit (terminate execution)

11 - Print character

Service 11 - Prints ASCII character corresponding to contents of low-order byte.

Arguments

a0
character to print

12 - Read character

Result

v0
contains character read

17 - Get cwd

30 - Time (program time)

Service 30 - Milliseconds since the run started, rather than since 1 January 1970 as in RARS: it is the time the program can observe passing, and in a testcase it comes from a virtual clock that starts at zero and only advances through the waits of service 32.

Result

a0
low order 32 bits of the program time
a1
high order 32 bits of the program time

32 - Sleep

Service 32 - Lets that much program time pass before the next instruction. The editor stays responsive while it waits and the wait costs no instructions, so a program idling on the keyboard never reaches the execution limit; in a testcase it completes at once and advances the virtual clock instead.

Arguments

a0
the length of time to sleep in milliseconds

34 - Print integer in hexadecimal

Displayed value is 8 hexadecimal digits, left-padding with zeroes if necessary.

Arguments

a0
integer to print

35 - Print integer in binary

Displayed value is 32 bits, left-padding with zeroes if necessary.

Arguments

a0
integer to print

36 - Print integer as unsigned

Displayed as unsigned decimal value.

Arguments

a0
integer to print

41 - Random int

Each stream (identified by a0 contents) is modeled by a different Random object. There are no default seed values, so use the Set Seed service (40) if replicated random sequences are desired.

Result

a0
contains the next pseudorandom, uniformly distributed int value from this random number generator's sequence

Arguments

a0
i.d. of pseudorandom number generator (any int)

42 - Random int range

Each stream (identified by a0 contents) is modeled by a different Random object. There are no default seed values, so use the Set Seed service (40) if replicated random sequences are desired.

Result

a0
contains pseudorandom, uniformly distributed int value in the range 0 <= [int] < [upper bound], drawn from this random number generator's sequence

Arguments

a0
i.d. of pseudorandom number generator (any int)
a1
upper bound of range of returned values

43 - Random float

Each stream (identified by a0 contents) is modeled by a different Random object. There are no default seed values, so use the Set Seed service (40) if replicated random sequences are desired.

Result

f0
contains the next pseudorandom, uniformly distributed float value in the range 0.0 <= f < 1.0 from this random number generator's sequence

Arguments

a0
i.d. of pseudorandom number generator (any int)

44 - Random double

Each stream (identified by a0 contents) is modeled by a different Random object. There are no default seed values, so use the Set Seed service (40) if replicated random sequences are desired.

Result

f0
contains the next pseudorandom, uniformly distributed double value in the range 0.0 <= f < 1.0 from this random number generator's sequence

Arguments

a0
i.d. of pseudorandom number generator (any int)

50 - ConfirmDialog

Result

a0
contains value of user-chosen option 0: Yes 1: No 2: Cancel

Arguments

a0
address of null-terminated string that is the message to user

51 - InputDialogInt

Result

a0
contains int read
a1
contains status value 0: OK status -1: input data cannot be correctly parsed -2: Cancel was chosen -3: OK was chosen but no data had been input into field

Arguments

a0
address of null-terminated string that is the message to user

52 - InputDialogFloat

Result

f0
contains float read
a1
contains status value 0: OK status -1: input data cannot be correctly parsed -2: Cancel was chosen -3: OK was chosen but no data had been input into field

Arguments

a0
address of null-terminated string that is the message to user

53 - InputDialogDouble

Result

f0
contains double read
a1
contains status value 0: OK status -1: input data cannot be correctly parsed -2: Cancel was chosen -3: OK was chosen but no data had been input into field

Arguments

a0
address of null-terminated string that is the message to user

54 - InputDialogString

See Service 8 note below table

Result

a1
contains status value 0: OK status. Buffer contains the input string. -2: Cancel was chosen. No change to buffer. -3: OK was chosen but no data had been input into field. No change to buffer. -4: length of the input string exceeded the specified maximum. Buffer contains the maximum allowable input string plus a terminating null.

Arguments

a0
address of null-terminated string that is the message to user
a1
address of input buffer
a2
maximum number of characters to read

55 - MessageDialog

Arguments

a0
address of null-terminated string that is the message to user
a1
the type of message to be displayed: 0: error message, indicated by Error icon 1: information message, indicated by Information icon 2: warning message, indicated by Warning icon 3: question message, indicated by Question icon other: plain message (no icon displayed)

56 - MessageDialogInt

Arguments

a0
address of null-terminated string that is an information-type message to user
a1
int value to display in string form after the first string

57 - Close file

Arguments

a0
file descriptor

58 - MessageDialogDouble

Arguments

a0
address of null-terminated string that is an information-type message to user
f12
double value to display in string form after the first string

59 - MessageDialogString

Arguments

a0
address of null-terminated string that is an information-type message to user
a1
address of null-terminated string to display after the first string

60 - MessageDialogFloat

Arguments

a0
address of null-terminated string that is an information-type message to user
f12
float value to display in string form after the first string

63 - Read from file

Result

v0
contains number of characters read (0 if end-of-file, negative if error)

Arguments

a0
file descriptor
a1
address of input buffer
a2
maximum number of characters to read

64 - Write to file

Result

v0
contains number of characters written (negative if error)

Arguments

a0
file descriptor
a1
address of output buffer
a2
number of characters to write

93 - Exit2 (terminate with value)

Service 93 - If the RISCV program is run under control of the MARS graphical interface (GUI), the exit code in a0 is ignored.

Arguments

a0
termination result

1024 - Open file

Service 1024 - MARS implements three flag values: 0 for read-only, 1 for write-only with create, and 9 for write-only with create and append. It ignores mode. The returned file descriptor will be negative if the operation failed. MARS maintains file descriptors internally and allocates them starting with 3. File descriptors 0, 1 and 2 are always open for: reading from standard input, writing to standard output, and writing to standard error, respectively (new in release 4.3).

Result

v0
contains file descriptor (negative if error)

Arguments

a0
address of null-terminated string containing filename
a1
flags
a2
mode

Registers

The 32 general purpose registers, the 32 the floating point extension adds, and the control and status registers the simulator implements.

General purpose registers

RISC-V has 32 general purpose registers, and with one exception the hardware treats them all alike: x0 reads as zero whatever is written to it, and the other 31 are plain 32 bit words, or 64 bit on the RV64 target. Everything else is convention, written down in the ABI and followed by every program that means to call another one.

Each register has a number and a name, and the assembler accepts both: addi t0, zero, 1 and addi x5, x0, 1 assemble to the same instruction. The names are what the panel shows and what a program should use, because the name says what the register is for. The convention divides them into registers a called function may destroy, the temporaries and the arguments, and registers it has to give back unchanged, the saved ones.

zero (x0)

Always reads as 0, and writing to it is silently ignored. It is not a wasted register: having a guaranteed zero is what lets one instruction do the work of many, so mv a0, a1 is really add a0, zero, a1, beqz t0, label is beq t0, zero, label, and a store of a constant zero needs no register loaded first.

ra (x1)

Return address. jal and jalr write the address of the following instruction here before jumping, and a function returns by executing ret, which is jalr zero, ra, 0. A function that calls another one has to save ra on the stack first, because the inner call overwrites it.

sp (x2)

Stack pointer, pointing at the lowest used word of the stack. A function makes room by subtracting from it on entry and gives the room back by adding the same amount before returning. The ABI expects it to stay aligned to 16 bytes at every call.

gp (x3)

Global pointer. It is set up once before the program starts and never changed, so that a global variable near it can be reached in a single instruction with a signed 12 bit offset instead of the two an arbitrary address needs.

tp (x4)

Thread pointer, the base of the storage private to the running thread. A program here has one thread and no use for it, but the ABI reserves it, so nothing else should be kept in it.

t0 - t2 (x5 - x7)

Temporaries. A called function may overwrite them freely, so a caller that still needs a value after the call has to save it, or keep it in a saved register instead.

s0, also written fp (x8)

The first saved register, and by convention the frame pointer: the fixed handle on the current stack frame for functions whose stack pointer moves while they run. The assembler accepts both spellings for the same register.

s1 (x9)

A saved register. A function that uses it must put back the value it found, which is what makes it the right place for anything that has to survive a call.

a0 - a1 (x10 - x11)

The first two arguments of a call, and the registers a result comes back in: a0 carries a single return value and a1 the second half of a pair. The environment calls that this simulator implements also take their argument in a0 and leave their result there.

a2 - a7 (x12 - x17)

Six more argument registers; anything beyond the eighth argument is passed on the stack. a7 has a second job here: it holds the number of the environment call ecall is about to make.

s2 - s11 (x18 - x27)

Ten more saved registers, preserved across calls by whoever uses them. A loop whose body calls a function keeps its counter in one of these.

t3 - t6 (x28 - x31)

Four more temporaries, with the same rule as t0 to t2: free to use, gone after a call.

Floating point registers

The floating point extension adds 32 registers of its own, f0 to f31, with the same kind of ABI names as the general ones. They are a separate file: no arithmetic instruction reads one of each, and a value crosses over only through an explicit instruction. fcvt.s.w ft0, t0 converts the integer in a general register into a single precision number, fcvt.w.s t0, ft0 converts back, and fmv.x.w copies the raw bits of a floating point register into an integer one while fmv.w.x copies them back, neither of them converting anything. The older spellings fmv.x.s and fmv.s.x assemble to the same two instructions. A comparison is the other place the two files meet: feq.s, flt.s and fle.s test two floating point registers and write 1 or 0 into a general register, so a floating point comparison reaches a branch through bnez or beqz rather than through a flag of its own.

Every register here is 64 bits wide, on both the 32 and the 64 bit targets, because that is what a double needs. A single precision value is stored NaN-boxed: it occupies the low 32 bits and the upper 32 are all ones, a pattern that reads as a NaN if a double instruction looks at it. That is deliberate, and it is why the panel shows NaN in the single format for a register holding a genuine double: it is the same protection, running the other way. fadd.s adds singles and fadd.d doubles, flw and fsw load and store a single, fld and fsd a double, and fcvt.d.s widens a single into a double when the two have to meet.

ft0 - ft7 (f0 - f7)

Floating point temporaries, destroyed by a call like the integer ones. The first eight registers of the file, which is why an example that needs one register usually reaches for ft0.

fs0 - fs1 (f8 - f9)

The first two floating point saved registers, preserved across calls by the function that uses them.

fa0 - fa7 (f10 - f17)

The floating point arguments of a call, and in fa0 the floating point return value. They sit beside the integer argument registers rather than counting against them, so a function taking an integer and a double is passed a0 and fa0.

fs2 - fs11 (f18 - f27)

Ten more floating point saved registers. Note that the ABI names run out of order against the numbers: fs2 is f18, well after fa7. The reason is the compressed encoding, the 16 bit form of the instruction set that this simulator does not assemble but that the ABI was written around: an instruction that short has only three bits for a register, which reaches f8 to f15 and no further, so the ABI put the registers a program uses most there, fs0, fs1 and fa0 to fa5, and the saved registers that were left over landed at f18 and above.

ft8 - ft11 (f28 - f31)

Four more floating point temporaries, closing the file. They follow the same rule as ft0 to ft7, and as t3 to t6 on the integer side: free to use, and gone after a call.

Control and status registers

The control and status registers are the machine talking about itself: how the floating point unit is rounding, why an exception happened, how many instructions have run. They are not addressed like the other registers. csrr t0, fcsr reads one into a general register and csrw t0, fcsr writes it back: the general register comes first in both of them and the control register second. Each is a short form of one of the csrr* instructions, which read the old value and write a new one in a single step: csrr is csrrs with zero as the value to set, so nothing is written, and csrw is csrrw with zero as the destination, so the old value is thrown away. The forms that take a constant instead of a register, csrwi and csrsi, are the exception to the order and name the control register first, as in csrsi ustatus, 1.

This simulator implements the seventeen registers below, the user level subset. On the 32 bit target a counter that needs 64 bits is read as two registers, the name for the low half and the name ending in h for the high half; on RV64 the plain name holds all of it.

ustatus (0x000)

The user status register. Only two bits of it are writable here: the one that enables user level interrupts, and the one that remembers whether they were enabled before the current handler was entered, so that uret can put things back as it found them. Entering a handler copies the first into the second and clears the first, which is why a handler is not interrupted by the thing it is handling.

fflags (0x001)

The five floating point exception flags: invalid operation, divide by zero, overflow, underflow and inexact. Arithmetic sets them and nothing clears them, so they say what has happened since the program started, or since it last wrote a zero here. This is not a separate register but the low five bits of fcsr under their own name.

frm (0x002)

The rounding mode the floating point instructions use when they are not given one: round to nearest with ties to even by default, with truncation and the two directed roundings selectable. Like fflags, it is a window onto fcsr, bits 5 to 7.

fcsr (0x003)

The floating point control and status register, which is the two registers above in one place: fflags is its low five bits and frm the three above them. Writing it writes both, which is how a program resets the flags and chooses a rounding mode in a single instruction.

uie (0x004)

Which user level interrupts are enabled, one bit per source. An interrupt is delivered only when its bit is set here and interrupts are enabled in ustatus.

utvec (0x005)

The address of the user level trap handler: where the machine jumps when an exception or an enabled interrupt happens. A program that means to handle its own traps writes the address of its handler here and also sets the enable bit of ustatus, with csrsi ustatus, 1, because this simulator only enters the handler when that bit is set. A trap taken without both of them stops the program with the usual error message.

uscratch (0x040)

A word the handler may use as it likes. The classic use is to give the handler a stack pointer of its own, since the trap arrives with the program halfway through something and no register free to borrow.

uepc (0x041)

The address of the instruction the trap interrupted. uret returns to it, so a handler that has fixed the cause returns unchanged, and a handler that means to skip the offending instruction adds 4 to this register first.

ucause (0x042)

Why the trap happened: a code such as an illegal instruction or a misaligned address, with the top bit set when the cause was an interrupt rather than an exception. A handler serving several causes reads this first.

utval (0x043)

The detail that goes with the cause: the address a load or store failed on, or the instruction that could not be decoded. Meaningless for causes that carry no such value.

uip (0x044)

Which interrupts are pending, in the same bit positions as uie. A source can be pending and not enabled, in which case nothing happens until the program enables it.

cycle, time, instret (0xC00 - 0xC02)

The three counters, read only: elapsed cycles, elapsed time, and the number of instructions retired. A program times a piece of itself by reading one of them before and after and subtracting.

cycleh, timeh, instreth (0xC80 - 0xC82)

The high halves of the three counters, for the 32 bit target where a 64 bit count does not fit in one register. Reading the pair safely means reading the high half, then the low, then the high again, and starting over if it changed in between.

Screen and memory-mapped I/O

RISC-V programs draw and read input through memory, not through system calls: the screen is a grid of words anywhere in memory, and the keyboard and the console are four words at 0xffff0000. Both are RARS's own tools, the bitmap display and the keyboard and display simulator, with the same parameters and the same register layout, so a program written for RARS runs here unchanged.

Bitmap display

One word of memory is one pixel. Its low 24 bits are the color, red in bits 23-16, green in 15-8 and blue in 7-0; the top byte is ignored. Words run left to right and then top to bottom, so the pixel below a word is one row of words further on.

The screen panel's Display button configures it, with RARS's own five parameters, and a program can ask for them itself with the @screen comment below. The parameters are saved with the project, and testcases run with them too.

1 Unit width and unit height in pixels: 1, 2, 4, 8, 16, 32. How large one word is drawn. Default 1 by 1.
2 Display width and height in pixels: 64, 128, 256, 512, 1024. Default 512 by 256. Divided by the unit size, they give the word grid: the default is 512 by 256 words, one megabyte of memory.
3 Base address for display: where the grid starts. 0x10000000 (global data), 0x10008000 ($gp), 0x10010000 (static data), 0x10040000 (heap), 0xffff0000 (memory map). Default 0x10010000 (static data), which is where .data puts your first label.
        .data
display:.space  262144          # 256 * 256 words

        .text
main:
        la      t0, display
        li      t1, 0x00ff8000  # low 24 bits: red 0xff, green 0x80, blue 0x00
        sw      t1, 0(t0)       # the pixel at the top left
        sw      t1, 1024(t0)    # 256 words further on: the one below it

Reserve the memory the grid covers, with .space or a label of your own: the screen shows whatever those words hold, and a program that writes past what it reserved is writing over something else. Undo walks the picture back with the code, because the picture is the memory the emulator rolled back.

Configuring the screen from the program

A comment line naming @screen sets those five parameters at every Build, before the first instruction runs, so opening a program and building it is all it takes. It is a comment, so the same file still assembles in RARS, where you set the parameters in the tool's window as usual.

# @screen unit=1 width=256 height=256 base=display

        .data
display:.space  262144          # 256 * 256 words

        .text
main:
        la      t0, display
width

The display width in pixels, one of 64, 128, 256, 512, 1024.

height

The display height in pixels, one of 64, 128, 256, 512, 1024.

unit

How many pixels wide and high one word is drawn, one of 1, 2, 4, 8, 16, 32. unitWidth and unitHeight set the two separately.

base

Where the grid starts: a label the program defines, which is the point of it — the program never has to know the address — or an address such as 0x10010000 or 268500992. A label not on a word boundary is rounded down to one.

  • Order and spacing do not matter, commas are allowed between settings, and unitWidth, unit-width and unitwidth are the same name.
  • What the directive leaves out keeps the value it had, and a program with no @screen line changes nothing at all: the configuration stays yours.
  • A value RARS has no entry for, an unknown setting or a label that does not exist is a warning on the directive's line, never an error: a comment cannot stop a program from assembling. A size off the list is replaced by the nearest one on it, and anything else is left as it was.
  • Changing a parameter in the Display popover afterwards wins, until the next Build reads the comment again.

Keyboard and display registers

Four words carry one character each way. Click the screen panel to give the program the keyboard; the ring around it says the editor's own shortcuts are off while it has focus. What the program transmits is appended to the console transcript, the same one print services write to, which is also what testcases assert on.

0xffff0000 Receiver control

Bit 0 is Ready: a typed character is waiting in the receiver data register. The device sets it and clears it; a program only reads it.

0xffff0004 Receiver data

The typed character, in the low byte. Reading it takes that character; the next one, if any, appears at once and Ready stays set until the queue is empty.

0xffff0008 Transmitter control

Bit 0 is Ready, and here it is always set: the console never makes a program wait to print.

0xffff000c Transmitter data

Storing a character in the low byte prints it on the console. ASCII 12, a form feed, clears the console instead.

        li      s0, 0xffff0000
poll:
        lw      t0, 0(s0)       # receiver control
        andi    t0, t0, 1       # the Ready bit
        bnez    t0, take
        li      a7, 32          # nothing typed yet: a wait costs no instructions
        li      a0, 10
        ecall
        j       poll
take:
        lw      t1, 4(s0)       # receiver data, one character
        sw      t1, 12(s0)      # transmitter data: print it

The receiver never loses a keystroke: what does not fit in the data register waits in a queue behind it, and Ready (1) stays set until that queue is empty. Bit 1 of either control register, RARS's interrupt-enable bit (2), stops the program with an error: this editor polls, it does not deliver device interrupts.

Program time

Service 30 (a7 before a ecall) answers with the time in milliseconds, low word in a0 and high word in a1, and service 32 waits for the milliseconds in a0. Time is counted from the start of the run rather than from 1970, so a program differences two reads exactly as it did before, and a wait costs no instructions — a program idling on the keyboard never reaches the execution limit. In a testcase both run on a virtual clock that starts at zero and only advances through the program's own waits, so a five second wait finishes at once and elapsed-time output is the same on every machine.

Differences from RARS

  • The display is always there: it is a panel next to the memory view rather than a tool you connect to the program before running it.
  • Interrupt-driven I/O is not supported. Setting the interrupt-enable bit of a control register stops the program with an error naming the feature; poll the Ready bit instead.
  • Time comes from the start of the run, and a testcase runs on a virtual clock. RARS answers with the host's wall clock.
  • There is no mouse: neither simulator's tools have one.
  • Programs live in examples/risc-v/ in the repository, one per feature, each naming the display it wants in an @screen comment; RARS has no such directive and ignores the line.