Chapter 5
RV32 Machine Instructions

5.1 Conventions and Terminology

When discussing instructions, the following abbreviations/notations are used:

5.1.1 XLEN

XLEN represents the bit-length of an x register in the machine architecture. Possible values are 32, 64 and 128.

5.1.2 sx(val)

Sign extend val to the left.

This is used to convert a signed integer value expressed using some number of bits to a larger number of bits by adding more bits to the left. In doing so, the sign will be preserved. In this case val represents the least MSBs of the value.

For more on sign-extension see section 2.3.

5.1.3 zx(val)

Zero extend val to the left.

This is used to convert an unsigned integer value expressed using some number of bits to a larger number of bits by adding more bits to the left. In doing so, the new bits added will all be set to zero. As is the case with sx(val), val represents the LSBs of the final value.

For more on zero-extension see 2.3.

5.1.4 zr(val)

Zero extend val to the right.

Some times a binary value is encoded such that a set of bits represented by val are used to represent the MSBs of some longer (more bits) value. In this case it is necessary to append zeros to the right to convert val to the longer value.

Figure 5.1 illustrates converting a 20-bit val to a 32-bit fullword.

pict

Figure 5.1: Zero-extending an integer to the right from 20 bits to 32 bits.

5.1.5 Sign Extended Left and Zero Extend Right

Some instructions such as the J-type (see subsection 5.3.2) include immediate operands that are extended in both directions.

Figure 5.2 and Figure 5.3 illustrates zero-extending a 20-bit negative number one bit to the right and sign-extending it 11 bits to the left:

pict

Figure 5.2: Sign-extending a positive 20-bit number 11 bits to the left and one bit to the right.

pict

Figure 5.3: Sign-extending a negative 20-bit number 11 bits to the left and one bit to the right.

5.1.6 m8(addr)

The contents of an 8-bit value in memory at address addr.

Given the contents of the memory dump shown in Figure 5.4, m8(0x42) refers to the memory location at address 42\(_{16}\) that currently contains the 8-bit value fc\(_{16}\).

The m\(_n\)(addr) notation can be used to refer to memory that is being read or written depending on the context.

When memory is being written, the following notation is used to indicate that the least significant 8 bis of source will be is written into memory at the address addr:

m8(addr) \(\leftarrow \) source

When memory is being read, the following notation is used to indicate that the 8 bit value at the address addr will be read and stored into dest:

dest \(\leftarrow \) m8(addr)

Note that source and dest are typically registers.



00000030  2f 20 72 65 61 64 20 61  20 62 69 6e 61 72 79 20
00000040  66 69 fc 65 20 66 69 6c  6c 65 64 20 77 69 74 68
00000050  20 72 76 33 32 49 20 69  6e 73 74 72 75 63 74 69
00000060  6f 6e 73 20 61 6e 64 20  66 65 65 64 20 74 68 65
Figure 5.4: Sample memory contents.

5.1.7 m16(addr)

The contents of an 16-bit little-endian value in memory at address addr.

Given the contents of the memory dump shown in Figure 5.4, m16(0x42) refers to the memory location at address 42\(_{16}\) that currently contains 65fc\(_{16}\). See also subsection 5.1.6.

5.1.8 m32(addr)

The contents of an 32-bit little-endian value in memory at address addr.

Given the contents of the memory dump shown in Figure 5.4, m32(0x42) refers to the memory location at address 42\(_{16}\) that currently contains 662065fc\(_{16}\). See also subsection 5.1.6.

5.1.9 m64(addr)

The contents of an 64-bit little-endian value in memory at address addr.

Given the contents of the memory dump shown in Figure 5.4, m64(0x42) refers to the memory location at address 42\(_{16}\) that currently contains 656c6c69662065fc\(_{16}\). See also subsection 5.1.6.

5.1.10 m128(addr)

The contents of an 128-bit little-endian value in memory at address addr.

Given the contents of the memory dump shown in Figure 5.4, m128(0x42) refers to the memory location at address 42\(_{16}\) that currently contains 7220687469772064656c6c69662065fc\(_{16}\). See also subsection 5.1.6.

5.1.11 .+offset

The address of the current instruction plus a numeric offset.

5.1.12 .-offset

The address of the current instruction minus a numeric offset.

5.1.13 pcrel_13

An address that is within \([-4096..4094]\) \([\)-0x1000..0x0ffe\(]\) of the current instruction location. These addresses are typically expressed in assembly source code by using labels. See subsection 5.3.6 for examples.

5.1.14 pcrel_21

