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进行对拍,以此验证各代码是否运行正确。

思考题

  1. controller发挥状态转移,控制内存和寄存器等储存元件发生变化,IFU中PC寄存器负责状态储存(当前位于的代码位置),通过beq相关端口实现状态转移(+4或者跳转)

  2. 有其合理性。IM只需要读取,因此选择ROM,而DM需要读取和写入,因此选用RAM,寄存器堆本身就由寄存器构成,因此选用寄存器组成符合其组成。

  3. splitter,用于切分指令码,定义见上方。

  4. nop对应指令码为0x00000000,其本质为一个sll指令,对$0 进行了移位,不产生任何影响。同时,不加入控制信号真值表,使其对应的所有指令控制值为0,那么不论对寄存器还是对内存的操作都不会实际发生。

  5. lw和sw指令对寄存器取值覆盖不全面,只有其为0的情况,应该再加入为负数和正数的情况。

    beq指令只有向后跳转的相等和不相等,应加入向前跳转的相关操作。

    • offset 方面,可以考虑以下情况:

      • offset 是正数
      • offset 是零
      • offset 是负数
    • 寄存器方面,可以考虑以下情况:

      • $base 寄存器中的值是正数
      • $base 寄存器中的值是零
      • $base 寄存器中的值是负数

    add应该在边界附近测试,0 及附近的数,32 位数边界附近的数。

    未涉及到sub指令。

    未对$0寄存器进行写入测试。

附录:

题目测试代码翻译:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
0x0000000000000000:  34 1C 00 00    ori $gp, $zero, 0 
0x0000000000000004: 34 1D 00 00 ori $sp, $zero, 0
0x0000000000000008: 34 01 34 56 ori $at, $zero, 0x3456
0x000000000000000c: 00 21 08 20 add $at, $at, $at
0x0000000000000010: 8C 01 00 04 lw $at, 4($zero)
0x0000000000000014: AC 01 00 04 sw $at, 4($zero)
0x0000000000000018: 3C 02 78 78 lui $v0, 0x7878
0x000000000000001c: 00 41 18 22 sub $v1, $v0, $at
0x0000000000000020: 3C 05 12 34 lui $a1, 0x1234
0x0000000000000024: 34 04 00 05 ori $a0, $zero, 5
0x0000000000000028: 00 00 00 00 nop
0x000000000000002c: AC 85 FF FF sw $a1, -1($a0)
0x0000000000000030: 8C 83 FF FF lw $v1, -1($a0)
0x0000000000000034: 10 65 00 01 beq $v1, $a1, 0x3c
0x0000000000000038: 10 00 00 0D b 0x70
0x000000000000003c: 34 67 04 04 ori $a3, $v1, 0x404
0x0000000000000040: 10 E3 00 0B beq $a3, $v1, 0x70
0x0000000000000044: 00 00 00 00 nop
0x0000000000000048: 3C 08 77 77 lui $t0, 0x7777
0x000000000000004c: 35 08 FF FF ori $t0, $t0, 0xffff
0x0000000000000050: 00 08 00 22 neg $zero, $t0
0x0000000000000054: 34 00 11 00 ori $zero, $zero, 0x1100
0x0000000000000058: 00 E6 50 20 add $t2, $a3, $a2
0x000000000000005c: 34 08 00 00 ori $t0, $zero, 0
0x0000000000000060: 34 09 00 01 ori $t1, $zero, 1
0x0000000000000064: 34 0A 00 01 ori $t2, $zero, 1
0x0000000000000068: 01 0A 40 20 add $t0, $t0, $t2
0x000000000000006c: 11 09 FF FE beq $t0, $t1, 0x68
0x0000000000000070: 10 00 FF FF b 0x70

所涉及的指令的手册解释

add

sub

ori
andi
lw
sw
beq
lui
j
sll