概述
54条指令单周期CPU设计
单周期CPU即取指、译码、执行、访存、写回五个阶段一起放在一个周期内完成。数据流图如下:
静态流水线CPU设计
流水线CPU将取指、译码、执行、访存、写回分为五个周期完成。相较于单周期CPU,多周期流水线CPU时钟频率高,执行指令更高效。
在单周期CPU的基础上添加一些寄存器来存放每一个阶段所需的数据以及控制信号,每一个时钟周期到来,就将本阶段处理完的数据以及下个阶段所需的控制信号下推到下个阶段的寄存器中去。
静态流水线CPU与单周期CPU的不同之处在于将取指、译码、执行、访存、写回分为了五个时钟周期,以流水线的工作方式处理每一条指令,当遇到数据冲突问题时,采用流水线暂停的方式来避免数据冲突。静态流水线CPU除了使用单周期CPU所需部件之外,还需要为每一个阶段添加一些寄存器来存放当前阶段所需要的数据和控制指令。需要添加的部件为:
- IF_ID部件:存放取指阶段取出的指令,并在下一个时钟周期接收取指阶段取出的新指令,同时将当前指令送到下一个阶段有关部件。
- Judge部件:判断两个数是否相等以及一个数是否等于零,在提前分支预测(beq/bne等跳转指令)时需要用到。
- ID_EX部件:存放在译码阶段经过ctrl控制器输出的部分控制信号以及下一个阶段处理所需的数据(从Regfiles寄存器堆中取出的数据)。并在下一个时钟周期将这些数据传到下一个阶段有关部件。
- EX_MEM部件:存放执行阶段处理后的数据以及一部分从ID_EX部件传过来的控制信号和数据,并在下一个时钟周期将这些数据传递给下一个阶段有关部件。
- MEM_WB部件:存放访存阶段从数据存储器中读取出来的数据以及从EX_MEM部件传递过来的控制信号,并在下一个时钟周期将这些数据传到下一阶段有关部件。
数据流图如下:(对照着数据流图很快就可以将各个部件组装成CPU)
动态流水线CPU设计
与静态流水线CPU有所不同的是,静态流水线CPU遇到数据冲突问题时采用暂停的方式避免冲突,而动态流水线则采用内部前推以及必要暂停(lw指令数据相关时)的方式来避免冲突,因此我们需要在静态流水线CPU的基础上添加多一些寄存器。
- fwda部件:数据选择器,选择EXE阶段处理的数据,可以是当前指令取出的Regfiles寄存器堆数据,也可以是从EXE阶段或者MEM阶段的前推过来的数据。
- fwdb部件:功能同fwda部件
数据流图如下
静态流水线仿真实例:
- 数据冲突
先执行addu $8,$3,$4,再执行addu $9,$8,$5,会引发数据冲突
从仿真波形中,我们可以看到addu $9,$8,$5在译码阶段得到的rs操作数的地址rsc为0x08与正在EXE级执行的addu $8,$3,$4执行的写回寄存器地址Ex_rf_waddr为0x08相同,产生数据冲突。按照静态流水线的处理方式应该做暂停处理。一共暂停了3个时钟周期,等到addu $8,$3,$4将运算结果写回寄存器0x08之后,此时addu $9,$8,$5的EXE级的ex_rs读取到0x08寄存器的数据后,可以继续向下执行。
- 跳转指令
执行的指令为beq $1,$2,0x00000007,机器码为0x10220007
从波形图中我们可以看到,在紧跟0x10220007机器指令后面紧跟一条0x00000000指令,这是一个延迟槽,这条延迟槽指令不会改变CPU的状态。而提前分支预测即是在译码阶段就判断是否需要跳转,如图所示,在译码阶段结束之后,下一个周期之后取指阶段的pc值就变成了0x00400048,即为跳转的目标地址。
动态流水线仿真实例:
- 数据冲突
先执行addu $8,$3,$4指令,再执行addu $9,$8,$5,引发数据冲突
从仿真图中我们可以看出,先执行addu $8,$3,$4执行再执行addu $9,$8,$5指令时,并没有出现流水线暂停现象。在addu $9,$8,$5指令译码阶段,控制器检测到$8寄存器需要被EXE级执行的addu $8,$3,$4指令写回,于是设置fwda数据选择器的控制信号,使EXE级的运算结果通过数据旁路内部前推至addu $9,$8,$5的译码阶段,如波形图中执行阶段的黄色箭头所指,这样就避免了数据冲突而导致流水线暂停的问题。
- 由于lw指令引发的数据冲突
先执行lw $11,0x00000004($31)指令,再执行sub $12,$10,$11指令,$11初始值为0x0000000b,而执行完lw指令后值为0x00000005,由于sub $12,$10,$11指令在译码时,lw指令还在执行EXE级,所以需要暂停一个时钟周期等到lw指令在MEM级将数据从DMEM存储器中取出后前推至sub $12,$10,$11指令的ID级之后sub指令才能继续执行。
从波形图中可以看出,sub指令在译码阶段暂停了一个周期,等到rt的值从0x0000000b变为0x00000005之后才继续执行。
- 跳转指令
执行beq $1,$2,0x00000007指令,后面接一条sll $0,$0,0作为延迟槽,无论分支成功与否总是被执行。
从波形图上可以看出,在beq指令在译码阶段判断出了是否需要跳转,在下一个周期就改变了pc的值,跳转成功。
总结
- 从原有的单周期CPU转换到静态流水线其实并不是一件很难的事情,只不过是在原来单周期的数据流上加上一些寄存器来保存当前已经处理好的数据,并让出处理这些数据的相关部件,使得这些部件可以被接下来的指令使用。然后使用时钟控制,使暂时保存在寄存器中的中间数据流向下一个部件,如此进行下去,一直到处理完毕。
- 每一条指令的数据通路图以及整体的数据通路图、控制信号表对于CPU的编码和Debug都起着至关重要的作用。在写代码之前,先在思考每一条指令的执行过程,然后画出所需的数据通路图,并写出所需的控制信号。在写代码时,每画出一条线,就在草稿纸上将该线涂上颜色,这样就可以使的编码的思路非常清晰。Debug的时候将CPU内部的一些数据线拉出来显示在modelsim上,仿真出错时,可以查看对应的数据是否有问题,进一步可以查看数据通路是否有问题、控制信号是否有问题。这样可以使得效率大大提高。
最后
以上就是朴实菠萝为你收集整理的组成原理-CPU设计的全部内容,希望文章能够帮你解决组成原理-CPU设计所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复