An address that is within \([-1048576..1048574]\) \([\)-0x100000..0x0ffffe\(]\) of the current instruction location. These addresses are typically expressed in assembly source code by using labels. See subsection 5.3.2 for an example.

5.1.15 pc

The current value of the program counter.

5.1.16 rd

An x-register used to store the result of instruction.

5.1.17 rs1

An x-register value used as a source operand for an instruction.

5.1.18 rs2

An x-register value used as a source operand for an instruction.

5.1.19 imm

An immediate numeric operand. The word immediate refers to the fact that the operand is stored within an instruction.

5.1.20 rsN[h:l]

The value of bits from h through l of x-register rsN. For example: rs1[15:0] refers to the contents of the 16 LSBs of rs1.

5.2 Addressing Modes

immediate, register, base-displacement, pc-relative

5.3 Instruction Encoding Formats

This document concerns itself with the RISC-V instruction formats shown in Figure 5.5.

pict

Figure 5.5: RISC-V instruction formats.

The method/format of the instructions has been designed with an eye on the ease of future manufacture of the machine that will execute them. It is easier to build a machine if it does not have to accommodate many different ways to perform the same task. The result is that a machine can be built with fewer gates, consumes less power, and can run faster than if it were built when a priority is on how a user might prefer to decode the same instructions from a hex dump.

Observe that all instructions have their opcode in bits 0-6 and when they include an rd register it will be specified in bits 7-11, an rs1 register in bits 15-19, an rs2 register in bits 20-24, and so on. This has a seemingly strange impact on the placement of any immediate operands.

When immediate operands are present in an instruction, they are placed in the remaining unused bits. However, they are organized such that the sign bit is always in bit 31 and the remaining bits placed so as to minimize the number of places any given bit is located in different instructions.

For example, consider immediate operand bits 12-19. In the U-type format they are in bit positions 12-19. In the J-type format they are also in positions 12-19. In the J-type format immediate operand bits 1-10 are in the same instruction bit positions as they are in the I-type format and immediate operand bits 5-10 are in the same positions as they are in the B-type and S-type formats.

While this is inconvenient for anyone looking at a memory hexdump, it does make sense when considering the impact of this choice on the number of gates needed to implement circuitry to extract the immediate operands.

5.3.1 U Type

The U-Type format is used for instructions that use a 20-bit immediate operand and an rd destination register.

The rd field contains an x register number to be set to a value that depends on the instruction.

If XLEN=32 then the imm value will extracted from the instruction and converted as shown in Figure 5.6 to form the imm_u value.

pict

Figure 5.6: Decoding a U-type instruction.

Notice that the 20-bits of the imm field are mapped in the same order and in the same relative position that they appear in the instruction when they are used to create the value of the immediate operand. Leaving the imm bits on the left, in the “upper bits” of the imm_u value suggests a rationale for the name of this format.

If XLEN=64 then the imm_u value in this example will be converted to the same two’s complement integer value by extending the sign-bit further to the left.

5.3.2 J Type

The J-type instruction format is used to encode the jal instruction with an immediate value that determines the jump target address. It is similar to the U-type, but the bits in the immediate operand are arranged in a different order.

Note that the imm_j value is an even 21-bit value in the range of \([-1048576..1048574]\) \([\)-0x100000..0x0ffffe\(]\) representing a pc-relative offset to the target address.

If XLEN=32 then the imm value will extracted from the instruction and converted as shown in Figure 5.7 to form the imm_j value.

pict

Figure 5.7: Decoding a J-type instruction.

The J-type format is used by the Jump And Link instruction that calculates the target address by adding imm_j to the current program counter. Since no instruction can be placed at an odd address the 20-bit imm value is zero-extended to the right to represent a 21-bit signed offset capable of expressing a wider range of target addresses than the 20-bit imm value alone.

5.3.3 R Type

pict

The R-type instructions are used for operations that set a destination register rd to the result of an arithmetic, logical or shift operation applied to source registers rs1 and rs2.

Note that instruction bit 30 (part of the the funct7 field) is used to select between the add and sub instructions as well as to select between srl and sra.

5.3.4 I Type

The I-type instruction format is used to encode instructions with a signed 12-bit immediate operand with a range of \([-2048..2047]\), an rd register, and an rs1 register.

If XLEN=32 then the 12-bit imm value example will extracted from the instruction and converted as shown in Figure 5.8 to form the imm_i value.

pict

Figure 5.8: Decoding an I-type Instruction.

A special case of the I-type is used for shift-immediate instructions where the imm field is used to represent the number of bit positions to shift as shown in Figure 5.9. In this variation, the least significant five bits of the imm field are extracted to form the shamt_i value.2

