目录 ← 首页
CS61C

I-Type

Learning Outcomes

  • Translate between I-type assembly instructions and machine instructions.
  • Reason about why load and jalr are I-Type instructions.
  • Translate jr and ret pseudoinstructions to machine instructions.

We now turn to our next instruction format: I-Type. While the “I” is for Immediate, the I-Type instruction format is used for a variety of instructions:

  • Register-immediate arithmetic instructions
  • Load instructions
  • The jalr instruction
  • (out of scope) Environment calls and breakpoints

The I-Type instruction format is the second and third rows of the instruction format table.

I-Type: Fields

We first discuss arithmetic instructions of the form opname rd rs1 imm like addi, xori, etc. The format is shown in #fig-i-type:

RISC-V I-type layout: assembly opname rd rs1 imm above a 32-bit bar with imm[11:0] (bits 31–20), rs1 (bits 19–15), funct3 (bits 14–12), rd (bits 11–7), and opcode (bits 6–0), labeling the 12-bit immediate, source register, and destination register fields.

The I-Type Instruction Format.

I-Type Fields:

  • Register operands: Notice that the register fields rs1 and rd are in the same positions in I-Type and R-type; this intentional design reduces hardware complexity.

  • Constant operand: The immediate field1 imm specifies a 12-bit-wide numeric constant. The I-Type has no second source register rs2, so imm reuses those bit positions to encode a larger numeric constant across bits 15 to 31.

    The 12-bit immediate is a two’s complement integer with range 211=2048-2^{11} = -2048 to 2111=20472^{11} - 1 = 2047. Before using this 12-bit-wide value in an operation, the hardware sign-extends it to a 32-bit-wide value.

  • Operation fields: opcode, funct3

Assembly Instruction \rightarrow Machine Instruction

Consider #fig-itype-addi-example, which translates addi x15 x1 -50 to a machine instruction.

Encoding of addi x15 x1 -50: imm[11:0] holds two’s complement 0b111111001110 for -50, rs1 is 0b00001 for x1, funct3 is 0b000 for add, rd is 0b01111 for x15, and the opcode is 0b0010011 for I-type arithmetic.

The I-Type instruction addi x15 x1 -50.

We follow the steps for translating assembly into machine code from earlier:

  1. Determine instruction format type. addi is I-type because it performs arithmetic betwen a register operand and a constant operand. We use the arithmetic instructions table on the RISC-V green card.

  2. Determine operation field codes.

    • opcode: 0010011 for all register-immediate arithmetic instructions
    • funct3: 000 for add
  3. Translate registers, immediates, etc.

    • rs1: Register x1. Translate 11 to 5-bit unsigned integer representation 00001.
    • rd: Register x15. Translate 1515 to 5-bit unsigned integer representation 01111.
    • imm: 50-50 as 12-bit two’s complement:
      • +50+50 is 0000 0011 0010.
      • Flip bits: 1111 1100 1101.
      • Add one to get 50-50: 1111 1100 1110.
  4. (if needed) Convert to hexadecimal.

    • We leave this as an exercise to you!

I-Type vs. R-Type

#fig-comparison-itype-rtype compares the two instruction formats we have seen so far:

Side-by-side R-type and I-type instruction format comparison: both formats share bit positions for opcode, rd, funct3, and rs1; R-type uses bits 31–20 for funct7 plus rs2, while I-type replaces that region with a 12-bit immediate imm[11:0].

I-Type instruction set comparison to R-Type instruction set.

Again, good design demands good compromises. If we only had the single R-Type format and specified imm as a 5-bit field replacing rs2, then we’d only be able to represent 32 immediate values. The I-Type field therefore expands the imm field across the R-type’s rs2 and funct7 fields to at least guarantee we can represent a wider range of 2122^{12} immediate values.

The I-type design’s consistency with R-type simplifies how hardware processes these two instruction formats. Constants are frequently short and can fit into the 12-bit imm field. For larger constants, we must use additional instructions like lui (load upper-immediate), which we discuss later.

Notice the 3-bit funct3 field is not sufficient to specify the 9 register-immediate arithmetic instructions, much less any load instructions. The I-Type therefore still has a few details. Onward!

Arithmetic Shifts (“I*-Type”)

While there is no official “I*-Type” instructions, the RV32I Unprivileged Manual says:

