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

impl

std › riscv › impl

RISC-V RV32I: its registers, instruction formats, and every base instruction, each emitted as a little-endian 32-bit word.

Import a dialect rather than this module: std.riscv.native for the standard assembly syntax, or std.riscv.c_like. Here every instruction takes its operands in order, lw rd, offset, rs1 rather than lw rd, offset(rs1).

from std.riscv.impl import *

loop:
    addi a0, a0, -1
    bne a0, zero, loop
13 05 f5 ff
e3 1e 05 fe

Immediates are plain ints, truncated to their field, so a negative one becomes its two’s-complement encoding. Branch and jump targets are labels; bitter works out the offset once the program is laid out.

Macros

add

rd = rs1 + rs2.

SyntaxParametersResultDescription
add rd, rs1, rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>

sub

rd = rs1 - rs2.

SyntaxParametersResultDescription
sub rd, rs1, rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>

sll

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

SyntaxParametersResultDescription
sll rd, rs1, rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>

slt

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

SyntaxParametersResultDescription
slt rd, rs1, rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>

sltu

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

SyntaxParametersResultDescription
sltu rd, rs1, rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>

xor

rd = rs1 ^ rs2.

SyntaxParametersResultDescription
xor rd, rs1, rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>

srl

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

SyntaxParametersResultDescription
srl rd, rs1, rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>

sra

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

SyntaxParametersResultDescription
sra rd, rs1, rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>

or

rd = rs1 | rs2.

SyntaxParametersResultDescription
or rd, rs1, rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>

and

rd = rs1 & rs2.

SyntaxParametersResultDescription
and rd, rs1, rs2rd: Reg, rs1: Reg, rs2: Regemits LittleEndian<RType, 32>

addi

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

SyntaxParametersResultDescription
addi rd, rs1, immrd: Reg, rs1: Reg, imm: intemits LittleEndian<IType, 32>

slti

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

SyntaxParametersResultDescription
slti rd, rs1, immrd: Reg, rs1: Reg, imm: intemits LittleEndian<IType, 32>

sltiu

rd = 1 if rs1 < imm as unsigned numbers, else 0. imm is sign-extended first, so sltiu rd, rs1, 1 tests for zero.

SyntaxParametersResultDescription
sltiu rd, rs1, immrd: Reg, rs1: Reg, imm: intemits LittleEndian<IType, 32>

xori

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

SyntaxParametersResultDescription
xori rd, rs1, immrd: Reg, rs1: Reg, imm: intemits LittleEndian<IType, 32>

ori

rd = rs1 | imm.

SyntaxParametersResultDescription
ori rd, rs1, immrd: Reg, rs1: Reg, imm: intemits LittleEndian<IType, 32>

andi

rd = rs1 & imm.

SyntaxParametersResultDescription
andi rd, rs1, immrd: Reg, rs1: Reg, imm: intemits LittleEndian<IType, 32>

slli

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

SyntaxParametersResultDescription
slli rd, rs1, shamtrd: Reg, rs1: Reg, shamt: intemits LittleEndian<IType, 32>

srli

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

SyntaxParametersResultDescription
srli rd, rs1, shamtrd: Reg, rs1: Reg, shamt: intemits LittleEndian<IType, 32>

srai

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

SyntaxParametersResultDescription
srai rd, rs1, shamtrd: Reg, rs1: Reg, shamt: intemits LittleEndian<IType, 32>

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.

SyntaxParametersResultDescription
jalr rd, rs1, offsetrd: Reg, rs1: Reg, offset: intemits LittleEndian<IType, 32>

ecall

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

SyntaxParametersResultDescription
ecallemits LittleEndian<IType, 32>

ebreak

Stops in a debugger.

SyntaxParametersResultDescription
ebreakemits LittleEndian<IType, 32>

lb

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

SyntaxParametersResultDescription
lb rd, offset, rs1rd: Reg, offset: int, rs1: Regemits LittleEndian<IType, 32>

