Dulranga's Notes
Semester 3Computer Architecture

RISC-V Architecture

pronounced as 'RISC-five', represents the fifth major generation of RISC research processors designed by the computer science department at UC Berkeley.

Modular Architecture

RISC-V has extendable modules and a Base. So each chip is named as [Base][Extension] Ex: RV64GC

Base

each chip must have One Base. This base tells about the registers size, memory address space.

  • RV32I: 32-bit registers, standard Integer instruction set (about 40 instructions).
  • RV64I: 64-bit registers, standard Integer instruction set (used for modern PCs and servers).
  • RV32E: An ultra-tiny "Embedded" base with only 16 registers (instead of the usual 32)
    • designed for microcontrollers like the ones in a smart toaster or a toothbrush.

Extensions

letters come after the base indicates included modules in the chip.

LetterNameDescription
MMultiplyAdds hardware instructions for integer multiplication and division.
AAtomicAdds instructions that allow multiple CPU cores to talk to memory without stepping on each other's toes.
F & DFloating PointAdds registers and instructions for single-precision (F) and double-precision (D) decimal math.
GGeneral PurposeShort form for Combination (I + M + A + F + D). This is not a separate extension, just a abbreviation.
CCompressedAllows the chip to read 16-bit instructions alongside standard 32-bit ones to save RAM space.

Ex: RV64GC means same as RV64IMAFDC a 64-bit general-purpose chip that also supports compressed instructions.

Register Convention

Physically, a standard RISC-V chip has 32 registers, labeled simply x0 to x31. To avoid remembering all the registers by position, RISC-V uses a naming convention known as ABI (Application Binary Interface).

Issue if Regs used randomly

if every programmer or compiler used these registers randomly, code written by person A wouldn't work with code written by person B. For example, your program might call a library function, and that function might accidentally overwrite the data you were right in the middle of using. So if you only use your own programming, its perfectly fine, but the moment you want to use someone else's programming or a team mate comes to collaboration, a lot of hiccups will occur.

Register Naming Convention

Strict ruleset called Application binary interface (ABI) to keep things in same track

RegisterABI NameDescription / RoleWho Saves It? (Preservation Rule)
x0zeroHardwired to the value 0N/A (Read-only)
x1raReturn Address (Where to jump back to after a function ends)Caller
x2spStack Pointer (Tracks temporary memory on the stack)Callee
x3gpGlobal Pointer (Points to global variables)N/A (Set once at startup)
x4tpThread Pointer (Used in multi-threaded programs)N/A (Set by Operating System)
x5 - x7t0 - t2Temporary registers (Quick scratchpads)Caller
x8s0 / fpSaved register 0 / Frame PointerCallee
x9s1Saved register 1Callee
x10 - x11a0 - a1Function Arguments / Return ValuesCaller
x12 - x17a2 - a7Function ArgumentsCaller
x18 - x27s2 - s11Saved registersCallee
x28 - x31t3 - t6More Temporary registersCaller

Understanding "Who Saves it"

function b(){
	 // stuff
}
function a(){
	b();
}
// we call a
a()

Imagine a calls b part.

  • a is the Caller
  • b is the Callee

1. Caller saved registers (t and a registers)

these are unprotected or volatile.

Rule - b() has full authority to delete/read/replace any value of temporary (t) or argument (a) registers

If a() want any of those values to be kept, it must manually put them into the RAM (stack) then load it back again once, b() returns.

2. Callee saved registers (s registers and sp)

these are protected or preserved.

Rule - b() is not allowed to change the values (i.e. forbidden from leaving dirty values) in these registers when it finish work. This does not mean it cannot change/read them, it can use those registers, but when it exit from stack, the initial values of s registers and sp must be the same.

Ex: If b() wants to use s2 for some math, it must first back up the original value of s2 onto the stack memory. Before it exits and returns to a(), it must restore that original value. a() can confidently leave data in s2 knowing it won't be modified by other functions.

Important

"Saved" means who is responsible for saving the register values from getting nuked.

  • Caller-Saved: Caller needs to make sure to pass it to Stack Memory to avoid getting replaced by Callee
  • Callee-Saved: Callee is responsible for avoiding the value from changing after exiting from stack

Special Purpose Registers

1. x0 (Zero Register)

This is a hardware level protected register. This cannot be edited by any instruction. A predefined 0 comes in handy in many situations to avoid instruction count from getting high. Ex: Avoid Move Instruction:

  1. COPY x1 to x2
  2. ADD x0 and x0 to x1

2. Argument & Return registers (a0-a7 and ra)

result = calculate(5, 10);
  1. The program places the numbers 5 and 10 into a0 and a1.
  2. It notes the line number it is currently on, saves it into ra (Return Address), and jumps to the calculate function.
  3. The calculate function runs, grabs its arguments out of a0 and a1, does the math, and drops the final answer back into a0.
  4. The function looks at ra, jumps back to where it came from, and the main program reads the answer right out of a0.

RISC-V Instruction Format (32bit)

RISC-V Instruction Format (32bit) check here

On this page