Skip to content

angusjhwu/RISC-Vibe-v1

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RiscVibe

Without writing a single line of code, only markdown files, I (and Claude Code) implemented two RISC-V 32I processors, aptly named "RiscVibe": a single-cycle processor, and a 5-stage pipelined processor. From making the Python assembler and custom assembly programs, to creating a test suite and an interactive processor visualizer.

To demonstrate, here is the 5-stage RiscVibe processor calculating fibonacci numbers displayed using the trace visualizer. 5-Stage RiscVibe processor calculating fibonacci numbers.

Processors:

  • Single-stage (riscvibe_1stage/) - All operations complete in one clock cycle, combinational instruction memory, no pipeline hazards
  • 5-stage pipeline (riscvibe_5stage/) - Classic IF/ID/EX/MEM/WB pipeline with data forwarding and hazard detection

See project-docs/PROCESSORS.md for detailed comparison and usage guide.

Features

Processor Architecture

  • 5-stage pipeline: Instruction Fetch (IF), Instruction Decode (ID), Execute (EX), Memory Access (MEM), Write Back (WB)
  • Full RV32I support: All 37 base integer instructions including arithmetic, logic, branches, jumps, loads, and stores
  • Data hazard handling:
    • EX-to-EX forwarding (1-cycle distance)
    • MEM-to-EX forwarding (2-cycle distance)
    • WB-to-ID bypass for register reads
    • Load-use stall detection with automatic pipeline bubble insertion
  • Control hazard handling: Branch/jump detection with pipeline flush (2-cycle penalty)
  • Memory system:
    • 4KB instruction memory (ROM, word-addressed)
    • 4KB data memory (byte-addressable, little-endian)
    • Byte, halfword, and word load/store with sign/zero extension

Assembler

  • Two-pass assembler written in Python
  • Full RV32I instruction support
  • Pseudo-instruction expansion (li, mv, j, ret, call, etc.)
  • Label resolution for branches and jumps
  • ABI register name support (ra, sp, a0-a7, t0-t6, s0-s11, etc.)
  • Outputs Verilog-compatible hex files

Testing Infrastructure

  • Automated regression test runner
  • 12 functional test programs covering ALU, loops, memory, and all hazard scenarios
  • Per-test register value validation
  • VCD waveform generation for debugging

Pipeline Visualizer

  • Interactive web-based visualization of pipeline execution
  • Cycle-by-cycle stepping with playback controls
  • Real-time display of all 5 pipeline stages with PC and disassembled instructions
  • Program view panel with FDXMW stage indicators showing instruction flow through pipeline
  • Register file contents with change highlighting and hex/decimal toggle
  • Hazard and forwarding signal visualization
  • JSON Lines trace format for external tool integration

Repository Structure

RiscVibe/
├── riscvibe_1stage/              # Single-cycle processor
│   ├── rtl/                      # SystemVerilog RTL modules
│   ├── tb/                       # Testbench
│   ├── sim/traces/               # Simulation trace outputs
│   ├── architecture.yaml         # Visualizer architecture config
│   └── Makefile                  # Build system
├── riscvibe_5stage/              # 5-stage pipelined processor
│   ├── rtl/                      # SystemVerilog RTL modules
│   │   ├── riscvibe_5stage_top.sv  # Top module
│   │   ├── *_stage.sv            # Pipeline stages (IF/ID/EX/MEM/WB)
│   │   ├── hazard_unit.sv        # Hazard detection
│   │   ├── forwarding_unit.sv    # Data forwarding
│   │   └── ...                   # ALU, control, memory modules
│   ├── tb/                       # Testbench
│   ├── sim/traces/               # Simulation trace outputs
│   ├── architecture.yaml         # Visualizer architecture config
│   └── Makefile                  # Build system
├── programs/                     # Test programs (.S and .hex)
├── riscvibe_asm/                 # Python assembler
├── sim/visualizer/               # Pipeline visualizer web app
│   ├── app.py                    # Flask backend server
│   ├── trace_parser.py           # JSONL trace file parser
│   └── templates/static/         # HTML/CSS/JavaScript
├── project-docs/                 # Design documentation
├── run_visualizer.sh             # Visualizer launch script
└── regression_pipeline.py        # Automated test runner

