将陆续上传本人写的新书《自己动手写CPU》(尚未出版),今天是第15篇,我尽量每周四篇

上一章建立了原始的OpenMIPS五级流水线结构,可是仅仅实现了一条ori指令,从本章開始,将逐步完好。

本章首先讨论了流水线数据相关问题。然后改动OpenMIPS以解决该问题。并在5.3节验证了解决效果。接着对逻辑、移位操作与空指令的指令格式、使用方法、作用进行了一一说明。在5.5节通过扩展OpenMIPS实现了这些指令,最后编写測试程序,对实现效果进行了检验。

5.1 流水线数据相关问题

我们在第4章实现的五级流水线结构非常easy。假设依照“简单即美(Simple is Beautiful)的标准,那么我们的流水线是美的,可是不完美,由于现实往往是复杂的,一个简单的流水线是解决不了如此多的现实问题的,本节探讨的数据相关问题就是当中一个问题。在我们实现逻辑、移位操作等其他指令之前。必须先讨论这个问题,由于这个问题已经影响到測试程序的编写了。

流水线中常常有一些被称为“相关”的情况发生,它使得指令序列中下一条指令无法依照设计的时钟周期运行,这些“相关”会减少流水线的性能。

流水线中的相关分为三种类型。

(1)结构相关:指的是在指令运行的过程中,因为硬件资源满足不了指令运行的要求,发生硬件资源冲突而产生的相关。

比方:指令和数据都共享一个存储器。在某个时钟周期,流水线既要完毕某条指令对存储器中数据的訪问操作,又要完毕兴许的取指令操作。这样就会发生存储器訪问冲突。产生结构相关。

(2)数据相关:指在流水线中运行的几条指令中。一条指令依赖于前面指令的运行结果。

(3)控制相关:指流水线中的分支指令或者其它须要改写PC的指令造成的相关。

结构相关、控制相关将在兴许指令分析中讨论,本节重点讨论数据相关的问题。流水线数据相关又分为三种情况:RAW、WAR、WAW。

  • RAW:Read After Write,如果指令j是在指令i后面运行的指令。RAW表示指令i将数据写入寄存器后,指令j才干从这个寄存器读取数据。

    如果指令j在指令i写入寄存器前尝试读出该寄存器的内容。将得到不对的数据。

  • WAR:Write After Read。如果指令j是在指令i后面运行的指令,WAR表示指令i读出数据后,指令j才干写这个寄存器。如果指令j在指令i读出数据前就写该寄存器,将使得指令i读出的数据不对。

  • WAW:Write After Write,如果指令j是在指令i后面运行的指令,WAW表示指令i将数据写入寄存器后,指令j才干将数据写入这个寄存器。如果指令j在指令i之前写该寄存器,将使得该寄存器的值不是最新值。

对于第4章建立的原始OpenMIPS五级流水线而言,从ori指令的实现过程能够知道,仅仅有在流水线回写阶段才会写寄存器(实际上其余指令也是一样的,在后面实现其余指令时,对这一点会更加清楚),因此不存在WAW相关。又由于仅仅能在流水线译码阶段读寄存器、回写阶段写寄存器,所以不存在WAR相关。所以OpenMIPS的流水线仅仅存在RAW相关。RAW相关有三种情况。

(1)相邻指令间存在数据相关

考虑例如以下代码。

1   ori $1,$0,0x1100        # $1 = $0 | 0x1100 = 0x1100
2 ori $2,$1,0x0020 # $2 = $1 | 0x0020 = 0x1120

第1条ori指令会写寄存器$1。随后的第2条ori指令须要读出$1的数据,可是第1条ori指令在回写阶段才会将其运算结果写入$1,而第2条ori指令在译码阶段就须要读取$1的值。此时第1条ori指令还处于运行阶段,所以得到的必定不是第1条ori指令计算得出的结果,按这个值运算,必定会出错。

如图5-1所看到的。

这样的情况能够称为相邻指令间存在数据相关。针对OpenMIPS详细情况。也能够称为流水线译码、运行阶段存在数据相关。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

(2)相隔1条指令的指令间存在数据相关

考虑例如以下代码。

1   ori $1,$0,0x1100        # $1 = $0 | 0x1100 = 0x1100
2 ori $3,$0,0xffff # $3 = $0 | 0xffff = 0xffff
3 ori $2,$1,0x0020 # $2 = $1 | 0x0020 = 0x1120

