从 01 开始 从 01 开始
首页
  • 计算机简史
  • 数字电路
  • 计算机组成原理
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • 数据库
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Node
  • Windows 使用技巧
  • 最全面的输入法教程
  • 浏览器
  • 终端软件
  • 装机
  • 笔记类软件
  • Markdown
  • 各大平台
  • 远程控制
  • RSS
  • 图片类工具
  • Office
  • 手机
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 教程简介
  • 英语学习方法论
  • 字母
  • 音标
  • 单词
  • 语法
  • 英语兔的相关视频
  • Larry 想做技术大佬的相关视频
  • 驾驶技能
  • 住房相关
  • 厨艺
  • 关于税
  • 理财
  • 睡眠
  • 皮肤
  • 口腔健康
  • 学会呼吸
  • 健身日志
  • 电影

    • 电影推荐
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 反腐
  • GFW
  • 404 内容
  • 审查与自我审查
  • 互联网
  • 2022
  • 2023
  • 2024
  • 2025
  • 关于本站
  • 关于博主
  • 网站动态
  • 公告栏
  • 友人帐
  • 从零开始搭建一个博客
  • 搭建邮件服务器
  • 本站分享
  • 文章分类
  • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 计算机简史
  • 数字电路
  • 计算机组成原理
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • 数据库
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Node
  • Windows 使用技巧
  • 最全面的输入法教程
  • 浏览器
  • 终端软件
  • 装机
  • 笔记类软件
  • Markdown
  • 各大平台
  • 远程控制
  • RSS
  • 图片类工具
  • Office
  • 手机
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 教程简介
  • 英语学习方法论
  • 字母
  • 音标
  • 单词
  • 语法
  • 英语兔的相关视频
  • Larry 想做技术大佬的相关视频
  • 驾驶技能
  • 住房相关
  • 厨艺
  • 关于税
  • 理财
  • 睡眠
  • 皮肤
  • 口腔健康
  • 学会呼吸
  • 健身日志
  • 电影

    • 电影推荐
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 反腐
  • GFW
  • 404 内容
  • 审查与自我审查
  • 互联网
  • 2022
  • 2023
  • 2024
  • 2025
  • 关于本站
  • 关于博主
  • 网站动态
  • 公告栏
  • 友人帐
  • 从零开始搭建一个博客
  • 搭建邮件服务器
  • 本站分享
  • 文章分类
  • 文章归档
  • 计算机历史

  • 数字电路

  • 计算机组成原理

    • 网课-计算机组成原理(北大-陆俊林)

      • 概述-计算机组成原理(北大-陆俊林)
      • 第1周-计算机组成章节视频简介
      • 101-电子计算机的兴起
      • 102-冯·诺依曼结构的要点
      • 103-冯·诺依曼结构的小故事
      • 104-计算机结构的简化模型
      • 105-计算机执行指令的过程
      • 106-计算机输入和输出
      • 107-冯诺依曼结构和具体实现
      • 201-设计自己的计算机
      • 202-x86 体系结构
      • 203-x86 指令简介
      • 204-复杂的 x86 指令举例
      • 205-MIPS 体系结构
      • 206-MIPS 指令简介
      • 301-算术运算和逻辑运算
      • 302-门电路的基本原理
      • 303-寄存器的基本原理
      • 304-逻辑运算的实现
      • 305-加法和减法的实现
      • 306-加法器的优化
      • 401-乘法的运算过程
      • 402-乘法器的实现
      • 403-乘法器的优化 1
      • 404-乘法器的优化 2
      • 405-除法的运算过程
      • 406-除法器的实现
      • 407-除法器的优化
      • 501-处理器的设计步骤
      • 502-数据通路的建立
      • 503-运算指令的控制信号
      • 504-访存指令的控制信号
      • 505-分支指令的控制信号
      • 506-控制信号的集成
      • 601-流水线的基本原理
      • 602-流水线的优化
      • 603-超标量流水线
      • 604-流水线的冒险
        • 结构冒险
        • 结构冒险示例 2
        • 数据冒险
        • 控制冒险
        • 小结
      • 605-数据冒险的处理
      • 606-控制冒险的处理
      • 701-存储层次结构概况
      • 702-DRAM 和 SRAM
      • 703-主存的工作原理
      • 704-主存技术的发展
      • 705-高速缓存的工作原理
      • 706-高速缓存的组织结构
      • 707-存储容量的计算
      • 801-中断和异常的来源
      • 802-中断向量表的结构
      • 803-中断向量表的发展
      • 804-中断的处理过程
      • 805-内部中断分类说明
      • 806-基于中断的功能调用
      • 901-输入输出接口的基本功能
      • 902-输入输出接口的编址方式
      • 903-输入输出的控制方式
      • 904-中断控制方式
      • 905-外部中断的处理过程
      • 906-直接存储器访问方式
  • 操作系统

  • Linux

  • 计算机网络

  • Git

  • 计算机小知识

  • 数据库

  • 计算机基础
  • 计算机组成原理
  • 网课-计算机组成原理(北大-陆俊林)
