Mini MIPS 32-bits CPU
32位单周期MIPS指令集CPU,仅仅支持10条指令:
- lw, sw
- lui, ori, addiu
- addu, slt
- beq, bne, j
具体实现可见:Mini-Mips32
部件构成
顶层模块:

CPU模块:

控制单元:

数据通路:

控制信号
| 指令 | reg_write | reg_dst | alu_src | branch | mem_write | mem_to_reg | aluop | jump | select_imm |
|---|---|---|---|---|---|---|---|---|---|
| R-type | 1 | 1 | 0 | 00 | 0 | 0 | 100 | 0 | 0 |
| beq | 0 | x | 0 | 01 | 0 | x | 010 | 0 | 0 |
| bne | 0 | x | 0 | 10 | 0 | x | 010 | 0 | 0 |
| j | 0 | x | x | 00 | 0 | x | xxx | 1 | 0 |
| addiu | 1 | 0 | 1 | 00 | 0 | 0 | 000 | 0 | 0 |
| ori | 1 | 0 | 1 | 00 | 0 | 0 | 011 | 0 | 0 |
| lui | 1 | 0 | 1 | 00 | 0 | 0 | 100 | 0 | 1 |
| lw | 1 | 0 | 1 | 00 | 0 | 1 | 000 | 0 | 0 |
| sw | 0 | x | 1 | 00 | 1 | x | 000 | 0 | 0 |
| invalid_op | x | x | x | xx | x | x | xxx | 0 | x |
指令流程
lw
lw指令为访存指令,当CPU根据instr解析其为lw指令的时候,首先将instr送入控制单元将其解析并将其控制信号输入数据通路。到达数据通路,首先经过reg_file,在reg_file从a1读入base寄存器的值作为src_a,将instr[15 : 0]符号扩展作为src_b。src_a与src_b经过ALU进行运算,这时alu_control表明进行加法运算,进行运算后作为读内存地址送入RAM并读取该地址的值,在之后将读到的值作为write_reg_data根据instr[20 : 16]作为写入寄存器的编号写到目标寄存器中,随后等下一个时钟沿到来的时候将pc+4并送给iaddr并进行下条指令的取指。
sw
sw指令大体与lw指令相同,不同之处在于从rt的寄存器中取出值将其写入base寄存器加上offset的内存地址中。
lui
lui指令将立即数imm写入寄存器rt的高16位,寄存器rt的低16位置0。在我的实现中,设计了一个select_imm的控制位,当select_imm为1时,将imm放在高16位,低16位置0作为sign_imm。此时ALU不做任何事,仅仅返回src_b。随后将值写入rt寄存器中。
ori
ori指令较为简单,只需从rs中取出值并与sign_imm进行或运算写入rt寄存器即可。
addiu
addiu指令将从rs寄存器中取出的值与sign_imm的值送入ALU相加并写入rt寄存器中。
addu
addu为R类型指令,根据funct来判断其alu_control。此时分别从rs和rd寄存器中取出的值进行相加并将其写入rt寄存器中。
slt
slt寄存器将rs寄存器中的值与rt寄存器中的值进行有符号数比较(此时将通过ALU的比较进行),若rs中的值较小,则将rd寄存器写入1,否则写入0。
beq
beq指令将rs寄存器与rt的寄存器进行比较,若相等则进行分支跳转。此时比较是通过ALU的减法操作来进行的,当zero为0时,则进入分支指令,此时分支指令的地址由offset左移两位进行符号扩展加上该分支指令对应的延迟槽的PC计算得到。
bne
与beq指令大体相同,只不过变为了不相等则跳转。我们branch由两位组成。计算式为alu_res = (zero & branch[0]) | (~zero & branch[1])。
j
无条件跳转,设置jump控制位,任何条件下都进行分支跳转。



