RISC-V CPU Project Report
RISC-V CPU Project Report
Insights from prior projects, such as Zhekai Zhang's MIPS CPU project, significantly contributed to the RISC-V CPU design by providing a foundational codebase for the cache and UART modules. Adapting these components from Zhang's code allowed leveraging existing implementations that follow best practices and have been tested in similar contexts . This not only accelerated development by avoiding the need to create these modules from scratch but also provided a framework for understanding and troubleshooting potential issues within these modules .
The RISC-V CPU project addresses data hazards through complete data forwarding, where data produced in the EX or MEM stages is directly passed to the ID stage. This minimizes RAW data hazards by allowing subsequent instructions to access the necessary data without waiting for the completion of the entire instruction cycle . However, the design still requires stalling if the producer instruction is a load instruction, which remains a limitation in completely eliminating stalls in the pipeline .
Automation through Makefiles improved the efficiency of the CPU project by streamlining the compilation and assembly of test programs using the RISC-V toolchain. By writing a Makefile, complex sets of commands for compiling and linking could be executed automatically, reducing manual input and potential for human error . This approach significantly reduced the overhead of program setup, allowed for easy repetition of similar tasks, and provided the developer with more time to focus on debugging and optimizing the CPU code instead of repetitive configuration tasks .
The main advantage of a 5-stage pipeline, implemented in the RISC-V CPU project, is the efficiency it brings to instruction processing by allowing multiple instructions to be processed at different stages simultaneously, thereby increasing throughput. The stages include Instruction Fetch (IF), Instruction Decode (ID), Execute (EX), Memory Access (MEM), and Write Back (WB). This pipeline design also includes complete data forwarding, which reduces data hazards by forwarding data from the EX or MEM stages directly to the ID stage, leading to fewer stalls during execution . The pipelining structure is crucial for maintaining high performance and efficient execution flows in the CPU design.
The pipeline's efficiency in the RISC-V CPU project is achieved by minimizing unused clock cycles, ensuring that each instruction cycle is productive and the pipeline stages remain active with instruction processing . However, the external factor of UART communication inhibits this efficiency. Due to its inherent latency, the UART protocol can make the pipeline appear sequential rather than parallel, as it forces instructions to pass through all stages before the next one can be fetched, especially when data dependencies occur . This bottleneck limits the effective throughput that pipelining is supposed to enhance.
The UART communication protocol can introduce latency because it serially transmits data between the CPU and the external memory simulator, potentially slowing down the instruction pipeline as it must wait for data transactions to complete . The cache design attempts to mitigate this by using an N-way set associative I-cache and D-cache, which enables faster data retrieval during repeated access patterns, such as loops. However, since UART is the main bottleneck, these caches primarily help in specific scenarios and don't fully resolve the inefficiencies caused by UART latency .
The FPGA implementation encountered several limitations, such as bugs that did not appear during simulation and issues with executing branch instructions correctly. The project identified that the original stall control design in Verilog led to latch generation, which is problematic for reliable execution on FPGA hardware . To address these limitations, future developments are expected to involve refining the Verilog code to avoid hidden traps like unintentional latches, improving simulation tools for better real-world fidelity, and enhancing debugging techniques to catch errors earlier in the development process .
The stall controller module in this RISC-V CPU architecture manages pipeline stalls by receiving stall requests from the IF, ID, and MEM stages and emitting stall signals to the appropriate modules to pause execution. This is crucial for handling instruction fetching and data dependencies that cause pipeline stalls . If this module malfunctions, it could lead to incorrect stalling, causing either unnecessary delays or insufficient stalls that would result in data hazards, ultimately leading to incorrect program execution or reduced CPU performance .
The absence of branch prediction in this RISC-V CPU impacts performance by increasing the likelihood of pipeline stalls, especially in programs with frequent branch instructions, as the CPU must wait until the branch decision is made without speculative execution. This limits instruction throughput and can degrade performance in branch-heavy code . Potential solutions include implementing dynamic branch prediction algorithms, such as two-level adaptive predictors, which can reduce misprediction penalties and improve overall pipeline utilization, albeit at the cost of increased complexity in the CPU design .
Testing the RISC-V CPU on an FPGA platform like Basys 3 posed challenges, as certain bugs not previously identified in the Vivado simulation emerged, such as branch instructions not executing correctly. This highlighted issues like latch generation caused by the original stall control design in Verilog HDL . The re-design to avoid latches reflects a key learning point, emphasizing the complexity and importance of understanding hardware-descriptive languages thoroughly. The experience showcased that simulations don't always replicate real hardware execution, prompting the need for more robust testing and debugging strategies .