CO-P3-设计文档-Logisim

MIPS单周期处理器设计

本文内容为原创,内容仅供参考,请勿照搬

1. 单周期数据通路设计

参考图

设计通路

最终设计

最终设计

顶层输出端口

最终设计


1.1 组合部件

1.1.1 ALU (算术逻辑运算单元)

  • in:
    • SrcA, SrcB
    • ALUCtrl [3:0]
    • Shift 移位数 5
    • FlowJudge 是否进行溢出判断
  • out:
    • Equal(zero)
    • Result
    • Overflow
  • 端口定义
信号名 方向 位宽 描述
SrcA I 32 32 位操作数 A
SrcB I 32 32 位操作数 B
ALUCtrl I 4 4 位运算控制信号
Shift I 5 5 位移位量 (shamt)
Result O 32 计算结果
Zero O 1 1 位零标志位 Equal(zero)
  • 功能定义
序号 功能名称 功能描述
1 运算选择 根据 4 位 ALUCtrl 信号,选择要执行的运算 (见下表)。
2 算术逻辑运算 SrcA, SrcBShift 执行选定的 32 位运算,并将结果输出到 Result 端口。
3 零标志位 比较 Result 端口的 32 位输出是否等于 0x00000000。如果是,Zero 端口输出 1,否则输出 0。

ALUCtrl (功能 1) 的详细逻辑:

  • 0000: Result = SrcA + SrcB (加法)
  • 0001: Result = SrcA - SrcB (减法)
  • 0010: Result = SrcA & SrcB (按位与)
  • 0011: Result = SrcA | SrcB (按位或)
  • 0100: Result = (SrcA < SrcB) ? 1 : 0 (有符号 slt)
  • 0101: Result = SrcB << Shift (逻辑左移)

ALU


1.1.2 GRF(通用寄存器组,也称为寄存器文件、寄存器堆)


  • in: RA1 RA2
    out: RD1=RF[RA1] , RD2=RF[RA2]

  • in: WA, WD, clk
    RegWrite out
    1 RF[WA] -> WD
    0
  • 端口定义
信号名 方向 位宽 描述
ReadAddr1 I 5 读端口 1 地址 RA1
ReadAddr2 I 5 读端口 2 地址 RA2
WriteAddr I 5 写端口地址 WA
WriteData I 32 32 位待写入数据 WD
RegWrite I 1 写使能信号
clk I 1 时钟信号
reset I 1 异步复位信号
ReadData1 O 32 RF[RA1]
ReadData2 O 32 RF[RA2]
  • 功能定义
序号 功能名称 功能描述
1 并发异步读
(Concurrent Read)
异步地(即立即)从 ReadAddr1ReadAddr2 指定的地址读取 32 位数据,并分别从 ReadData1ReadData2 端口输出。 (即 RD1=RF[RA1], RD2=RF[RA2])
2 同步写
(Synchronous Write)
RegWrite = 1 时,在 clk 信号的上升沿,将 WriteData 端口的 32 位数据写入到 WriteAddr 指定的寄存器。 (即 RF[WA] = WD)
3 $zero 寄存器逻辑 对应的 ReadData 端口必须输出 0x00000000
Reg0 永远不能被修改。
4 异步复位

寄存器堆内部结构

GRF


1.1.3 DM (数据存储器)

  • MemRead RE

    • in: A
      out: RD = DM[A]
  • MemWrite WE
    • clk
      in: A, WD
      out: DM[A] = WD
  • 端口定义
信号名 方向 位宽 描述
Address I 32 32 位字节地址 (来自 ALUResult)
WriteData I 32 32 位待写入数据 (WA)
MemRead I 1 读使能信号 (RE)
MemWrite I 1 写使能信号 ( WE)
clk I 1 时钟信号 (用于同步写入)
reset I 1 异步复位信号 (用于清空 RAM)
ReadData O 32 32 位读出数据 (送往 MemtoReg MUX)
  • 功能定义
序号 功能名称 功能描述
1 地址映射
(Address Mapping)
将输入的 32 位字节地址 Address,通过提取 [13:2] 位,转换为内部 RAM 所需的 12 位字地址
2 存储器读
(Memory Read)
MemRead = 1 时,异步地从转换后的字地址中读取 32 位数据,并将其从 ReadData 端口输出。 (即 RD = DM[A])
3 存储器写
(Memory Write)
MemWrite = 1 时,在 clk 信号的上升沿,将 WriteData 端口的32位数据写入到转换后的字地址。 (即 DM[A] = WD)
4 异步复位 reset = 1 时,异步地将内部 RAM 的所有单元清零。

