Skip to content
hex-7546Public

About

Contains a deep dive into the fundamentals and advanced applications of RISC-V processor

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 

Repository files navigation

RISC-V Architecture: Detailed Analysis & Learnings

This repository is designed to share the learnings regarding the fundamentals and advanced concepts of computer architecture, processors and RISC-V. It covers the core components of processors, memory systems, instruction sets, practical applications and much more.

Table of Contents

  1. Introduction to digital world
  2. Processors
  3. Binary and Data Representation
  4. Registers: Processor's Workspace
  5. Memory System Architecture
  6. Processor Execution Models
  7. RISC-V ISA
  8. Control Flow and Program Structure
  9. Advanced RISC_V Features and Extensions
  10. Experimentation with Simulator

Introduction to Digital World

Processors are an integral part of our lives. They are present in almost all of the electronic devices we use on a day to day basis from our smartphones all the way to our cars

image

Processors

Termed as the "brain" of the computer, processor in simple words is an extremely fast calculator that can perform the following functions: Arithmetic, Logic Operations, Comparison, Access memory, Make decisions and Input/Output

Instruction Execution Cycle

Every processor follows a basic this basic cycle billions of times per second

  1. Fetch: Get the next instruction from memory
  2. Decode: Figure out the instruction
  3. Execute: Perform the operation
  4. Writeback: Store the result
  5. Repeat: Move to the next instruction
image

Processor Performance

Clock Speed (Frequency)

Indicates how many instruction cycles processor can attempt in one second. It is measured in Hertz (Hz)

image

Instruction per Cycle

  1. Simple Processors = 1 instr. per cycle
  2. Superscalar Processors = 2-4 instr. per cycle
  3. High-performance Processors = 4-8 instr. per cycle

Performance Calculation

CPU Performance is calculated using a formula

image

Binary and Data Representation

In computer chip, information is stored using voltage levels. High voltage is represented as 1 and low voltage as 0. It can be converted to other number systems

image

Signed and Unsigned Numbers

  1. Unsigned Numbers - Use all bits for magnitude
  • 8 bit: 0 to 255
  • 16 bit: 0 to 65535
  1. Signed Numbers - Use to represent negative numbers. Uses two's complement representation
    • 8 bit: -127 to +127
    • 16 bit: -32768 to +32767
image

Registers

Registers are tiny storage elements built directly into the processor chip using transistors arranged as flipflops

OIP-987733606 (Shows MSB and LSB in 8-bit)

RISC-V Register Set

RISC-V has 32 general purpose registers (x0-x31) plus special registers

image
  1. Register x0 : Hardwired to contain zero only. It is used for copying, clearing, loading and discarding calculations
  2. Register x1 : Return address. Cpu returns here after executing a function
  3. Register x2 : Stack pointer. Points to the top of stack
  4. Register x3 : Global Pointer
  5. Register x4 : Thread Pointer
  6. Register x5 - x7 : Temporaries. To store temporary values
  7. Register x8 : Saved Register/Frame Pointer.
  8. Register x9 : Saved Register. Used to preserve original values
  9. Register x10 - x11 : Function Arguments/Return Values. Stores first two arguements and return values
  10. Register x12 - x17 : Arguments. Stores 3-8 function arguements
  11. Register x18 - x27 : Saved Register
  12. Register x28 - x31 : Temporaries

Caller Saved Registers: Registers: t0-t6, a0-a7 Used to store temporary values. Can be easily overwritten by Callee Function. The caller must save the value if it needs the value later on.

Callee Saved Register: Registers: s0-s11 Callee must save these registers if it modifies them and restore them before returning. Because caller expects these registers to remain unchanged

            ┌───────────────────────────┐
            │         MAIN()            │
            ├───────────────────────────┤
            │   Uses t0, a0, a1         │  ← Caller-saved
            │   Saves t0 before calling │
            │   Calls FUNC()            │
            ├───────────────────────────┤
                     ↓  JAL
            ┌───────────────────────────┐
            │         FUNC()            │
            ├───────────────────────────┤
            │   Uses s0, s1             │  ← Callee-saved
            │   Saves s0, s1 on stack   │
            │   Restores before return  │
            └───────────────────────────┘

Memory System Architecture

