Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

c_like

std › riscv › 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 + a1 is add, and a0 <- a0 + 1 is addi.
  • >>> is a logical shift right, and >> an arithmetic one.
  • Loads and stores smaller than a word name their width before mem: i8, u8, i16 or u16.
  • Unsigned comparisons (sltu, sltiu, bltu, bgeu), lui, auipc, ecall, ebreak, li, la and ascii have no C-like spelling, and keep their plain name a, b, c syntax.

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.

SyntaxParametersResultDescriptionFrom
rd = rs1 + rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>std.riscv.impl

sub

rd = rs1 - rs2.

SyntaxParametersResultDescriptionFrom
rd = rs1 - rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>std.riscv.impl

sll

rd = rs1 << rs2, shifting by the low 5 bits of rs2.

SyntaxParametersResultDescriptionFrom
rd = rs1 << rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>std.riscv.impl

slt

rd = 1 if rs1 < rs2 as signed numbers, else 0.

SyntaxParametersResultDescriptionFrom
rd = rs1 < rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>std.riscv.impl

sltu

rd = 1 if rs1 < rs2 as unsigned numbers, else 0.

SyntaxParametersResultDescriptionFrom
sltu rd, rs1, rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>std.riscv.impl

xor

rd = rs1 ^ rs2.

SyntaxParametersResultDescriptionFrom
rd = rs1 ^ rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>std.riscv.impl

srl

rd = rs1 >> rs2, shifting in zeros, by the low 5 bits of rs2.

SyntaxParametersResultDescriptionFrom
rd = rs1 >>> rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>std.riscv.impl

sra

rd = rs1 >> rs2, shifting in copies of the sign bit, by the low 5 bits of rs2.

SyntaxParametersResultDescriptionFrom
rd = rs1 >> rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>std.riscv.impl

or

rd = rs1 | rs2.

SyntaxParametersResultDescriptionFrom
rd = rs1 | rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>std.riscv.impl

and

rd = rs1 & rs2.

SyntaxParametersResultDescriptionFrom
rd = rs1 & rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>std.riscv.impl

addi

rd = rs1 + imm, with a 12-bit signed imm.

SyntaxParametersResultDescriptionFrom
rd <- rs1 + immrd: Reg, rs1: Reg, imm: intemits LittleEndian<IType, 32>std.riscv.impl

slti

rd = 1 if rs1 < imm as signed numbers, else 0.

SyntaxParametersResultDescriptionFrom
rd <- rs1 < immrd: Reg, rs1: Reg, imm: intemits 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.

SyntaxParametersResultDescriptionFrom
sltiu rd, rs1, immrd: Reg, rs1: Reg, imm: intemits LittleEndian<IType, 32>std.riscv.impl

xori

rd = rs1 ^ imm. xori rd, rs1, -1 is bitwise NOT.

SyntaxParametersResultDescriptionFrom
rd <- rs1 ^ immrd: Reg, rs1: Reg, imm: intemits LittleEndian<IType, 32>std.riscv.impl

ori

rd = rs1 | imm.

SyntaxParametersResultDescriptionFrom
rd <- rs1 | immrd: Reg, rs1: Reg, imm: intemits LittleEndian<IType, 32>std.riscv.impl

andi

rd = rs1 & imm.

SyntaxParametersResultDescriptionFrom
rd <- rs1 & immrd: Reg, rs1: Reg, imm: intemits LittleEndian<IType, 32>std.riscv.impl

slli

rd = rs1 << shamt, for shamt from 0 to 31.

SyntaxParametersResultDescriptionFrom
rd <- rs1 << shamtrd: Reg, rs1: Reg, shamt: intemits LittleEndian<IType, 32>std.riscv.impl

srli

rd = rs1 >> shamt, shifting in zeros, for shamt from 0 to 31.

SyntaxParametersResultDescriptionFrom
rd <- rs1 >>> shamtrd: Reg, rs1: Reg, shamt: intemits LittleEndian<IType, 32>std.riscv.impl

srai

rd = rs1 >> shamt, shifting in copies of the sign bit, for shamt from 0 to 31.

SyntaxParametersResultDescriptionFrom
rd <- rs1 >> shamtrd: Reg, rs1: Reg, shamt: intemits 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.

SyntaxParametersResultDescriptionFrom
rd = call[rs1 + offset]rd: Reg, rs1: Reg, offset: intemits LittleEndian<IType, 32>std.riscv.impl

ecall