DM


1.1.4 nPC – 有限状态机:

  • PC (程序计数器) —状态转移—> nPC
    • PC 寄存器 – 状态存储模块

      • en, reset, clk
    • NPC 模块 – 状态转移电路

    • Pc += 4

    • in:

      • pc
      • IsB –> Offset(32) << 2 + pc
      • JUMP –> In_26(26) << 2 + pc[31:28]
      • JR –> Ra
    • out:

      • Next_PC
      • PC+4
  • 端口定义
信号名 方向 位宽 描述
PC_in I 32 PC 的值 (来自 IFU 模块)
Offset_Ext I 32 32 位符号扩展的立即数 (来自 EXT 模块)
imm26 I 26 26 位跳转立即数 (来自 Splitter_Unit 模块)
Ra I 32 rs 寄存器的值 (来自 GRFReadData1)
IsB I 1 分支使能信号。(Main_Control[Branch] AND ALU[Zero])
JUMP I 1 j 跳转使能信号 (来自 Main_Control_Unit)
JR I 1 jr 跳转使能信号 (来自 ALU_Control_Unit)
Next_PC O 32 计算得出的下一条指令地址 (送往 IFUNext_PC 端口)
PC_plus_4 O 32 PC + 4 的值 (来自 IFU 模块)
  • 功能定义
序号 功能名称 功能描述
1 分支地址计算
(Branch Target Calculation)
计算 beq 指令的目标地址:
Branch_Target = PC_plus_4 + (Offset_Ext << 2)
2 跳转地址计算
(Jump Target Calculation)
计算 j 指令的目标地址:
Jump_Target = { PC_plus_4[31:28] , (imm26 << 2) }
3 PC 优先级选择
(Next PC Selection)
使用一个 4-to-1 MUX (多路选择器),根据 JR, JUMP, IsB 信号的优先级,在四个可能的下一地址中选择一个作为 Next_PC 输出。

PC 优先级选择 (功能 3) 的详细逻辑:

  • JR = 1: Next_PC = Ra (最高优先级)
  • JR = 0, JUMP = 1: Next_PC = Jump_Target
  • JR = 0, JUMP = 0, IsB = 1: Next_PC = Branch_Target
  • JR = 0, JUMP = 0, IsB = 0: Next_PC = PC_plus_4 (默认顺序执行)

nPC


1.1.5 IFU(取指令单元)

IM (指令存储器)
  • 端口定义
信号名 方向 位宽 描述
A I 32 32 位字节地址 (来自 IFU 模块的 PC)
RD O 32 从存储器中读取的 32 位指令码
  • 功能定义
序号 功能名称 功能描述
1 地址映射
(Address Mapping)
将输入的 32 位字节地址 A,通过减去起始地址偏移量 0x3000 并右移两位(即提取 [13:2] 位),转换为 12 位的字地址
2 指令读取
(Instruction Read)
使用转换后的 12 位字地址,从内部 ROM (只读存储器) 中异步读取一条 32 位的指令,并将其从 RD 端口输出。

IMm

IFU (取指令单元)
  • 端口定义
信号名 方向 位宽 描述
Next_PC I 32 下一个时钟周期将要载入的 PC 值 (来自 NPC 模块)
clk I 1 系统时钟信号
reset I 1 系统异步复位信号
stop I 1 时钟使能 (Clock Enable) 信号 (低电平有效,用于暂停 PC)
PC O 32 当前 PC 寄存器中存储的地址值 (送往 IMNPC)
Instr O 32 PC 对应的当前指令码 (来自 IM 模块)
  • 功能定义
序号 功能名称 功能描述
1 PC 更新
(PC Update)
clk 上升沿,且 stop 信号为 0 (无效) 时,将 Next_PC 的值载入 PC 寄存器。
2 PC 复位
(PC Reset)
reset 信号为 1 时,异步地将 PC 寄存器的值强制设为起始地址 0x00003000
3 指令获取
(Instruction Fetch)
PC 寄存器的当前值输出到 PC 端口,并将其送至内部的 IM 模块,以获取对应的 32 位指令,并从 Instr 端口输出。
4 PC+4 计算
(PC+4 Calculation)
并行地计算 PC 寄存器当前值加 4 的结果,并从 PC_plus_4 端口输出。

IFU


1.1.6 EXT (拓展单元)

将16位立即数符号拓展为32位。这里为了提高可拓展性,添加了 OPExt 接口

  • 端口定义
