博客及仓库

苯人P7学的非常的水,对很多东西理解的都不到位,害怕误导大家,所以索性就放一些别的同学的博客,供大家参考

每年的教程和要求都会有不同程度的改动,大家还是要以自己的教程要求为准

19级-rfhits-P7仓库

21级-Bluebean的博客

P7 课下 & 课上总结 - 北航计算机组成原理 | Test Blog = FlyingLandlord’s Blog

[BUAA-CO-Lab] P7 MIPS 微体系 | ROIFE BLOG

BUAA-CO/p7 at master · roife/BUAA-CO (github.com)

BUAA-CO-2021/P7 at master · flyinglandlord/BUAA-CO-2021 (github.com)

下面几个是学长的设计文档,可能在测试上能提供一些帮助

【BUAA-CO】p7流水线CPU-Ultra | volca’s blog (volcaxiao.top)

P7 设计文档 | TARDIS (steve-strange.github.io)

讨论区一些很好的贴子

部分P7课下易错点

王暄雨 2218**** (学生)

以下只是我个人总结的一些易错点,如有错误欢迎大家批评指正。

1.当 *CP0* 中的 *Req* 信号处于高位时

  • 清空 D, E, M, W 级流水线寄存器。
  • PC 的值强制修改到异常处理程序的入口:32'h00004180
  • 保证异常发生时不会对 DM 等外部模块产生写信号(即 m_data_byteen == 4'h0)。
  • 正处于 E 级的指令不应修改乘除模块。

2.优先级

  • 中断的优先级要高于异常,在写CP0时要注意
  • reset > Req > eret > stall,在写pc时要注意

3.特殊处理PC和Delayslot

当处于阻塞时外部产生了中断信号,我们记录的 EPC 将会是 0。这会导致错误的产生。

所以要在阻塞时让 pcBD 这两个信号依旧正常流水。

4.延迟槽异常的特殊处理

对于异常情况只要考虑异常指令是不是延迟槽指令,如果是延迟槽指令,那么存的是异常指令的 PC - 4,如果不是,那么就存异常指令的 PC。

P7第二次上机题目分享

蒋孝淳 2237**** (学生)

分享一下本学期第二次P7上机的题目及笔者的实现思路,供大家交流与参考~

本次上机共5题,完成4题即可通过。其中前4题是对课下的强测,第5题为指令的修改。

前四题

分别针对所实现cpu的功能异常中断冒险进行强测,如果课下的实现没有问题,应该能够顺利通过。

第五题

题意转译

条件判断访问外设im和dm的地址是否在合法区间中,其中im(即取值pc)合法区间为,dm(即读写合法区间)为。 题面很长,主要有两层意思。

  1. cp0模块中新增7号寄存器和21号寄存器,应使它们可以通过mfc0mtc0指令正常访问。
    其中7号寄存器在片选信号sel(即这两条指令的后三位,见英文指令集)为0时,保存数值为imLoBoundarysel为1时,保存数值为dmLoBoundary
    21号寄存器在片选信号sel为0时,保存数值为imHiBoundarysel为1时,保存数值为dmHiBoundary
    image-20231220203604596
  2. 实现cp0SR寄存器的16、17位。 当且仅当SR[16]==1时,对访问im的地址合法性进行检查。若不合法,应给出AdEL异常。
    当且仅当SR[17]==1时,对访问dm的地址合法性进行检查。若为load型指令且不合法,给出AdEL异常;若为Store型指令且不合法,给出AdES异常。
    应当保证其他指令不会出现课下没有实现过的异常。

需要注意的地方: 以一个例子说明,lw指令计算出来的地址为0x0000_0000,那么你需要保证0x0000_0003也要在合法区间中;而且只需要考虑dm,无需考虑时钟或中断发生器的访问地址。

做法分享

针对1,只需要在cp0中增加相关寄存器,并修改mfc0mtc0的相关实现即可。

针对2,只需要将cp0中的check信号和边界信息给出,并增加相关异常的判断即可。

此外,cp0指令可能带来修改check信号/修改边界信息带来的“后续指令对im访问不合法,但缺少阻塞”问题,将新增的检查与cp0放在流水线同一级(笔者的设计中,位于M级),此时能够保证指令到达该处时,前面的指令对cp0中寄存器的更新已经完成(如有),保证运行的正确性。

以上就是P7第二次上机的主要题目分析,欢迎有兴趣的同学继续研究讨论~

预祝各位同学上机顺利,取得理想的成绩!

p7-课下总结

童欣 2237**** (学生)

以下是我在写p7课下时看教程与博客产生的一些问题,记录一下它们的回答~

eret不支持延迟槽,若正常操作会带来什么影响?应如何操作以避免这种影响?

image-20231220203703710如图所示,

设计1:当eret流到D级时检测eret,并把F级NPC改成EPC.

NPC = (D_eret) ? EPC : else;

导致的问题:直接类比beq的跳转,eret的下一条指令A不可避免地会从IM中被取出来,而它本来不应该流进来的.故这样的设计会导致PC一个周期的错误.但是,之前beq如此设计是因为只有流到D级利用D级CMP模块比较两个数,才能得到跳转结果(即NPC);而eret的下一条指令的PC一定是EPC.

所以改成设计2:当eret流到D级时检测eret,若为eret则F级PC直接输出为EPC,否则仍为原来的值.NPC从而为PC + 4

F_PC = (D_eret) ? EPC : F_PC_tmp;
F_NPC = (D_eret) ? EPC + 4;

直观的图像表示:(来自答疑时一位同学画的图)

image-20231220203739649

syscall的exccode在哪一级判断?

无所谓.在我的设计中,我在D级判断.

不过其实在教程中异常处理流的实现->异常码这一节中,异常码exccode越小的异常,优先级越高.

在未出现异常时,exccode应该用哪个数字表示?

教程中,中断的exccode为0,但是中断是从外部输入的,与内部异常无关;而exccode是由内部异常被判断出来的.故把未出现异常的exccode设置为0即可. (不要设置一些奇怪的数,比如5'd31之类的()一是因为上机可能增加新的异常exccode,二是因为这样每一级判断exccode的时候把异常exccode当成"非零值",而非"非31值"处理,从而出错)

F级中NPC模块对rst/req/stall/eret的处理?

  • 优先级rst>req>stall>D_eret
  • 为什么req>D_eret? 其实这种情况不会发生.req的同时D_eret,意味着异常处理程序出现了异常,而这是得到保证不会出现的.
  • 为什么stall>D_eret? 当D_eret和stall同时发生,即D级是eret,E/M级存在mtc0指令产生stall信号,这意味着EPC还没有准备好,还需要再stall一会儿.那么必须要优先处理stall,再处理D_eret.
  • 以上讨论也可以理解为,D_eret只是流水级内部的一个小指令,而req/stall都更为宏观,故应处理更为宏观的信号.

PC\bd在流水时对rst/req/stall的异常处理?

(基于CP0设置在M级)

  • bd在F级判断后,向后流水,直至流到CP0模块用于判断EPC

  • rst清空:PC归为32'h0000_3000,其它信号都为0

    req清空:PC归为32'h0000_4180,其它信号都为0

    注意以下的信号优先级!!否则中测会出现interrupt count的问题!

  • FD级:优先级:rst>req>stall

    • rst:全部流水信号按照rst清空;
    • req:部分流水信号按照req清空
    • stall:所有流水信号保持不变.
  • DE级:优先级rst>req>stall

    • rst:全部流水信号按照rst清空;
    • req:全部流水信号按照req清空
    • stall:部分流水信号清空,PC,bd继续向下一级正常流水
  • EM级:优先级rst>req

    • rst:全部流水信号按照rst清空
    • req:全部流水信号按照req清空
  • MW级:优先级rst>req

    • rst:全部流水信号按照rst清空
    • req:全部流水信号按照req清空

怎么保证异常指令不会产生结果?

这里的结果指向各种寄存器里存进去了值,包括GRF,DM,hi,lo 一种比较粗暴的实现方法:假如这条指令有异常,那么就把它视作nop向后流水,具体来说是这样:

E_instr = (E_exccode != 0) ? 0 : E_instr_tmp;//以E级要从EM流水线寄存器向M级流水的E_instr为例子

通过这种方法,大多数异常指令都将不能发挥作用.但是当CP0放在M级时,有可能产生一个小bug,见下一个问题

CP0设在M级时,怎么保证DM不会存进异常指令让它存的值?

有两种方法.

  • 法一:将存数/取数异常(adel/ades)置于E级判断.即在ALU运算出ALU_result之后,判断其是否是这两种异常,得到E_exccode. 由上一个问题的例子可知,因为E_exccode不为0,我们将从E级准备向M级流水的E_instr清零了,从而M级得不到存数/取数的相关 信息, 不会对DM产生影响.

  • 法二:将存数/取数异常(adel/ades)置于M级初判断,得到M_exccode接入CP0.若CP0显示产生异常(即req为1),那么将DM的写使能byteen置0,从而无法写入(这里易错,上一个问题提到的"视为nop"处理方法在这种架构中会因为太晚判断(即到了CP0所在级才判断)exccode而失效,必须要改DM写使能)

    具体来说:

    assign m_data_byteen = (req) ? 4'b0 :
    m_data_byteen_tmp;

乘除槽MDU怎么对中断信号进行反应?

根据教程P7提交要求->中断异常约束中下图:

image-20231220203800618

我们只需要在mult/div/multu/divu等乘除法相关指令的启动信号判断中加入!req,在mthi/mtlo等写hi/lo相关指令的写使能信号中加入!req即可.

p7课上题目记录

张奕彤 2237****(学生)

前四题

  • 前四题均是对课下正确性的检验,没有任何需要新增的指令。

第五题

  • 第五题需要新增两条指令(ll与sc),感觉难度并不低。
  • 首先需要做的是在CP0内增加一个一位的寄存器LLbit。
  • LL类似LW,SC类似SW,可以访问或存储计时器的外设和DM,异常类型分别与LW,SW相同。
LL指令(Load Linked Word)
  • 编码:

image-20231220204331143

  • 格式:ll rt, offset(base)
  • 描述:
    • GPR[rt] ← memory[GPR[base] + offset];
    • LLbit置为高电平。
  • 操作:
vAddr ← sign_extend(offset) + GPR[base]
if vAddr1..0 ≠ 2'b00 then
SignalException(AddressError)
endif
GPR[rt] ← memory[GPR[base] + offset]
LLbit ← 1
  • 其他:当reset为高电平或者eret指令执行时,LLbit需要置为低电平。
SC指令(Store Conditional Word)
  • 编码:

image-20231220204312898

  • 格式:sc rt, offset(base)
  • 描述:
    • 如果LLbit为高电平,则将GPR[rt]存入memory[GPR[base] + offset];
    • 无论LLbit是否为高电平,均需要将LLbit无符号扩展至32位存入GPR[rt]。
  • 操作:
vAddr ← sign_extend(offset) + GPR[base]
if vAddr1..0 ≠ 2'b00 then
SignalException(AddressError)
endif
if LLbit then
memory[GPR[base] + offset] ← GPR[rt]
endif
GPR[rt]← 31'b0 || LLbit
  • 其他:记得不太清楚了,大概是为了保证数据合法性的约束,不过我当时做的时候并没有多么考虑这条指令的其他部分。