课程project复习 - CPU-hazard
2016-03-24 20:50
204 查看
一、什么是hazards
hazards是CPU在当前周期无法获取所要取的寄存器的值的问题。出现情况主要分为以下三种:
1、一般计算
第一个ADD将和赋给gr3,第二个ADD则是要用到gr3的值。如果第二个ADD想要gr3的值,必须等到第一个ADD执行到WB阶段,才能得到gr3被更新之后的值。所以还要等3个周期。因此,中间的三个ADD其实都应该换成nop,否则gr3就是更新之前的值,导致最后的结果不是我们实际想要的。
软件的解决方法就是添加nop了,但现在要用硬件的解决办法:data_forwarding:其实不用等到第一个ADD执行到WB才能得到更新之后的gr3的值,因为这个值是在ID和EX之间(ALU)计算出来的,然后存入了ALUo,进而赋给reg_C、reg_C1,最后才到gr3。所以可以通过data forwarding,利用这些提前得到计算结果的中间变量给reg_A/B赋值,如下图所示:
2、LOAD指令
通过data forwarding解决了两个计算指令之间的冲突,但是它不能解决所有的赋值问题。LOAD的问题就不能:
因为LOAD指令是从内存中取值,所以ALU计算出来的ALUo和赋给的reg_C都只是从内存中取值的地址,而不是从内存中得到的值。这个值是在MEM阶段才得到的。所以中间必须等待一个周期,才能用data forwarding的方式,获取d_datain的值。这种方法就是Stall。
实现方式:在下个周期内,维持pc的值。然后id_ir赋为nop指令,也就是什么都不做。(所以其实和软件实现的思路一样……)
3、跳转指令
如果当前指令已经是跳转指令了,那么,肯定不能让在指令内存中紧接着的指令执行了,否则可能会导致意想之外的情况发生。
怎么解决呢?方法依然是Stall,因为要保持pc不变。
二、代码实现
通过前面对hazards的两种情况的解释,应该对实现有一个大致的框架了:用组合逻辑实现,每次判断id_ir和ex_ir、mem_ir、wb_ir之间的关系,然后将判断结果写入变量中,供下一个周期到来时,CPU判断是否需要data forwarding或者stall。
1、data forwarding
① change_ex、change_mem、change_wb:判断前1~3条指令是否会修改r1的值(必要性:如果都不会修改寄存器的值,就不需要data forwarding了)
② spe_idir:大部分计算指令的reg_A对应的寄存器的地址都是id_ir的6~4位,但是ADDI、SUBI和LDIH这三个比较特殊,reg_A是10~8位,由于这个位置是接下来判断是否需要data forwarding的关键,所以要特别区分这种状态。
③ needForwardRegA、needForwardRegB:判断当前指令是否会修改r1的值
④ ForwardRegA、ForwardRegB:是否需要进行data forwarding,如果需要,又要判断和哪个指令发生了hazards,以确定reg_A/B应该取什么值
⑤ ForwardSmdr:这个是后来才发现的问题,别忘了ID阶段还对smdr赋值了,这个变量储存了执行STORE的时候储存进内存的值,它的值也是从寄存器中取的,所以也要进行data forwarding:
⑥ ID阶段,对reg_A、reg_B、smdr的赋值:
reg_A:
reg_B:
smdr:
2、Stall
① needRegA、needRegB:判断i_datain是不是需要从寄存器中取值
② stallPc、stallInstr:在needRegA和needRegB的基础上,判断id_ir是不是LOAD指令、寄存器地址是否对应、是不是跳转指令,进而判断是否需要stall
③ 在IF阶段对PC和id_ir的赋值
三、板上验证
经过前面好多步骤终于写好了hazard,下一步就是验证它能不能工作了。测试代码就是修改instr_mem的指令,修改data_mem的数据。而指令都是类似汇编语言的指令,其实只要根据每一个指令的结构认真阅读,就可以理解了。
1、冒泡排序
2、最小公倍数、最大公约数
四、资料下载
代码&测试代码
hazards是CPU在当前周期无法获取所要取的寄存器的值的问题。出现情况主要分为以下三种:
1、一般计算
第一个ADD将和赋给gr3,第二个ADD则是要用到gr3的值。如果第二个ADD想要gr3的值,必须等到第一个ADD执行到WB阶段,才能得到gr3被更新之后的值。所以还要等3个周期。因此,中间的三个ADD其实都应该换成nop,否则gr3就是更新之前的值,导致最后的结果不是我们实际想要的。
软件的解决方法就是添加nop了,但现在要用硬件的解决办法:data_forwarding:其实不用等到第一个ADD执行到WB才能得到更新之后的gr3的值,因为这个值是在ID和EX之间(ALU)计算出来的,然后存入了ALUo,进而赋给reg_C、reg_C1,最后才到gr3。所以可以通过data forwarding,利用这些提前得到计算结果的中间变量给reg_A/B赋值,如下图所示:
2、LOAD指令
通过data forwarding解决了两个计算指令之间的冲突,但是它不能解决所有的赋值问题。LOAD的问题就不能:
因为LOAD指令是从内存中取值,所以ALU计算出来的ALUo和赋给的reg_C都只是从内存中取值的地址,而不是从内存中得到的值。这个值是在MEM阶段才得到的。所以中间必须等待一个周期,才能用data forwarding的方式,获取d_datain的值。这种方法就是Stall。
实现方式:在下个周期内,维持pc的值。然后id_ir赋为nop指令,也就是什么都不做。(所以其实和软件实现的思路一样……)
3、跳转指令
如果当前指令已经是跳转指令了,那么,肯定不能让在指令内存中紧接着的指令执行了,否则可能会导致意想之外的情况发生。
怎么解决呢?方法依然是Stall,因为要保持pc不变。
二、代码实现
通过前面对hazards的两种情况的解释,应该对实现有一个大致的框架了:用组合逻辑实现,每次判断id_ir和ex_ir、mem_ir、wb_ir之间的关系,然后将判断结果写入变量中,供下一个周期到来时,CPU判断是否需要data forwarding或者stall。
1、data forwarding
① change_ex、change_mem、change_wb:判断前1~3条指令是否会修改r1的值(必要性:如果都不会修改寄存器的值,就不需要data forwarding了)
② spe_idir:大部分计算指令的reg_A对应的寄存器的地址都是id_ir的6~4位,但是ADDI、SUBI和LDIH这三个比较特殊,reg_A是10~8位,由于这个位置是接下来判断是否需要data forwarding的关键,所以要特别区分这种状态。
③ needForwardRegA、needForwardRegB:判断当前指令是否会修改r1的值
④ ForwardRegA、ForwardRegB:是否需要进行data forwarding,如果需要,又要判断和哪个指令发生了hazards,以确定reg_A/B应该取什么值
⑤ ForwardSmdr:这个是后来才发现的问题,别忘了ID阶段还对smdr赋值了,这个变量储存了执行STORE的时候储存进内存的值,它的值也是从寄存器中取的,所以也要进行data forwarding:
⑥ ID阶段,对reg_A、reg_B、smdr的赋值:
reg_A:
reg_B:
smdr:
2、Stall
① needRegA、needRegB:判断i_datain是不是需要从寄存器中取值
② stallPc、stallInstr:在needRegA和needRegB的基础上,判断id_ir是不是LOAD指令、寄存器地址是否对应、是不是跳转指令,进而判断是否需要stall
③ 在IF阶段对PC和id_ir的赋值
三、板上验证
经过前面好多步骤终于写好了hazard,下一步就是验证它能不能工作了。测试代码就是修改instr_mem的指令,修改data_mem的数据。而指令都是类似汇编语言的指令,其实只要根据每一个指令的结构认真阅读,就可以理解了。
1、冒泡排序
2、最小公倍数、最大公约数
四、资料下载
代码&测试代码
相关文章推荐
- js数组的splice函数
- TextView设置文字大小
- VS2010关于error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
- poj2411(轮廓线动态规划)
- 15个数的大小
- Linux软件包安装命令
- bindservice流程梳理
- 微软笔试-Professor Q's Software
- 深入浅出linux系统umask值及其对应的文件权限讲解
- eclipse安装gpd插件以及部署jBPM4.4示例
- h264码率设定建议
- 第三周项目三(1)-输出星号图
- 关于搭建环境时的异常The web application [] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to un
- BZOJ_P2440 [中山市选2011]完全平方数(数论+莫比乌斯反演+容斥原理)
- 【BZOJ4454】C Language Practice
- Problem E
- 哎,说好坚持,又拖延了,踏实现在,展望未来
- 第四周项目5-用递归方法求解(1)求n的阶乘
- PAT乙级1002
- 项目 2-太乐了