2023-06-13
目录

604-流水线的冒险

# 604-流水线的冒险

流水线技术之所以能提高性能究其本质是利用了时间上的并行性, 那它让原本应该先后执行的指令在时间上一定程度的并行起来,然而这也会带来一些冲突和矛盾, 进而可能引发错误,这就是我们这一节所需要探讨的问题。

‍‍

首先我们来看什么是冒险。 在流水线当中我们希望每一个时钟周期都有一条指令进入流水线开始执行, 但是在某些情况下下一条指令无法按照预期开始执行, 那这种情况就被称为冒险。冒险分为三种,

一是结构冒险。在这里结构是指硬件电路当中的某个部件, 如果这条指令所需要的硬件部件还在为之前的指令工作无法为这条指令提供服务, 那就产生了结构冒险。

第二种是数据冒险, 如果这条指令需要某个数据而之前的指令正在操作这个数据,那这条指令就无法执行, 这种情况称为数据冒险。

第三种是控制冒险,如果现在要执行哪条指令, 是由之前指令的运行结果来决定的,而现在之前指令的结果还没有产生,那就导致了控制冒险。 那下面我们会逐个分析这些冒险。

​

‍

# 结构冒险

首先来看结构冒险, 我们还是通过一个指令执行的例子来讲, 这是一条指令在流水线中执行的步骤,那我们是用每一步动作的缩写来表示的, 那现在我们换一种描述的方式用这每一步所用到的硬件部件来表示, 那么注意到取指阶段需要用到指令存储器, 译码阶段需要用到寄存器堆,执行阶段需要用 ALU,访存阶段需要用数据存储器, 而写回阶段也需要用寄存器堆。 用这样的方式我们比较容易看出在哪些时刻会有可能出现硬件部件的争抢情况。

‍

那么假设执行的这么一段指令的序列,第一条是一个 Load 的指令,后面是若干其他的指令, 那么期望这些指令依次进入流水线开始执行, 那么注意在是第四个时钟周期 Load 的指令要从存储器中读取数据, 而与此同时取指部件也要从存储器当中读取第三条指令的编码, 那如果我们这个系统当中指令和数据是存放在同一个存储器当中的, 而对于一个存储器在同一个时刻只能接受一个读操作,那这里就会发生结构冒险,那如果我们只能使用同一个存储器怎么来解决这个问题呢?

​

‍

‍

其实方法很简单,既然不能同时读,那就不读好了, 那在这个时钟周期首先让 Load 的指令去读存储器你获得它所需要的数据, 而取指部件这时不读存储卡而是让流水线停顿。 在所谓停顿,也不是什么都不管,必须要将相关的控制信号视为不改变及其状态的值, 那这种设置我们就称为一个空泡。

​

这个表示也是形象化的描述了流水线停顿这一事情。 这样这个结构冒险就被消除了,而第三条指令的取指被延后到下一个周期才开始。 当然我们也会说这样会不会和第一条指令的访存产生冲突呢? 那当然如果第一条指令也是访存指令, 那还是会发生结构冒险。那流水线还需要再停顿一个周期, 第三条指定要等到下一个周期再进行取指。如果连续出现几条访存指令, 那后面流水线就会连续的停顿, 这样效率很低,但是从另一个角度讲这是一种非常安全又简便的方法,用这种方法其实可以解决各种冒险。

‍

‍

‍

当然既然它效率比较低,我们还是要尽量避免让流水线停顿。 所以在现在的处理器当中我们通常还是将指令和数据分别放在不同的存储器当中, 就是靠在存储器当中设置独立的指令高度缓存和数据高度缓存来实现的。

​

我们还是要强调的在计算机中主存储器也就是内存是统一存放指令和数据的, 这也是冯诺依曼结构的要求,只是在 CPU 当中的一级高速缓存会采用指令和数据分别存放的方式, 那这种结构冒险我们现在就已经解决了。

‍

‍

# 结构冒险示例 2

