- 实验目的
1、理解五级流水线中冲突的产生条件以及类型模块,分析冲突对于流水线正常操作的影响以及它们可能会带来的错误执行结果,同时寻求解决方案,并改进原有代码使得流水线可以正常运行。
2、通过理解各种算法的运用,即解析它们的流程需要的指令,在本实验中包括最小公倍数、最大公因数、64位加法、冒泡排序等算法的解析,然后在五级流水线上进行跑指令运算,类似于上一次对于init_test的指令测试集,然后在板子上进行验证。
3、理解这3次项目来的整体思想,加深对于工程搭建以及五级流水线的理解,同时总结整一个项目下来的感想。 - 原理分析
- Hazard冲突的理解
对于之前的五级流水线的工程构建,我们一直都没有谈到冲突这么一回事,那么为什么会突然冒出这个东西出来呢?或者说它的存在是累赘吗?或者只是单单为了增强流水线的某方面性能呢?显然答案是冲突是个非常严重的问题,之前我们之所以没有谈到这个问题,同时它也仿佛没有给我们带来什么困扰,是因为我们的指令代码几乎每一行的后面都加3了个Nop指令,这是解决冲突的方法,但显然太笨了我们不可能对于一般的指令都去刻意地添加Nop使得程序得以正常运行,同时如果我们在上一次写代码的时候有留意的话,也会发现其实一些指令的后面加了Nop与没加是一样,但有一些确实一定要加的,其实当时我们可能可以大致推测到只要后面的两三条指令与前面指令的寄存器没有关系,那么就没有必要添加Nop,都能想到这一步了,那么问题也就开始接近我们的主题了,这其实就是我们遇到的一个常见的冲突,前面的指令对于某一个寄存器进行了赋值,但是下一条指令立即就要求使用该寄存器的值,那么这时候就会使用到之前留给该寄存器的值,而不是我们想要的,因为我们上一条指令的值还没有等到它赋给该寄存器的时间周期,我们就已经对它进行取值了,这就是一种冲突,只是举个例子,下面我们进行详细的讲解。
流水线的冲突对于具体的流水线来说,其实就是由于某些相关的存在使得指令流的下一条或者几条指令不能在指定的时钟准确执行。流水线的冲突通常包括了两种类型,第一是我们刚刚提到的数据冲突,我们可以理解为在指令执行时,我们的指令需要取到前一条指令还没有最终写到的寄存器的数值,这时就会取到错误的数值,专业一点的说法就是我们在安排指令时,当有关的指令(这里我们假定他们会使用到前面的指令处理的寄存器),靠得足够近时,它们在流水线中的重叠执行或者重新排序会改变指令读写操作数的顺序,使之不同于它们非流水实现时的顺序。我们可以简单借用一下老师上课时讲过的例子来看,左边是指令,右边是它们的一个执行周期列表,NG表示该指令出现了错误,而OK则表示可以正常运行,如图:
可以看到在第一条指令在第一个时钟周期执行之后,第二个时钟周期到来时,我们开始执行第二条指令,因为它的加法指令用到了3号寄存器,而3号寄存器的值需要刚好前一条指令加法执行后的结果,所以当在第二条指令译码时,取到的3号寄存器的值不是前一条指令执行后的值,因为时间还没到!,同样对于第三条指令,我们对于3号寄存器的需求也刚好在第一条指令得到结果之前,以此类推,只有当第五条指令到来时我们才能准确读到3号寄存器的值,(前提是在此之前,有有对3号寄存器做出什么赋值操作,否则我们的值又会错下去!!),当然对于第四条指令,可能有参考一些其他流水线的设计会发现,为什么也是错误的,答案是因为我们无法保证读到的刚好是在赋值之后,可能我们在设计的时候可以弄成前半周期写完操作,后半周期读完操作,这样就可以完美解决问题了,也使得第四条指令可以成功执行ÿ