BUAA-CO-p5-课上
bmoal
op | rs | 00000 | offset |
---|
如果你在课下加过bltzal
,那么这题就很简单了。在CMP中判断1的个数,如果符合标准,将Branch
置1,然后将Branch
送如CTRL和NPC,CTRL负责根据Branch
生成写入地址,如果符合条件就往31里写PC+8,不符合就写入地址置0。需要注意的是Branch
信号需要随流水往下传
lc
op | rs | rt | offset |
---|
逆天指令,码量较大,码完了还有奇怪bug,爬了…
ae
op | rs | 00000 | imm |
---|
标准~~(?)~~的I
型指令,只需要改ALU
。但是这题课上的RTL语言有问题,所以建议先用Mars跑一遍,理解了指令真正的要求之后再码代码
课上加指令总结
写在前面
作为24届的学生,23届21届20届学长的博看肯定是不少看的,往年课上的考题也是不少研究的,但是今年P5能够明显感觉比往年难了不少(无论第一轮还是第二轮),主要表现在指令执行的动作更加灵活多变了,比如T2。以下经验仅适用于“没那么灵活”的指令,因为这些经验均是在练习往年题目时总结得到的,也许它们对以后上机的帮助没有那么大,但却是不得不掌握的基础。如果有下届同学看到此篇博客,祝好。
计算类:
- 写入地址确定:只需要增加ALU的计算功能即可,
Tuse
和Tnew
与其他R指令保持一致即可 - 写入地址不确定:阻塞一个周期,待指令进入M级后恢复,这时写入地址被算出,可以进行正常转发
条件Branch/Jump:
增加CMP模块功能,用CMP模块判断跳转条件(因此Tuse=0
)
-
条件跳转 + 无条件连接:正常给
GRFWaddr
赋值即可,无需特别处理 -
条件跳转 + 条件连接:让
D_Branch
信号随指令一起流水,在CTRL中使写能信号赋值处加上和该级Branch
的逻辑与 -
清空延迟槽:
Forward Control
模块加入D_Branch
端口,如果是新指令且不跳转则清空延迟槽,但如果正在阻塞则不清空,即FD_EN = (new_instr && ~D_Branch) && ~stall;
条件Load:
一般来说,这个条件是由DM
的读数决定的,因此我们可以在DM
中生成check
信号并输入到M_CTRL
中,据此生成M_GPRWaddr
。但由于正确的check
(亦即正确的写入地址)到M级才能获得,所以我们需要对可能的写入地址都进行阻塞
-
condition: GPR[rt] <- RD; else: GPR[rs] <- RD
或condition: GPR[rt] <- RD; else: not_write
:这两类本质上是一样的,因为我的GRF没有写使能,若不写则将GPRWaddr
设为0即可。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// E级阻塞rs rt,M级不做特殊处理
// E_Tnew=1, M_Tnew=0
assign stall = (D_rs != 0 && T_use_rs < E_T_new && (E_new_instr ? (D_rs == E_rs || D_rs == E_rt) : D_rs == E_GPRWaddr)) ? 1 :
(D_rt != 0 && T_use_rt < E_T_new && (E_new_instr ? (D_rt == E_rs || D_rt == E_rt) : D_rt == E_GPRWaddr)) ? 1 :
(D_rs != 0 && T_use_rs < M_T_new && D_rs == M_GPRWaddr) ? 1 :
(D_rt != 0 && T_use_rt < M_T_new && D_rt == M_GPRWaddr) ? 1 :
0;
// E、M级阻塞rs rt
// E_Tnew=2, M_Tnew=1
assign stall = (D_rs != 0 && T_use_rs < E_T_new && (E_new_instr ? (D_rs == E_rs || D_rs == E_rt) : D_rs == E_GPRWaddr)) ? 1 :
(D_rt != 0 && T_use_rt < E_T_new && (E_new_instr ? (D_rt == E_rs || D_rt == E_rt) : D_rt == E_GPRWaddr)) ? 1 :
(D_rs != 0 && T_use_rs < M_T_new && (M_new_instr ? (D_rs == M_rs || D_rs == M_rt) : D_rs == M_GPRWaddr)) ? 1 :
(D_rt != 0 && T_use_rt < M_T_new && (M_new_instr ? (D_rt == M_rs || D_rt == M_rt) : D_rt == M_GPRWaddr)) ? 1 :
0;
// E M级全阻塞
// 同上
assign stall = (D_rs != 0 && T_use_rs < E_T_new && (E_new_instr ? 1 : D_rs == E_GPRWaddr)) ? 1 :
(D_rt != 0 && T_use_rt < E_T_new && (E_new_instr ? 1 : D_rt == E_GPRWaddr)) ? 1 :
(D_rs != 0 && T_use_rs < M_T_new && (M_new_instr ? 1 : D_rs == M_GPRWaddr)) ? 1 :
(D_rt != 0 && T_use_rt < M_T_new && (M_new_instr ? 1 : D_rt == M_GPRWaddr)) ? 1 :
0; -
GPR[RD[4:0]] <- RD
,即写入地址取决于RD的值。这种情况需要在W级才能知道写入地址,因此E级和M级都需要进行全阻塞。
1
2
3
4
5assign stall = (D_rs != 0 && T_use_rs < E_T_new && (E_new_instr ? 1 : D_rs == E_GPRWaddr)) ? 1 :
(D_rt != 0 && T_use_rt < E_T_new && (E_new_instr ? 1 : D_rt == E_GPRWaddr)) ? 1 :
(D_rs != 0 && T_use_rs < M_T_new && (M_new_instr ? 1 : D_rs == M_GPRWaddr)) ? 1 :
(D_rt != 0 && T_use_rt < M_T_new && (M_new_instr ? 1 : D_rt == M_GPRWaddr)) ? 1 :
0;同样的,要在M级CTRL中更新写入地址。
1
2
3assign GRFWaddr = /* something else */ :
(stage == M && new_instr) ? RD[4:0] :
5'd0;在CTRL中更新写入地址的好处就是在mips顶层模块中无需进行特殊处理(如加线)与多路选择
BUAA-CO-p5-课上