第1条ori指令会写寄存器$1。第3条ori指令在译码阶段须要读取寄存器$1,此时第1条ori指令还处于訪存阶段。所以得到的必定也不是正确的值。

如图5-2所看到的。这样的情况能够称为相隔1条指令的指令间存在数据相关。针对OpenMIPS详细情况。也能够称为流水线译码、訪存阶段存在数据相关。

(3)相隔2条指令的指令间存在数据相关

考虑例如以下代码。

1   ori $1,$0,0x1100        # $1 = $0 | 0x1100 = 0x1100
2 ori $3,$0,0xffff # $3 = $0 | 0xffff = 0xffff
3 ori $4,$0,0xffff # $4 = $0 | 0xffff = 0xffff
4 ori $2,$1,0x0020 # $2 = $1 | 0x0020 = 0x1120

第1条ori指令会写寄存器$1,第4条ori指令在译码阶段须要读取寄存器$1。此时第1条指令处于回写阶段,在回写阶段最后的时钟上升沿才会将运算结果写入$1,所以第4条ori指令得到的不是正确的寄存器$1的值。如图5-3所看到的。这样的情况能够称为相隔2条指令的指令间存在数据相关,针对OpenMIPS详细情况,也能够称为流水线译码、回写阶段存在数据相关。

当中相隔2条指令存在数据相关(即流水线译码、回写阶段存在数据相关)这样的情况,在第4章设计的Regfile模块中已经得到了解决,Regfile模块部分代码例如以下。

module regfile(
......
); ...... /****************************************************************
*********** 第三段:读port1的读操作 *********
*****************************************************************/ // raddr1是读地址、waddr是写地址、we是写使能、wdata是要写入的数据
always @ (*) begin ...... end else if((raddr1 == waddr) && (we == `WriteEnable)
&& (re1 == `ReadEnable)) begin
rdata1 <= wdata; ...... end /****************************************************************
*********** 第四段:读port2的读操作 *********
*****************************************************************/ // raddr2是读地址、waddr是写地址、we是写使能、wdata是要写入的数据
always @ (*) begin ...... end else if((raddr2 == waddr) && (we == `WriteEnable)
&& (re2 == `ReadEnable)) begin
rdata2 <= wdata; ...... end endmodule

在读操作中有一个推断,假设要读取的寄存器。是在下一个时钟上升沿要写入的寄存器。那么就将要写入的数据直接作为结果输出。如此就攻克了相隔2条指令存在数据相关的情况。

对于相邻指令间存在数据相关、相隔1条指令的指令间存在数据相关这两种情况。有三种解决方法。

(1)插入暂停周期:当检測到相关时,在流水线中插入一些暂停周期,如图5-4所看到的。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

(2)编译器调度:编译器检測到相关后,能够改变部分指令的运行顺序,如图5-5所看到的。

(3)数据前推:将计算结果从其产生处直接送到其它指令须要处或全部须要的功能单元处,避免流水线暂停。如图5-6所看到的的样例,新的$1值实际在第1条ori指令的运行阶段已经计算出来了。能够直接将该值从第1条ori指令的运行阶段送入第2条ori指令的译码阶段,从而使得第2条ori指令在译码阶段得到$1的新值。也能够直接将该值从第1条ori指令的訪存阶段送入第3条ori指令的译码阶段,从而使得第3条ori指令在译码阶段也得到$1的新值。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

读者须要注意,第(3)种方法有一个前提就是新的寄存器的值能够在运行阶段计算出来,假设是载入指令,那么就不满足这个前提,由于载入指令在訪存阶段才干获得终于结果。这是一种load相关,本书将在实现载入存储指令的时候考虑这样的情况,本章暂不考虑。

下一次将介绍OpenMIPS对数据相关问题的解决措施,敬请关注!

