P3-logisim单周期CPU(简化指令)
logisim单周期CPU(简化指令)
模块设计
整体视图:

1. GRF(寄存器堆)

端口名 | 输入\输出 | 位宽 | 功能 |
---|---|---|---|
clk | Input | 1 | 时钟信号 |
reset | Input | 1 | 复位信号 |
WE | Input | 1 | 使能信号 |
A1 | Input | 4:0 | 输入寄存器地址端口1,对应指令码25:21 |
A2 | Input | 4:0 | 输入寄存器地址端口2,对应指令码20:16 |
A3 | Input | 4:0 | 输入寄存器地址端口3,根据R型或I型指令分别对应指令码15:11和20:16 |
WD | Input | 31:0 | 数据输入端口,输入一个32位数据,存入编码为A3的寄存器中 |
RD1 | Output | 31:0 | 输出编码为A1中输入的寄存器中的值 |
RD2 | Output | 31:0 | 输出编码为A2中输入的寄存器中的值 |
2. DM

使用一个RAM实现,str口连接MemWrite信号,ld口连接Mem2Reg信号,clr口连接reset异步复位信号,输入数据为GRF模块的RD2口。
DM中一个字是一个地址,按字节为14位(16K),按字为12位地址端口应该连接ALU输出端的2~13位。
3. IFU

端口名 | 输入\输出 | 位宽 | 功能 |
---|---|---|---|
clk | Input | 1 | 时钟信号 |
reset | Input | 1 | 复位信号 |
beq_if | Input | 1 | beq使能信号 |
j_if | Input | 1 | j指令pc选择 |
Inster | Output | 31:0 | 当前pc所指内存对应指令码 |
pc | Output | 31:0 | 输出的真实pc值(偏移0x00003000) |
外部引入两个对应位置的寄存器通过ALU的减法结果,通过与门和nPC_Sel(判断指令是否为beq)连接,实现beq(if$[rs]==$[rt]): PC=PC+offest+4。
IM:
通过ROM元件存储和读入指令代码,PC在内部为0x00000000起始,而外部为0x00003000,需要加一个偏移量,之后j型指令需注意地址问题。
ROM中一个字是一个地址,按字为12位地址端口应该连接ALU输出端的2~13位。
4.splitter(切分指令码)
端口名 | 输入\输出 | 位宽 | 功能 |
---|---|---|---|
instr | Input | 31:0 | 指令码 |
Opcode | Output | 5:0 | 高六位opcode |
rs | Output | 4:0 | rs寄存器序号 |
rt | Output | 4:0 | rt寄存器序号 |
rd | Output | 4:0 | rd寄存器序号 |
6-10(暂定) | Output | 4:0 | 输出6-10位 |
func | Output | 5:0 | 输出func码 |
imm | Output | 15:0 | 输出低16位立即数imm |
5.ALU

端口名 | 输入\输出 | 位宽 | 功能 |
---|---|---|---|
ALUOp | Input | 2:0 | ALU功能选择 |
A | Input | 31:0 | 待处理数字1 |
B | Input | 31:0 | 待处理数字2 |
result | Output | 31:0 | 计算结果 |
ALUOp:
000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
---|---|---|---|---|---|---|---|
add | sub | mul | div | and | or | sll | lui |
6.EXT

端口名 | 输入\输出 | 位宽 | 功能 |
---|---|---|---|
imm16 | Input | 15:0 | 16位立即数 |
EXTOp | Input | 1 | 位扩展选择功能 |
ext32 | Output | 31:0 | 位扩展计算结果 |
EXTOp:
0:0扩展
1:符号扩展
7.controller

