This is the final project for the course CS214 Computer Organization at SUSTech. The project is to implement a simple 5-stage pipelined CPU in Verilog. The CPU is based on the RISC-V instruction set architecture (ISA). The CPU is capable of executing the RV32I base integer instruction set except sb, sh, ecall and ebreak instructions.
This project runs on Minisys board, not EGO-1 board. Please make sure you have the correct board before running the project.
This repository contains the following contents:
- Pipelined CPU source code
- Assembly files and COE files for testing
- Useful tools: RARS(a RISC-V assembly code simulator), UARTCoe_v3.0.exe(a UART transmit tool). The tools can be found under SUSTech-CS214-Computer-Organization-Project/Assembly
- 5-stage pipeline: The CPU is implemented with a 5-stage pipeline, including Instruction Fetch (IF), Instruction Decode (ID), Execute (EX), Memory Access (MEM), and Write Back (WB).
- Forwarding Unit: The CPU is equipped with a forwarding unit to handle data hazards.
- Hazard Detection Unit: The CPU is equipped with a hazard detection unit to handle load-use hazards.
- Branch Prediction: The CPU is equipped with a simple branch prediction module to predict the program counter value.
luiandauipcInstructions: The CPU is capable of executingluiandauipcinstructions.- Bug-free: During our testing, the CPU is bug-free for its hardware implementation. We are confident that any program that runs on the RARS simulator will run correctly on our CPU. If you find any bugs, please let us know.
- Well documented: Each module is documented in detail, we hope this can help you understand the code, because this helped us a lot :)
Please refer to the report for detailed information about the project structure.
- Download the project to your local machine.
- Open Vivado and connect your FPGA board to your computer.
- Program the FPGA with the pre-built bitstream
Top.bit.
- Download the project to your local machine.
- Open
Pipeline_CPU.xprin Vivado. - Import design files
Pipeline_CPU.srcs/sources_1to the project (please make sure you haveuart_bmpg_0IP core, which is a custom IP core provided by the instructor and does not exist in vivado by default). - Import constraints file
Pipeline_CPU.srcs/constrs_1/new/Constraint.xdcto the project. - Run generate bitstream.
- Write your program in RARS.
- Set Memory Configuration to
Compact, Text at Address 0underSettings/ Memory Configuration. - Assemble your program.
- Dump your instructions to
inst.txtand data todata.txtusing theFile/Dump Memoryfunction, set dump format toHexadecimal Text.
- Copy and paste your
inst.txtanddata.txtto the same directory asGenUBit_RISC_V.bat,rars2coe.exeandUARTCoe_v3.0.exe(provided under/Assembly). - Run
GenUBit_RISC_V.batto generateprgmip32.coeanddmem32.coe. - Set
prgmip32.coeanddmem32.coeas the initial memory content in theInstruction MemoryandData Memoryrespectively. - Run generate bitstream.
- Copy and paste your
inst.txtanddata.txtto the same directory asGenUBit_RISC_V.bat,rars2coe.exeandUARTCoe_v3.0.exe(provided under/Assembly). - Run
GenUBit_RISC_V.batto generateout.txt. - Run
UartAssist.exe, set the baud rate to 128000, and loadout.txt. - Run generate bitstream and program the FPGA.
- Press P2 on the FPGA board to enter the UART communication mode.
- Send the program to the FPGA by clicking
SendinUartAssist.exe. - Wait until
Program Doneis displayed inUartAssist.exe. - Press S6 (Reset) on the FPGA board to start the program.
For the sake of code quality, we have some regulations for the code:
- Naming:
- Variable: Use
snake_casefor variable names. Example:read_data- value: No special requirements
- flag: Use _flag as the suffix. Example:
mem_read_flag - data: For data from/to memory/register, use _data as the suffix. Example:
write_data - constant: Use all uppercase with underscore for constants. Example:
HALF_PERIOD(should be defined in a separate parameter file under/Parameters)
- stage: If the variable is present in multiple stages, put stage name as the final suffix. Example:
instruction_IF - Module: Use
snake_casewith uppercase for module names. Example:Decoder - Instance: Use
<module_name> + _ + Instancefor instance names. Example:Decoder_Instance - Ip Core: Use
snake_casewith suffix_ipfor IP core names. Example:CPU_Main_Clock_ip
- Variable: Use
- Constants: For all constants, please put them in the
Parameters.vand reference them in the code. An example is shown inInstruction_Fetch.v. - Instantiation: When instantiating a module, please use the following format:
For example:
<module_name> <module_name> + _ + Instance( .<port_name>(<port_name>) );
Controller Controller_Instance( .inst(inst), .branch_flag(branch_flag), .ALU_Operation(ALU_Operation), .ALU_src_flag(ALU_src_flag), .mem_read_flag(mem_read_flag), .mem_write_flag(mem_write_flag), .mem_to_reg_flag(mem_to_reg_flag), .reg_write_flag(reg_write_flag) );