KV32 is a complete RISC-V 32-bit processor implementation with RV32IMAC_Zicsr support, featuring a 5-stage pipeline, instruction cache, a 1-to-10 AXI4-Lite interconnect with nine on-chip peripherals, and both RTL and functional simulators.
- ISA: RV32IMA_Zicsr (Integer, Multiplication, Atomic, CSR extensions)
- Pipeline: 5-stage (Fetch, Decode, Execute, Memory, Writeback)
- Hazard Handling: Data forwarding, pipeline stalls, branch prediction
- Privilege: Machine mode (M-mode) support
- CSRs: Full CSR support including mstatus, mie, mtvec, mepc, mcause, etc.
- Interrupts: Timer, software, and external interrupt support
- Exceptions: Illegal instruction, ECALL, EBREAK, load/store faults
- Bus Interface: AXI4-Lite 1-to-10 interconnect (single master, ten slaves)
- Memory: 2MB RAM at
0x8000_0000with DPI-C access for ELF loading - Instruction Cache: 2-way set-associative, 4 KB, 32-byte cache lines (configurable)
- Power Management: WFI-triggered clock gating via ICG cell (BUFGCE on Xilinx FPGA); auto-wakes on any pending M-mode interrupt (timer, software, external); IRQ pulse capture ensures single-cycle pulses are not missed; 1-cycle wake latency
- Peripherals:
- CLINT — timer (
mtime/mtimecmp) and software interrupts - PLIC — platform-level interrupt controller
- UART — high-speed serial I/O (up to 25 Mbaud)
- I2C — master controller
- SPI — master controller with 4 chip-selects
- GPIO — up to 128 configurable I/O pins
- Timer/PWM — four independent 32-bit timers
- DMA — memory-to-memory transfer engine
- Magic — simulation console output and exit control
- CLINT — timer (
- Simulation:
- Verilator-based RTL simulation with FST/VCD tracing
- Fast functional ISA simulator (kv32sim) with GDB stub
- ELF file loader for both simulators
| Slave | Device | Base Address | End Address | Size | Description |
|---|---|---|---|---|---|
| 0 | RAM | 0x8000_0000 |
0x801F_FFFF |
2 MB | Main memory |
| 1 | Magic | 0x4000_0000 |
0x4000_FFFF |
64 KB | Simulation console and exit control |
| 2 | CLINT | 0x0200_0000 |
0x020B_FFFF |
768 KB | mtime, mtimecmp, software interrupt |
| 3 | PLIC | 0x0C00_0000 |
0x0CFF_FFFF |
16 MB | Platform-level interrupt controller |
| 4 | DMA | 0x2000_0000 |
0x2000_FFFF |
64 KB | Memory-to-memory DMA engine |
| 5 | UART | 0x2001_0000 |
0x2001_FFFF |
64 KB | Serial I/O (up to 25 Mbaud) |
| 6 | I2C | 0x2002_0000 |
0x2002_FFFF |
64 KB | I2C master controller |
| 7 | SPI | 0x2003_0000 |
0x2003_FFFF |
64 KB | SPI master, 4 chip-selects |
| 8 | Timer/PWM | 0x2004_0000 |
0x2004_FFFF |
64 KB | Four independent 32-bit timers/PWM |
| 9 | GPIO | 0x2005_0000 |
0x2005_FFFF |
64 KB | Up to 128 configurable GPIO pins |
| Address | Name | Description |
|---|---|---|
0x4000_0000 |
KV_MAGIC_CONSOLE |
Write a byte to emit a character to the simulator console |
0x4000_0004 |
KV_MAGIC_EXIT |
Write exit code (0→write 1 for PASS; N→write (N<<1)|1 for FAIL) |
0x4000_1000 |
KV_NCM_BASE |
Non-cacheable memory (512 B); I-cache bypassed for all fetches from this region |
Refer to docs/sdk_api_reference.adoc and docs/kv32_soc_datasheet.adoc for register-level details.
kv32/
├── rtl/ # RTL source files
│ ├── core/ # Core processor modules
│ │ ├── kv32_pkg.sv # Package definitions
│ │ ├── kv32_core.sv # Top-level core
│ │ ├── kv32_alu.sv # ALU
│ │ ├── kv32_decoder.sv # Instruction decoder
│ │ ├── kv32_regfile.sv # Register file
│ │ └── kv32_csr.sv # CSR unit
│ ├── kv32_soc.sv # SoC top-level
│ ├── axi_pkg.sv # AXI definitions
│ ├── axi_xbar.sv # AXI crossbar/interconnect
│ ├── axi_arbiter.sv # AXI arbiter
│ ├── kv32_icache.sv # 2-way set-associative instruction cache
│ ├── kv32_pm.sv # Power manager (WFI clock gating, BUFGCE/ICG)
│ ├── axi_clint.sv # CLINT (mtime/mtimecmp/msip)
│ ├── axi_plic.sv # PLIC placeholder
│ ├── axi_uart.sv # UART with AXI wrapper
│ ├── axi_i2c.sv # I2C master controller
│ ├── axi_spi.sv # SPI master controller
│ ├── axi_dma.sv # DMA engine
│ ├── axi_gpio.sv # GPIO controller
│ ├── axi_timer.sv # Timer/PWM
│ ├── axi_magic.sv # Simulation console and exit
│ ├── mem_axi.sv # Memory to AXI bridge (read/write)
│ └── mem_axi_ro.sv # Memory to AXI bridge (read-only, ICache bypass)
├── testbench/ # Testbench files
│ ├── tb_kv32_soc.sv # SystemVerilog wrapper
│ ├── tb_kv32_soc.cpp # Verilator C++ testbench
│ ├── axi_memory.sv # 2MB memory with DPI-C
│ ├── elfloader.h # ELF loader header
│ └── elfloader.cpp # ELF loader implementation
├── sim/ # Software simulator
│ ├── kv32sim.cpp # Main simulator
│ ├── kv32sim.h # Header
│ ├── riscv-dis.cpp # Disassembler
│ └── Makefile # Build file
├── sw/ # Software directory
├── docs/ # Documentation
│ ├── pipeline_architecture.md # Pipeline design doc
│ └── pipeline_forwarding.svg # Pipeline diagram
├── build/ # Build outputs
│ ├── kv32soc # Verilator simulator
│ └── kv32sim # Software simulator
├── Makefile # Main build system
└── env.config # Environment configuration
- Verilator 5.0+ (for RTL simulation)
- GCC/Clang with C++11 support
- RISC-V GCC toolchain (for compiling programs)
- Make
make build-rtlThis creates build/kv32soc Verilator simulator.
make build-simThis creates build/kv32sim functional simulator.
make allmake cleanFor troubleshooting and development, enable debug messages:
# Build with debug enabled
DEBUG=1 make build-rtl
# Run test with debug
DEBUG=1 make rtl-simpleDebug messages show:
- Pipeline stage transitions (IF→ID→EX→MEM→WB)
- AXI bus transactions (read/write addresses and data)
- Memory operations
- Instruction execution details
SystemVerilog assertions are enabled by default to verify design integrity. To disable assertions for faster simulation:
# Disable assertions (not recommended for debugging)
make ASSERT=0 rtl-simpleAssertions verify:
- Core Pipeline: PC alignment, register protection, data forwarding, hazard detection
- Instruction Buffer: FIFO integrity, overflow/underflow protection
- Store Buffer: State machine correctness, count consistency
- SoC Integration: AXI protocol compliance, memory interface correctness
- X/Z Detection: Unknown values on critical control signals
When an assertion fails, the simulator displays the error location and description.
make rtl-<test> # Run test with RTL simulator
make sim-<test> # Run test with software simulatorSee Testing section for available tests and details.
./build/kv32soc program.elf- Generates
kv32soc.vcdwaveform file - Outputs console text via magic address writes
- Exits when program writes to EXIT_MAGIC_ADDR
Usage: ./kv32sim [options] <elf_file>
Options:
--isa=<name> Specify ISA (default: rv32ima_zicsr)
Supported: rv32ima, rv32ima_zicsr
--trace Enable Spike-format trace logging (alias for --log-commits)
--log-commits Enable Spike-format trace logging
--rtl-trace Enable RTL-format trace logging
--log=<file> Specify trace log output file (default: sim_trace.txt)
+signature=<file> Write signature to file (RISCOF compatibility)
+signature-granularity=<n> Signature granularity in bytes (1, 2, or 4, default: 4)
-m<base>:<size> Specify memory range (e.g., -m0x80000000:0x200000)
Default: -m0x80000000:0x200000 (2MB at 0x80000000)
--instructions=<n> Limit execution to N instructions (0 = no limit)
--gdb Enable GDB stub for remote debugging
--gdb-port=<port> Specify GDB port (default: 3333)
Examples:
./kv32sim program.elf
./kv32sim --log-commits --log=output.log program.elf
./kv32sim --rtl-trace --log=rtl_trace.txt program.elf
./kv32sim --log-commits -m0x80000000:0x200000 program.elf
./kv32sim --gdb --gdb-port=3333 program.elf
./kv32sim +signature=output.sig +signature-granularity=4 test.elfgtkwave kv32soc.vcdBoth simulators support loading ELF files directly:
- RTL Simulator: Uses DPI-C to load ELF segments into memory before simulation
- Software Simulator: Parses ELF and loads into internal memory array
Example program usage:
#include "kv_platform.h" /* sw/include/kv_platform.h */
int main() {
kv_magic_putc('H');
kv_magic_putc('e');
kv_magic_putc('l');
kv_magic_putc('o');
kv_magic_putc('\n');
kv_magic_exit(0);
return 0;
}- IF (Instruction Fetch): Fetches instructions from memory via AXI
- ID (Instruction Decode): Decodes instructions, reads register file
- EX (Execute): ALU operations, branch resolution, CSR access
- MEM (Memory): Data memory access via AXI
- WB (Write Back): Writes results to register file
- Data Hazards: Forwarding from EX/MEM/WB stages
- Load-Use Hazards: Pipeline stall (1 cycle)
- Control Hazards: Branch prediction (not-taken), flush on mispredict
- Structural Hazards: Instruction/data arbitration via axi_arbiter
The SoC uses AXI4-Lite for all peripheral accesses. The instruction-fetch path additionally uses AXI4 burst transfers (INCR/WRAP) for cache-line fills.
- Address Width: 32 bits
- Data Width: 32 bits
- Byte Strobes: 4 bits (byte/halfword/word access)
- Response Codes: OKAY, DECERR (unmapped addresses)
- Topology: single master → 10 slaves via
axi_xbar - Bursts: INCR/WRAP supported on the instruction port (ICache line fills)
Edit env.config to set tool paths:
RISCV_PREFIX=/path/to/riscv-toolchain/bin/riscv32-unknown-elf-
VERILATOR=/usr/local/bin/verilatorThe sw/ directory contains example test programs organized by folder:
- common/: Shared code, headers, and linker scripts
- Other folders: Each folder contains a specific test program
Use the following make targets to run tests:
make rtl-<test> # Run <test> with Verilator RTL simulationExample:
make rtl-hello # Run hello test with RTL simulator
make rtl-timer # Run timer test with RTL simulatormake sim-<test> # Run <test> with fast software simulatorExample:
make sim-hello # Run hello test with software simulator
make sim-timer # Run timer test with software simulatorCheck the sw/ directory for available test programs. Each subdirectory (except common/) represents a test that can be run with the above commands.
If you want to compile a program manually:
riscv32-unknown-elf-gcc -march=rv32ima_zicsr -mabi=ilp32 \
-nostartfiles -T linker.ld -o program.elf program.cImportant Notes:
- The
_zicsrextension is required for CSR instructions (mandatory in newer GCC versions) - Floating-point
printfsupport requires properly configuredlibgccfor RV32IMAC - Current common library provides:
puts(),putc(), and basic console I/O via_write() - For printf functionality, include
printf.cfrom common/ and ensure-lgccis added to link against compiler runtime
When building test programs with make <test> or make rtl-<test>, the following files are generated in build/:
- .elf: Executable ELF file
- .dis: Disassembly listing (objdump output)
- .readelf: ELF file information
- kv32soc.vcd: Waveform file (RTL simulation only)
# Terminal 1: Start simulator with GDB server
./build/kv32sim -g 3333 program.elf
# Terminal 2: Connect GDB
riscv32-unknown-elf-gdb program.elf
(gdb) target remote :3333
(gdb) break main
(gdb) continueDetailed documentation is available in the docs/ directory:
- Pipeline Architecture: Comprehensive guide to the 5-stage pipeline implementation, including:
- Pipeline stage details (IF, ID, EX, MEM, WB)
- Data forwarding and hazard handling
- Pipeline registers and control flow
- Performance characteristics
- Visual pipeline diagram with forwarding paths
Additional documentation:
- Source code comments in RTL files
- Inline comments in test programs
- Debug output messages (enable with
DEBUG=1)
- RTL Simulation: ~100-500 Hz (depends on host)
- Software Simulator: ~1-10 MHz
- Target FPGA Frequency: 50-100 MHz
- Single-issue, in-order pipeline
- Instruction cache only — no data cache (D-cache); all data accesses go directly to the AXI bus
- No MMU / virtual memory
- No floating-point unit
- CSR support limited to M-mode
See LICENSE file for details.
- RISC-V Instruction Set Manual
- RISC-V Privileged Architecture
- Verilator User Guide
- AXI4-Lite Protocol Specification
Contributions are welcome! Please ensure:
- Code follows existing style
- All tests pass
- Documentation is updated
- Commit messages are descriptive
See git history for contributors.