A Verilog implementation of a 32-bit MIPS single-cycle CPU supporting exactly 14 instructions strictly according to the single-cycle-datapath:
add
sub
and
or
lw
sw
slt
beq
bne
j
jal
srl
sltiu
lhu
MIPS_SingleCycleProcessor/
├── src/ # All Verilog modules for the CPU
│ ├── pc.v # Program Counter
│ ├── adder.v # PC+4 adder
│ ├── instr_mem.v # Instruction memory + decoder
│ ├── control_unit.v # Control‐signal generator
│ ├── reg_file.v # 32×32 register file
│ ├── sign_ext.v # Sign/zero‐extender
│ ├── mux_reg_dst.v # RegDest MUX
│ ├── shift_left_2_branch.v # Branch‐offset shifter
│ ├── mux_alu_src.v # ALU‐src MUX
│ ├── alu_control.v # ALU control decoder
│ ├── alu.v # Core ALU (add/sub/and/or/slt/srl)
│ ├── data_mem.v # Data memory (word + half‐word)
│ ├── mux_memtoreg.v # Mem‐to‐Reg MUX
│ ├── shift_left_2_jump.v # Jump‐address shifter
│ ├── alu_branch.v # Branch‐target adder
│ ├── mux_br_sel.v # Branch MUX (beq/bne)
│ └── mux_jump_sel.v # Final PC‐in MUX (branch vs. jump)
├── tb/ # Testbench & program file
│ ├── processor_tb.v # Drives the 14‐instruction test
│ └── program1.mem # 14×32-bit instruction hex words
├── img/ # Diagrams
│ └── Screenshot 2025-05-12 003011.png
└── README.md # This file
Instr. | RegDst | Jump | ExtSel | Branch | Bne | MemRead | MemWrite | MemtoReg | ALUSrc | RegWrite | Jal |
---|---|---|---|---|---|---|---|---|---|---|---|
R-type | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
srl | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
lw |
0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 0 |
sw |
x | 0 | 1 | 0 | 0 | 0 | 1 | x | 1 | 0 | 0 |
beq |
x | 0 | 1 | 1 | 0 | 0 | 0 | x | 0 | 0 | 0 |
bne |
x | 0 | 1 | 1 | 1 | 0 | 0 | x | 0 | 0 | 0 |
j |
x | 1 | x | 0 | 0 | 0 | 0 | x | x | 0 | 0 |
jal |
x | 1 | x | 0 | 0 | 0 | 0 | x | x | 1 | 1 |
sltiu |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
lhu |
0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 0 |
ALUOp | funct (R-type) | Instruction | Action | alu_control |
---|---|---|---|---|
00 | — | lw /sw /lhu |
ADD | 0010 |
01 | — | beq /bne |
SUB | 0110 |
11 | — | sltiu |
SLTU | 1010 |
10 | 100000 |
add |
ADD | 0010 |
10 | 100010 |
sub |
SUB | 0110 |
10 | 100100 |
and |
AND | 0000 |
10 | 100101 |
or |
OR | 0001 |
10 | 101010 |
slt |
SLT | 0111 |
10 | 000010 |
srl |
SRL | 1001 |
- Instruction memory: 1 KB (256 × 32 bits), word-aligned
- Data memory: 1 KB (256 × 32 bits), word-aligned;
lhu
reads half-word zero-extended
tb/program1.mem
One 32-bit hex word per line (big-endian), 14 entries:01095020 # add $t2,$t0,$t1 01095822 # sub $t3,$t0,$t1 01096024 # and $t4,$t0,$t1 01096825 # or $t5,$t0,$t1 ad0b0004 # sw $t3,4($t0) 8d0c0004 # lw $t4,4($t0) 0109702a # slt $t6,$t0,$t1 00128082 # srl $s0,$t1,2 11090002 # beq $t0,$t1,offset 15090000 # bne $t0,$t1,offset 0800000c # j 0x30 00000000 # nop 0c00000d # jal 0x34 2d0a0001 # sltiu $t2,$t0,1 950c0002 # lhu $t4,2($t0)
- To modify the program, open
tb/program1.mem
, edit or reorder the 14 hex words, save, and rerun the testbench. - Initialization in
processor_tb.v
before simulation:- Registers
uut.REG_FILE.registers[8] = 32'd5; // $t0 uut.REG_FILE.registers[9] = 32'd3; // $t1 uut.REG_FILE.registers[11] = 32'd99; // $t3 uut.REG_FILE.registers[18] = 32'd7; // $s2 (for SRL)
- Data memory
uut.DATA_MEMORY.memory[0] = 32'h0000ABCD; uut.DATA_MEMORY.memory[1] = 32'hDEADBEEF; uut.DATA_MEMORY.memory[9] = 32'h12345678;
- Instruction memory
$readmemh("program1.mem", uut.INSTR_MEM.memory);
- Registers
cd src
iverilog -g2012 -o ../build/run.vvp *.v ../tb/processor_tb.v
cd ..
vvp build/run.vvp