c_like
RISC-V RV32I written as expressions instead of mnemonics:
a0 = a1 + a2, a1 = mem[sp + 8], if (a0 != zero) goto loop.
from std.riscv.c_like import *
loop:
a0 <- a0 + -1
if (a0 != zero) goto loop
a1 = mem[sp + 8]
13 05 f5 ff
e3 1e 05 fe
83 25 81 00
- A register-register operation uses
=, and one with an immediate uses<-:a0 = a0 + a1isadd, anda0 <- a0 + 1isaddi. >>>is a logical shift right, and>>an arithmetic one.- Loads and stores smaller than a word name their width before
mem:i8,u8,i16oru16. - Unsigned comparisons (
sltu,sltiu,bltu,bgeu),lui,auipc,ecall,ebreak,li,laandasciihave no C-like spelling, and keep their plainname a, b, csyntax.
Import this instead of std.riscv.native, never alongside it: both
assign syntax to the same instructions.
Re-exports std.riscv.impl.
Macros
add
rd = rs1 + rs2.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = rs1 + rs2 | rd: Reg, rs1: Reg, rs2: Reg | emits LittleEndian<RType, 32> | std.riscv.impl |
sub
rd = rs1 - rs2.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = rs1 - rs2 | rd: Reg, rs1: Reg, rs2: Reg | emits LittleEndian<RType, 32> | std.riscv.impl |
sll
rd = rs1 << rs2, shifting by the low 5 bits of rs2.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = rs1 << rs2 | rd: Reg, rs1: Reg, rs2: Reg | emits LittleEndian<RType, 32> | std.riscv.impl |
slt
rd = 1 if rs1 < rs2 as signed numbers, else 0.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = rs1 < rs2 | rd: Reg, rs1: Reg, rs2: Reg | emits LittleEndian<RType, 32> | std.riscv.impl |
sltu
rd = 1 if rs1 < rs2 as unsigned numbers, else 0.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
sltu rd, rs1, rs2 | rd: Reg, rs1: Reg, rs2: Reg | emits LittleEndian<RType, 32> | std.riscv.impl |
xor
rd = rs1 ^ rs2.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = rs1 ^ rs2 | rd: Reg, rs1: Reg, rs2: Reg | emits LittleEndian<RType, 32> | std.riscv.impl |
srl
rd = rs1 >> rs2, shifting in zeros, by the low 5 bits of rs2.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = rs1 >>> rs2 | rd: Reg, rs1: Reg, rs2: Reg | emits LittleEndian<RType, 32> | std.riscv.impl |
sra
rd = rs1 >> rs2, shifting in copies of the sign bit, by the low 5 bits of
rs2.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = rs1 >> rs2 | rd: Reg, rs1: Reg, rs2: Reg | emits LittleEndian<RType, 32> | std.riscv.impl |
or
rd = rs1 | rs2.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = rs1 | rs2 | rd: Reg, rs1: Reg, rs2: Reg | emits LittleEndian<RType, 32> | std.riscv.impl |
and
rd = rs1 & rs2.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = rs1 & rs2 | rd: Reg, rs1: Reg, rs2: Reg | emits LittleEndian<RType, 32> | std.riscv.impl |
addi
rd = rs1 + imm, with a 12-bit signed imm.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd <- rs1 + imm | rd: Reg, rs1: Reg, imm: int | emits LittleEndian<IType, 32> | std.riscv.impl |
slti
rd = 1 if rs1 < imm as signed numbers, else 0.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd <- rs1 < imm | rd: Reg, rs1: Reg, imm: int | emits LittleEndian<IType, 32> | std.riscv.impl |
sltiu
rd = 1 if rs1 < imm as unsigned numbers, else 0. imm is
sign-extended first, so sltiu rd, rs1, 1 tests for zero.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
sltiu rd, rs1, imm | rd: Reg, rs1: Reg, imm: int | emits LittleEndian<IType, 32> | std.riscv.impl |
xori
rd = rs1 ^ imm. xori rd, rs1, -1 is bitwise NOT.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd <- rs1 ^ imm | rd: Reg, rs1: Reg, imm: int | emits LittleEndian<IType, 32> | std.riscv.impl |
ori
rd = rs1 | imm.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd <- rs1 | imm | rd: Reg, rs1: Reg, imm: int | emits LittleEndian<IType, 32> | std.riscv.impl |
andi
rd = rs1 & imm.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd <- rs1 & imm | rd: Reg, rs1: Reg, imm: int | emits LittleEndian<IType, 32> | std.riscv.impl |
slli
rd = rs1 << shamt, for shamt from 0 to 31.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd <- rs1 << shamt | rd: Reg, rs1: Reg, shamt: int | emits LittleEndian<IType, 32> | std.riscv.impl |
srli
rd = rs1 >> shamt, shifting in zeros, for shamt from 0 to 31.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd <- rs1 >>> shamt | rd: Reg, rs1: Reg, shamt: int | emits LittleEndian<IType, 32> | std.riscv.impl |
srai
rd = rs1 >> shamt, shifting in copies of the sign bit, for shamt from 0
to 31.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd <- rs1 >> shamt | rd: Reg, rs1: Reg, shamt: int | emits LittleEndian<IType, 32> | std.riscv.impl |
jalr
Jumps to rs1 + offset (with bit 0 cleared) and puts the address of the
next instruction in rd. jalr zero, ra, 0 returns from a function.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = call[rs1 + offset] | rd: Reg, rs1: Reg, offset: int | emits LittleEndian<IType, 32> | std.riscv.impl |
ecall
Calls the execution environment, e.g. a Linux system call.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
ecall | emits LittleEndian<IType, 32> | std.riscv.impl |
ebreak
Stops in a debugger.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
ebreak | emits LittleEndian<IType, 32> | std.riscv.impl |
lb
Loads the byte at rs1 + offset into rd, sign-extended.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = i8 mem[rs1 + offset] | rd: Reg, offset: int, rs1: Reg | emits LittleEndian<IType, 32> | std.riscv.impl |
lh
Loads the 16-bit halfword at rs1 + offset into rd, sign-extended.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = i16 mem[rs1 + offset] | rd: Reg, offset: int, rs1: Reg | emits LittleEndian<IType, 32> | std.riscv.impl |
lw
Loads the 32-bit word at rs1 + offset into rd.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = mem[rs1 + offset] | rd: Reg, offset: int, rs1: Reg | emits LittleEndian<IType, 32> | std.riscv.impl |
lbu
Loads the byte at rs1 + offset into rd, zero-extended.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = u8 mem[rs1 + offset] | rd: Reg, offset: int, rs1: Reg | emits LittleEndian<IType, 32> | std.riscv.impl |
lhu
Loads the 16-bit halfword at rs1 + offset into rd, zero-extended.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = u16 mem[rs1 + offset] | rd: Reg, offset: int, rs1: Reg | emits LittleEndian<IType, 32> | std.riscv.impl |
sb
Stores the low byte of rs2 at rs1 + offset.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
i8 mem[rs1 + offset] = rs2 | rs2: Reg, offset: int, rs1: Reg | emits LittleEndian<SType, 32> | std.riscv.impl |
sh
Stores the low 16 bits of rs2 at rs1 + offset.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
i16 mem[rs1 + offset] = rs2 | rs2: Reg, offset: int, rs1: Reg | emits LittleEndian<SType, 32> | std.riscv.impl |
sw
Stores rs2 at rs1 + offset.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
mem[rs1 + offset] = rs2 | rs2: Reg, offset: int, rs1: Reg | emits LittleEndian<SType, 32> | std.riscv.impl |
beq
Branches to the label target if rs1 == rs2.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
if (rs1 == rs2) goto target | rs1: Reg, rs2: Reg, target: int | emits LittleEndian<BType, 32> | std.riscv.impl |
bne
Branches to the label target if rs1 != rs2.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
if (rs1 != rs2) goto target | rs1: Reg, rs2: Reg, target: int | emits LittleEndian<BType, 32> | std.riscv.impl |
blt
Branches to the label target if rs1 < rs2 as signed numbers.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
if (rs1 < rs2) goto target | rs1: Reg, rs2: Reg, target: int | emits LittleEndian<BType, 32> | std.riscv.impl |
bge
Branches to the label target if rs1 >= rs2 as signed numbers.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
if (rs1 >= rs2) goto target | rs1: Reg, rs2: Reg, target: int | emits LittleEndian<BType, 32> | std.riscv.impl |
bltu
Branches to the label target if rs1 < rs2 as unsigned numbers.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
bltu rs1, rs2, target | rs1: Reg, rs2: Reg, target: int | emits LittleEndian<BType, 32> | std.riscv.impl |
bgeu
Branches to the label target if rs1 >= rs2 as unsigned numbers.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
bgeu rs1, rs2, target | rs1: Reg, rs2: Reg, target: int | emits LittleEndian<BType, 32> | std.riscv.impl |
lui
rd = imm << 12: loads a 20-bit upper immediate.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
lui rd, imm | rd: Reg, imm: int | emits LittleEndian<UType, 32> | std.riscv.impl |
auipc
rd = pc + (imm << 12): an address relative to this instruction.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
auipc rd, imm | rd: Reg, imm: int | emits LittleEndian<UType, 32> | std.riscv.impl |
jal
Jumps to the label target and puts the address of the next instruction
in rd. jal ra, f calls f; jal zero, l just jumps.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
rd = call(target) | rd: Reg, target: int | emits LittleEndian<JType, 32> | std.riscv.impl |
li
Loads the constant imm into rd: addi rd, zero, imm when it fits in
12 signed bits, else lui for the upper 20 bits then, unless they’re
zero, addi for the rest.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
li rd, imm | rd: Reg, imm: int | std.riscv.impl |
la
Loads the address of the label symbol into rd: auipc for the upper
20 bits of the distance, then addi for the rest.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
la rd, symbol | rd: Reg, symbol: int | std.riscv.impl |
ascii
A string literal’s UTF-8 bytes, with no terminator: GNU’s .ascii.
| Syntax | Parameters | Result | Description | From |
|---|---|---|---|---|
ascii source | <S>, source: S | std.riscv.impl |
Re-exported
From std.riscv.impl: Reg, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, zero, ra, sp, gp, tp, t0, t1, t2, s0, fp, s1, a0, a1, a2, a3, a4, a5, a6, a7, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, t3, t4, t5, t6, Opcode, Funct3, Funct7, Bit1, Imm4, Imm5, Imm6, Imm7, Imm8, Imm10, Imm12, Imm20, RType, IType, SType, BType, UType, JType, Byte, Bytes.