System Dependencies

Required

  • Icarus Verilog (iverilog, vvp) - Open-source Verilog/SystemVerilog simulator
  • Python 3.8+ - For the assembler and test runner

Optional

  • GTKWave - Waveform viewer for debugging

Installation

macOS (Homebrew):

brew install icarus-verilog gtkwave python3

Ubuntu/Debian:

sudo apt install iverilog gtkwave python3

Arch Linux:

sudo pacman -S iverilog gtkwave python

Quick Start

Choose a processor: cd riscvibe_1stage (single-cycle) or cd riscvibe_5stage (pipelined)

Run the default test

cd riscvibe_5stage
make

Run a specific test program

cd riscvibe_5stage
make PROGRAM=test_fib

Generate trace for visualizer

cd riscvibe_5stage
make trace PROGRAM=test_fib

View waveforms

cd riscvibe_5stage
make wave

Makefile Targets

Both processors support these Makefile targets:

Target Description
make or make all Compile and simulate (default: test_alu)
make compile Compile only
make sim Run simulation only
make trace Compile and run with trace logging for visualizer
make wave Open waveforms in GTKWave
make clean Remove generated files

Variables

  • PROGRAM - Test program name without .hex (default: test_alu)
  • MAX_CYCLES - Maximum simulation cycles (default: 10000)

Test Programs

Functional Tests

Test Description
test_alu All ALU operations: add, sub, shifts, comparisons, logical
test_fib Fibonacci sequence with loops and branches
test_bubblesort Bubble sort algorithm with memory operations

Pipeline Hazard Tests

Test Description
test_hazard_ex_ex EX-to-EX data forwarding
test_hazard_mem_ex MEM-to-EX data forwarding
test_hazard_load_use Load-use stall insertion
test_hazard_branch Branch flush verification
test_hazard_jal JAL instruction hazards
test_hazard_jalr JALR instruction hazards
test_hazard_x0 x0 register hardwiring
test_hazard_chain Chained data dependencies
test_hazard_comprehensive Combined hazard scenarios

Regression Testing

# Run all tests
./regression_pipeline.py

# Verbose output
./regression_pipeline.py -v

# Run specific test
./regression_pipeline.py --test test_fib

# List available tests
./regression_pipeline.py --list

Results are saved to sim/regression_report.txt with detailed logs in sim/logs/.

Running Your Own Programs

Writing RISC-V Assembly

Create a .S file in the programs/ directory. Example:

# my_program.S - Simple example
    addi x1, x0, 10      # x1 = 10
    addi x2, x0, 20      # x2 = 20
    add  x3, x1, x2      # x3 = x1 + x2 = 30

    # Store result to memory
    sw   x3, 0(x0)       # mem[0] = 30

    # End program (required)
    ecall

Important: All programs must end with ecall or ebreak to terminate simulation.

Supported Instructions

R-Type (register-register): add, sub, sll, slt, sltu, xor, srl, sra, or, and

I-Type (immediate): addi, slti, sltiu, xori, ori, andi, slli, srli, srai

Load: lb, lh, lw, lbu, lhu

Store: sb, sh, sw

Branch: beq, bne, blt, bge, bltu, bgeu

Jump: jal, jalr

Upper immediate: lui, auipc

System: ecall, ebreak

Pseudo-instructions: nop, li, mv, not, neg, j, jr, ret, call, beqz, bnez, blez, bgez, bltz, bgtz

Assembling Your Program

python3 -m riscvibe_asm programs/my_program.S -o programs/my_program.hex

Add -v for verbose output showing each instruction encoded.

Running Your Program

make TESTPROG=programs/my_program.hex

Or step by step:

make compile TESTPROG=programs/my_program.hex
make sim

Viewing Waveforms

After simulation, view internal signals with GTKWave:

make wave

The VCD file is saved to sim/riscvibe_5stage.vcd.

Using the Pipeline Visualizer