lh

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

SyntaxParametersResultDescription
lh rd, offset, rs1rd: Reg, offset: int, rs1: Regemits LittleEndian<IType, 32>

lw

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

SyntaxParametersResultDescription
lw rd, offset, rs1rd: Reg, offset: int, rs1: Regemits LittleEndian<IType, 32>

lbu

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

SyntaxParametersResultDescription
lbu rd, offset, rs1rd: Reg, offset: int, rs1: Regemits LittleEndian<IType, 32>

lhu

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

SyntaxParametersResultDescription
lhu rd, offset, rs1rd: Reg, offset: int, rs1: Regemits LittleEndian<IType, 32>

sb

Stores the low byte of rs2 at rs1 + offset.

SyntaxParametersResultDescription
sb rs2, offset, rs1rs2: Reg, offset: int, rs1: Regemits LittleEndian<SType, 32>

sh

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

SyntaxParametersResultDescription
sh rs2, offset, rs1rs2: Reg, offset: int, rs1: Regemits LittleEndian<SType, 32>

sw

Stores rs2 at rs1 + offset.

SyntaxParametersResultDescription
sw rs2, offset, rs1rs2: Reg, offset: int, rs1: Regemits LittleEndian<SType, 32>

beq

Branches to the label target if rs1 == rs2.

SyntaxParametersResultDescription
beq rs1, rs2, targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>

bne

Branches to the label target if rs1 != rs2.

SyntaxParametersResultDescription
bne rs1, rs2, targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>

blt

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

SyntaxParametersResultDescription
blt rs1, rs2, targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>

bge

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

SyntaxParametersResultDescription
bge rs1, rs2, targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>

bltu

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

SyntaxParametersResultDescription
bltu rs1, rs2, targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>

bgeu

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

SyntaxParametersResultDescription
bgeu rs1, rs2, targetrs1: Reg, rs2: Reg, target: intemits LittleEndian<BType, 32>

lui

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

SyntaxParametersResultDescription
lui rd, immrd: Reg, imm: intemits LittleEndian<UType, 32>

auipc

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

SyntaxParametersResultDescription
auipc rd, immrd: Reg, imm: intemits LittleEndian<UType, 32>

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.

SyntaxParametersResultDescription
jal rd, targetrd: Reg, target: intemits LittleEndian<JType, 32>

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.

SyntaxParametersResultDescription
li rd, immrd: Reg, imm: int

la

Loads the address of the label symbol into rd: auipc for the upper 20 bits of the distance, then addi for the rest.

SyntaxParametersResultDescription
la rd, symbolrd: Reg, symbol: int

ascii

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

SyntaxParametersResultDescription
ascii source<S>, source: S

Types

Reg

type Reg = bits<5>

A register number, 0 to 31.

Opcode

type Opcode = bits<7>

The 7-bit major opcode, which picks the format and family.

Funct3

type Funct3 = bits<3>

The 3-bit funct3 field, which picks the instruction within a family.

Funct7

type Funct7 = bits<7>

The 7-bit funct7 field of an R-type instruction.

Bit1

type Bit1 = bits<1>

A one-bit field.

Imm4

type Imm4 = bits<4>

A 4-bit immediate field.

Imm5

type Imm5 = bits<5>

A 5-bit immediate field.

Imm6

type Imm6 = bits<6>

A 6-bit immediate field.

Imm7

type Imm7 = bits<7>

A 7-bit immediate field.

Imm8

type Imm8 = bits<8>

An 8-bit immediate field.

Imm10

type Imm10 = bits<10>

A 10-bit immediate field.

Imm12

type Imm12 = bits<12>

A 12-bit immediate field.

Imm20

type Imm20 = bits<20>

A 20-bit immediate field.

RType

struct RType

The R-type format: register-register operations.

IType

struct IType

The I-type format: register-immediate operations, loads, jalr and system calls.

SType

struct SType