Note also that bit 30 (the imm instruction field bit labeled ‘b’) is used to select between arithmetic and logical shifting.

pict

Figure 5.9: Decoding an I-type Shift Instruction.

 00002640: 6f 00 00 00 6f 00 00 00  b7 87 00 00 03 a5 07 43 *o...o..........C*
 00002650: 67 80 00 00 00 00 00 00  76 61 6c 3d 00 00 00 00 *g.......val=....*
 00002660: 00 00 00 00 80 84 2e 41  1f 85 45 41 80 40 9a 44 *.......A..EA.@.D*
 00002670: 4f 11 f3 c3 6e 8a 67 41  20 1b 00 00 20 1b 00 00 *O...n.gA ... ...*
 00002680: 44 1b 00 00 14 1b 00 00  14 1b 00 00 04 1c 00 00 *D...............*

Figure 5.10: An Example Memory Dump.

5.3.5 S Type

The S-type instruction format is used to encode instructions with a signed 12-bit immediate operand with a range of \([-2048..2047]\), an rs1 register, and an rs2 register.

If XLEN=32 then the 12-bit imm value example will extracted from the instruction and converted as shown Figure 5.11 to form the imm_s value.

pict

Figure 5.11: Decoding an S-type Instruction.

5.3.6 B Type

The B-type instruction format is used for branch instructions that require an even immediate value that is used to determine the branch target address as an offset from the current instruction’s address.

If XLEN=32 then the 12-bit imm value example will extracted from the instruction and converted as shown in Figure 5.12 to form the imm_b value.

pict

Figure 5.12: Decoding a B-type Instruction.

Note that imm_b is expressed in the instruction as a target address that is converted to an even 13-bit value in the range of \([-4096..4094]\) \([\)-0x1000..0x0ffe\(]\) representing a pc-relative offset to the target address. For example, consider the branch instructions in the following code:

00000000: 00520063  beq    x4,x5,0x0    # branches to self (address 0x0)
00000004: 00520463  beq    x4,x5,0xc    # branches to address 0xc
00000008: fe520ce3  beq    x4,x5,0x0    # branches to address 0x0
0000000c: 00100073  ebreak

The instruction at address 0x0 has a target address of zero and imm_b is zero because the offset from the “current instruction” to the target is zero.4

The instruction at address 0x4 has a target address of 0xc and it has an imm_b of 0x08 because 0x4 + 0x08 = 0x0c.

The instruction at address 0x8 has a target address of zero and imm_b is 0xfffffff8 (-8) because 0x8 + 0xfffffff8 = 0x0.

5.4 CPU Registers

The registers are names x0 through x31 and have aliases suited to their conventional use. The following table describes each register.

Note that the calling calling convention specifies that only some of the registers are to be saved by functions if they alter their contents. The idea being that accessing memory is time-consuming and that by classifying some registers as “temporary” (not saved by any function that alter its contents) it is possible to carefully implement a function with less need to store register values on the stack in order to use them to perform the operations of the function.

The lack of grouping the temporary and saved registers is due to the fact that the E extension only has the first 16 registers and some of the instructions in the C extension can only refer to the first 16 registers.





Reg ABI/AliasDescription Saved








x0 zero Hard-wired zero
x1 ra Return address
x2 sp Stack pointer yes
x3 gp Global pointer
x4 tp Thread pointer
x5 t0 Temporary/alternate link register
x6-7 t1-2 Temporaries
x8 s0/fp Saved register/frame pointer yes
x9 s1 Saved register yes
x10-11a0-1 Function arguments/return value
x12-17a2-7 Function arguments
x18-27s2-11 Saved registers yes
x28-31t3-6 Temporaries




5.5 memory

Note that RISC-V is a little-endian machine.

All instructions must be naturally aligned to their 4-byte boundaries. [?, p. 5]

If a RISC-V processor implements the C (compressed) extension then instructions may be aligned to 2-byte boundaries.[?, p. 68]

Data alignment is not necessary but unaligned data can be inefficient. Accessing unaligned data using any of the load or store instructions can also prevent a memory access from operating atomically. [?, p.19]

1 When XLEN is 64 or 128, the shift distance will be given by the least-significant 6 or 7 bits of rs2 respectively. For more information on how shifting works, see section 2.4.

2When XLEN is 64 or 128, the shamt_i field will consist of 6 or 7 bits respectively.

3 When XLEN is 64 or 128, the shift distance will be given by the least-significant 6 or 7 bits of the imm field respectively. For more information on how shifting works, see section 2.4.

4This is in contrast to many other instruction sets with pc-relative addressing modes that express a branch target offset from the “next instruction.”