信号名 方向 位宽 描述
Imm_16 I 16 16位立即数输入信号
OPExt I 1 符号拓展信号
0:无符号拓展(0拓展)
1:符号拓展
Imm_32 O 32 32位立即数输出信号
  • 功能定义
序号 功能名称 功能描述
1 符号拓展 将16位立即数进行符号拓展

EXT


1.1.7 SPLI(指令分离器模块)

  • 端口定义
信号名 方向 位宽 描述
Instr I 32 来自 IFU (指令存储器) 的 32 位完整指令码
Opcode O 6 操作码 ([31:26]),送往 Main Control Unit
rs O 5 源寄存器 1 ([25:21]),送往 GRF[RA1]NPC[Ra]
rt O 5 源寄存器 2 / 目标 ([20:16]),送往 GRF[RA2]RegDst MUX
rd O 5 目标寄存器 ([15:11]),送往 RegDst MUX
shamt O 5 移位量 ([10:6]),送往 ALU[Shamt]
funct O 6 功能码 ([5:0]),送往 ALU Control Unit
imm16 O 16 16 位立即数 ([15:0]),送往 EXTLUI Shifter
imm26 O 26 26 位跳转地址 ([25:0]),送往 NPC
  • 功能定义
序号 功能名称 功能描述
1 指令字段分离
(Instruction Field Separation)
将 32 位的 Instruction 输入,根据 MIPS 指令格式,并行地分离为 Op, rs, rt, rd, shamt, funct, imm16imm26 共 8 个字段,并从对应端口输出。

SPLI


指令格式

R型指令格式

R型指令格式

add,sub,and,or rd, rs, rt
操作 Op Rs Rt Rd Shamt Func
位宽 6 5 5 5 5 6

LW&SW指令格式

LW&SW指令格式

lw,sw rt, rs, imm16
操作 Op Rs Rt imm
位宽 6 5 5 16

分支指令格式

分支指令格式

beq rs, rt, imm16
操作 Op Rs Rt imm
位宽 6 5 5 16

跳转指令格式

跳转指令格式

j add26
操作 Op JAdd
位宽 6 26

2. 单周期控制器设计

单周期控制器设计

2.1 单周期通路所需控制信号

2.1.1 ALU控制(ALUCtrl):4位

输入 ALUCtrl 运算
A, B 0000 A & B
A, B 0001 A | B
A, B 0010 A + B
A, B 0110 A - B

2.1.2 8个控制信号:

控制信号 0 1
RegDst Reg堆写入端地址:Rt Reg堆写入端地址:Rd
RegWrite Reg写入:Reg[WA] = WD
ALUSrc ALU-B:RD2 ALU-B:imm Signext
PCSrc PC = (PC+4) PC = NAdd (beq目的地址)
PCJump PC = MUX的输出 PC = J指令目的地址
MemRead DM读(输出)
MemWrite DM写(输入)
MemtoReg Reg写入 <– ALU Reg写入 <– DM
Branch 为Beq指令

2.2 控制器设计

controler

2.2.1 Main Control Unit

2.1 设计思路
  1. MemtoReg (2 位):
    • 00: ALUResult (用于 R-type, ori)
    • 01: DM[ReadData] (用于 lw)
    • 10: LUI_Value (用于 lui)
  2. ExtOp (1 位): 用于控制扩展单元。
    • 0: 零扩展 (for ori)
    • 1: 符号扩展 (for lw, sw, beq)
  3. Jump (1 位): (图中的 PCJump) 用于 j 指令。
  4. JR 信号: 已移至 ALU Control Unit
2.2 端口定义
  • 输入 (Inputs):
    • Opcode[5:0]: 来自指令码的 [31:26] 位 (操作码)。
  • 输出 (Outputs):
    • RegDst[0]: (1: R-type 写 rd, 0: I-type 写 rt)
    • ALUSrc[0]: (1: 立即数, 0: GRF[ReadData2])
    • MemtoReg[1:0]: (2 位) (写回 GRF 的数据源选择)
    • RegWrite[0]: (1: 允许写入 GRF)
    • MemRead[0]: (1: 允许读取 DM)
    • MemWrite[0]: (1: 允许写入 DM)
    • Branch[0]: (1: beq 指令)
    • Jump[0]: (1: j 指令)
    • ExtOp[0]: (1: 符号扩展, 0: 零扩展)
    • ALUOp[2:0]: (3 位) (送往 ALU Control Unit)
