Skip to content

About

A 32-bit RV32I RISC-V processor built from scratch in SystemVerilog, with a modular ALU, register file, instruction decoder, control unit, program counter, instruction/data memory, and integrated CPU datapath. Developed incrementally to explore RTL design, processor architecture, and hardware verification.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

RV32I RISC-V Processor Core

I'm building a simple 32-bit RISC-V processor in SystemVerilog as a way to get more practical experience with computer architecture and RTL design.

I had studied processor architecture and digital logic before, but I wanted to actually build the things I was learning about instead of only working with block diagrams. So I decided to start with a small RISC-V core and build it piece by piece.

This project is still a work in progress.

Where I'm at

So far, I've built and tested the main building blocks of the processor:

  • ALU
  • Register file
  • Program counter
  • Instruction memory
  • Instruction fetch
  • Instruction decoder
  • Immediate generator
  • Control unit
  • ALU input multiplexer
  • Data memory
  • Basic integrated CPU datapath

The ALU supports:

  • ADD
  • SUB
  • AND
  • OR
  • XOR
  • SLL
  • SRL
  • SRA
  • SLT
  • SLTU

I've also implemented and tested several RISC-V immediate instructions, including:

  • ADDI
  • ANDI
  • ORI
  • XORI
  • SLTI
  • SLTIU

The individual modules are tested separately before being connected to the CPU. I've also started testing multiple instructions together at the CPU level.

For example, the current CPU test gives:

ADDI:  PASS
ANDI:  PASS
ORI:   PASS
XORI:  PASS
SLTI:  PASS
SLTIU: PASS

I-TYPE ALU TEST COMPLETE

Load and store instructions are the next part I'm working on.

How I'm approaching it

I'm not trying to write the whole processor in one go.

I started with the ALU, tested it, then moved on to the register file, decoder, immediate generation, control logic, memory, and so on. Once the individual pieces worked, I started connecting them together.

This has been useful because some of the problems aren't really visible when you're just looking at a processor diagram. For example, I've had to deal with clock edges, register write timing, reset behavior, instruction encoding, and figuring out why something that looks correct on paper isn't behaving correctly in simulation.

That's probably been one of the most useful parts of the project so far.

Current design

At the moment, the basic flow is:

        Program Counter
               │
               ▼
       Instruction Memory
               │
               ▼
       Instruction Decoder
               │
        ┌──────┴──────┐
        ▼             ▼
  Register File   Control Unit
        │
        ▼
        ALU
        │
        ▼
    Data Memory

The design is written as separate SystemVerilog modules rather than one large CPU module. I'm doing this partly to keep the design manageable and partly so that I can test each block on its own.

Verification

Each major module has its own testbench.

I'm using Icarus Verilog to compile and simulate the SystemVerilog RTL.

So far I've tested things such as:

  • ALU operations
  • Register reads and writes
  • x0 staying at zero
  • Immediate generation
  • Instruction decoding
  • Program counter operation
  • Instruction fetch
  • Data memory reads and writes
  • ALU input selection
  • Integrated CPU instruction execution

There is still a lot more verification to do as the processor grows.

Project Structure

rv32i_project/
│
├── rtl/
│   ├── alu.sv
│   ├── alu_input_mux.sv
│   ├── control_unit.sv
│   ├── data_memory.sv
│   ├── immediate_generator.sv
│   ├── instruction_decoder.sv
│   ├── instruction_fetch.sv
│   ├── instruction_memory.sv
│   ├── program_counter.sv
│   ├── register_file.sv
│   └── rv32i_cpu.sv
│
├── tb/
│   ├── alu_tb.sv
│   ├── alu_input_mux_tb.sv
│   ├── control_unit_tb.sv
│   ├── data_memory_tb.sv
│   ├── immediate_generator_tb.sv
│   ├── instruction_decoder_tb.sv
│   ├── instruction_fetch_tb.sv
│   ├── instruction_memory_tb.sv
│   ├── program_counter_tb.sv
│   ├── register_file_tb.sv
│   └── rv32i_cpu_tb.sv
│
├── README.md
└── .gitignore

What's next

I'm planning to keep extending the processor as I learn more.

The next things I want to work on are:

  1. Finish LW and SW
  2. Add branches such as BEQ and BNE
  3. Add JAL and JALR
  4. Expand the supported RV32I instructions
  5. Run small RISC-V assembly programs
  6. Improve the CPU-level testbench
  7. Experiment with a fixed-point datapath
  8. Learn more about caches and memory hierarchies
  9. Eventually try synthesizing the RTL and looking at timing

Why RISC-V?

I chose RISC-V because the ISA is open and relatively easy to understand compared with many commercial processor architectures.

It also gives me something real to work toward. Instead of designing an arbitrary CPU with instructions I made up myself, I can gradually work toward implementing an actual instruction set and eventually run real RISC-V code on it.

Tools

  • SystemVerilog
  • Icarus Verilog
  • VS Code
  • Git
  • GitHub

Author

Majid Khan B.S. Electrical Engineering, UET Peshawar

About

A 32-bit RV32I RISC-V processor built from scratch in SystemVerilog, with a modular ALU, register file, instruction decoder, control unit, program counter, instruction/data memory, and integrated CPU datapath. Developed incrementally to explore RTL design, processor architecture, and hardware verification.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages