BUAA_CO_P4
P4_Verilog
实现10指令单周期CPU
需求分析
实现10指令:add
, sub
, ori
, lw
, sw
, beq
, lui
, jal
, jr
, nop
在8指令的基础上增量开发实现10指令,我们首先分析新增指令的功能
jal
:将pc + 4
写入31号寄存器 + 跳转到指定地址jr
:从31号寄存器中读出 + 跳转到指定地址
思路分析
由于
jal
要求写入31号寄存器,所以的RegAddr
需要至少3种编码,也就是说RegDst
至少需要2位,分别对应写入寄存器编号来自rt
rd
和 31号1
2
3[1:0] RegDst // RegDst == 2'b00 RegAddr是rt对应的寄存器 (默认)
// RegDst == 2'b01 RegAddr是rd对应的寄存器
// RegDst == 2'b10 RegAddr是31号寄存器同时要回写的内容
WriteBack
也要发生变化,WriteBack
的取值有4种可能,所以WBSource
至少需要2位,分别对应WriteBack
来自ALU_ans
,WD
,imm_ext
,和pc + 4
1
2
3
4
5
6
7
8
9[1:0] WBSource // WBSource == 2'b00 WriteBack = ALU_ans (默认)
// WBSource == 2'b01 WriteBack = WD
// WBSource == 2'b10 WriteBack = imm_ext
// WBSource == 2'b11 WriteBack = pc + 4
/* 2'b01 对应 lw
2'b10 对应 lui
2'b11 对应 jal
*/接下来要实现的是跳转功能,输入
IFU
的32位shift
可能有两种情况,分别是分支指令时的imm_ext
和j
指令时的jumpAddr
。jumpAddr
是pc
要跳转到的地址,而imm_ext
还要在IFU
的npc
模块里完成进一步的处理才能成为分支指令时的npc
。
顶层电路
控制信号
1 | [1:0] RegDst // RegDst == 2'b00 写入rt对应的寄存器 (默认) |
add | sub | nop | ori | lw | sw | lui | beq | jal | jr | |
---|---|---|---|---|---|---|---|---|---|---|
[1:0] RegDst | 01 | 01 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 |
Branch | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
MemRead | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
MemtoReg | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
[1:0] ALUOp | 00 | 01 | 00 | 11 | 00 | 00 | 00 | 01 | 00 | 00 |
MemWrite | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
ALUSrc | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
RegWrite | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 |
isLui | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
isJal | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
isJr | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
jump | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
思考题
Q1:阅读下面给出的
DM
的输入示例中,根据你的理解回答,这个addr
信号是从哪里来的?地址信号addr
位数为什么是[11:2]而不是[9:0] ?A1:
addr
是访存地址,来自于ALU
的输出。在DM
中数据按字储存,故需要将addr
除以4。
Q2:在设计控制器时可以记录下指令对应的控制信号如何取值,也可以记录下控制信号每种取值所对应的指令。请分析两种做法各自的优劣。
Q2:
指令对应信号:优点是分析简单,只需要思考每条指令的数据通路即可获得控制信号取值;缺点是码量大,对于每个指令都要设置所有信号的取值。不够简洁。
信号对应指令:优点是简洁清晰(为每个信号设置默认值为0,在当前指令需要改变信号值时再更改);缺点是不够直观,容易出错。
Q3:在相应的部件中,复位信号的设计都是同步复位,这与
P3
中的设计要求不同。请对比同步复位与异步复位这两种方式的reset
信号与clk
信号优先级的关系。A3:同步复位时
clk
优先级高于reset
,只有在clk
处于上升沿时才考虑reset
信号。异步复位时reset
优先级高于clk
,只有reset
为低电平时才考虑时钟变化带来的影响。
Q4:C 语言是一种弱类型程序设计语言。C 语言中不对计算结果溢出进行处理,这意味着 C 语言要求程序员必须很清楚计算结果是否会导致溢出。因此,如果仅仅支持 C 语言,MIPS 指令的所有计算指令均可以忽略溢出。 请说明为什么在忽略溢出的前提下,addi 与 addiu 是等价的,add 与 addu 是等价的。
A4:这里通过
add
和addu
来说明。addu
的操作是简单的,我们考虑add
的操作:1
2
3
4
5
6temp = (GPR[rs][31] || GPR[rs]) + (GPR[rt][31] || GPR[rt])
if temp[32] ≠ temp[31] then
SignalException(IntegerOverflow)
else
GPR[rd] ← temp31..0
endif在上述操作中,我们将32位加数
A1
和A2
符号拓展至33位,他们的和记为temp
。temp
的低32位事实上就是A1
+A2
在不考虑溢出时的的结果(因为有溢出时这个溢出会被向上进位至33位)。