Calls the execution environment, e.g. a Linux system call.

SyntaxParametersResultDescriptionFrom
ecallemits LittleEndian<IType, 32>std.riscv.impl

ebreak

Stops in a debugger.

SyntaxParametersResultDescriptionFrom
ebreakemits LittleEndian<IType, 32>std.riscv.impl

lb

Loads the byte at rs1 + offset into rd, sign-extended.

SyntaxParametersResultDescriptionFrom
rd = i8 mem[rs1 + offset]rd: Reg, offset: int, rs1: Regemits LittleEndian<IType, 32>std.riscv.impl

lh

Loads the 16-bit halfword at rs1 + offset into rd, sign-extended.

SyntaxParametersResultDescriptionFrom
rd = i16 mem[rs1 + offset]rd: Reg, offset: int, rs1: Regemits LittleEndian<IType, 32>std.riscv.impl

lw

Loads the 32-bit word at rs1 + offset into rd.

SyntaxParametersResultDescriptionFrom
rd = mem[rs1 + offset]rd: Reg, offset: int, rs1: Regemits LittleEndian<IType, 32>std.riscv.impl

lbu

Loads the byte at rs1 + offset into rd, zero-extended.

SyntaxParametersResultDescriptionFrom
rd = u8 mem[rs1 + offset]rd: Reg, offset: int, rs1: Regemits LittleEndian<IType, 32>std.riscv.impl

lhu

Loads the 16-bit halfword at rs1 + offset into rd, zero-extended.

SyntaxParametersResultDescriptionFrom
rd = u16 mem[rs1 + offset]rd: Reg, offset: int, rs1: Regemits LittleEndian<IType, 32>std.riscv.impl

sb

Stores the low byte of rs2 at rs1 + offset.

SyntaxParametersResultDescriptionFrom
i8 mem[rs1 + offset] = rs2rs2: Reg, offset: int, rs1: Regemits LittleEndian<SType, 32>std.riscv.impl

sh

Stores the low 16 bits of rs2 at rs1 + offset.

SyntaxParametersResultDescriptionFrom
i16 mem[rs1 + offset] = rs2rs2: Reg, offset: int, rs1: Regemits LittleEndian<SType, 32>std.riscv.impl

sw

Stores rs2 at rs1 + offset.

SyntaxParametersResultDescriptionFrom
mem[rs1 + offset] = rs2rs2: Reg, offset: int, rs1: Regemits LittleEndian<SType, 32>std.riscv.impl

beq

Branches to the label target if rs1 == rs2.

SyntaxParametersResultDescriptionFrom
if (rs1 == rs2) goto targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>std.riscv.impl

bne

Branches to the label target if rs1 != rs2.

SyntaxParametersResultDescriptionFrom
if (rs1 != rs2) goto targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>std.riscv.impl

blt

Branches to the label target if rs1 < rs2 as signed numbers.

SyntaxParametersResultDescriptionFrom
if (rs1 < rs2) goto targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>std.riscv.impl

bge

Branches to the label target if rs1 >= rs2 as signed numbers.

SyntaxParametersResultDescriptionFrom
if (rs1 >= rs2) goto targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>std.riscv.impl

bltu

Branches to the label target if rs1 < rs2 as unsigned numbers.

SyntaxParametersResultDescriptionFrom
bltu rs1, rs2, targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>std.riscv.impl

bgeu

Branches to the label target if rs1 >= rs2 as unsigned numbers.

SyntaxParametersResultDescriptionFrom
bgeu rs1, rs2, targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>std.riscv.impl

lui

rd = imm << 12: loads a 20-bit upper immediate.

SyntaxParametersResultDescriptionFrom
lui rd, immrd: Reg, imm: intemits LittleEndian<UType, 32>std.riscv.impl

auipc

rd = pc + (imm << 12): an address relative to this instruction.

SyntaxParametersResultDescriptionFrom
auipc rd, immrd: Reg, imm: intemits 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.

SyntaxParametersResultDescriptionFrom
rd = call(target)rd: Reg, target: intemits 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.

SyntaxParametersResultDescriptionFrom
li rd, immrd: Reg, imm: intstd.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.

SyntaxParametersResultDescriptionFrom
la rd, symbolrd: Reg, symbol: intstd.riscv.impl

ascii

A string literal’s UTF-8 bytes, with no terminator: GNU’s .ascii.

SyntaxParametersResultDescriptionFrom
ascii source<S>, source: Sstd.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.