RISC-V CPU Visualization

Note: We are still working on this project and plan to add functionality that will allow you to upload your own RISC-V code to visualize. For now, explore these pre-programmed examples. Have fun learning! :)

Demo Structure

This interactive demo is organized into these key sections:

Start by selecting either the Sequential CPU or Pipelined CPU demo below to explore different architecture approaches.

This demo provides interactive visualizations of RISC-V CPU implementations, demonstrating both sequential and pipelined architectures.

Sequential CPU

A single-cycle implementation. Simple to understand but less efficient.

Features:

  • Complete instruction execution in a single cycle
  • Direct visualization of control and data paths
  • Step-by-step execution with register and memory updates

Pipelined CPU

A 5-stage pipelined implementation with hazard detection and forwarding for improved performance.

Features:

  • 5 pipeline stages: IF, ID, EX, MEM, WB
  • Data hazard detection and resolution
  • Forwarding paths to minimize stalls
  • Branch prediction and resolution

Demo Programs

Sequential CPU Program

The Sequential CPU demo executes the following RISC-V program:

addi x1, x0, 15    # Initialize x1 = 15
addi x2, x0, 25    # Initialize x2 = 25
addi x3, x0, 7     # Initialize x3 = 7
addi x4, x0, 18    # Initialize x4 = 18
add x5, x1, x2     # Add: x5 = x1 + x2
sub x6, x2, x1     # Subtract: x6 = x2 - x1
and x7, x1, x3     # Bitwise AND: x7 = x1 & x3
or x8, x1, x3      # Bitwise OR: x8 = x1 | x3
sd x5, 0(x0)       # Store x5 to memory[0]
sd x6, 8(x0)       # Store x6 to memory[8]
ld x9, 0(x0)       # Load from memory[0] to x9
ld x10, 8(x0)      # Load from memory[8] to x10
add x11, x9, x10   # x11 = x9 + x10
sub x12, x9, x10   # x12 = x9 - x10
beq x11, x12, skip # Branch if x11 == x12
addi x13, x0, 100  # x13 = 100
or x14, x11, x12   # x14 = x11 | x12
and x15, x11, x12  # x15 = x11 & x12
sd x14, 16(x0)     # Store x14 to memory[16]
sd x15, 24(x0)     # Store x15 to memory[24]
skip:
addi x16, x0, 50   # x16 = 50
add x17, x16, x15  # x17 = x16 + x15
sub x18, x17, x14  # x18 = x17 - x14
beq x17, x18, end  # Branch if x17 == x18
ld x19, 16(x0)     # Load from memory[16] to x19
ld x20, 24(x0)     # Load from memory[24] to x20
or x21, x19, x20   # x21 = x19 | x20
and x22, x19, x20  # x22 = x19 & x20
sd x21, 32(x0)     # Store x21 to memory[32]
sd x22, 40(x0)     # Store x22 to memory[40]
end:
nop

Program Explanation:

This program demonstrates all supported RISC-V instructions in a sequential execution:

  1. Register Initialization: Sets initial values in registers x1-x4 using immediate values
  2. Arithmetic Operations: Performs addition and subtraction between registers
  3. Logical Operations: Performs bitwise AND and OR operations
  4. Memory Operations: Stores and loads values to/from memory
  5. Branching: Uses conditional branches to control program flow
  6. Control Flow: Demonstrates label-based branching with two code paths

The sequential execution allows you to observe how each instruction fully completes before the next one begins, with all data paths and control signals visible during each step.

Pipelined CPU Program

The Pipelined CPU demo executes the following RISC-V program:

start:
              ld x1, 0(x0)    # Load n from memory
              addi x2, x0, 0     # x2 = 0 (Fib(0))
              addi x3, x0, 1     # x3 = 1 (Fib(1))
              beq x1, x0, done   # If n == 0, return Fib(0)
              addi x1, x1, -1   # Decrement n by 1 to account for Fib(1)
              beq x1, x0, done1  # If n == 1, return Fib(1)
          
          loop:
              add x4, x2, x3   # x4 = x2 + x3 (Fib(n) = Fib(n-1) + Fib(n-2))
              add x2, x3, x0    # x2 = x3 (shift Fib(n-1) to Fib(n-2))
              add x3, x4, x0    # x3 = x4 (shift Fib(n) to Fib(n-1))
              addi x1, x1, -1   # Decrement n
              beq x1, x0, done1  # Repeat until n == 0
              beq x0, x0, loop
          
          done1:
              add x4, x3, x0    # Return Fib(1)
          
          done:
              # x4 holds the Fibonacci result
              addi x0, x0, 0
              nop

Program Explanation:

This Fibonacci calculator demonstrates pipeline hazards and their resolution:

  1. Data Hazards: The program creates register dependencies between instructions (registers are both read and written in consecutive instructions), triggering the forwarding unit.
  2. Control Hazards: The multiple branch instructions create control hazards that demonstrate branch prediction and pipeline flushing.
  3. Fibonacci Implementation: The program calculates the Fibonacci sequence:
    • Loads n=10 from memory location 0
    • Initializes with Fib(0)=0 and Fib(1)=1
    • Iteratively computes Fib(n) = Fib(n-1) + Fib(n-2)
    • For n=10, the result will be Fib(10)=55

When the program completes, x4 will contain the 10th Fibonacci number (55). Following the execution shows how the pipeline handles data dependencies and branch predictions in this more complex algorithm. The first instruction demonstrates memory access hazards by loading the value from memory.

Supported Instructions

Instruction Format Operation Description
add R-type add rd, rs1, rs2 rd ← rs1 + rs2
sub R-type sub rd, rs1, rs2 rd ← rs1 - rs2
and R-type and rd, rs1, rs2 rd ← rs1 & rs2
or R-type or rd, rs1, rs2 rd ← rs1 | rs2
addi I-type addi rd, rs1, imm rd ← rs1 + imm
ld I-type ld rd, offset(rs1) rd ← Memory[rs1 + offset]
sd S-type sd rs2, offset(rs1) Memory[rs1 + offset] ← rs2
beq B-type beq rs1, rs2, offset if (rs1 == rs2) PC ← PC + offset

Sequential vs Pipelined CPU

The demo demonstrates two fundamentally different approaches to CPU design:

The pipelined implementation includes mechanisms to handle:

Additional Resources