我们再来看下一种情况,还是这段代码, 如果再过了一个时钟周期,这时候 iii 的指令就要将从存储器中读出的数写入寄存器堆了。 而与此同时我们注意到第三条指令也在读寄存器堆, 那这里就出现了两条指令同时要对一个硬件部件进行操作的情况。 要解决这个冒险我们就得让寄存器堆同时支持读寄存器和写寄存器, 那我们是如何让寄存器堆提供这样的功能的呢?其实这和寄存器堆本身的特性有关, 相对来说寄存器堆的读写速度比较快, 我们假设读或者写寄存器的延迟为 100ps,而其他部件比如说 ALU 的延迟就就比较大,视为 200ps, 那么我们就可以在前半个时钟周期用于完成寄存器堆的写, 后半个时钟周期用来完成读操作,并且在寄存器堆上设置独立的读写口,这样就可以在一个时钟周期内同时完成了读和写的操作。

​

‍

‍

‍

那这两种机构冒险的情况在我们设计这个处理器的初期就已经避免了, 我们在选择处理器的组件时就考虑到了不同指令对各个部件的需求, 从而使得不同的指令不至于争抢同一个硬件部件。 虽然从这个例子看来我们用这个处理器并没有结构冒险的情况, 但是如果要设计一个新的处理器,结构冒险仍然是我们优先要考虑并解决的问题。

# 数据冒险

那好我们再来看一个数据冒险的例子。比如说这段指令的代码第一条减法指令, 它的运算结果会放倒 t0 寄存器当中,而下一条指令需要将 t0 寄存器作为加法运算的一个原操作数, 从这段代码的功能看来加法指令所用的 t0 寄存器的内容,显然应该是减法指令的运算结果。

但是在流水线处理器上, 加法指令开始执行时,这条减法指令的运算结果可能还没有写到 t0 寄存器当中去, 我们结合图示来进行说明。 减法指令需要到第五个周期也就写回这个周期才会将运算结果写到 t0 寄存器当中去, 而加法指令在第三个周期也就它自己的译码这个阶段就需要读出 t0 寄存器, 那从这里就可以看出,这条加法指令需要用前一条指定的运算结果, 但是在这个时刻这个运算结果还没有写回到寄存器当中去, 这就产生了数据冒险,如果不做任何处理任由加法指令去读取寄存器堆,那此时得到的 t0 寄存器的值肯定不是由前面这条减法指令运算得出的,这样就会导致这个程序运行结果的错误。

​

‍

那么如何来解决这个问题呢? 还记得我刚才提过那个万能的方法吗?只要遇到冒险我们用上它就能解决。 对了,这个方法就是让流水线停顿。 既然你结果还没有产生,那我就等,等到你结果产生, 根据这个流水线的结构我们需要让流水线停顿两个周期,这样在加法指令读寄存器堆的时候,减法指令已经将运算的结果写回到了 t0 寄存器当中去, 所以加法指令读到的是正确的数值。

​

# 控制冒险

那么再来看一个控制冒险的例子,这段代码第一条指令是条件分支指令,后续跟了若干的指令,那我们也结合图示来说明, 我们要注意的是在第二个时钟周期,处理器就应该去取下一条指令了,但这个时候实际上并不知道是否真的会发生分支, 这条分支指令一直要到执行阶段结束,才能知道分支的条件是否成立,也就在 600ps 这个时候,而处理器希望在 200ps 的时候就去取下一条指令,这里就产生了控制冒险,因为这个区指定的动作如何进行应该由上一条地指令的运行结果来决定, 而上一条指令的运行结果至少要到两个时钟周期之后才能产生,那在还没有确定是否发生分支的情况下如何进行下一次的取值呢?

‍

‍

​

那如果单纯只想解决这个冒险,而不考虑性能的损失的话, 我们还可以用那个万能的方法, 就是让流水线停顿。 我们需要插入两个空泡,那么在执行阶段结束之后,我们就知道要从哪个地方开始取新的指令了。这样就可以解决这个控制冒险。

​

# 小结

现在我们已经知道了这些冒险所带来的影响, 如果不好好解决这些问题,流水线处理器就没有使用的价值, 所以我们之后还需要对其中的一些重点 做深入的分析。

上次更新: 2024/9/29 12:08:10
603-超标量流水线
605-数据冒险的处理

← 603-超标量流水线 605-数据冒险的处理→

最近更新
01
2025 年 2 月记
02-28
02
最全面的浏览器教程-完结撒花
02-16
03
这个工具可以轻松搞到你的浏览器账户密码!
02-15
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式