The S-type format: stores. The 12-bit offset is split around the registers.

BType

struct BType

The B-type format: conditional branches. The offset’s bits are spread across the word the way the spec lays them out, and resolved by bitter.

UType

struct UType

The U-type format: a 20-bit upper immediate.

JType

struct JType

The J-type format: jal. Like B-type, its offset’s bits are spread across the word, and resolved by bitter.

Byte

type Byte = bits<8>

A byte.

Bytes

struct Bytes<const N: int>

N bytes, packed by bitter in order.

Some of its fields are generated by @for or @if.

Constants

ConstantTypeValueDescription
x0Reg(0)A general-purpose register. x0 always reads as zero.
x1Reg(1)A general-purpose register. x0 always reads as zero.
x2Reg(2)A general-purpose register. x0 always reads as zero.
x3Reg(3)A general-purpose register. x0 always reads as zero.
x4Reg(4)A general-purpose register. x0 always reads as zero.
x5Reg(5)A general-purpose register. x0 always reads as zero.
x6Reg(6)A general-purpose register. x0 always reads as zero.
x7Reg(7)A general-purpose register. x0 always reads as zero.
x8Reg(8)A general-purpose register. x0 always reads as zero.
x9Reg(9)A general-purpose register. x0 always reads as zero.
x10Reg(10)A general-purpose register. x0 always reads as zero.
x11Reg(11)A general-purpose register. x0 always reads as zero.
x12Reg(12)A general-purpose register. x0 always reads as zero.
x13Reg(13)A general-purpose register. x0 always reads as zero.
x14Reg(14)A general-purpose register. x0 always reads as zero.
x15Reg(15)A general-purpose register. x0 always reads as zero.
x16Reg(16)A general-purpose register. x0 always reads as zero.
x17Reg(17)A general-purpose register. x0 always reads as zero.
x18Reg(18)A general-purpose register. x0 always reads as zero.
x19Reg(19)A general-purpose register. x0 always reads as zero.
x20Reg(20)A general-purpose register. x0 always reads as zero.
x21Reg(21)A general-purpose register. x0 always reads as zero.
x22Reg(22)A general-purpose register. x0 always reads as zero.
x23Reg(23)A general-purpose register. x0 always reads as zero.
x24Reg(24)A general-purpose register. x0 always reads as zero.
x25Reg(25)A general-purpose register. x0 always reads as zero.
x26Reg(26)A general-purpose register. x0 always reads as zero.
x27Reg(27)A general-purpose register. x0 always reads as zero.
x28Reg(28)A general-purpose register. x0 always reads as zero.
x29Reg(29)A general-purpose register. x0 always reads as zero.
x30Reg(30)A general-purpose register. x0 always reads as zero.
x31Reg(31)A general-purpose register. x0 always reads as zero.
zerox0x0, which always reads as zero.
rax1x1: the return address.
spx2x2: the stack pointer.
gpx3x3: the global pointer.
tpx4x4: the thread pointer.
t0x5x5: a temporary.
t1x6x6: a temporary.
t2x7x7: a temporary.
s0x8x8: saved across calls.
fpx8x8: the frame pointer, the same register as s0.
s1x9x9: saved across calls.
a0x10x10: a function argument and return value.
a1x11x11: a function argument and return value.
a2x12x12: a function argument.
a3x13x13: a function argument.
a4x14x14: a function argument.
a5x15x15: a function argument.
a6x16x16: a function argument.
a7x17x17: a function argument.
s2x18x18: saved across calls.
s3x19x19: saved across calls.
s4x20x20: saved across calls.
s5x21x21: saved across calls.
s6x22x22: saved across calls.
s7x23x23: saved across calls.
s8x24x24: saved across calls.
s9x25x25: saved across calls.
s10x26x26: saved across calls.
s11x27x27: saved across calls.
t3x28x28: a temporary.
t4x29x29: a temporary.
t5x30x30: a temporary.
t6x31x31: a temporary.