BUAA-CO-p5-课上

BUAA-CO-p5-课上

bmoal

op rs 00000 offset

cnt0num_of_zero(GPR[rs])cnt0 \leftarrow \operatorname{num\_of\_zero}(GPR[rs])

cnt1num_of_one(GPR[rs])cnt1 \leftarrow \operatorname{num\_of\_one}(GPR[rs])

conditioncnt1>cnt0condition \leftarrow cnt1 \gt cnt0

ifconditionthen\operatorname{if} condition \operatorname{then}

PCPC+4+sign_ext(offset02)\qquad PC \leftarrow PC + 4 + \operatorname{sign\_ext}(offset||0^2)

GPR[31]PC+8\qquad GPR[31] \leftarrow PC + 8

如果你在课下加过bltzal,那么这题就很简单了。在CMP中判断1的个数,如果符合标准,将Branch置1,然后将Branch送如CTRL和NPC,CTRL负责根据Branch生成写入地址,如果符合条件就往31里写PC+8,不符合就写入地址置0。需要注意的是Branch信号需要随流水往下传

lc

op rs rt offset

addr1GPR[rs]+sign_ext(offset)addr1 \leftarrow GPR[rs] + \operatorname{sign\_ext}(offset)

addrGPR[rt]+sign_ext(offset)addr \leftarrow GPR[rt] + \operatorname{sign\_ext}(offset)

data1Mem[addr1]data1 \leftarrow Mem[addr1]

dataMem[addr]data \leftarrow Mem[addr]

ifdata1>datathen\operatorname{if} data1 \gt data \operatorname{then}

GPR[data14..0]data1\qquad GPR[data1_{4..0}] \leftarrow data1

else\operatorname{else}

GPR[data4..0]data\qquad GPR[data_{4..0}] \leftarrow data

逆天指令,码量较大,码完了还有奇怪bug,爬了…

ae

op rs 00000 imm

temp16imm0  ^0temp_{16} \leftarrow imm_0 \space \hat \space 0

temp17imm1  ^imm0temp_{17} \leftarrow imm_1 \space \hat \space imm_0

temp18imm2  ^imm1temp_{18} \leftarrow imm_2 \space \hat \space imm_1

......

temp31imm15  ^imm14temp_{31} \leftarrow imm_{15} \space \hat \space imm_{14}

temp15..0imm15..0temp_{15..0} \leftarrow imm_{15..0}

GPR[rs]tempGPR[rs] \leftarrow temp

标准~~(?)~~的I型指令,只需要改ALU。但是这题课上的RTL语言有问题,所以建议先用Mars跑一遍,理解了指令真正的要求之后再码代码

课上加指令总结

写在前面

作为24届的学生,23届21届20届学长的博看肯定是不少看的,往年课上的考题也是不少研究的,但是今年P5能够明显感觉比往年难了不少(无论第一轮还是第二轮),主要表现在指令执行的动作更加灵活多变了,比如T2。以下经验仅适用于“没那么灵活”的指令,因为这些经验均是在练习往年题目时总结得到的,也许它们对以后上机的帮助没有那么大,但却是不得不掌握的基础。如果有下届同学看到此篇博客,祝好。

计算类:

  • 写入地址确定:只需要增加ALU的计算功能即可,TuseTnew与其他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] <- RDcondition: 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
    5
    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;

    同样的,要在M级CTRL中更新写入地址。

    1
    2
    3
    assign GRFWaddr = /* something else */ :
    (stage == M && new_instr) ? RD[4:0] :
    5'd0;

    在CTRL中更新写入地址的好处就是在mips顶层模块中无需进行特殊处理(如加线)与多路选择

作者

OWPETER

发布于

2024-11-18

更新于

2024-12-02

许可协议

评论