/mips-cpu

💻 A 5-stage pipeline MIPS CPU implementation in Verilog.

Primary LanguageVerilogMIT LicenseMIT

MIPS-CPU

A MIPS CPU in Verilog.

Making a MIPS CPU is a non-trivial task. But with the help of mips-simulator, my previous project on describing circuit logic in functional programming language, this project can be done easily by directly translating Haskell into Verilog.

All CPU and CPU simulators I've made are listed below.

Technique Implementation
RISC-V v1 5-stage pipeline simulator C++
RISC-V v2 dynamic scheduling simulator
Tomasulo + Speculation
C++
MIPS 5-stage pipeline simulator Haskell
MIPS 5-stage pipeline CPU Verilog

Variable naming and wire naming are nearly identical in Haskell version and Verilog version. Here I compare some code snippets between Verilog and Haskell.

Circuit Logic in Haskell and Verilog

signals and circuit logic

pc'' = 
    if take_branch then branch_pc 
    else next_pc
assign ex_pc = take_branch ? 
    branch_pc : next_pc;

stage input

-- use stage reg data type

data ID_EX_Reg = ID_EX_Reg {
    id_alu_op :: Word32,
    id_alu_src1 :: Word32,
    id_alu_src2 :: Word32,
    id_opcode :: Word32,
    id_pc :: Word32,
    ...
    }

stageExecute :: ID_EX_Reg -> (EX_MEM_Reg, (Bool, Word32))
// feed signals directly

module Execute(
    input [`OP] alu_op,
    input [`WORD] alu_src1,
    input [`WORD] alu_src2,
    input [`OP] id_opcode,
    input [`WORD] id_pc,
    ...

cycle on clock

-- return data from this cycle

cpu_cycle :: Registers -> Registers

next_regs = Registers   new_rf
                        new_hi
                        new_lo
                        imem'
                        new_dmem
                        new_pc
                        next_if_id_reg
                        next_id_ex_reg
                        next_ex_mem_reg
                        next_mem_wb_reg
// events

always @ (negedge clk) begin
    if (!out_id_stall) begin
        stage_if_inst <= out_if_inst;
        stage_if_pc <= out_if_pc;
        stage_if_branch_taken <= 0;
        pc <= out_if_next_pc;
    end
end

stage with multiple outputs

-- use tuple

out_id_stall   = snd stage_id_out
stage_id_regs  = fst stage_id_out
// use signals directly

InstDecode instDecode (
    ... (stage regs)
    .stall (out_id_stall),
    ... (other modules)
);

decode helper

-- defined as functions

extMode :: Word32 -> Bool
extMode 0x0C = False
extMode 0x0D = False
extMode 0x0E = False
extMode 0x24 = False
extMode 0x25 = False
extMode _    = True
module ExtMode(
    input [5:0] opcode,
    output reg signExt);

    always @ (opcode) begin
        case (opcode)
            6'h0c: signExt = 0;
            6'h0d: signExt = 0;
            6'h0e: signExt = 0;
            6'h24: signExt = 0;
            6'h25: signExt = 0;
            default: signExt = 1;
        endcase
    end
endmodule

Relationship

Verilog Haskell
ALU aluRead in ALU
ALUOp mapALUOp + isArithmeticOp in ALU
BranchOp isBranchOp + branchRtVal = overrideRt in Branch
BranchOut branchOut in Branch
ExtMode extMode in ALU
Forward Forward
IsShift isShift in ALU
MemoryOp memoryMode + memoryLoad + memoryStore + isMemoryOp + memoryMode in Memory
SignExt signExt in ALU
ZeroExt zeroExt in ALU
Execute StageExecute
InstDecode InstDecode
InstFetch InstFetch
Memory StageMem
WriteBack embedded in CPU
CPU CPU
RegisterFile RegisterFile
DataMemory dmem in Registers
InstMemory imem in Registers
signals in CPU StageReg

All signals in stage registers and in stage modules are exactly the same, except that:

  • Stage with multiple outputs has multiple output signals in Verilog.
  • In Verilog, forward module logic is located in CPU.
  • In Verilog, memory is located, and operates in CPU. Memory stage sends signals out of the module.
  • In Verilog, write back is a standalone stage.

Project Report

Pipelined Processor (Chinese) Single-Cycle Processor (Chinese)