自己动手写CPU之第五阶段(1)——流水线数据相关问题的更多相关文章

  1. 自己动手写CPU之第五阶段(2)——OpenMIPS对数据相关问题的解决措施

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版).今天是第16篇.我尽量每周四篇 5.2 OpenMIPS对数据相关问题的解决措施 OpenMIPS处理器採用数据前推的方法来解决流水 ...

  2. 自己动手写CPU之第五阶段(3)——MIPS指令集中的逻辑、移位与空指令

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第17篇.我尽量每周四篇 5.4 逻辑.移位操作与空指令说明 MIPS32指令集架构中定义的逻辑操作指令有8条:and.and ...

  3. 自己动手写CPU之第七阶段(7)——乘累加指令的实现

    将陆续上传本人写的新书<自己动手写CPU>.今天是第30篇.我尽量每周四篇 亚马逊的销售地址例如以下.欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8 ...

  4. 自己动手写CPU之第六阶段(2)——移动操作指令实现思路

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第21篇,我尽量每周四篇 6.2 移动操作指令实现思路 6.2.1 实现思路 这6条移动操作指令能够分为两类:一类是不涉及特殊 ...

  5. 自己动手写CPU之第四阶段(3)——MIPS编译环境的建立

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版).今天是第13篇.我尽量每周四篇 4.4 MIPS编译环境的建立 OpenMIPS处理器在设计的时候就计划与MIPS32指令集架构兼容 ...

  6. 自己动手写CPU之第七阶段(2)——简单算术操作指令实现过程

    将陆续上传本人写的新书<自己动手写CPU>.今天是第25篇.我尽量每周四篇 亚马逊的预售地址例如以下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8 ...

  7. 自己动手写CPU之第七阶段(5)——流水线暂停机制的设计与实现

    将陆续上传本人写的新书<自己动手写CPU>,今天是第28篇.我尽量每周四篇 China-pub的预售地址例如以下(有文件夹.内容简单介绍.前言): http://product.china ...

  8. 自己动手写CPU之第八阶段(4)——转移指令实现过程2

    将陆续上传本人写的新书<自己动手写CPU>,今天是第36篇,我尽量每周四篇 开展晒书评送书活动,在亚马逊.京东.当当三大图书站点上,发表<自己动手写CPU>书评的前十名读者,均 ...

  9. 自己动手写CPU之第七阶段(6)——乘累加指令实现思路

    将陆续上传本人写的新书<自己动手写CPU>.今天是第29篇.我尽量每周四篇 亚马逊的销售地址例如以下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8 ...

随机推荐

  1. Oracle数据库使用存储过程实现分页

    注:本示例来源于韩顺平[10天玩转oracle数据库]视频教程 1.创建包同时创建游标 create or replace package pagingPackage is type paging_c ...

  2. 解决struts2配置文件没有提示的问题

    1.在WEB-INF下新建一个dtd文件夹 2.将

  3. C++编程规范和标准总结

    文件名: 每个源代码文件应该有一个包含文件.每个包含文件描述了单个类或者多个类相结合的集合.一般头文件(.h,或.hpp)包含类的定义而不是实例.因此包含文件可以用在多个文件当中,源文件(.c,.或c ...

  4. Java算法简介及排序剖析

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 从小白晋升,一路走来:从helloworld,到JFrame,再到Android:从城外小子,到内城 ...

  5. LeetCode——Binary Tree Level Order Traversal II

    Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...

  6. 深入浅出NodeJS——异步I/O

    底层操作系统,异步通过信号量.消息等方式有着广泛的应用. PHP语言从头到尾都是以同步堵塞方式执行,利于程序猿顺序编写业务逻辑. 异步I/O.事件驱动.单线程构成Node的基调. why异步I/O ( ...

  7. Zjnu Stadium(hdu3047带权并查集)

    题意:一个300列的无限行的循环场地,a b d代表a,b顺时针相距d的距离,现在给你一些距离,判断是否有冲突,如果有冲突计算冲突的次数 思路:带权并查集 a,b的距离等于b到根节点的距离 - a到根 ...

  8. Vue.js快速入门

    Vue.js介绍 Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的.相比于Angular.js,Vue.js提供了更加简洁.更易于理解的API,使得我们 ...

  9. Unity uGUI 登录及注册功能

    上次我们已经完成了登录界面的模拟功能,今天咱们把上次没做完的继续完善下!那么废话少说直接开始吧! PS:本次完善的功能有: 1,增加对数据库的操作. 2,使用了MD5Key值加密 3,完善登录和组测功 ...

  10. CSS3实现图片鼠标悬浮放大效果

    .excerpt .focus a img{ -webkit-transition: all ease .3s; transition: all ease .3s }.excerpt .focus a ...