P4 CPU设计文档
设计要求
处理器为 32 位单周期处理器,不考虑延迟槽,应支持的指令集为:
add, sub, ori, lw, sw, beq, lui, jal, jr, nop
,其中:nop
为空指令,机器码0x00000000
,不进行任何有效行为(修改寄存器等)。add, sub
按无符号加减法处理(不考虑溢出)。
需要采用模块化和层次化设计。顶层文件为 mips.v,有效的驱动信号要求包括且仅包括同步复位信号 reset 和时钟信号 clk,接口定义如下:
1
2
3
4module mips(
input clk,
input reset
);
设计草稿
数据通路模块定义
PC
信号名 | 方向 | 功能 |
---|---|---|
NPC[31:0] | I | 输入下一个 PC 值 |
clk | I | 时钟信号 |
reset | I | 同步复位信号 |
PC[31:0] | O | 输出当前 PC 值 |
NPC
信号名 | 方向 | 功能 |
---|---|---|
PC[31:0] | I | 输入当前的 PC 值,用于计算 NPC 值 |
offset[31:0] | I | 偏移量 |
nPC_sel[2:0] | I | NPC 输出选择信号 |
Branch | I | 跳转信号 |
instr_index[25:0] | I | 机器码 26 位 instr_index |
Ra[31:0] | I | 输入$ra 寄存器的值 |
NPC[31:0] | O | 输出 NPC 值 |
PC_add_4[31:0] | O | 输出 PC+4 值 |
nPC_sel 的信号功能:
信号 | 功能 |
---|---|
3’b000 | NPC = PC + 4 |
3’b001 | NPC = Branch ? PC + 4 + (offset << 2) : PC + 4 |
3’b010 | NPC = (PC31...28的 32 位无符号扩展数 << 28) + (instr_index 的 32 位无符号拓展数 << 2) |
3’b011 | NPC = Ra |
IM
信号 | 方向 | 功能 |
---|---|---|
A[31:0] | I | 输入指令地址 |
RD[31:0] | O | 输出指令 |
由于指令地址起始值为 0x0000_3000,对 A 减去 0x0000_3000 后,取其[13:2]位值,记为 no,从指令存储器中取第 no 条指令输出给 RD。
指令存储器容量为 4096 × 32bit。
GRF
信号 | 方向 | 功能 |
---|---|---|
A1[4:0] | I | 输入需要读取的寄存器 Reg1 的序号 |
A2[4:0] | I | 输入需要读取的寄存器 Reg2 的序号 |
A3[4:0] | I | 输入需要写入的寄存器的序号 |
WD3[31:0] | I | 写入数据 |
clk | I | 时钟信号 |
WE3 | I | 写使能信号 |
reset | I | 同步复位信号 |
PC[31:0] | I | 相应指令的储存地址 |
RD1[31:0] | O | 输出从寄存器 Reg1 中读取的内容 |
RD2[31:0] | O | 输出从寄存器 Reg2 中读取的内容 |
0 号寄存器值始终为 0。
DM
信号 | 方向 | 功能 |
---|---|---|
A[31:0] | I | 输入内存地址 |
WD[31:0] | I | 输入需要写入的数据 |
clk | I | 时钟信号 |
reset | I | 同步复位信号 |
WE | I | 写使能信号 |
PC[31:0] | I | 相应指令的储存地址 |
RD[31:0] | O | 输出从内存中读取的数据 |
取 A[13:2]的值记为 no,表示数据存储器第 no 处位置。
数据存储器容量为 3072 × 32bit。
ALU
信号 | 方向 | 功能 |
---|---|---|
SrcA[31:0] | I | 输入计算数 A |
SrcB[31:0] | I | 输入计算数 B |
Shift[4:0] | I | 输入移位量 Shift |
Op[2:0] | I | 操作数 Op |
Result[31:0] | O | 输出运算结果 |
Zero | O | Zero = (A == B); |
Op 信号功能:
信号 | 类型 | 操作 |
---|---|---|
3’b000 | ADD(无符号,不考虑溢出) | SrcA + SrcB |
3’b001 | SUB(无符号,不考虑溢出) | SrcA - SrcB |
3’b010 | OR | SrcA | SrcB |
3’b011 | SHIFT | SrcB << Shift |
EXT
信号 | 方向 | 功能 |
---|---|---|
Imm[15:0] | I | 输入 16 位立即数 |
ExtOp | I | 扩展类型 |
Ext_Imm[31:0] | O | 输出扩展立即数 |
ExtOp 信号功能:
信号 | 操作 |
---|---|
1’b0 | 无符号拓展 |
1’b1 | 符号拓展 |
控制单元模块
信号 | 方向 | 功能 |
---|---|---|
Op[5:0] | I | 机器码 Op 字段 |
Funct[5:0] | I | 机器码 Funct 字段 |
RegDst[1:0] | O | 指定要写入的寄存器地址 |
ALUSrc[1:0] | O | 指定 ALU 的 SrcB |
MemtoReg[1:0] | O | 指定写入 GRF 的源数据 |
RegWrite | O | GRF 写使能信号 |
MemWrite | O | DM 写使能信号 |
nPC_sel[2:0] | O | 指定 NPC 的值 |
ExtOp[1:0] | O | 指定立即数扩展类型 |
ALUOp[2:0] | O | 指定 ALU 运算类型 |
ShiftOp | O | 指定移位量 |
RegDst 信号功能:
信号 | 写入寄存器地址 |
---|---|
2’b00 | Instr[20:16] |
2’b01 | Instr[15:11] |
2’b10 | 31 |
ALUSrc 信号功能:
信号 | SrcB |
---|---|
2’b00 | GRF 的 RD2 |
2’b01 | Ext_Imm |
MemtoReg 信号功能:
信号 | 写入 GRF 的源数据 |
---|---|
2’b00 | ALU 的 Result |
2’b01 | DM 的 RD |
2’b10 | PC+4 |
ShiftOp 信号功能:
信号 | 移位量 |
---|---|
1’b0 | 16 |
nPC_sel 信号接入 NPC,ExtOp 信号接入 EXT,ALUOp 信号接入 ALU。
指令与信号的对应关系参照 Logisim 的 Control Unit:
测试方案
借助讨论区的.asm
自动生成文件main.exe
,生成随机测试代码。然后根据自己编写的脚本将
Mars 和 ISE 的输出结果重定向到相应的文件:
1 | @echo off |
最后将两个 txt 文本的内容对拍以查找错误。
思考题
1. 阅读下面给出的 DM 的输入示例中(示例 DM 容量为 4KB,即 32bit × 1024 字),根据你的理解回答,这个 addr 信号又是从哪里来的?地址信号 addr 位数为什么是 [11:2] 而不是 [9:0] ?
addr
信号来自ALU
的输出。
由于输入的 memory address 地址值都是 4
的倍数,所以取addr
的[11:2]位。
2. 思考上述两种控制器设计的译码方式,给出代码示例,并尝试对比各方式的优劣。
1.指令对应的控制信号如何取值:
1 | always @(*)begin |
2.控制信号每种取值所对应的指令
1 | wire add = Op == 6'b0 && Funct == 6'h20; |
第一种方式便于查错,但代码量大。第二种便于插入新指令、代码量小,但不容易维护。
3. 在相应的部件中,复位信号的设计都是同步复位,这与 P3 中的设计要求不同。请对比同步复位与异步复位这两种方式的 reset 信号与 clk 信号优先级的关系。
同步复位,clk
信号优先级>reset
信号:
1 | always@(posedge clk)begin |
异步复位,clk
信号优先级<reset
信号:
1 | always@(posedge clk or posedge reset)begin |
4. C 语言是一种弱类型程序设计语言。C 语言中不对计算结果溢出进行处理,这意味着 C 语言要求程序员必须很清楚计算结果是否会导致溢出。因此,如果仅仅支持 C 语言,MIPS 指令的所有计算指令均可以忽略溢出。 请说明为什么在忽略溢出的前提下,addi 与 addiu 是等价的,add 与 addu 是等价的。提示:阅读《MIPS32® Architecture For Programmers Volume II: The
MIPS32® Instruction Set》中相关指令的 Operation 部分。
addi
:
addiu
:
可见若不考虑溢出,addi
和addiu
最终都是将GPR[rs] + sign_extend(immediate)
赋值到GPR[rt]
中。add
和addu
同理。