Memory Hierarchy

Computer memory is organized in a hierarchy based on speed, size and cost:

image

Virtual Memory

Virtual Memory creates an illusion that each program has access to a large, private memory space even though the physical memory is limited and shared.

Virtual View (Programs' Perspective)

image

Physical View (Reality)

image

How does Virtual Memory Works

Step 1 — Virtual Addresses Every program thinks it has access to a huge memory space. Program A sees addresses from 0x00000000 → 0xFFFFFFFF (4 GB). Program B also sees the same range. But physically, they share the same RAM.

Step 2 — MMU Translates Virtual → Physical The MMU (Memory Management Unit) converts virtual addresses into physical addresses using:

  • Page tables (mapping virtual pages → physical pages).
  • TLB (Translation Lookaside Buffer) for speed

MMU Translation Process

  1. Checks TLB for cached translation. If address found the translation of address is quick.
  2. If not found, it consults Page tables to find the pages: Virtual Page: 0x10000 and Physical Page: 0x01200
  3. Combines page address with offset: Virtual Address: 0x10000000 = Page 0x10000 + Offset 0x000 Physical Address: 0x01200000 = Page 0x01200 + Offset 0x000
  4. Access memory at 0x01200000

Processor Execution Models

In-Order Execution

In-order processors execute instructions exactly in the sequence they appear in the program one by one.

Screenshot 2025-09-06 131530

Advantages

  • suitable for simple hardware designs
  • lower power consumption
  • easier to debug
  • lower cost to manufacture

Disadvantages

  • limited performance
  • cannot perform instruction level parallelism
  • stalls on memory access

Out-of-Order Execution

Out-of-order processors can rearrange instruction execution to improve performance as long as dependencies are respected

image

Key components:

  1. Instruction Queue: Buffer(temp storage) holding multiple instructions so that CPU knows what instructions are upcoming
  2. Reservation Stations: Hold instructions waiting for operands(data). Allows CPU to prepare instructions in advance and execute them when data is ready
  3. Reorder Buffer: Ensure instructions complete in program order even if instructions finish out of order
  4. Register Renaming: Eliminate false dependencies. Hardware renames registers to avoid false dependencies

Advantages

  • higher performance on typical programs
  • better utilization of execution units
  • hides memory latency
  • exploits instruction-level parallelism

Disadvantages

  • complex hardware design
  • higher power consumption
  • expensive to manufacture

Superscalar Execution

Superscalar processors have multiple execution units and can execute multiple instructions simultaneously.

image

Resources

  • 2-4 Integer ALU's
  • 1-2 Multiply/Divide units
  • 2-3 Load/Store units (memory access)
  • 1-2 Branch units
  • 2-4 Floating-point units


image

Issue Width vs Execution Width

  1. Issue Width: How many instructions can be sent to execution units per cycle
  2. Execution Width: How many instructions can actually be completed per cycle

Example: A "4-issue" processor can send 4 instructions to execution units per cycle, but due to dependencies and resource conflicts. might only complete 2.3 instructions per cycle on average

VLIW (Very Long Instruction Word)

VLIW processors move the complexity of instruction scheduling from hardware to software (the compiler). Each instruction word contains multiple operations that are guaranteed to be independent

image

Example in RISC Asm:

image

Note: Instruction Scheduling: deciding order in which instructions are executed

Specialized Execution Models

Dataflow Processors

Execute instructions as soon as their operands(data) are available, regardless of program order. Execution is driven by data availability and not by instruction sequence
image

Vector Processors

Execute same instructions on multiple data elements simultaneously
image

RISC-V ISA

Instruction Formats (Binary Encoding)

Instruction Width - no. of bits used to represent single instruction in an ISA.

RISC-V uses 32-bit fixed instruction-width for various reasons:

  1. simplicity: easier to decode and fetch
  2. performance: predictable instruction fetch
  3. alignment: instructions naturally align to 4-byte boundaries
  4. pipelining: uniform instruction size simplifies pipeline stages

R-Type Format (Register-Register Operations)

Used when both operands come from register and the result is stored in another register
image

Detailed Field Analysis

  1. opcode : 0-6 bits. Instruction family (0110011 for R-type arithmetic)
  2. rd : 7-11 bits. Destination register (00000-11111 for x0-x31)
  3. funct3 : 12-14 bits. Operation type (000=ADD/SUB, 001=SLL, etc)
  4. rs1 : 15-19 bits. First source register (00000-11111 for x0-x31)
  5. rs2 : 20-24 bits. Second source register (00000-11111 for x0-x31)
  6. funct7 : 25-31 bits. Additional operation info (0000000=ADD, 0100000=SUB)

Example
image

I-Type Format (Immediate Operations)

Used when one operand is constant (immediate)
image

Example
image

Load/Store Architecture

In RISC-V only dedicated load/store instructions can access memory. This has several advantages:

  1. simpler instruction formats
  2. easier pipeline
  3. more predictable timing
  4. better compiler optimization

Example
image

Memory Access Instructions

Supposing at Adress 0x1000 : 0x87654321 (32-bit word). It is of 4 Bytes where:
Byte 0x1000 : 0x21
Byte 0x1001 : 0x34
Byte 0x1002 : 0x56
Byte 0x1003 : 0x78

Assuming x1 contains 0x1000

  • Load Word (32-bit)
    lw x2, 0(x1) -> x2 = 0x87654321

  • Load Halfword (16-bit) with sign extension
    lh x2, 0(x1) -> x2 = 0x4321
    loads bytes from 0x1000 to 0x1001 = 0x4321
    since bit 15 = 0 i.e. 0x4321 is positive
    x2 = 0x00004321

    lh x2, 2(x1) -> x2 = 0x8765
    loads bytes from 0x1002 to 0x1003 = 0x8765
    since bit 15 = 1 i.e. 0x8765 is negative
    x2 = 0xFFFF8765

  • Load Halfword Unsigned (16-bit)
    lhu x2, 2(x1) -> x2 = 0x8765
    loads bytes from 0x1002 to 0x1003 = 0x8765
    always zero-extended regardless of sign bit
    x2 = 0x00008765

  • Load Byte (8-bit) with sign extension
    lw x2, 0(x1) -> x2 = 0x21
    loads byte from 0x1000 = 0x21
    since bit 7 = 0 i.e. 0x21 is positive
    x2 = 0x00000021

    lw x2, 3(x1) -> x2 = 0x87
    loads byte from 0x1003 = 0x87
    since bit 7 = 1 i.e. 0x87 is negative
    x2 = 0xFFFFFF87

  • Load Word (8-bit) Unsigned
    lw x2, 3(x1) -> x2 = 0x87
    loads byte 0x1003 = 0x87
    always zero-extended regardless of sign bit
    x2 = 0x00000087

Address Calculation Modes

The only mode in RISC-V to calculate address is:
Base + Offset addressing

Address = register_value + sign_extended_immediate

  1. Array Access

    Suppose an example
    image
    CASE 1: When index cannot be fit inside 12-bit offset
    slli x12, x11, 2 - x12 = index * 4 (shift left 2 means multiply by 4)
    add x12, x10, x12 - x12 = base + (index * 4)
    lw x13, 0(x12)

    CASE 2: When index can be fit inside 12-bit offset
    lw x13, 20(x10) - loads array[5] directly (20 = 5 * 4)

  2. Structure Member Access

    Suppose an example
    image
    Note : int x, int y, int z are all of 4 bytes hence offset is 4

    lw x14, 4(x10)

  3. Stack Access
    Local variables at negative offsets from frame pointer
    lw x15, -8(s0) - loads local variable at fp-8
    sw x16, -12(s0) - store to local variable at fp-12

  4. Global Variable Access using global pointer
    lw x17, 100(gp) - load global variable at gp+100
    sw x17, 200(gp) - store global variable at gp+200

Control Flow and Program Structure

Conditional Branches

Branch Instruction Format (B-type)

Branch Instruction is used when we have to jump to another location if a condition is true
image

Note

  1. imm[11] : jump offset bit
  2. imm[4:1] : next 4-bit of jump offset
  3. imm[10:5] : next 6-bit of jump offset
  4. imm[12:11] : part of jump offset (sign bit)

Branch Condition and Implementation

image

Instructions

  1. BEQ - branch if equal. checks equality of two registers by subtracting them and equating them to 0
  2. BNE - branch if not equal. checks non equality of two registers by subtracting them and ensuring result is not 0
  3. BLT - branch if less than (signed). checks if one register is less than other by subtracting them and branches if sign bit is set or 1
  4. BGE - branch if greater or equal (signed). checks if one register is greater than other by subtracting them if sign bit is clear or 0
  5. BLTU - branch if less than unsigned. checks if one register is less than other by subtracting them and if carry over takes place
  6. BGEU - branch if greater or equal unsigned. checks if one register is greater than other by subtracting them and no carry over is generated

Other Instructions

  1. BLE - branch if less than or equal
  2. BEQZ - branch if equal to zero
  3. BNEZ - branch if not equal to zero

See Example

Loop Implementation

For Loop

for (i = 0; i < n; i++)
x1 = i
x2 = n

li   x1, 0         # initialize i = 0
# assume x2 contains n already (loop limit)

loop_start: # <--- loop label

bge  x1, x2, loop_end # if i >= n, exit loop

# ---- Loop body ----
# process array[i] or do work here
# -------------------

addi x1, x1, 1     # i++
j    loop_start    # go back to start of loop

loop_end:
# loop finished

Notes loop_start - this is a label. CPU doesn't execute it. It just marks the memory the address in memory so instructions inside it know where to go j - unconditional jump. Always goes back to the instruction at loop_start. This creates the repetition

Countdown Loop

Instead of counting up (usual looping), countdown loop starts from i = n and ends at i = 0. It is more efficient compared to countup loop as equating to zero is more easier than any other number
image

While Loop

image

Do-While Loop

image

Advanced RISC_V Features and Extensions

RISC-V uses a modular approach where the base instruction set (RV32I or RV64I) is extended with additional instruction sets for specific needs

Standard Extensions

RISC-V has many instructions for meeting various purposes

Extension Description Purpose and Insructions
A Atomic instructions Atomic memory operations for multithreading
C Compressed instructions Shorter 16-bit instructions to save memory
D Double-precision floating-point 64-bit floating math
F Single-precision floating-point 32-bit floating math
G Shorthand for IMAFD extensions Short for the combo of IMAFD
H Hypervisor extension For visual support
I Integer Basic integer instruction set (required)
M Integer multiplication and division Hardware multiplication and division
P Packed-SIMD instructions Multimedia and DSP tasks
Q Quad-precision floating-point 128-bit floating math
V Vector operations SIMD operations for AI & HFC

Notes: SIMD - Single instructions, multiple data HFC - High Performance Computing

Examples

Name Description
RV32I Supports only basic operations natively on 32 bits
RV32GC General purpose uses on 32 bits with support for compressed instructions
RV64IMACV For intensive and parallel integer-only computing
RV64GCV Theoretically suitable for future personal computers

Experimentation/Tinkering with Simulator

I'm using the Venus Simulator for trying out simple programs to grasp more about RISC-V Assembly

1. Printing something on console

Steps:

  1. Creating a .data section where variables are stored
  2. message: is a label which stores a string
image
image

2. Adding two numbers in RISC-V assembly

Steps:

  1. Creating a .data section where variables are stored
  2. a: and b: are labels
  3. .word 8 allocates 4 bytes and stores value 8
  4. .word 7 allocates 4 bytes and stores value 7
  5. .text declares the code section
  6. .main label marking the starting point of code
image

Output: Answer is 15 or F stored in t3 image

3. Creating a simple function that multiples 4 numbers together

Steps:

  1. Defines 4 arguments inside main
  2. allocate stack space first
  3. saves the return address
  4. saves the s0 and moves the stack pointer
  5. multiplies the arguements
  6. stores the result in a0
  7. restores s0, return address and deallocate stack space

image

Output: Answer is 360 written as 168 in hexadecimal saved at a0 image

4. Creating a simple control flow program

Steps:

  1. Defines two variables in the .data section
  2. Loads their address first and then load the values of the variable in a0 and a1
  3. The program is that if a >= 10 and b <= 20 then result = a + b, if both are false result = b*2, else result = a - b.

image

Output: Since both the values satisfies the condition the result is a + b or 12 + 16 = 28 image

About

Contains a deep dive into the fundamentals and advanced applications of RISC-V processor

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors