Peacock CPU: A 64-bit 5-stage pipelined Power ISA CPU

Project Overview

Designed and implemented a fully functional 64-bit, 5-stage pipelined CPU targeting the Scalar Fixed-point Subset (SFS) of Power ISA v3.1C specification. The CPU was written in Veryl HDL and verified end-to-end using a custom software golden model. This project demonstrates deep understanding of processor microarchitecture, pipelining, and hardware-software co-design.

Major Features

  • Major features of this project are:
  • Five pipeline stages: Fetch, Decode, Execute, Memory, Writeback.
  • Register Files : A general-purpose-register register file with 32 x 64-bit wide registers and a special-purpose-register register file, both with parametrized bypass enable support ALU.
  • Instruction Decoder: Decodes 50+ Power ISA instructions including arithmetic, logical, shifts, and memory operations
  • Memory: Separate data and instruction memories with parametrized latency modelling and a 64-bit wide bus.
  • Operations: An ALU that supports various operations such as addition, logical ops (AND, OR, XOR), rotates and shifts.
  • Hazard Detection: A hazard detection unit that detects RAW hazards in the pipeline and branch mis-predicts and stalls or flushes the pipeline accordingly.
  • Test Generation: A Python assembly test generation module that generates randomized assembly to test the processor.
  • Verification: A software golden model of the spec written in Rust for automated instruction-by-instruction verification against the RTL processor.

Five-Stage Pipeline Architecture

  • Pipeline Architecture: Implemented classic 5-stage pipeline: Fetch → Decode → Execute → Memory → Writeback. Optimized for higher clock frequency by reducing combinational delay between stages.
  • A 5-stage classic MIPS/RISC style pipeline is used as it is faster than a simpler single-cycle implementation. Adding pipeline registers decreases the combinational delay between any two flip-flops and thus increases the clock frequency the processor can operate at. The five stages are: Fetch, Decode, Execute, Memory, and Writeback. Fetch deals with getting the next instruction from the instruction memory, stalls happening in the Fetch stage due to instruction memory latency. Decode takes the raw 32-bit instruction and decodes or expands it into different fields, specifying which operation to perform and which registers to read from and also decodes any immediates. It also handles reading from the register file. Execute performs the computation specified by the decoded instruction, or in the case of memory access instructions, calculates the effective address from which to read the data memory. Memory reads from and writes into the data memory at the effective address calculated by the execute stage, or if the instruction is not a memory access instruction, does nothing. The pipeline also stalls in Memory due to data memory latency. Writeback handles writing back into the register files.

Hazard Management

  • Built a Hazard Detection Unit to handle RAW hazards, data hazards, and branch mispredictions. Implemented pipeline stalls and flushes for correct execution.
  • While pipelining the processor increases performance, it also increases the complexity of the processor, as now there are upto 5 instructions travelling though the 5 stages of the pipeline at any single point in time. Care must be taken that each pipeline stage only operates on the correct data for any instruction and data doesn’t skip any pipeline register. Additionally, there are also read-after-write (RAW) hazards that happen when a earlier instruction writes data that is read by an later instruction, both instructions being in different pipeline stages at the same time. This means that the later instruction can read incorrect data since the register file is written to only when the earlier instruction reaches the writeback stage and the decode stage of the later instruction occurs before that. These now need to be detected and then the pipeline needs to be stalled to ensure correct execution. This is done by the hazard detection unit.

Branch Prediction

Implemented Predict-Not-Taken branch predictor. Branch target calculated in Execute stage with pipeline flush on misprediction. Additionally, calculation of the branch target for branch instructions happens in the Execute stage, so either the pipeline needs to stall upon encountering a branch instruction which would require additional instruction decoding in the Fetch stage, or we can add branch prediction and predict if the branch will be taken or not. If we do branch prediction, we need to flush out incorrectly fetched instructions from the pipeline registers once we know the actual branch target in Execute. This project uses a simple predict-not-taken branch predictor for simplicity, always predicting that any branches will not be taken and fetching the linearly next instruction from memory, correcting this prediction by flushing in Execute later if needed.

Randomized Assembly Generation

In order to effectively test the processor and reduce blind spots in verification, valid assembly test cases are generated with random values and random registers. This is better than having fixed test cases as it allows for broader coverage of the instruction set and uncovers edge cases that fixed test cases might miss.

Lockstep testing against software golden model

To ensure functional correctness of the RTL implementation, the processor is verified in lockstep against a software golden model that serves as the authoritative reference for Power ISA behavior. During simulation, both the RTL design and the golden model execute the same instruction stream, and their architectural states such as general-purpose registers, special-purpose registers, condition register fields, and memory contents are compared after each instruction retires. Any divergence immediately flags a potential bug in the hardware implementation, pinpointing the exact instruction where the mismatch occurred. This approach is particularly valuable for a complex ISA like Power, where subtle behaviors involving carry/overflow flags, branch prediction side effects, or multi-cycle instructions can easily be misinterpreted from the specification. The golden model is written in Rust and is easier to validate against the ISA specification and can be updated quickly when clarifications arise, making it a stable reference point.

Feedback

I appreciate any feedback and constructive criticism about this project. Feel free to contact me using the links provided on the homepage.