Skip to content

Repository files navigation

Python-Based RISC-V Simulator

A Python simulator for stepping through RISC-V machine code in both non-pipelined and five-stage pipelined execution modes.

This project is useful when you want to see how instructions move through fetch, decode, execute, memory access and writeback, while watching registers, memory, branch behavior and cache statistics change as the program runs.

What It Simulates

  • A 32-bit RV32-style subset of RISC-V.
  • Non-pipelined execution with a shared cache model.
  • Pipelined execution with separate instruction and data cache models.
  • Optional forwarding for the pipelined simulator.
  • Stage-by-stage console traces for instruction flow and control signals.
  • Register, memory and cache-state dumps after execution.

Supported Instructions

R format  - add, sub, mul, div, rem, and, or, xor, sll, srl, sra, slt
I format  - addi, andi, ori, xori, slli, srli, srai, slti, lb, lh, lw, lbu, lhu, jalr
S format  - sb, sh, sw
SB format - beq, bne, blt, bge, bltu, bgeu
U format  - auipc, lui
UJ format - jal

The simulator uses RV32-width architectural semantics: arithmetic and register writes wrap to 32 bits, signed loads are sign-extended, unsigned loads are zero-extended, byte and halfword stores keep only the low 8 or 16 bits, and jalr clears the low target bit.

Quick Start

Clone the repository, then run one of the sample programs from the project root.

Pipelined Mode

python3 main.py ./TestCase/factorial.mc \
  --cache_size 2048 \
  --num_blocks_per_set 8 \
  --block_size 64 \
  --pipelined 1 \
  --forwarding 1 \
  --print_registers 2

Non-Pipelined Mode

python3 main.py ./TestCase/factorial.mc \
  --cache_size 1024 \
  --num_blocks_per_set 4 \
  --block_size 64 \
  --pipelined 2

CLI Options

Option Required Description
test_file Yes Path to the .mc machine-code input file.
--cache_size Yes Cache size in bytes.
--num_blocks_per_set Yes Number of blocks per cache set.
--block_size Yes Cache block size in bytes.
--pipelined Yes 1 for pipelined mode, 2 for non-pipelined mode.
--forwarding Pipelined only 1 enables forwarding, 2 disables forwarding.
--print_registers Pipelined only 1 prints registers every cycle, 2 suppresses cycle-by-cycle register printing.

Simulator dumps are written next to the input file. Output filenames include the execution mode and cache configuration.

Input File Format

Input files use the .mc format:

<address> <machine_code_or_data_byte>

Example:

0x0        0x10000517
0x4        0x00052503
0x54       0xFFFFFFFF
0x10000000 0x07

Rules and address assumptions:

  • The text segment comes first.
  • The data segment follows the termination instruction.
  • Text starts at 0x00000000.
  • Data starts at 0x10000000.
  • Stack starts at 0x7FFFFFFC.
  • Heap starts at 0x10007FE8.
  • The text segment must end with 0xFFFFFFFF.
  • Data entries are loaded byte-by-byte.

Sample Programs

The TestCase/ directory contains ready-to-run machine-code programs:

File Behavior
factorial.mc Computes factorial for the input value and leaves the result in x10.
sumtilln.mc Computes the sum of positive integers through n and leaves the result in x10.
fibonacci.mc Writes a Fibonacci sequence into data memory.
bubblesort.mc Sorts the byte array stored in data memory.

Console Output

The simulator prints a detailed trace as it executes:

  1. FETCH: memory access through the PMI and the fetched instruction register (IR).
  2. DECODE: instruction fields, format detection, immediate values and control signals.
  3. EXECUTE: register reads, ALU operands and ALU result.
  4. MEMORY ACCESS: load/store activity, RY selection and PC updates.
  5. REGISTER UPDATE: register writeback when enabled.
  6. Pipeline details: cycle completion, stalls, flushes and optional register snapshots.
  7. Cache statistics: accesses, hits, misses and victim blocks.

Pipelined output files also include run statistics such as total cycles, instruction count, CPI, hazard counts, stalls and branch mispredictions.

Testing

The repository includes a pytest regression suite for both simulator implementations.

python3 -m venv .venv
.venv/bin/python -m pip install -r requirements-dev.txt
.venv/bin/python -m pytest -q

The tests cover:

  • All sample .mc programs.
  • RV32 wrapping and sign behavior.
  • Shifts, lui, auipc, jal, jalr and branches.
  • Signed div/rem, including divide-by-zero and overflow edge cases.
  • Signed and unsigned loads.
  • Byte, halfword and word stores.
  • Pipelined forwarding and hazard-sensitive branch behavior.
  • Cache block accounting and pipelined CPI.
  • Rejection of unsupported ALU encodings.

Project Layout

.
├── main.py
├── riscv_utils.py
├── requirements-dev.txt
├── TestCase/
│   ├── bubblesort.mc
│   ├── factorial.mc
│   ├── fibonacci.mc
│   └── sumtilln.mc
├── non_pipelined/
│   ├── ALU.py
│   ├── IAG.py
│   ├── control.py
│   ├── memory.py
│   └── register.py
├── pipelined/
│   ├── ALU.py
│   ├── IAG.py
│   ├── buffer.py
│   ├── control.py
│   ├── memory.py
│   └── register.py
└── tests/
    ├── conftest.py
    └── test_correctness.py

Notes

  • The simulator is intentionally verbose; the trace is part of the learning/debugging experience.
  • Infinite recursion or programs without a reachable termination instruction can run indefinitely or crash.
  • The implemented instruction set is a project subset, not a full RV32IM compliance suite.

About

A Python RV32 RISC-V simulator with non-pipelined and five-stage pipelined execution modes, optional forwarding, cache modeling, and stage-by-stage instruction/register/memory traces.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages