Content

  1. Overview
  2. RISC-V
    1. Base Integer Design
    2. Instruction Encoding
    3. Memory Model

Overview

ISA defines the contract between H/W and S/W. Usually includes:

  • Observable state of a processor
  • A set of machine instructions
  • Semantics of the instruction and processor execution
* ISA
Assembly Code -> |Assembler| -> Machine Instructions

RISC-V

Base Integer Design

  • 32 32-bit general-purpose registers
    • x0 - x31
    • ABI names for use in assembler
  • Additional Program Counter (PC)

Why 32 registers?

Too less -> not enough for 3-address format (2-address increases instruction counts and lowers frequency) More -> helps with high-performance code (loop unrolling, software pipelining, cache tiling, etc.) 32-bit size of instruction -> makes 32 registers (5 bits) fit better

Instruction Encoding

  • Good encoding optimizes:
    • Regularity
    • Simple hardware decode
    • Instruction length
    • Extensibility
  • 6 general types of instructions
    • R-type, I-type, S-type, SB-type, U-type, UJ-type
    • Instructions with the same type shares similar encoding
R-Type (Register-Register) Instructions
  • Arithmetic: ADD, SUB
  • Bit Operations: AND, OR, XOR, SLL, SRL, SRA
  • Comparison: SLT, SLTU

2 source registers, 1 dest register.

|func|rs2|rs1|func|rd|opcode|
  7    5   5   3   5    7

Number of registers affects number of bits to encode rs/rd, hence affects number of instructions encodable.

I-Type (Register-Immediate) Instructions
  • Arithmetic: ADDI (SUBI isn't needed, just put negative number for ADDI)
  • Bit Operations: ANDI, ORI, XORI
  • Comparison: SLTI, SLTIU

1 source registers, 1 dest register.

|imm |rs1|func|rd|opcode|
  12   5   3   5    7

Range for immediate value: [-2^11, 2^11-1]

Number of registers affects number of bits to encode rs/rd, hence affects range of immediate value.

U-Type Instructions
  • LUI (Load Upper Immediate)
|imm |rd|opcode|
  20  5    7
// Example - building larger immediate
// to load from 0x12345678
lui t0 0x12345
addi t0 0 0x678
lw t1 0(t0)
Memory Operations
* LOAD (I-type)
|imm    |rs1  |func  |rd   |opcode|
  12      5     3     5       7
 offset  base  width  dest   LOAD   // width: W/H/B

// example
int y = e + f[3]; // e: a0, f: a1, y: a2
=>
lw t0, 12(a1) # 12=3x4(int size)
ADD a2, a0, t0 

* STORE (S-type)
|imm    |rs2  |rs1  |func  |imm    |opcode|
  7        5    5      3      5       7
 offset  src   base  width  offset   STORE

Using offset because not enough bits for 32-bit addresses. And mostly we jump to an address not too far away. Split immediate for register specifiers to be aligned, which helps simplifying decoding (which is usually on the critical paths).

Conditional Branch & Unconditional Jump
* Branch (SB-type)
|imm|imm|rs2  |rs1  |func|imm|imm |opcode|  
  1   6    5     5     3   4   1     7
 offset  src2  src1        offset  BRANCH

// immediate: signed offset in multiples of 2

* Jump-And-Link (UJ-type)
|imm|imm|imm|imm|rd    |opcode|
  1   10  1   8    5      7
      offset      dest   JAL         // dest: return address
# jump to (offset*2 + PC)      

|imm   |rs1  |funct3|rd  |opcode|
  12     5      3     5     7
 offset base    0    dest  JALR      // dest: return address
# jump to (offset + rs1)    

// immediate: signed offset in multiples of 2
// plain jump: rd=x0

For returning to return address: jalr zero, ra

Two's Complement

  • 2's complement of an n-bit number v is the value 2^n - v
  • 1's complement +
  • For {b_n-1, b_n-2, ..., b0}, 2's complement is -2^(n-1)*b_n-1 + sum_i=0_to_n-2(bi * 2^i)
  • Range: [-2^(n-1), 2^(n-1)-1]

Sign Extension

Fill the additional bits with the most significant bit.

Memory Model

  • Byte-addressable: each address corresponds to 1 byte
  • Little endian byte addressing scheme: the LSB is at lowest address

endian

  • Words aligned at 4-byte boundary; half-words aligned at 2-byte boundary

References

results matching ""

    No results matching ""