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
控制位,任何条件下都进行分支跳转。