├── LICENSE ├── Makefile ├── README.md ├── mips_hex ├── 0-imem.mem ├── 1-test-add.mem ├── 2-basic-arithmetic.mem ├── 3-basic-compare.mem ├── 4-branch.mem ├── 5-simple-mem.mem ├── 6-mem.mem ├── 7-jump.mem ├── control-hazard.mem ├── data-hazard.mem └── load-use.mem ├── src ├── CPU.v ├── Cache.v ├── DataMemory.v ├── InstMemory.v ├── Module │ ├── ALU.v │ ├── ALUOp.v │ ├── BranchOp.v │ ├── BranchOut.v │ ├── ExtMode.v │ ├── Forward.v │ ├── IsShift.v │ ├── MemoryOp.v │ ├── SignExt.v │ ├── TakeBranch.v │ └── ZeroExt.v ├── RegisterFile.v └── Stage │ ├── Execute.v │ ├── InstDecode.v │ ├── InstFetch.v │ ├── Memory.v │ └── WriteBack.v └── tests ├── ALUOp_tb.v ├── ALU_tb.v ├── BranchOp_tb.v ├── CPU_tb.v ├── DataMemory_tb.v ├── ExtMode_tb.v ├── InstMemory_tb.v ├── IsShift_tb.v ├── MemoryOp_tb.v ├── RegisterFile_tb.v ├── SignExt_tb.v ├── TakeBranch_tb.v └── ZeroExt_tb.v /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Alex Chi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TESTBENCH = tests 2 | SRCS = src/CPU.v src/Module/SignExt.v src/Module/ZeroExt.v src/Module/ALUOp.v \ 3 | src/Module/ExtMode.v src/Module/IsShift.v src/Module/ALU.v \ 4 | src/DataMemory.v src/InstMemory.v src/RegisterFile.v \ 5 | src/Module/MemoryOp.v src/Module/BranchOp.v \ 6 | src/Module/BranchOut.v src/Module/Forward.v \ 7 | src/Stage/InstFetch.v src/Stage/InstDecode.v src/Stage/Execute.v \ 8 | src/Stage/Memory.v src/Stage/WriteBack.v src/Cache.v 9 | RESULT = result 10 | V_FLAG = -g2005-sv 11 | 12 | #------------------------------------------------------------------------------ 13 | # You should't be changing what is below 14 | #------------------------------------------------------------------------------ 15 | all: simulate 16 | 17 | lint: 18 | verilator --lint-only $(SRCS) 19 | 20 | simulate: 21 | iverilog -o $(TESTBENCH).vvp $(SRCS) $(TESTBENCH).v 22 | vvp $(TESTBENCH).vvp > $(TESTBENCH)_log.txt 23 | 24 | test_%: 25 | @echo "test: $*" 26 | iverilog -o $(TESTBENCH)/$*_tb.vvp $(SRCS) $(TESTBENCH)/$*_tb.v 27 | vvp $(TESTBENCH)/$*_tb.vvp > $(TESTBENCH)/$*_log.txt 28 | @grep "ALEX_TEST_SUCCESS" $(TESTBENCH)/$*_log.txt 29 | 30 | test: test_SignExt test_ZeroExt test_ALU test_ALUOp test_DataMemory test_InstMemory test_IsShift test_RegisterFile test_IsShift test_ExtMode 31 | @echo "Test Complete." 32 | 33 | gtkwave: 34 | gtkwave $(RESULT).vcd 35 | 36 | scansion: simulate 37 | open /Applications/Scansion.app $(RESULT).vcd 38 | 39 | clean: 40 | rm -rf $(TESTBENCH).vvp $(RESULT).vcd $(TESTBENCH)_log.txt $(TESTBENCH)/*_log.txt $(TESTBENCH)/*.vvp 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MIPS-CPU 2 | 3 | A MIPS CPU in Verilog. 4 | 5 | Making a MIPS CPU is a non-trivial task. But with the help of mips-simulator, 6 | my previous project on describing circuit logic in functional programming language, 7 | this project can be done easily by directly translating Haskell into Verilog. 8 | 9 | 10 | All CPU and CPU simulators I've made are listed below. 11 | 12 | | | Technique | Implementation | 13 | |---------------------------------------------------------------------|------------------------------------------------|----------------| 14 | | [RISC-V v1](https://github.com/skyzh/RISCV-Simulator/tree/pipeline) | 5-stage pipeline simulator | C++ | 15 | | [RISC-V v2](https://github.com/skyzh/RISCV-Simulator) | dynamic scheduling simulator
Tomasulo + Speculation | C++ | 16 | | [MIPS](https://github.com/skyzh/mips-simulator) | 5-stage pipeline simulator | Haskell | 17 | | [MIPS](https://github.com/skyzh/mips-cpu) | 5-stage pipeline CPU | Verilog | 18 | 19 | 20 | Variable naming and wire naming are nearly identical in Haskell version and Verilog version. 21 | Here I compare some code snippets between Verilog and Haskell. 22 | 23 | ## Circuit Logic in Haskell and Verilog 24 | 25 | **signals and circuit logic** 26 | 27 | ```haskell 28 | pc'' = 29 | if take_branch then branch_pc 30 | else next_pc 31 | ``` 32 | 33 | ```verilog 34 | assign ex_pc = take_branch ? 35 | branch_pc : next_pc; 36 | ``` 37 | 38 | **stage input** 39 | 40 | ```haskell 41 | -- use stage reg data type 42 | 43 | data ID_EX_Reg = ID_EX_Reg { 44 | id_alu_op :: Word32, 45 | id_alu_src1 :: Word32, 46 | id_alu_src2 :: Word32, 47 | id_opcode :: Word32, 48 | id_pc :: Word32, 49 | ... 50 | } 51 | 52 | stageExecute :: ID_EX_Reg -> (EX_MEM_Reg, (Bool, Word32)) 53 | ``` 54 | 55 | ```verilog 56 | // feed signals directly 57 | 58 | module Execute( 59 | input [`OP] alu_op, 60 | input [`WORD] alu_src1, 61 | input [`WORD] alu_src2, 62 | input [`OP] id_opcode, 63 | input [`WORD] id_pc, 64 | ... 65 | ``` 66 | 67 | **cycle on clock** 68 | 69 | ```haskell 70 | -- return data from this cycle 71 | 72 | cpu_cycle :: Registers -> Registers 73 | 74 | next_regs = Registers new_rf 75 | new_hi 76 | new_lo 77 | imem' 78 | new_dmem 79 | new_pc 80 | next_if_id_reg 81 | next_id_ex_reg 82 | next_ex_mem_reg 83 | next_mem_wb_reg 84 | ``` 85 | 86 | ```verilog 87 | // events 88 | 89 | always @ (negedge clk) begin 90 | if (!out_id_stall) begin 91 | stage_if_inst <= out_if_inst; 92 | stage_if_pc <= out_if_pc; 93 | stage_if_branch_taken <= 0; 94 | pc <= out_if_next_pc; 95 | end 96 | end 97 | ``` 98 | 99 | **stage with multiple outputs** 100 | 101 | ```haskell 102 | -- use tuple 103 | 104 | out_id_stall = snd stage_id_out 105 | stage_id_regs = fst stage_id_out 106 | ``` 107 | 108 | ```verilog 109 | // use signals directly 110 | 111 | InstDecode instDecode ( 112 | ... (stage regs) 113 | .stall (out_id_stall), 114 | ... (other modules) 115 | ); 116 | ``` 117 | 118 | **decode helper** 119 | 120 | ```haskell 121 | -- defined as functions 122 | 123 | extMode :: Word32 -> Bool 124 | extMode 0x0C = False 125 | extMode 0x0D = False 126 | extMode 0x0E = False 127 | extMode 0x24 = False 128 | extMode 0x25 = False 129 | extMode _ = True 130 | ``` 131 | 132 | ```verilog 133 | module ExtMode( 134 | input [5:0] opcode, 135 | output reg signExt); 136 | 137 | always @ (opcode) begin 138 | case (opcode) 139 | 6'h0c: signExt = 0; 140 | 6'h0d: signExt = 0; 141 | 6'h0e: signExt = 0; 142 | 6'h24: signExt = 0; 143 | 6'h25: signExt = 0; 144 | default: signExt = 1; 145 | endcase 146 | end 147 | endmodule 148 | ``` 149 | 150 | ## Relationship 151 | 152 | | Verilog | Haskell | 153 | |--------------|---------------------------------------------------------------------------| 154 | | ALU | aluRead in ALU | 155 | | ALUOp | mapALUOp + isArithmeticOp in ALU | 156 | | BranchOp | isBranchOp + branchRtVal = overrideRt in Branch | 157 | | BranchOut | branchOut in Branch | 158 | | ExtMode | extMode in ALU | 159 | | Forward | Forward | 160 | | IsShift | isShift in ALU | 161 | | MemoryOp | memoryMode + memoryLoad + memoryStore + isMemoryOp + memoryMode in Memory | 162 | | SignExt | signExt in ALU | 163 | | ZeroExt | zeroExt in ALU | 164 | | Execute | StageExecute | 165 | | InstDecode | InstDecode | 166 | | InstFetch | InstFetch | 167 | | Memory | StageMem | 168 | | WriteBack | embedded in CPU | 169 | | CPU | CPU | 170 | | RegisterFile | RegisterFile | 171 | | DataMemory | dmem in Registers | 172 | | InstMemory | imem in Registers | 173 | | signals in CPU | StageReg | 174 | 175 | All signals in stage registers and in stage modules are exactly the same, except that: 176 | 177 | * Stage with multiple outputs has multiple output signals in Verilog. 178 | * In Verilog, forward module logic is located in CPU. 179 | * In Verilog, memory is located, and operates in CPU. Memory stage sends signals out of the module. 180 | * In Verilog, write back is a standalone stage. 181 | 182 | ## Project Report 183 | 184 | [Pipelined Processor (Chinese)](https://github.com/skyzh/mips-cpu/files/4628149/pipelined-processor.pdf) 185 | [Single-Cycle Processor (Chinese)](https://github.com/skyzh/mips-cpu/files/4628151/single-cycle-processor.pdf) 186 | -------------------------------------------------------------------------------- /mips_hex/0-imem.mem: -------------------------------------------------------------------------------- 1 | deadbeef -------------------------------------------------------------------------------- /mips_hex/1-test-add.mem: -------------------------------------------------------------------------------- 1 | 24040064 2 | 240500c8 3 | 00853020 4 | -------------------------------------------------------------------------------- /mips_hex/2-basic-arithmetic.mem: -------------------------------------------------------------------------------- 1 | 24000064 2 | 2000fc18 3 | 3401ffff 4 | 3c01ffff 5 | 00012021 6 | 00012821 7 | 00013021 8 | 00013821 9 | 00842020 10 | 00a52821 11 | 20c600e9 12 | 24c600e9 13 | 24080064 14 | 3c0800e9 15 | 240900e9 16 | 3c09ffff 17 | 01095025 18 | 350bfffe 19 | 01096024 20 | 310dfffe 21 | 00087022 22 | 00087823 23 | 3c010000 24 | 3421ffff 25 | 00018822 26 | 3c010000 27 | 3421ffff 28 | 00019023 29 | 01099826 30 | 3914ffff 31 | 0109a827 32 | -------------------------------------------------------------------------------- /mips_hex/3-basic-compare.mem: -------------------------------------------------------------------------------- 1 | 3c01000f 2 | 34244240 3 | 3c01001e 4 | 34258480 5 | 24060014 6 | 3c01fffe 7 | 34277960 8 | 00044280 9 | 00c44804 10 | 00045283 11 | 00c45807 12 | 00046282 13 | 00c46806 14 | 00e4702a 15 | 00e4782b 16 | 28f0d8f0 17 | 2cf12710 18 | -------------------------------------------------------------------------------- /mips_hex/4-branch.mem: -------------------------------------------------------------------------------- 1 | 24020064 2 | 24030032 3 | 2405ffce 4 | 10420001 5 | 240800e9 6 | 14430001 7 | 240900e9 8 | 04010001 9 | 240a00e9 10 | 04410001 11 | 240a00e9 12 | 1c400001 13 | 240b00e9 14 | 0043082a 15 | 10200001 16 | 240c00e9 17 | 0063082a 18 | 10200001 19 | 240c00e9 20 | 04a00001 21 | 240e00e9 22 | 18000001 23 | 240f00e9 24 | 18a00001 25 | 240f00e9 26 | -------------------------------------------------------------------------------- /mips_hex/5-simple-mem.mem: -------------------------------------------------------------------------------- 1 | 24040010 2 | a0042000 3 | ac042010 4 | 80052000 5 | 8c062010 6 | -------------------------------------------------------------------------------- /mips_hex/6-mem.mem: -------------------------------------------------------------------------------- 1 | 24112000 2 | 24120000 3 | 24150200 4 | 02329820 5 | a2720005 6 | 22520001 7 | 02b2082a 8 | 1020fffb 9 | 24112000 10 | 24120000 11 | 24150200 12 | 24140000 13 | 24170000 14 | 02329820 15 | 82740005 16 | 22520001 17 | 0297b820 18 | 02b2082a 19 | 1020fffa 20 | -------------------------------------------------------------------------------- /mips_hex/7-jump.mem: -------------------------------------------------------------------------------- 1 | 0c000004 2 | 2405091d 3 | 08000007 4 | 241100e9 5 | 240600e9 6 | 03e00008 7 | 24075b25 8 | 24105b25 9 | -------------------------------------------------------------------------------- /mips_hex/control-hazard.mem: -------------------------------------------------------------------------------- 1 | 0c000001 2 | 0c000002 3 | 0c000003 4 | 0c000004 5 | 0c000005 6 | 0c000006 7 | 240403e8 8 | -------------------------------------------------------------------------------- /mips_hex/data-hazard.mem: -------------------------------------------------------------------------------- 1 | 24040064 2 | 240500c8 3 | 00853020 4 | 00a52820 5 | 00c63020 6 | 00a52820 7 | 00c63020 8 | 00a52820 9 | 00c63020 10 | 00a52820 11 | 00c63020 12 | 00a52820 13 | 00c63020 14 | 00a52820 15 | 00c63020 16 | 00a52820 17 | 00c63020 18 | -------------------------------------------------------------------------------- /mips_hex/load-use.mem: -------------------------------------------------------------------------------- 1 | 24040064 2 | 24062000 3 | a0c40000 4 | 80c50000 5 | 20a507d0 6 | 80c40000 7 | 00852020 8 | -------------------------------------------------------------------------------- /src/CPU.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | `define WORD 31:0 4 | `define REG 4:0 5 | `define OP 5:0 6 | 7 | module CPU( 8 | input wire clk, 9 | input reset); 10 | 11 | // PC Register 12 | reg [`WORD] pc; 13 | 14 | // Branch Prediction Result 15 | wire correct_branch_prediction; 16 | wire [`WORD] branch_jump_target; 17 | 18 | // --- STAGE --- 19 | // InstFetch 20 | 21 | // --- INPUT --- 22 | wire [`WORD] if_pc = !correct_branch_prediction ? branch_jump_target : pc; 23 | 24 | // --- STAGE REGS --- 25 | reg [`WORD] stage_if_inst; 26 | reg [`WORD] stage_if_pc; 27 | reg stage_if_branch_taken; 28 | 29 | // --- OUTPUT --- 30 | wire [`WORD] out_if_next_pc; 31 | wire [`WORD] out_if_inst; 32 | wire [`WORD] out_if_pc; 33 | 34 | wire [`WORD] if_addr; 35 | wire [`WORD] if_inst; 36 | wire if_inst_ready; 37 | 38 | wire [`WORD] imem_addr; 39 | wire [`WORD] imem_data; 40 | 41 | Cache cache( 42 | .clk (clk), 43 | .address (if_addr), 44 | .reset (reset), 45 | .data (if_inst), 46 | .ready (if_inst_ready), 47 | // MODULE: Inst Memory 48 | .inst_data (imem_data), 49 | .inst_addr (imem_addr)); 50 | 51 | InstMemory imem( 52 | .address (imem_addr), 53 | .data (imem_data) 54 | ); 55 | 56 | InstFetch instFetch( 57 | .if_pc (if_pc), 58 | .inst (out_if_inst), 59 | .pc (out_if_pc), 60 | .next_pc (out_if_next_pc), 61 | .inst_pc (if_addr), 62 | .inst_ready(if_inst_ready), 63 | .if_inst (if_inst) 64 | ); 65 | 66 | wire out_id_stall; 67 | wire [`WORD] if_next_pc = out_id_stall ? if_pc : out_if_next_pc; 68 | 69 | // --- CLOCK --- 70 | always @ (negedge clk) begin 71 | if (!out_id_stall) begin 72 | stage_if_inst <= out_if_inst; 73 | stage_if_pc <= out_if_pc; 74 | stage_if_branch_taken <= 0; // branch prediction: always not taken 75 | pc <= if_next_pc; 76 | end 77 | end 78 | 79 | // --- STAGE --- 80 | // InstDecode 81 | // --- STAGE REGS --- 82 | reg [`OP] stage_id_alu_op; 83 | reg [`WORD] stage_id_alu_src1; 84 | reg [`WORD] stage_id_alu_src2; 85 | reg [`OP] stage_id_opcode; 86 | reg [`WORD] stage_id_pc; 87 | reg stage_id_alu_branch_mask; 88 | reg [`WORD] stage_id_branch_pc; 89 | reg [`WORD] stage_id_next_pc; 90 | reg [`REG] stage_id_rf_dest; 91 | reg [`WORD] stage_id_mem_data; 92 | reg stage_id_branch_taken; 93 | reg stage_id_force_jump; 94 | 95 | // --- STAGE INTERMEDIATES --- 96 | wire [`REG] out_id_forward_op1; 97 | wire [`REG] out_id_forward_op2; 98 | wire forward_depends_1; 99 | wire forward_depends_2; 100 | wire forward_stalls_1; 101 | wire forward_stalls_2; 102 | wire [`WORD] forward_result_1; 103 | wire [`WORD] forward_result_2; 104 | wire [`REG] rf_src1; 105 | wire [`REG] rf_src2; 106 | wire [`WORD] rf_out1; 107 | wire [`WORD] rf_out2; 108 | wire [`OP] out_id_alu_op; 109 | wire [`WORD] out_id_alu_src1; 110 | wire [`WORD] out_id_alu_src2; 111 | wire [`OP] out_id_opcode; 112 | wire [`WORD] out_id_pc; 113 | wire out_id_alu_branch_mask; 114 | wire [`WORD] out_id_branch_pc; 115 | wire [`WORD] out_id_next_pc; 116 | wire [`REG] out_id_rf_dest; 117 | wire [`WORD] out_id_mem_data; 118 | wire out_id_branch_taken; 119 | wire out_id_force_jump; 120 | 121 | // --- Execute STAGE INTERMEDIATES --- 122 | wire [`WORD] out_ex_alu_out; 123 | wire [`OP] out_ex_opcode; 124 | wire [`WORD] out_ex_pc; 125 | wire [`REG] out_ex_rf_dest; 126 | wire [`WORD] out_ex_mem_data; 127 | 128 | // --- Memory STAGE REGS --- 129 | reg [`WORD] stage_mem_pc; 130 | reg [`WORD] stage_mem_out; 131 | reg [`WORD] stage_mem_alu_out; 132 | reg [`OP] stage_mem_opcode; 133 | reg [`REG] stage_mem_rf_dest; 134 | 135 | // --- Memory STAGE INTERMEDIATES --- 136 | wire [`WORD] out_mem_pc; 137 | wire [`WORD] out_mem_out; 138 | wire [`WORD] out_mem_alu_out; 139 | wire [`OP] out_mem_opcode; 140 | wire [`REG] out_mem_rf_dest; 141 | wire [`WORD] dmem_addr; 142 | wire [`WORD] dmem_in; 143 | wire dmem_write; 144 | wire dmem_read; 145 | wire [2:0] dmem_mode; 146 | wire [`WORD] dmem_out; 147 | 148 | // --- WriteBack STAGE INTERMEDIATES --- 149 | wire [`REG] rf_dest; 150 | wire [`WORD] rf_data; 151 | wire rf_write; 152 | 153 | // Forwarding 154 | Forward forward1( 155 | .ex_opcode (out_ex_opcode), 156 | .ex_dest (out_ex_rf_dest), 157 | .ex_val (out_ex_alu_out), 158 | .mem_opcode (out_mem_opcode), 159 | .mem_dest (out_mem_rf_dest), 160 | .mem_alu_val (out_mem_alu_out), 161 | .mem_val (out_mem_out), 162 | .wb_opcode (stage_mem_opcode), 163 | .wb_dest (stage_mem_rf_dest), 164 | .wb_val (rf_data), 165 | .src (out_id_forward_op1), 166 | .data (forward_result_1), 167 | .depends (forward_depends_1), 168 | .stall (forward_stalls_1) 169 | ); 170 | 171 | Forward forward2( 172 | .ex_opcode (out_ex_opcode), 173 | .ex_dest (out_ex_rf_dest), 174 | .ex_val (out_ex_alu_out), 175 | .mem_opcode (out_mem_opcode), 176 | .mem_dest (out_mem_rf_dest), 177 | .mem_alu_val (out_mem_alu_out), 178 | .mem_val (out_mem_out), 179 | .wb_opcode (stage_mem_opcode), 180 | .wb_dest (stage_mem_rf_dest), 181 | .wb_val (rf_data), 182 | .src (out_id_forward_op2), 183 | .data (forward_result_2), 184 | .depends (forward_depends_2), 185 | .stall (forward_stalls_2) 186 | ); 187 | 188 | RegisterFile rf( 189 | .clk (clk), 190 | .src1 (rf_src1), 191 | .src2 (rf_src2), 192 | .dest (rf_dest), 193 | .data (rf_data), 194 | .write (rf_write), 195 | .out1 (rf_out1), 196 | .out2 (rf_out2), 197 | .reset (reset) 198 | ); 199 | 200 | InstDecode instDecode( 201 | .if_pc (stage_if_pc), 202 | .inst (stage_if_inst), 203 | .if_branch_taken (stage_if_branch_taken), 204 | .alu_op (out_id_alu_op), 205 | .alu_src1 (out_id_alu_src1), 206 | .alu_src2 (out_id_alu_src2), 207 | .opcode (out_id_opcode), 208 | .id_pc (out_id_pc), 209 | .alu_branch_mask (out_id_alu_branch_mask), 210 | .branch_pc (out_id_branch_pc), 211 | .next_pc (out_id_next_pc), 212 | .rf_dest (out_id_rf_dest), 213 | .mem_data (out_id_mem_data), 214 | .id_branch_taken (out_id_branch_taken), 215 | .force_jump (out_id_force_jump), 216 | .stall (out_id_stall), 217 | // MODULE: Forward 218 | .forward_op1 (out_id_forward_op1), 219 | .forward_op2 (out_id_forward_op2), 220 | .forward_depends_1 (forward_depends_1), 221 | .forward_depends_2 (forward_depends_2), 222 | .forward_stalls_1 (forward_stalls_1), 223 | .forward_stalls_2 (forward_stalls_2), 224 | .forward_result_1 (forward_result_1), 225 | .forward_result_2 (forward_result_2), 226 | // MODULE: RegisterFile 227 | .rf_src1 (rf_src1), 228 | .rf_src2 (rf_src2), 229 | .rf_out1_prev (rf_out1), 230 | .rf_out2_prev (rf_out2) 231 | ); 232 | 233 | // --- CLOCK --- 234 | always @ (negedge clk) begin 235 | if (!correct_branch_prediction || out_id_stall) begin 236 | // Bubble 237 | stage_id_alu_op <= 0; 238 | stage_id_alu_src1 <= 0; 239 | stage_id_alu_src2 <= 0; 240 | stage_id_opcode <= 0; 241 | stage_id_pc <= 0; 242 | stage_id_alu_branch_mask <= 0; 243 | stage_id_branch_pc <= 0; 244 | stage_id_next_pc <= 0; 245 | stage_id_rf_dest <= 0; 246 | stage_id_mem_data <= 0; 247 | stage_id_branch_taken <= 0; 248 | stage_id_force_jump <= 0; 249 | end else begin 250 | stage_id_alu_op <= out_id_alu_op; 251 | stage_id_alu_src1 <= out_id_alu_src1; 252 | stage_id_alu_src2 <= out_id_alu_src2; 253 | stage_id_opcode <= out_id_opcode; 254 | stage_id_pc <= out_id_pc; 255 | stage_id_alu_branch_mask <= out_id_alu_branch_mask; 256 | stage_id_branch_pc <= out_id_branch_pc; 257 | stage_id_next_pc <= out_id_next_pc; 258 | stage_id_rf_dest <= out_id_rf_dest; 259 | stage_id_mem_data <= out_id_mem_data; 260 | stage_id_branch_taken <= out_id_branch_taken; 261 | stage_id_force_jump <= out_id_force_jump; 262 | end 263 | end 264 | 265 | // --- STAGE --- 266 | // Execute 267 | 268 | // --- STAGE REGS --- 269 | reg [`WORD] stage_ex_alu_out; 270 | reg [`OP] stage_ex_opcode; 271 | reg [`WORD] stage_ex_pc; 272 | reg [`REG] stage_ex_rf_dest; 273 | reg [`WORD] stage_ex_mem_data; 274 | 275 | Execute execute( 276 | .alu_op (stage_id_alu_op), 277 | .alu_src1 (stage_id_alu_src1), 278 | .alu_src2 (stage_id_alu_src2), 279 | .id_opcode (stage_id_opcode), 280 | .id_pc (stage_id_pc), 281 | .alu_branch_mask (stage_id_alu_branch_mask), 282 | .branch_pc (stage_id_branch_pc), 283 | .next_pc (stage_id_next_pc), 284 | .id_rf_dest (stage_id_rf_dest), 285 | .id_mem_data (stage_id_mem_data), 286 | .id_branch_taken (stage_id_branch_taken), 287 | .force_jump (stage_id_force_jump), 288 | .alu_out (out_ex_alu_out), 289 | .ex_opcode (out_ex_opcode), 290 | .ex_pc (out_ex_pc), 291 | .ex_rf_dest (out_ex_rf_dest), 292 | .ex_mem_data (out_ex_mem_data), 293 | .correct_branch_prediction (correct_branch_prediction), 294 | .branch_jump_target (branch_jump_target) 295 | ); 296 | 297 | // --- CLOCK --- 298 | always @ (negedge clk) begin 299 | stage_ex_alu_out <= out_ex_alu_out; 300 | stage_ex_opcode <= out_ex_opcode; 301 | stage_ex_pc <= out_ex_pc; 302 | stage_ex_rf_dest <= out_ex_rf_dest; 303 | stage_ex_mem_data <= out_ex_mem_data; 304 | end 305 | 306 | // --- STAGE --- 307 | // Memory 308 | 309 | Memory memory( 310 | .ex_alu_out (stage_ex_alu_out), 311 | .ex_opcode (stage_ex_opcode), 312 | .ex_pc (stage_ex_pc), 313 | .ex_rf_dest (stage_ex_rf_dest), 314 | .ex_mem_data (stage_ex_mem_data), 315 | .mem_pc (out_mem_pc), 316 | .mem_out (out_mem_out), 317 | .mem_alu_out (out_mem_alu_out), 318 | .mem_opcode (out_mem_opcode), 319 | .mem_rf_dest (out_mem_rf_dest), 320 | // MODULE: Data Memory 321 | .dmem_out (dmem_out), 322 | .dmem_addr (dmem_addr), 323 | .dmem_in (dmem_in), 324 | .dmem_write (dmem_write), 325 | .dmem_read (dmem_read), 326 | .dmem_mode (dmem_mode) 327 | ); 328 | 329 | // --- CLOCK --- 330 | always @ (negedge clk) begin 331 | stage_mem_pc <= out_mem_pc; 332 | stage_mem_out <= out_mem_out; 333 | stage_mem_alu_out <= out_mem_alu_out; 334 | stage_mem_opcode <= out_mem_opcode; 335 | stage_mem_rf_dest <= out_mem_rf_dest; 336 | end 337 | 338 | // Data Memory 339 | 340 | DataMemory dmem( 341 | .clk (clk), 342 | .address (dmem_addr), 343 | .writeData (dmem_in), 344 | .memWrite (dmem_write), 345 | .memRead (dmem_read), 346 | .mode (dmem_mode), 347 | .reset (reset), 348 | .readData (dmem_out) 349 | ); 350 | 351 | // STAGE: Write Back 352 | WriteBack writeback( 353 | .pc (stage_mem_pc), 354 | .mem_out (stage_mem_out), 355 | .mem_rf_dest (stage_mem_rf_dest), 356 | .alu_out (stage_mem_alu_out), 357 | .opcode (stage_mem_opcode), 358 | .rf_dest (rf_dest), 359 | .rf_write (rf_write), 360 | .rf_data (rf_data) 361 | ); 362 | 363 | always @ (negedge reset) begin 364 | pc <= 0; 365 | stage_if_inst <= 0; 366 | stage_if_pc <= 0; 367 | stage_if_branch_taken <= 0; 368 | stage_id_alu_op <= 0; 369 | stage_id_alu_src1 <= 0; 370 | stage_id_alu_src2 <= 0; 371 | stage_id_opcode <= 0; 372 | stage_id_pc <= 0; 373 | stage_id_alu_branch_mask <= 0; 374 | stage_id_branch_pc <= 0; 375 | stage_id_next_pc <= 0; 376 | stage_id_rf_dest <= 0; 377 | stage_id_mem_data <= 0; 378 | stage_id_branch_taken <= 0; 379 | stage_id_force_jump <= 0; 380 | stage_ex_alu_out <= 0; 381 | stage_ex_opcode <= 0; 382 | stage_ex_pc <= 0; 383 | stage_ex_rf_dest <= 0; 384 | stage_ex_mem_data <= 0; 385 | stage_mem_pc <= 0; 386 | stage_mem_out <= 0; 387 | stage_mem_alu_out <= 0; 388 | stage_mem_opcode <= 0; 389 | stage_mem_rf_dest <= 0; 390 | end 391 | endmodule 392 | -------------------------------------------------------------------------------- /src/Cache.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module Cache( 4 | input clk, 5 | input [`WORD] address, 6 | input reset, 7 | output[`WORD] data, 8 | output ready, 9 | // MODULE: Inst Memory 10 | input [`WORD] inst_data, 11 | output reg [`WORD] inst_addr); 12 | 13 | parameter cache_size = 256; 14 | 15 | reg valid [255:0]; 16 | reg [21:0] cache_tag [255:0]; 17 | reg [`WORD] cache_line [255:0]; 18 | 19 | integer i; 20 | 21 | always @ (negedge reset) begin 22 | for (i = 0; i < cache_size; i++) begin 23 | valid[i] = 0; 24 | end 25 | end 26 | 27 | wire [21:0] tag = address[31:10]; 28 | wire [7:0] index = address[9:2]; 29 | 30 | wire [21:0] inst_tag = inst_addr[31:10]; 31 | wire [7:0] inst_index = inst_addr[9:2]; 32 | 33 | assign ready = (tag == cache_tag[index] && valid[index]); 34 | assign data = ready ? cache_line[index] : 0; 35 | 36 | always @ (negedge clk) begin 37 | inst_addr <= address; 38 | valid[inst_index] <= 1; 39 | cache_tag[inst_index] <= inst_tag; 40 | cache_line[inst_index] <= inst_data; 41 | end 42 | endmodule 43 | -------------------------------------------------------------------------------- /src/DataMemory.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module DataMemory( 4 | input clk, 5 | input [31:0] address, 6 | input [31:0] writeData, 7 | input [2:0] mode, 8 | input memWrite, 9 | input memRead, 10 | input reset, 11 | output [31:0] readData); 12 | 13 | parameter mem_size = 65536; 14 | reg [7:0] memFile [0:mem_size]; 15 | 16 | always @ (negedge clk) begin 17 | if (memWrite) 18 | case (mode) 19 | 1: memFile[address] <= writeData[7:0]; 20 | 2: begin 21 | // assume little endian 22 | memFile[address] <= writeData[7:0]; 23 | memFile[address + 1] <= writeData[15:8]; 24 | memFile[address + 2] <= writeData[23:16]; 25 | memFile[address + 3] <= writeData[31:24]; 26 | end 27 | endcase 28 | end 29 | 30 | assign readData = (reset || !memRead) ? 0 : ( 31 | mode == 1 ? {{24{memFile[address][7]}}, memFile[address]} : ( 32 | mode == 2 ? {memFile[address + 3], memFile[address + 2], memFile[address + 1], memFile[address]} : 0 33 | )); 34 | endmodule 35 | -------------------------------------------------------------------------------- /src/InstMemory.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module InstMemory( 4 | input [31:0] address, 5 | output [31:0] data); 6 | 7 | parameter mem_size = 65536; 8 | // parameter mem_file = "2-basic-arithmetic.mem"; 9 | // parameter mem_file = "3-basic-compare.mem"; 10 | // parameter mem_file = "4-branch.mem"; 11 | // parameter mem_file = "5-simple-mem.mem"; 12 | parameter mem_file = "6-mem.mem"; 13 | // parameter mem_file = "load-use.mem"; 14 | // parameter mem_file = "control-hazard.mem"; 15 | // parameter mem_file = "data-hazard.mem.mem"; 16 | 17 | reg [31:0] memFile [0:mem_size]; 18 | 19 | integer i; 20 | initial begin 21 | for(i = 0; i < mem_size; i = i + 1) begin 22 | memFile[i] = 0; 23 | end 24 | $readmemh(mem_file, memFile); 25 | end 26 | 27 | assign data = memFile[address >>> 2]; 28 | endmodule 29 | -------------------------------------------------------------------------------- /src/Module/ALU.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | // ALU module 4 | module ALU( 5 | input [5:0] ALUopcode, 6 | input [31:0] op1, 7 | input [31:0] op2, 8 | output reg [31:0] out, 9 | output reg zero); 10 | 11 | always @ (ALUopcode or op1 or op2) begin 12 | case (ALUopcode) 13 | // add 14 | 6'h20: out = op1 + op2; 15 | // addu 16 | 6'h21: out = op1 + op2; 17 | // addi 18 | 6'h08: out = op1 + op2; 19 | // addiu 20 | 6'h09: out = op1 + op2; 21 | // sub 22 | 6'h22: out = op1 - op2; 23 | // subu 24 | 6'h23: out = op1 - op2; 25 | // and 26 | 6'h24: out = op1 & op2; 27 | // andi 28 | 6'h0C: out = op1 & op2; 29 | // nor 30 | 6'h27: out = ~(op1 | op2); 31 | // or 32 | 6'h25: out = op1 | op2; 33 | // ori 34 | 6'h0D: out = op1 | op2; 35 | // xor 36 | 6'h26: out = op1 ^ op2; 37 | // xori 38 | 6'h0E: out = op1 ^ op2; 39 | // lui 40 | 6'h0F: out = {op2[15:0], op1[15:0]}; 41 | // sll 42 | 6'h00: out = op2 <<< op1; 43 | // sllv 44 | 6'h04: out = op2 <<< op1; 45 | // sra 46 | 6'h03: out = $signed(op2) >>> op1; 47 | // srav 48 | 6'h07: out = $signed(op2) >>> op1; 49 | // srl 50 | 6'h02: out = op2 >>> op1; 51 | // srlv 52 | 6'h06: out = op2 >>> op1; 53 | // slt 54 | 6'h2A: if ($signed(op1) < $signed(op2)) out = 1; else out = 0; 55 | // slti 56 | 6'h0A: if ($signed(op1) < $signed(op2)) out = 1; else out = 0; 57 | // sltu 58 | 6'h2B: if (op1 < op2) out = 1; else out = 0; 59 | // sltiu 60 | 6'h0B: if (op1 < op2) out = 1; else out = 0; 61 | default: out = 0; 62 | endcase 63 | 64 | if (out == 0) zero = 1; else zero = 0; 65 | end 66 | endmodule 67 | -------------------------------------------------------------------------------- /src/Module/ALUOp.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | // This module maps opcoode to ALUop 4 | module ALUOp( 5 | input [5:0] opcode, 6 | output reg [5:0] ALUopcode, 7 | output reg arithmetic_op); 8 | 9 | always @ (opcode) begin 10 | case (opcode) 11 | // branch instructions 12 | // beq, bne = sub 13 | 6'h04: ALUopcode = 6'h22; 14 | 6'h05: ALUopcode = 6'h22; 15 | // bgez, bltz = slt 16 | 6'h01: ALUopcode = 6'h2A; 17 | // bgtz, blez = slt 18 | 6'h06: ALUopcode = 6'h2A; 19 | 6'h07: ALUopcode = 6'h2A; 20 | // lb, lw, sb, sw = add 21 | 6'h20: ALUopcode = 6'h20; 22 | 6'h23: ALUopcode = 6'h20; 23 | 6'h28: ALUopcode = 6'h20; 24 | 6'h2B: ALUopcode = 6'h20; 25 | // jal = add 26 | 6'h03: ALUopcode = 6'h20; 27 | // other instructions stay the same 28 | default: ALUopcode = opcode; 29 | endcase 30 | case (opcode) 31 | 6'h00: arithmetic_op = 1; 32 | 6'h08: arithmetic_op = 1; 33 | 6'h09: arithmetic_op = 1; 34 | 6'h0C: arithmetic_op = 1; 35 | 6'h0D: arithmetic_op = 1; 36 | 6'h0E: arithmetic_op = 1; 37 | 6'h0F: arithmetic_op = 1; 38 | 6'h0A: arithmetic_op = 1; 39 | 6'h0B: arithmetic_op = 1; 40 | default: arithmetic_op = 0; 41 | endcase 42 | end 43 | endmodule 44 | -------------------------------------------------------------------------------- /src/Module/BranchOp.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | // This module decodes branch op 4 | module BranchOp( 5 | input [5:0] opcode, 6 | output reg branch_op, 7 | output reg override_rt, 8 | output reg [31:0] rt_val); 9 | 10 | always @ (*) begin 11 | case (opcode) 12 | // beq 13 | 6'h04: branch_op = 1; 14 | // bne 15 | 6'h05: branch_op = 1; 16 | // bgez, bltz 17 | 6'h01: branch_op = 1; 18 | // bgtz 19 | 6'h07: branch_op = 1; 20 | // blez 21 | 6'h06: branch_op = 1; 22 | default: branch_op = 0; 23 | endcase 24 | case (opcode) 25 | // blez 26 | 6'h06: begin override_rt = 1; rt_val = 1; end 27 | // bgtz 28 | 6'h07: begin override_rt = 1; rt_val = 1; end 29 | // bgez, bltz 30 | 6'h01: begin override_rt = 1; rt_val = 0; end 31 | default: begin override_rt = 0; rt_val = 0; end 32 | endcase 33 | end 34 | endmodule 35 | -------------------------------------------------------------------------------- /src/Module/BranchOut.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | // This module generates alu for branch op 4 | module BranchOut( 5 | input [5:0] opcode, 6 | input [`REG] rt, 7 | output reg alu_branch_mask); 8 | 9 | always @ (*) begin 10 | case (opcode) 11 | // beq 12 | 6'h04: alu_branch_mask = 0; 13 | // bne 14 | 6'h05: alu_branch_mask = 1; 15 | // bgez, bltz 16 | 6'h01: alu_branch_mask = rt == 0; 17 | // bgtz 18 | 6'h07: alu_branch_mask = 0; 19 | // blez 20 | 6'h06: alu_branch_mask = 1; 21 | default: alu_branch_mask = 0; 22 | endcase 23 | end 24 | endmodule 25 | -------------------------------------------------------------------------------- /src/Module/ExtMode.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | // This module checks if an operation requires zero extenstion 4 | module ExtMode( 5 | input [5:0] opcode, 6 | output reg signExt); 7 | 8 | always @ (opcode) begin 9 | case (opcode) 10 | 6'h0c: signExt = 0; 11 | 6'h0d: signExt = 0; 12 | 6'h0e: signExt = 0; 13 | 6'h24: signExt = 0; 14 | 6'h25: signExt = 0; 15 | default: signExt = 1; 16 | endcase 17 | end 18 | endmodule 19 | -------------------------------------------------------------------------------- /src/Module/Forward.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | // This module forwards information 4 | module Forward( 5 | input [`OP] ex_opcode, 6 | input [`REG] ex_dest, 7 | input [`WORD] ex_val, 8 | input [`OP] mem_opcode, 9 | input [`REG] mem_dest, 10 | input [`WORD] mem_alu_val, 11 | input [`WORD] mem_val, 12 | input [`OP] wb_opcode, 13 | input [`REG] wb_dest, 14 | input [`WORD] wb_val, 15 | input [`REG] src, 16 | output reg [`WORD] data, 17 | output reg depends, 18 | output reg stall 19 | ); 20 | wire ex_is_arithmetic_op; 21 | wire ex_is_link_op = ex_opcode == 3; 22 | wire ex_is_memory_load; 23 | wire mem_is_arithmetic_op; 24 | wire mem_is_link_op = mem_opcode == 3; 25 | wire mem_is_memory_load; 26 | wire wb_is_arithmetic_op; 27 | wire wb_is_link_op = wb_opcode == 3; 28 | wire wb_is_memory_load; 29 | 30 | /* verilator lint_off PINMISSING */ 31 | ALUOp ex_aluop(.opcode (ex_opcode), .arithmetic_op (ex_is_arithmetic_op)); 32 | ALUOp mem_aluop(.opcode (mem_opcode), .arithmetic_op (mem_is_arithmetic_op)); 33 | ALUOp wb_aluop(.opcode (wb_opcode), .arithmetic_op (wb_is_arithmetic_op)); 34 | 35 | MemoryOp ex_memop(.opcode (ex_opcode), .load (ex_is_memory_load)); 36 | MemoryOp mem_memop(.opcode (mem_opcode), .load (mem_is_memory_load)); 37 | MemoryOp wb_memop(.opcode (wb_opcode), .load (wb_is_memory_load)); 38 | /* verilator lint_on PINMISSING */ 39 | 40 | always @(*) begin 41 | data = 0; 42 | depends = 0; 43 | stall = 0; 44 | if (src == 0) begin 45 | data = 0; 46 | depends = 0; 47 | stall = 0; 48 | end else if (ex_dest == src && (ex_is_arithmetic_op || ex_is_link_op)) begin 49 | data = ex_val; 50 | stall = 0; 51 | depends = 1; 52 | end else if (ex_dest == src && ex_is_memory_load) begin 53 | data = 0; 54 | stall = 1; 55 | depends = 1; 56 | end else if (mem_dest == src && (mem_is_arithmetic_op || mem_is_link_op)) begin 57 | data = mem_alu_val; 58 | stall = 0; 59 | depends = 1; 60 | end else if (mem_dest == src && mem_is_memory_load) begin 61 | data = mem_val; 62 | stall = 0; 63 | depends = 1; 64 | end else if (wb_dest == src && (wb_is_arithmetic_op || wb_is_memory_load || wb_is_link_op)) begin 65 | data = wb_val; 66 | stall = 0; 67 | depends = 1; 68 | end 69 | end 70 | endmodule 71 | -------------------------------------------------------------------------------- /src/Module/IsShift.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | // This module checks if an operation requires shamt 4 | module IsShift( 5 | input [5:0] funct, 6 | output reg shift); 7 | 8 | always @ (funct) begin 9 | case (funct) 10 | 6'h02: shift = 1; 11 | 6'h03: shift = 1; 12 | 6'h00: shift = 1; 13 | default: shift = 0; 14 | endcase 15 | end 16 | endmodule 17 | -------------------------------------------------------------------------------- /src/Module/MemoryOp.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | // This module decodes memory op 4 | module MemoryOp( 5 | input [5:0] opcode, 6 | output reg store, 7 | output reg load, 8 | output reg memory_op, 9 | output reg [2:0] memory_mode); 10 | 11 | always @ (*) begin 12 | case (opcode) 13 | 6'h20: load = 1; 14 | 6'h23: load = 1; 15 | default: load = 0; 16 | endcase 17 | case (opcode) 18 | 6'h28: store = 1; 19 | 6'h2b: store = 1; 20 | default: store = 0; 21 | endcase 22 | case (opcode) 23 | // lb, sb 24 | 6'h20: memory_mode = 1; 25 | 6'h28: memory_mode = 1; 26 | // lw, sw 27 | 6'h23: memory_mode = 2; 28 | 6'h2B: memory_mode = 2; 29 | default: memory_mode = 0; 30 | endcase 31 | memory_op = load | store; 32 | end 33 | endmodule 34 | -------------------------------------------------------------------------------- /src/Module/SignExt.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module SignExt( 4 | input [15:0] unextended, 5 | output reg [31:0] extended); 6 | 7 | always @ (unextended) begin 8 | extended = {{16{unextended[15]}}, unextended}; 9 | end 10 | endmodule 11 | -------------------------------------------------------------------------------- /src/Module/TakeBranch.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | // This module decides whether to take branch 4 | module TakeBranch( 5 | input [5:0] opcode, 6 | input [4:0] rt, 7 | input alu_zero, 8 | output reg take_branch); 9 | 10 | always @ (*) begin 11 | casez ({opcode, rt[3:0]}) 12 | 10'h4?: take_branch = alu_zero; 13 | 10'h5?: take_branch = !alu_zero; 14 | 10'h11: take_branch = alu_zero; 15 | 10'h10: take_branch = !alu_zero; 16 | 10'h70: take_branch = alu_zero; 17 | 10'h60: take_branch = !alu_zero; 18 | default: take_branch = 0; 19 | endcase 20 | end 21 | endmodule 22 | -------------------------------------------------------------------------------- /src/Module/ZeroExt.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module ZeroExt( 4 | input [15:0] unextended, 5 | output reg [31:0] extended); 6 | 7 | always @ (unextended) begin 8 | extended = {16'b0, unextended}; 9 | end 10 | endmodule 11 | -------------------------------------------------------------------------------- /src/RegisterFile.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module RegisterFile( 4 | input clk, 5 | input [4:0] src1, 6 | input [4:0] src2, 7 | input [4:0] dest, 8 | input [31:0] data, 9 | input write, 10 | input reset, 11 | output wire [31:0] out1, 12 | output wire [31:0] out2); 13 | 14 | reg [31:0] regs [31:0]; 15 | 16 | integer i; 17 | 18 | always @ (negedge reset) begin 19 | for (i = 0; i < 32; i = i + 1) begin 20 | regs[i] = 0; 21 | end 22 | end 23 | 24 | always @ (negedge clk) begin 25 | if (write) begin 26 | regs[dest] <= data; 27 | end 28 | end 29 | 30 | assign out1 = (src1 == 0 || reset) ? 0 : regs[src1]; 31 | assign out2 = (src2 == 0 || reset) ? 0 : regs[src2]; 32 | endmodule 33 | -------------------------------------------------------------------------------- /src/Stage/Execute.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module Execute( 4 | input [`OP] alu_op, 5 | input [`WORD] alu_src1, 6 | input [`WORD] alu_src2, 7 | input [`OP] id_opcode, 8 | input [`WORD] id_pc, 9 | input alu_branch_mask, 10 | input [`WORD] branch_pc, 11 | input [`WORD] next_pc, 12 | input [`REG] id_rf_dest, 13 | input [`WORD] id_mem_data, 14 | input id_branch_taken, 15 | input force_jump, 16 | output [`WORD] alu_out, 17 | output [`OP] ex_opcode, 18 | output [`WORD] ex_pc, 19 | output [`REG] ex_rf_dest, 20 | output [`WORD] ex_mem_data, 21 | output correct_branch_prediction, 22 | output [`WORD] branch_jump_target 23 | ); 24 | assign ex_mem_data = id_mem_data; 25 | assign ex_rf_dest = id_rf_dest; 26 | assign ex_opcode = id_opcode; 27 | 28 | wire alu_zero; 29 | 30 | ALU alu ( 31 | .ALUopcode (alu_op), 32 | .op1 (alu_src1), 33 | .op2 (alu_src2), 34 | .out (alu_out), 35 | .zero (alu_zero)); 36 | 37 | // MODULE: Branch 38 | wire is_branch; 39 | /* verilator lint_off PINMISSING */ 40 | BranchOp branchOp( 41 | .opcode (id_opcode), 42 | .branch_op (is_branch) 43 | ); 44 | /* verilator lint_on PINMISSING */ 45 | 46 | wire take_branch = is_branch && (alu_zero ^ alu_branch_mask); 47 | assign ex_pc = take_branch ? branch_pc : next_pc; 48 | 49 | assign correct_branch_prediction = 50 | !((take_branch != id_branch_taken) || force_jump); 51 | 52 | assign branch_jump_target = (take_branch != id_branch_taken) ? ex_pc : 53 | (force_jump ? next_pc : 0); 54 | 55 | endmodule -------------------------------------------------------------------------------- /src/Stage/InstDecode.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module InstDecode( 4 | input [`WORD] inst, 5 | input [`WORD] if_pc, 6 | input if_branch_taken, 7 | output [`OP] alu_op, 8 | output [`WORD] alu_src1, 9 | output [`WORD] alu_src2, 10 | output [`OP] opcode, 11 | output [`WORD] id_pc, 12 | output alu_branch_mask, 13 | output [`WORD] branch_pc, 14 | output [`WORD] next_pc, 15 | output [`REG] rf_dest, 16 | output [`WORD] mem_data, 17 | output id_branch_taken, 18 | output force_jump, 19 | output stall, 20 | // MODULE: Forward 21 | input forward_depends_1, 22 | input forward_depends_2, 23 | input forward_stalls_1, 24 | input forward_stalls_2, 25 | input [`WORD] forward_result_1, 26 | input [`WORD] forward_result_2, 27 | output wire [`REG] forward_op1, 28 | output wire [`REG] forward_op2, 29 | // MODULE: RegisterFile 30 | output wire [`REG] rf_src1, 31 | output wire [`REG] rf_src2, 32 | input wire [`WORD] rf_out1_prev, 33 | input wire [`WORD] rf_out2_prev 34 | ); 35 | wire [`WORD] pc = if_pc; 36 | assign opcode = inst[31:26]; 37 | wire [`REG] rs = inst[25:21]; 38 | wire [`REG] rt = inst[20:16]; 39 | wire [`REG] rd = inst[15:11]; 40 | wire [`REG] shamt = inst[10:6]; 41 | wire [`OP] funct = inst[`OP]; 42 | wire [15:0] imm = inst[15:0]; 43 | wire [`WORD] imm_sign_ext; 44 | wire [`WORD] imm_zero_ext; 45 | wire [`WORD] shamt_zero_ext = {{27'b0}, shamt}; 46 | SignExt signExt(.unextended (imm), .extended (imm_sign_ext)); 47 | ZeroExt zeroExt(.unextended (imm), .extended (imm_zero_ext)); 48 | wire is_shift; 49 | IsShift isShift(.funct (funct), .shift (is_shift)); 50 | wire is_type_R = (opcode == 0); 51 | wire use_shamt = is_shift && is_type_R; 52 | wire [`WORD] jump_target = {4'b00, inst[25:0], 2'b00} | (pc & 32'hf0000000); 53 | wire is_branch; 54 | wire is_memory; 55 | 56 | // MODULE: Register File 57 | assign rf_src1 = rs; 58 | assign rf_src2 = is_type_R || is_branch || is_memory_store ? rt : 0; 59 | assign rf_dest = is_type_R ? rd : ( 60 | opcode == 3 ? 31 : rt); 61 | wire [`WORD] rf_out1 = forward_depends_1 ? forward_result_1 : rf_out1_prev; 62 | wire [`WORD] rf_out2 = override_rt ? branch_alu_rt_val : 63 | (forward_depends_2 ? forward_result_2 : rf_out2_prev); 64 | 65 | // MODULE: Branch 66 | wire [`WORD] imm_offset = imm_sign_ext <<< 2; 67 | assign branch_pc = pc + 4 + imm_offset; 68 | assign next_pc = (opcode == 2 || opcode == 3) ? jump_target : 69 | (opcode == 0 && funct == 8 ? rf_out1 : pc + 4); 70 | wire override_rt; 71 | wire [`WORD] branch_alu_rt_val; 72 | BranchOp branchOp( 73 | .opcode (opcode), 74 | .branch_op (is_branch), 75 | .override_rt (override_rt), 76 | .rt_val (branch_alu_rt_val) 77 | ); 78 | BranchOut branchOut( 79 | .opcode (opcode), 80 | .rt (rt), 81 | .alu_branch_mask (alu_branch_mask) 82 | ); 83 | assign force_jump = opcode == 2 || opcode == 3 || (opcode == 0 && funct == 8); 84 | 85 | // MODULE: Forward 86 | assign forward_op1 = rf_src1; 87 | assign forward_op2 = rf_src2; 88 | wire alu_use_rf_out_1; 89 | wire alu_use_rf_out_2; 90 | assign stall = (alu_use_rf_out_1 && forward_stalls_1) || 91 | (alu_use_rf_out_2 && forward_stalls_2) || 92 | (is_memory_store && forward_stalls_2); 93 | 94 | 95 | // MODULE: Memory 96 | wire [`OP] mapped_op; 97 | /* verilator lint_off PINMISSING */ 98 | ALUOp aluOp( 99 | .opcode (opcode), 100 | .ALUopcode (mapped_op)); 101 | /* verilator lint_on PINMISSING */ 102 | wire is_memory_load; 103 | wire is_memory_store; 104 | wire [2:0] memory_mode; 105 | MemoryOp memoryOp( 106 | .opcode (opcode), 107 | .store (is_memory_store), 108 | .load (is_memory_load), 109 | .memory_op (is_memory), 110 | .memory_mode (memory_mode)); 111 | assign mem_data = forward_depends_2 ? forward_result_2 : rf_out2; 112 | 113 | // MODULE: ALU 114 | wire ext_mode; 115 | ExtMode extMode ( 116 | .opcode (opcode), 117 | .signExt (ext_mode)); 118 | assign alu_op = is_type_R ? funct : mapped_op; 119 | wire [`WORD] alu_imm = ext_mode ? imm_sign_ext : imm_zero_ext; 120 | assign alu_use_rf_out_1 = !use_shamt && opcode != 3; 121 | assign alu_use_rf_out_2 = is_type_R || is_branch; 122 | assign alu_src1 = use_shamt ? shamt_zero_ext : 123 | (opcode == 3 ? pc : rf_out1); 124 | assign alu_src2 = alu_use_rf_out_2 ? rf_out2 : 125 | (opcode == 3 ? 4 : alu_imm); 126 | 127 | // Other Modules 128 | assign id_pc = pc; 129 | assign id_branch_taken = if_branch_taken; 130 | endmodule 131 | -------------------------------------------------------------------------------- /src/Stage/InstFetch.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module InstFetch( 4 | input [`WORD] if_pc, 5 | output [`WORD] inst, 6 | output [`WORD] pc, 7 | output [`WORD] next_pc, 8 | output [`WORD] inst_pc, 9 | input inst_ready, 10 | input [`WORD] if_inst 11 | ); 12 | wire [`WORD] imem_addr = if_pc; 13 | assign inst_pc = if_pc; 14 | assign inst = inst_ready ? if_inst : 0; 15 | assign pc = if_pc; 16 | assign next_pc = inst_ready ? pc + 4 : pc; 17 | endmodule 18 | -------------------------------------------------------------------------------- /src/Stage/Memory.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module Memory( 4 | input [`WORD] ex_alu_out, 5 | input [`OP] ex_opcode, 6 | input [`WORD] ex_pc, 7 | input [`REG] ex_rf_dest, 8 | input [`WORD] ex_mem_data, 9 | output [`WORD] mem_pc, 10 | output [`WORD] mem_out, 11 | output [`WORD] mem_alu_out, 12 | output [`OP] mem_opcode, 13 | output [`REG] mem_rf_dest, 14 | // MODULE: Data Memory 15 | input [`WORD] dmem_out, 16 | output [`WORD] dmem_addr, 17 | output [`WORD] dmem_in, 18 | output dmem_write, 19 | output dmem_read, 20 | output [2:0] dmem_mode 21 | ); 22 | assign mem_pc = ex_pc; 23 | assign mem_out = dmem_out; 24 | assign mem_alu_out = ex_alu_out; 25 | assign mem_opcode = ex_opcode; 26 | assign mem_rf_dest = ex_rf_dest; 27 | 28 | /* verilator lint_off PINMISSING */ 29 | MemoryOp memoryOp( 30 | .opcode (ex_opcode), 31 | .store (dmem_write), 32 | .load (dmem_read), 33 | .memory_mode (dmem_mode)); 34 | /* verilator lint_on PINMISSING */ 35 | assign dmem_addr = ex_alu_out; 36 | assign dmem_in = ex_mem_data; 37 | 38 | endmodule 39 | -------------------------------------------------------------------------------- /src/Stage/WriteBack.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module WriteBack( 4 | input [`WORD] pc, 5 | input [`WORD] mem_out, 6 | input [`WORD] alu_out, 7 | input [`REG] mem_rf_dest, 8 | input [`OP] opcode, 9 | output [`REG] rf_dest, 10 | output [`WORD] rf_data, 11 | output rf_write 12 | ); 13 | wire is_branch; 14 | /* verilator lint_off PINMISSING */ 15 | BranchOp branchOp( 16 | .opcode (opcode), 17 | .branch_op (is_branch) 18 | ); 19 | /* verilator lint_on PINMISSING */ 20 | 21 | wire is_mem_store; 22 | wire is_mem_load; 23 | 24 | /* verilator lint_off PINMISSING */ 25 | MemoryOp memoryOp( 26 | .opcode (opcode), 27 | .store (is_mem_store), 28 | .load (is_mem_load)); 29 | /* verilator lint_on PINMISSING */ 30 | 31 | assign rf_data = is_mem_load ? mem_out : alu_out; 32 | assign rf_write = !is_branch && !is_mem_store && opcode != 2; 33 | assign rf_dest = mem_rf_dest; 34 | endmodule 35 | -------------------------------------------------------------------------------- /tests/ALUOp_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module ALUOp_tb; 4 | reg [5:0] opcode; 5 | wire [5:0] aluOpcode; 6 | wire isArithmetic; 7 | ALUOp aluOp(opcode, aluOpcode, isArithmetic); 8 | 9 | initial begin 10 | $dumpfile("result.vcd"); 11 | $dumpvars; 12 | for (opcode = 0; opcode < 6'h3f; opcode = opcode + 1) begin 13 | #1; 14 | end 15 | $display("ALEX_TEST_SUCCESS"); 16 | $finish; 17 | end 18 | endmodule 19 | -------------------------------------------------------------------------------- /tests/ALU_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module ALU_tb; 4 | reg [5:0] opcode; 5 | reg [31:0] op1; 6 | reg [31:0] op2; 7 | wire [31:0] out; 8 | wire zero; 9 | ALU alu(opcode, op1, op2, out, zero); 10 | 11 | initial begin 12 | $dumpfile("result.vcd"); 13 | $dumpvars; 14 | opcode = 6'h2a; 15 | op1 = 20; 16 | op2 = -20; 17 | #1; 18 | $display("ALEX_TEST_SUCCESS"); 19 | $finish; 20 | end 21 | endmodule 22 | -------------------------------------------------------------------------------- /tests/BranchOp_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module BranchOp_tb; 4 | reg [5:0] opcode; 5 | wire [5:0] is_branch; 6 | wire override_rt; 7 | wire [31:0] rt_val; 8 | BranchOp branchOp(opcode, is_branch, override_rt, rt_val); 9 | 10 | initial begin 11 | $dumpfile("result.vcd"); 12 | $dumpvars; 13 | for (opcode = 0; opcode < 6'h3f; opcode = opcode + 1) begin 14 | #1; 15 | end 16 | $display("ALEX_TEST_SUCCESS"); 17 | $finish; 18 | end 19 | endmodule 20 | -------------------------------------------------------------------------------- /tests/CPU_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | 3 | module CPU_tb; 4 | reg reset; 5 | reg clk; 6 | 7 | parameter PERIOD = 10; 8 | always #(PERIOD) clk = !clk; 9 | 10 | CPU cpu (clk, reset); 11 | 12 | integer i; 13 | 14 | initial begin 15 | $dumpfile("result.vcd"); 16 | $dumpvars; 17 | reset = 1; 18 | clk = 0; 19 | #30; 20 | reset = 0; 21 | #200000; 22 | reset = 1; 23 | for (i = 0; i < 32; i = i + 1) begin 24 | $display("x%-2d %x %d", i, cpu.rf.regs[i], cpu.rf.regs[i]); 25 | end 26 | $display("ALEX_TEST_SUCCESS"); 27 | $finish; 28 | end 29 | endmodule 30 | -------------------------------------------------------------------------------- /tests/DataMemory_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module DataMemory_tb; 4 | reg clk; 5 | reg [31:0] address; 6 | reg [31:0] writeData; 7 | reg memWrite; 8 | reg memRead; 9 | wire [31:0] readData; 10 | 11 | parameter PERIOD = 10; 12 | always #(PERIOD*2) clk = !clk; 13 | 14 | DataMemory dataMemory(clk, address, writeData, memWrite, memRead, 1'b0, readData); 15 | 16 | initial begin 17 | $dumpfile("result.vcd"); 18 | $dumpvars; 19 | clk = 1; 20 | #20; 21 | memWrite = 1; 22 | address = 10; 23 | writeData = 100; 24 | #20; 25 | address = 20; 26 | writeData = 200; 27 | #20; 28 | memWrite = 0; 29 | memRead = 1; 30 | address = 10; 31 | #1; 32 | if (readData != 100) begin 33 | $display("ALEX_TEST_FAILED %m %d", readData); 34 | $finish; 35 | end 36 | #20; 37 | address = 20; 38 | #1; 39 | if (readData != 200) begin 40 | $display("ALEX_TEST_FAILED %m %d", readData); 41 | $finish; 42 | end 43 | #20; 44 | $display("ALEX_TEST_SUCCESS"); 45 | $finish; 46 | end 47 | endmodule 48 | -------------------------------------------------------------------------------- /tests/ExtMode_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module ExtMode_tb; 4 | reg [5:0] opcode; 5 | wire signExt; 6 | ExtMode extMode(opcode, signExt); 7 | 8 | initial begin 9 | $dumpfile("result.vcd"); 10 | $dumpvars; 11 | for (opcode = 0; opcode < 6'h3f; opcode = opcode + 1) begin 12 | #1; 13 | end 14 | $display("ALEX_TEST_SUCCESS"); 15 | $finish; 16 | end 17 | endmodule 18 | -------------------------------------------------------------------------------- /tests/InstMemory_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module InstMemory_tb; 4 | reg clk; 5 | reg [31:0] address; 6 | wire [31:0] readData; 7 | 8 | parameter PERIOD = 10; 9 | always #(PERIOD*2) clk = !clk; 10 | 11 | InstMemory instMemory(clk, address, readData); 12 | 13 | initial begin 14 | $dumpfile("result.vcd"); 15 | $dumpvars; 16 | clk = 1; 17 | #20; 18 | address = 0; 19 | #20; 20 | address = 1; 21 | $display("ALEX_TEST_SUCCESS"); 22 | $finish; 23 | end 24 | endmodule 25 | -------------------------------------------------------------------------------- /tests/IsShift_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module IsShift_tb; 4 | reg [5:0] funct; 5 | wire [5:0] shift; 6 | IsShift isShift(funct, shift); 7 | 8 | initial begin 9 | $dumpfile("result.vcd"); 10 | $dumpvars; 11 | for (funct = 0; funct < 6'h3f; funct = funct + 1) begin 12 | #1; 13 | end 14 | $display("ALEX_TEST_SUCCESS"); 15 | $finish; 16 | end 17 | endmodule 18 | -------------------------------------------------------------------------------- /tests/MemoryOp_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module MemoryOp_tb; 4 | reg [5:0] opcode; 5 | wire store; 6 | wire load; 7 | wire memory_op; 8 | wire [2:0] memory_mode; 9 | MemoryOp memoryOp(opcode, store, load, memory_op, memory_mode); 10 | 11 | initial begin 12 | $dumpfile("result.vcd"); 13 | $dumpvars; 14 | for (opcode = 0; opcode < 6'h3f; opcode = opcode + 1) begin 15 | #1; 16 | end 17 | $display("ALEX_TEST_SUCCESS"); 18 | $finish; 19 | end 20 | endmodule 21 | -------------------------------------------------------------------------------- /tests/RegisterFile_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module Registers_tb; 4 | reg clk; 5 | reg [4:0] readReg1; 6 | reg [4:0] readReg2; 7 | reg [4:0] writeReg; 8 | reg [31:0] writeData; 9 | reg regWrite; 10 | wire [31:0] readData1; 11 | wire [31:0] readData2; 12 | 13 | parameter PERIOD = 10; 14 | always #(PERIOD*2) clk = !clk; 15 | 16 | RegisterFile registerFile(clk, readReg1, readReg2, writeReg, writeData, regWrite, 1'b0, readData1, readData2); 17 | 18 | initial begin 19 | $dumpfile("result.vcd"); 20 | $dumpvars; 21 | clk = 1; 22 | #100; 23 | regWrite = 1; 24 | writeReg = 10; 25 | writeData = -1; 26 | #110; 27 | writeReg = 20; 28 | writeData = -2; 29 | #120; 30 | writeReg = 30; 31 | writeData = -3; 32 | #130; 33 | readReg1 = 20; 34 | readReg2 = 30; 35 | if (readData1 != -2 || readData2 != -3) begin 36 | $display("ALEX_TEST_FAILED %m"); 37 | $finish; 38 | end 39 | #500; 40 | $display("ALEX_TEST_SUCCESS"); 41 | $finish; 42 | end 43 | endmodule -------------------------------------------------------------------------------- /tests/SignExt_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module SignExt_tb; 4 | reg signed [15:0] unextended; 5 | wire signed [31:0] extended; 6 | SignExt signExt(unextended, extended); 7 | 8 | initial begin 9 | $dumpfile("result.vcd"); 10 | $dumpvars; 11 | for (unextended = -32768; unextended < 32767; unextended = unextended + 1) begin 12 | #1; 13 | if (unextended != extended) begin 14 | $display("ALEX_TEST_FAILED %m"); 15 | $finish; 16 | end 17 | end 18 | $display("ALEX_TEST_SUCCESS"); 19 | $finish; 20 | end 21 | endmodule 22 | -------------------------------------------------------------------------------- /tests/TakeBranch_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module TakeBranch_tb; 4 | reg [5:0] opcode; 5 | reg [4:0] rt; 6 | reg alu_zero; 7 | wire take_branch; 8 | TakeBranch takeBranch(opcode, rt, alu_zero, take_branch); 9 | 10 | initial begin 11 | $dumpfile("result.vcd"); 12 | $dumpvars; 13 | for (opcode = 0; opcode < 6'h3f; opcode = opcode + 1) begin 14 | #1; 15 | rt = 0; 16 | alu_zero = 0; 17 | #1; 18 | rt = 1; 19 | alu_zero = 0; 20 | #1; 21 | rt = 0; 22 | alu_zero = 1; 23 | #1; 24 | rt = 1; 25 | alu_zero = 1; 26 | end 27 | $display("ALEX_TEST_SUCCESS"); 28 | $finish; 29 | end 30 | endmodule 31 | -------------------------------------------------------------------------------- /tests/ZeroExt_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module ZeroExt_tb; 4 | reg [15:0] unextended; 5 | wire [31:0] extended; 6 | ZeroExt zeroExt(unextended, extended); 7 | 8 | initial begin 9 | $dumpfile("result.vcd"); 10 | $dumpvars; 11 | for (unextended = 0; unextended < 65535; unextended = unextended + 1) begin 12 | #1; 13 | if (unextended != extended) begin 14 | $display("ALEX_TEST_FAILED %m"); 15 | $finish; 16 | end 17 | end 18 | $display("ALEX_TEST_SUCCESS"); 19 | $finish; 20 | end 21 | endmodule 22 | --------------------------------------------------------------------------------