Shifts by a constant are encoded as a specialization of the I-type format.

In this course we will call these “I*-Type” (where the asterisk is “mostly I-Type, save some details”). Consider #tab-istar-type and the following excerpt from the manual:

The operand to be shifted is in rs1, and the shift amount is encoded in the lower 5 bits of the I-immediate field. The right shift type is encoded in bit 30.

Observations:

  • Arithmetic bitshift operations need only a 5-bit unsigned immediate, in imm[4:0]. The maximum bitshift is 32; anything larger will shift all data off the register, which is 32 bits wide.

  • The upper seven bits2 are not part of the immediate and used very similarly to the funct7 field for R-Type instructions sll, srl, and sra.

    • Like with R-type, Bit 30 is a flag that indicates when it is necessary to sign-extend.
    • If Bit 30 is on, insert leading 1’s (for srai).
    • If Bit 30 is off, just zero-extend for srli (and slli, where left-shifts are only ever logical).

Load Instructions

Remember, instruction formats are simply just formats. The operation specifies what the hardware actually does. However, keeping the same instruction format allows us to simplify and reuse certain hardware.

Load instructions are one such example. Recall from an earlier section:

The load word instruction:

  • Computes a memory address R[rs1]+imm
  • Load a word from this address in memory, M[R[rs1] + imm][31:0] into a destination register, rd.

Loads can therefore use the I-Type instruction format (@fig-load-operation-isa):

  • imm, rs1, rd fields
  • opcode (as all instructions do). Loads use opcode 000 0011.
  • funct3 specifies partial loads and signed/unsigned loads.

I-type layout for loads: syntax loadop rd imm(rs1) with immediate imm[11:0] as a byte offset added to the base rs1, funct3, rd as destination of the loaded value, and the load opcode field; color-coding differentiates the immediate, source register, and destination register.

Load instructions use I-Type instruction format.

Observations:

  • The fact that loads perform a memory access is irrelevant to how we specify the instruction. The instruction bits simply provide enough information for the hardware to decode and execute the correct instruction.
  • Loads do share some similarities with other I-Type instructions. Notably, loads also perform register-immediate addition to compute the memory address as R[rs1] + imm. Loads can therefore reuse any hardware needed for register-immediate arithmetic instructions.

We recommend reviewing the earier chapter for the description of each load instruction in #tab-i-type-loads.

Load Example

jalr: I-Type

We recommend reviewing jump instructions before continuing:

Jump and Link Register (jalr rd rs1 imm). Link the “return address” (PC + 4) to a register rd. Then perform an unconditional jump by setting PC to R[rs1] + imm.

The jalr instruction can also be supported with the I-Type format (@fig-jalr-isa):

  • imm, rs1, rd fields
  • opcode (as all instructions do). jalr uses opcode 110 0111.
  • funct3 is not particularly needed, since there is only one jalr instruction. However, because the I-Type format requires it, jalr uses 000.

I-type jalr layout including the immediate field imm[11:0] as an offset added to source register rs1 to form the jump target, funct3, rd receiving the link value PC plus four, and opcode; annotations differentiate the offset, base register, and link destination.

jalr instruction format. The program counter is updated to the base register plus a numeric constant, e.g., PC = R[rs1] + imm.

Observations:

  • Like with loads, the fact that jalr accesses PC is irrelevant to how we specify the instruction.
  • Like with loads, jalr also performs register-immediate addition, jalr can therefore reuse register-immediate arithmetic hardware to compute the jump address R[rs1] + imm.

Design Decisions for I-Type

This section is intended for you to develop your intuition for I-Type instructions using what you learned in this section.

Consider the I-Type instructions3 shown in #tab-i-type, which is a reformatting of the rightmost columns of relevant tables on the RISC-V green card.

See explanation [above].

First question: see explanation [above]. Second question: See a later section.

Footnotes

  1. Again, immediates are called as such because their bit patterns are directly encoded into the machine instruction.

  2. The course RISC-V green card labels these upper 7 bits as “funct7”–a misnomer, because I-Types don’t have a funct7 field. As per the RISC-V Unprivileged Manual these upper 7 bits should really be relabeled imm[11:5]–part of the imm[11:0] field, but not considered part of the numeric constant.

  3. ecall, ebreak are out of scope in our discussion, but see more details in the RISC-V Green Card and the RISC-V Unprivileged Manual.