简要概述

P7上机共5题,前四题均为课下强测,分别为功能强测转发阻塞强测异常强测中断强测,保证课下实现功能没有问题即可通过,最后一题是课上新指令题,可能是新指令或异常处理(第一次是withdraw指令,涉及利用CP0中新增寄存器以实现撤销操作,具体内容可参考Lazyfish的博客

T5 Watch Exception(第二次)

题目描述

新增异常Watch,分为IMWatchDMWatch,异常码均为5'd23,要求在CP0中新增2个32位18、19号寄存器WatchLoWatchHi,均可通过mtc0和mfc0读写。WatchLo中高16位存放IM地址,低16位中存储DM地址,WatchHi[0]用于全局监视使能的控制,Watch[1]用于store类型指令监视使能的控制,WatchHi[2]用于load类型指令监视使能的控制,WatchHi[3]用于指令PC值监视使能的控制。

  • IMWatchIM异常:当指令PC值与WatchLo中高16位做32位0拓展后相等时,若全局监视使能和PC值监视使能均打开,则触发IMWatch异常。
  • DMWatchDM异常:当store指令的地址范围包含WatchLo中低16位做32位0拓展后的地址时,若全局监视使能和store类型指令监视使能均打开,则触发DMWatch异常;当load指令的地址范围包含WatchLo中低16位做32位0拓展后的地址时,若全局监视使能和load类型指令监视使能均打开,则触发DMWatch异常。
  • 注意:对于IM异常,优先级高于除PC值未对齐或地址越界外的其他异常;对于DM异常,不保证WatchLo中DM地址字段对齐,IMWatch异常优先级低于取数存数异常AdELAdES。受害指令在延迟槽内时,IM异常记录的EPC为跳转指令;若受害指令是乘除器指令,则触发IM异常不应该触发乘除槽,即精确异常。

解题思路

个人认为至少有两种思路,下面简单叙述一下。

  1. 第一种是在D级判断D指令是否触发IMWatch异常,同时在冒险阻塞单元中特判如果D级或者M级是mtc0指令且修改了WatchLoWatchHi寄存器,则将D级指令阻塞,直到阻塞结束得到了正确的WatchLoWatchHi才判断。E级乘除器MDU需要特判出现IMWatch异常则禁止乘除槽。对于DMWatch异常,需要针对不同存取指令比较WatchLo[16:0]拓展后的地址范围,如lw或者sw指令比较[32:2]是否相等,lh或sh指令比较[32:1]是否相等,lb或sb指令比较[32:0]是否相等。注意需要特判WatchHi[0]WatchHi[1]WatchHi[2]WatchHi[3]是否打开,否则不触发异常。
  2. IM异常和DM也可以都在M级判断,只需要实现MDU的撤销操作,我的CPU架构中触发乘除槽后,当回合即会将计算结果存入tempHitempLo寄存器,故在M级判断异常后,如果是受害指令是乘除槽相关指令,将tempHitempLo以及计数器、busy等清零即可;DM异常处理与第一种方法相同。

此题还需要注意,WatchLoWatchHi需要支持全部32位的读写,不能在F级判断IM异常,否则需要阻塞前面的mtc0指令一直到M级结束,这将导致TLE。

T5 Memory Limitation(第三次)

题目描述

在CP0中添加32位18号寄存器LowerLimit,32位19号寄存器UpperLimit,可正常通过mtc0/mfc0修改内容,UpperLimit[15:0]LowerLimit[15:0]存上下界内存地址的[15:0],通过32位0扩展得到UpperAddressLowerAddress,对[LowerAddress, UpperAddress)内的内存读写操作进行如下限制(注意地址区间范围的开闭)。
LowerLimit[31:16]UpperLimit[31:16]1的个数之和为奇数时只允许读,如果写将导致AdES异常,当LowerLimit[31:16]UpperLimit[31:16]1的个数之和为偶数时只允许写,如果读将导致AdEL异常。
保证LowerLimit[15:0] \leqslant UpperLimit[15:0],且LowerLimit[15:0]UpperLimit[15:0]0x0000-0x3000之间。若LowerLimit[15:0] == UpperLimit[15:0],则不限制任何内存读写。

解题思路

整理一下需要做的事,增加两个寄存器,修改MTC0MFC0指令,把寄存器中的数据传到BE和DE中,在BE和DE中判断是否禁止读或者写,比较地址和区间的关系,如果存在限制且读/写则触发异常。
看着很简单,其实也确实如此,但最需要注意的是这个问题:地址只要包含了限制区间,同时在禁止读/写时进行了读/写操作,就会导致异常,那显然我们需要根据存取指令是字、半字还是字节来计算出操作的地址范围,然后与限制区间进行比较,如果存在交集,则触发异常。我们可以反过来,即判断存取指令的地址范围只落在限制范围的一侧,如此则不触发异常。