2.3 真值表
指令 Opcode RegDst ALUSrc MemtoReg RegWrite MemRead MemWrite Branch Jump ExtOp ALUOp[2:0]
R-type 000000 1 0 00 1 0 0 0 0 X 100
lw 100011 0 1 01 1 1 0 0 0 1 000
sw 101011 X 1 XX 0 0 1 0 0 1 000
beq 000100 X 0 XX 0 0 0 1 0 1 001
ori 001101 0 1 00 1 0 0 0 0 0 010
lui 001111 0 X 10 1 0 0 0 0 X XXX
addi 001000 0 1 00 1 0 0 0 0 1 000
j 000010 X X XX 0 0 0 0 1 X XXX

3 位 ALUOp 编码:

  • 000: lw/sw (主控制器要求 ADD)
  • 001: beq (主控制器要求 SUB)
  • 010: ori (主控制器要求 OR)
  • 011: (预留, e.g., for andi)
  • 100: R-type (主控制器说:“我不知道,请查看 funct 码”)
  • 101: (预留, e.g., for xori)
  • 110: (预留, e.g., for addi)
  • 111: (预留)

关于 nop (0x00000000) 的说明:
nop 指令的 Opcode000000Funct000000

  1. Main Control 会将其视为 R-type
  2. ALU Control 会将其视为 sll
  3. 它最终执行 sll $zero, $zero, 0
  4. 控制器会尝试将结果 0 写入 $zero 寄存器。

顶层逻辑补充

  • 最终的 RegWrite 信号: jr 指令不应该写寄存器。因此,连接到 GRF 的最终 RegWrite_Enable 信号应该是:
    • RegWrite_Enable = Main_Control[RegWrite] AND ( NOT ALU_Control[JR] )

主控单元逻辑实现

MCU


2.2.2 ALU Control Unit

1.2 端口定义
  • 输入 (Inputs):
    • ALUOp[2:0]: 来自 Main Control Unit (主控制器) 的 3 位操作码。
    • Func[5:0]: 来自指令码的 [5:0] 位 (功能码)。
  • 输出 (Outputs):
    • ALUCtrl[3:0]: 送往 ALU 的 4 位最终运算码 (我们之前已约定 0000=ADD, 0001=SUB, 0010=AND, 0011=OR, 0100=SLT, 0101=SLL)。
    • JR[0]: (新增输出) 用于 jr 指令。当 ALUOp=100Func=001000 时,此信号为 1。
1.3 真值表
ALUOp[2:0] (输入) Func[5:0] (输入) 备注 (指令) ALUCtrl[3:0] (输出) JR[0] (输出)
000 X (任意) lw / sw 0000 (ADD) 0
001 X (任意) beq 0001 (SUB) 0
010 X (任意) ori 0011 (OR) 0
011 X (任意) (预留) X (e.g., 0000) 0
100 100000 add 0000 (ADD) 0
100 100010 sub 0001 (SUB) 0
100 100100 and 0010 (AND) 0
100 101010 slt 0100 (SLT) 0
100 000000 sll (或 nop) 0101 (SLL) 0
100 001000 jr X (e.g., 0000) 1
(other) (other) (Undefined) X (e.g., 0000) 0

ACU


课下总结:
P3做出来两道题,也算是通过了,第一周的时候没估算好要完成的时间,结果周日前没做完,直接拖了一周进度。
于是周一喜提上机放假,最终又花了一天半多才完成最终版。
但是最终版甚至连弱测都没有通过。省略漫长的debug阶段,最终还是通过求助助教,发现bug的原因竟是 多了一个ROM !!
把这个ROM改成逻辑元件后,就通过了。
不能有多余ROM的原因,是评测机在评测时,这会通过正则匹配到ROM,然后读取其中的数据,所以我增加一个ROM后就会导致评测出错。


思考题

  1. 现在我们的模块中 IM 使用 ROM, DM 使用 RAM, GRF 使用 Register,这种做法合理吗? 请给出分析,若有改进意见也请一并给出。
    A:合理。ROM是只读存储器,因此可以用来储存指令;RAM既可以读也可以写,因此满足DM对读写的要求;GRF是寄存器堆,需要较高的读写速度,因此适合用寄存器实现。
  2. 事实上,实现 nop 空指令,我们并不需要将它加入控制信号真值表,为什么?请给出你的理由。
    A:nop指令码为0x00000000,相当于sll $0, $0, 0, 相当于把$0寄存器中的值左移0位并写入$0寄存器,因为$0的值始终为0,不会被修改,因此该指令执行后没有任何影响。即使cpu没有设置sll指令,nop指令也不会对电路中任何元件进行操作,对电路没有任何影响。