The pipeline visualizer provides an interactive web-based view of pipeline execution:

  1. Generate a trace file:

    cd riscvibe_5stage
    make trace PROGRAM=test_fib

    This creates sim/traces/test_fib_trace.jsonl containing cycle-by-cycle processor state.

  2. Start the visualizer:

    cd sim/visualizer
    python app.py
  3. Open in browser: Navigate to http://localhost:5050

  4. Load and explore:

    • Click "Load Architecture" and select the architecture file (riscvibe_1stage/architecture.yaml or riscvibe_5stage/architecture.yaml) matching your trace
    • Click "Load Trace" to load your trace file (e.g., riscvibe_5stage/sim/traces/test_fib_trace.jsonl)
    • Use playback controls or keyboard shortcuts:
      • Space - Play/Pause
      • / - Step backward/forward
      • Home / End - Jump to start/end
    • View pipeline stages with PC and disassembled instructions (e.g., addi x1, x0, 10)
    • Toggle register display between hex and decimal formats
    • Monitor hazard and forwarding signals in real-time

Writing C Programs

To run C programs, you'll need a RISC-V cross-compiler toolchain:

  1. Install the toolchain:

    # macOS
    brew tap riscv-software-src/riscv
    brew install riscv-tools
    
    # Ubuntu
    sudo apt install gcc-riscv64-unknown-elf
  2. Write your C program:

    // my_program.c
    int main() {
        int a = 10;
        int b = 20;
        int c = a + b;
        return c;
    }
  3. Compile and convert to hex:

    # Compile to object file
    riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -nostdlib -T linker.ld my_program.c -o my_program.elf
    
    # Extract binary
    riscv64-unknown-elf-objcopy -O binary my_program.elf my_program.bin
    
    # Convert to hex (you'll need a bin2hex script)
    xxd -p -c 4 my_program.bin | awk '{print $1}' > my_program.hex

    Note: You'll need a minimal linker script (linker.ld) and startup code for proper execution. For simple programs, writing directly in assembly is recommended.

Memory Map

Region Address Range Size Description
Instruction Memory 0x0000 - 0x0FFF 4 KB Read-only, word-aligned
Data Memory 0x0000 - 0x0FFF 4 KB Read/write, byte-addressable

Note: Instruction and data memory are separate (Harvard architecture).

Supported ISA

RiscVibe implements the complete RV32I base integer instruction set (37 instructions):

Format Instructions Count
R-type ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND 10
I-type ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI 9
Load LB, LH, LW, LBU, LHU 5
Store SB, SH, SW 3
Branch BEQ, BNE, BLT, BGE, BLTU, BGEU 6
Jump JAL, JALR 2
U-type LUI, AUIPC 2

Future Work

Near-term Improvements

  • Branch prediction: Add a simple branch predictor (BTB or bimodal) to reduce branch penalty from 2 cycles to ~1 cycle on average
  • Memory-mapped I/O: Add UART or other peripherals for external communication
  • Interrupt support: Implement basic interrupt handling with CSR registers
  • Performance counters: Add cycle counter, instruction counter, and other CSRs

Extensions

  • M extension: Integer multiplication and division (MUL, DIV, REM)
  • C extension: Compressed 16-bit instructions for improved code density
  • Zicsr extension: Control and Status Register instructions
  • F extension: Single-precision floating-point

Infrastructure

  • FPGA synthesis: Provide constraints and scripts for common FPGA boards (Arty A7, DE10-Nano)
  • Formal verification: Add formal property checking with SymbiYosys
  • Continuous integration: GitHub Actions for automated regression on PRs
  • Code coverage: Add simulation coverage metrics
  • Verilator support: Add Verilator compilation for faster simulation

Advanced Features

  • Cache hierarchy: Instruction and data caches with configurable size/associativity
  • MMU/virtual memory: Page tables and address translation for OS support
  • Multi-core: Extend to dual-core with cache coherency
  • Out-of-order execution: Superscalar pipeline with register renaming

Documentation

Additional documentation is available in project-docs/:

License

This project is open source. See individual files for license information.

About

Vibecoding a RISC-V processor and seeing how far Anthropic Claude takes it.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors