3

cpu设计和实现(流水线暂停)

 1 year ago
source link: https://blog.csdn.net/feixiaoxing/article/details/128065698
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

cpu设计和实现(流水线暂停)

嵌入式-老费 已于 2022-11-27 17:40:43 修改 474

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        前面我们说过,数字电路里面流水线的引入,主要是为了提高数据的处理效率。那么,鉴于此,为什么又要对流水线进行暂停处理呢?直接在某一个阶段,把所有的工作都完成不行吗?举个例子来说,如果指令在exe阶段的时候,同时需要处理乘法和加法(madd指令),那样不是也可以吗。其实,这么做,确实是可以的。但是,真的这么做的话,会大幅度降低时钟运算频率,那样会反而得不偿失了。

1、从verilog到电路

        大家习惯于编写verilog代码。但是本质上来说,这其实也是在设计电路。只不过,我们设计的是数字电路。现在假设有这样一段代码,

        这段代码的功能比较简单。就是说,在每次时钟上升沿发生的时候,如果a为真,将b传递给d;反之,将c传递给d。大家可能在看这段代码的时候,认为只是一个简单的时序电路。其实,这里面既包含了组合逻辑,也包含了时序逻辑,

        上面的代码换一种写法,这样就比较容易看清楚了。所有的信号都会汇集成temp,也就是一个wire。最终在clk上升沿发生的时候,把temp传递给d。到了这一步,其实继续扩展一下思路,想象下翻译成的最终电路是什么样子的,

8e8d677d2b964aebb33d0ac059d51ee7.png

         上面这个电路其实就能说明数字电路翻译的基本原理了。如果信号a为真,那么下面c的输入其实无关紧要了。因为此时信号的输出只和b相关;同样而言,如果信号a为假,那么上面b的信号就无关紧要了,输出信号就只和c有关。通过上图可以看出,两个信号都会通过或门直接传递给触发器。这样在时钟沿来的时候,把这个信号传递给d寄存器了。

        可以看到,如果门电路不是很多的时候,那么组合逻辑的延时不是很明显。但是如果时序逻辑之间的组合逻辑过于复杂,那么整个电路的时钟频率是很难拉起来的。这个时候,与其降低时钟频率,不如暂停一下流水线,等待几个时钟反而要划算的多。

2、添加更多的运算指令

        前面一章引入了HI、LO寄存器,这就说明可以添加更多的数学运算指令了,而不仅仅是之前的逻辑运算指令、移位运算指令。常见的简单算术操作都可以添加进来了,比如说add、addi、addiu、addu、sub、subu、clo、clz、slt、slti、sltu、mul、mult、multu。关于乘法,这里有三个指令,分别是mul、mult、multu。注意,mul是把结果保存在通用寄存器里面的,而mult和multu是把运算结果保存在HI、LO寄存器里面的。

        准备必要的汇编代码,



newCodeMoreWhite.png

        翻译成inst_rom.data文件,



newCodeMoreWhite.png

        总共汇编代码有43行,所有生成的汇编指令也有43条。

93a572c7edcf4e768aec107687b68689.png

        做好了所有的准备工作之后,就可以开始分析波形图。依次把pc寄存器、wb寄存器、regfile寄存器、wb_hi&wb_lo寄存器、hi_o&lo_o寄存器拉进来。从第一条指令,向1号寄存器写入0x00008000,接着第二条指令继续向1号寄存器写入0x80000000,这样不断通过阅读寄存器的数值,结合阅读汇编代码,来验证cpu的实现是否正确。如果错误,还要回头看一下中间的时序逻辑和组合逻辑对不对。

        如果希望查看HI和LO寄存器,可以直接选中w_whilo,查看当w_whilo为1的时候,写入的数值是什么,对应的汇编指令是什么,和我们之前的期待是不是一样的。

bdee9818eb4c405d9f277e9d052e4a14.png

3、暂停流水线

        之前我们谈到了暂停流水线这个功能,可是怎么实现这个功能呢?一般来说,对于cpu各个执行模块,还会衍生出来一个control模块,这个control模块会控制流水线是暂停,还是flush掉。今天我们讨论的情况仅仅是暂停。而且就是算暂停,也有可能出现一部分暂停、一部分不暂停的情况。



newCodeMoreWhite.png

         这就是负责对流水线进行仲裁的ctrl模块,它搜集各个模块的请求,又马上给出一个综合的结果进行输出处理。以pc_reg.v为例,



newCodeMoreWhite.png

        没有递增之前,可能pc不停增加就可以了。现在的话,pc需要接收stall的结果,且只有在stall不存在的时候,才能不停递增pc寄存器。

        之前我们提到过madd指令,现在就看看,如果有了这个指令,ex阶段应该怎么处理,

        简单分析下,初次计算madd的时候,cnt_i肯定是0,那么这里肯定显示算一个临时结果hilo_temp_o,同时stallreq_for_madd_msub申请流水线暂停,cnt_o修改为1;等到下一个周期的时候,将之前的hilo_temp_o通过hilo_temp_i重新获取进来,和HI、LO重新做计算,生成hilo_temp1,stallreq_for_madd_msub也恢复。注意,这里cnt_o没有直接设置为2’b00,主要是为了防止其他情形导致流水线暂停的时候,不会出现重复计算的情况发生。

        另外注意,这里的cnt_i、cnt_o都被ex_mem模块保存了。

        一切都准备好了,就可以开始测试了。先准备好汇编文件,



newCodeMoreWhite.png

        接着就是翻译成二进制文件数据,

        有了这一切就可以开始进行波形图的分析了,

53e69263a8ca4d3f8d7a5da6a3b07aa0.png

        因为涉及到流水线的查看,所以这个时候可以重点观察下stall信号和pc地址的变更。观察发现,210ns的时候ce生效。290ns的时候数据准备写入,写入的地址是寄存器1,写入的数据是0x0000ffff,这和我们观察的汇编指令代码是一致的。

35ebf25c84034d32ad96c25e1aaa77dc.png

         在350ns的时候,我们发现pc地址出现了暂停,stall信号出现了,这个时候表明处于ex阶段的应该是madd指令。注意,不是mult指令,mult是在不需要流水线暂停的。为了判断我们的分析是否正确,可以把mem_whilo、mem_hi、mem_lo信号加进来。

f8f21ef8e8b74280b53b36957618a4db.png

        可以看到除了第一次mem_whilo为1,是因为乘法运算之后,后面的每一次计算,都需要等待两个周期,mem_hi和mem_lo才会又获得正确的数据。 以此类推,后面的几条指令,都会发生流水线暂停的操作,每次都是暂停1个时钟周期后,又立马回复正常。整个流程就是这样一个结果。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK