P7课上题目回忆和思路分享[BUAA-CO]
简要概述
P7上机共5题,前四题均为课下强测,分别为功能强测、转发阻塞强测、异常强测和中断强测,保证课下实现功能没有问题即可通过,最后一题是课上新指令题,可能是新指令或异常处理(第一次是withdraw
指令,涉及利用CP0中新增寄存器以实现撤销操作,具体内容可参考Lazyfish的博客)
T5 Watch Exception(第二次)
题目描述
新增异常Watch
,分为IMWatch
和DMWatch
,异常码均为5'd23
,要求在CP0中新增2个32位18、19号寄存器WatchLo
和WatchHi
,均可通过mtc0和mfc0读写。WatchLo
中高16位存放IM地址,低16位中存储DM地址,WatchHi[0]
用于全局监视使能的控制,Watch[1]
用于store类型指令监视使能的控制,WatchHi[2]
用于load类型指令监视使能的控制,WatchHi[3]
用于指令PC值监视使能的控制。
IMWatch
IM异常:当指令PC值与WatchLo
中高16位做32位0拓展后相等时,若全局监视使能和PC值监视使能均打开,则触发IMWatch异常。DMWatch
DM异常:当store指令的地址范围包含WatchLo
中低16位做32位0拓展后的地址时,若全局监视使能和store类型指令监视使能均打开,则触发DMWatch异常;当load指令的地址范围包含WatchLo
中低16位做32位0拓展后的地址时,若全局监视使能和load类型指令监视使能均打开,则触发DMWatch异常。- 注意:对于IM异常,优先级高于除PC值未对齐或地址越界外的其他异常;对于DM异常,不保证
WatchLo
中DM地址字段对齐,IMWatch
异常优先级低于取数存数异常AdEL
和AdES
。受害指令在延迟槽内时,IM异常记录的EPC为跳转指令;若受害指令是乘除器指令,则触发IM异常不应该触发乘除槽,即精确异常。
解题思路
个人认为至少有两种思路,下面简单叙述一下。
- 第一种是在D级判断D指令是否触发
IMWatch
异常,同时在冒险阻塞单元中特判如果D级或者M级是mtc0指令且修改了WatchLo
或WatchHi
寄存器,则将D级指令阻塞,直到阻塞结束得到了正确的WatchLo
和WatchHi
才判断。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]
是否打开,否则不触发异常。 - IM异常和DM也可以都在M级判断,只需要实现MDU的撤销操作,我的CPU架构中触发乘除槽后,当回合即会将计算结果存入
tempHi
和tempLo
寄存器,故在M级判断异常后,如果是受害指令是乘除槽相关指令,将tempHi
和tempLo
以及计数器、busy等清零即可;DM异常处理与第一种方法相同。
此题还需要注意,
WatchLo
和WatchHi
需要支持全部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扩展得到UpperAddress
和LowerAddress
,对[LowerAddress
, UpperAddress
)内的内存读写操作进行如下限制(注意地址区间范围的开闭)。
当LowerLimit[31:16]
与UpperLimit[31:16]
1的个数之和为奇数时只允许读,如果写将导致AdES
异常,当LowerLimit[31:16]
与UpperLimit[31:16
]1的个数之和为偶数时只允许写,如果读将导致AdEL
异常。
保证LowerLimit[15:0]
UpperLimit[15:0]
,且LowerLimit[15:0]
、UpperLimit[15:0]
在0x0000-0x3000
之间。若LowerLimit[15:0]
UpperLimit[15:0]
,则不限制任何内存读写。
解题思路
整理一下需要做的事,增加两个寄存器,修改MTC0
和MFC0
指令,把寄存器中的数据传到BE和DE中,在BE和DE中判断是否禁止读或者写,比较地址和区间的关系,如果存在限制且读/写则触发异常。
看着很简单,其实也确实如此,但最需要注意的是这个问题:地址只要包含了限制区间,同时在禁止读/写时进行了读/写操作,就会导致异常,那显然我们需要根据存取指令是字、半字还是字节来计算出操作的地址范围,然后与限制区间进行比较,如果存在交集,则触发异常。我们可以反过来,即判断存取指令的地址范围只落在限制范围的一侧,如此则不触发异常。