端口名 | 输入\输出 | 位宽 | 功能 |
---|---|---|---|
Opcode | Input | 5:0 | 高六位opcode |
Func | Input | 5:0 | 指令码 |
RegDst | Output | 1 | REG选择 |
ALUSrc | Output | 1 | imm选择入alu的B口 |
Mem2Reg | Output | 1 | mem读出使能 |
RegWrite | Output | 1 | reg写使能 |
Npc_sel | Output | 1 | beq选择 |
ExtOp | Output | 1 | ext选择 |
J_if | Output | 1 | 是否跳转 |
Sll_Sel | Output | 1 | 移位选择 |
ALUop | Output | 2:0 | alu操作 |
通过输入的指令码各部分,进行操作状态输出。
*** mul和div指令未实现,暂不列出***
执行指令 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
信号名 | add | sub | andi | ori | lui | j | sw | lw | beq | nop/sll |
op | 000000 | 000000 | 001100 | 001101 | 001111 | 000010 | 101011 | 100011 | 000100 | 000000 |
func | 100000 | 100010 | 000000 | |||||||
RegDst | 1(rd) | 1 | 0 | 0(rt) | 0 | 0 | 0 | 0 | 0 | 1 |
ALUSrc | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 0 |
Mem2Reg | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
RegWrite | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 1 |
MemWrite | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
Npc_sel | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
ExtOp | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
ALU_ctr1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 1(sub验证) | 0 |
ALU_ctr2 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
ALU_ctr3 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
J_if | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
Sll_Sel | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
各信号功能:
- RegDst:被写入的寄存器的编码,由于MIPS中R型指令和I型指令被写入寄存器的编码对应的指令码位数不相同,故需要多路选择器对信号进行选择,多路选择器选择信号连接RegDst,R型指令时置1(rd),I型指令时置0(rt)。
- ALUsrc:选择使用立即数还是使用GRF的RD2口输出数据,指令码为R型指令时置0,I型指令时置1
- Mem2Reg:是否将数据存储器中的数据读入寄存器中,lw为1。
- RegWrite:是否将数据写入寄存器堆中,连接GRF模块的使能端,需要向寄存器堆中写入数据时为1。
- MenWrite:是否将数据写入数据存储器中,连接数据存储器的写入使能端,需要向数据存储器中写入数据时为1。
- Npc_sel:跳转信号,当指令为beq时,该信号置1,指令存储器输入端选择输入信号为当前pc值加立即数,和两寄存器是否相等的判断通过与门接入IFU的beq_if。
- ExtOp:位扩展器功能选择,为0时高位0扩展,为1时高位符号扩展。
- ALU_ctr:ALU计算结果选择信号,addu时为00,subu时为01,ori时为10,lui时为11。
- J_if:j指令时pc行为控制。
- Sll_Sel:sll指令时指令码切分选择控制。
测试方案
通过mars编写汇编程序,编写相关测试代码,将mars生成的机器码通过文件导入到logisim,通过向内存中输入中间数据,和mars进行对拍,以此验证各代码是否运行正确。
思考题
-
controller发挥状态转移,控制内存和寄存器等储存元件发生变化,IFU中PC寄存器负责状态储存(当前位于的代码位置),通过beq相关端口实现状态转移(+4或者跳转)
-
有其合理性。IM只需要读取,因此选择ROM,而DM需要读取和写入,因此选用RAM,寄存器堆本身就由寄存器构成,因此选用寄存器组成符合其组成。
-
splitter,用于切分指令码,定义见上方。
-
nop对应指令码为0x00000000,其本质为一个sll指令,对$0 进行了移位,不产生任何影响。同时,不加入控制信号真值表,使其对应的所有指令控制值为0,那么不论对寄存器还是对内存的操作都不会实际发生。
-
lw和sw指令对寄存器取值覆盖不全面,只有其为0的情况,应该再加入为负数和正数的情况。
beq指令只有向后跳转的相等和不相等,应加入向前跳转的相关操作。
-
offset 方面,可以考虑以下情况:
- offset 是正数
- offset 是零
- offset 是负数
-
寄存器方面,可以考虑以下情况:
$base
寄存器中的值是正数$base
寄存器中的值是零$base
寄存器中的值是负数
add应该在边界附近测试,0 及附近的数,32 位数边界附近的数。
未涉及到sub指令。
未对$0寄存器进行写入测试。
-
附录:
题目测试代码翻译:
1 | 0x0000000000000000: 34 1C 00 00 ori $gp, $zero, 0 |
所涉及的指令的手册解释
add
sub
ori
andi
lw
sw
beq
lui
j
sll