我们终于准备好要开始本章的主要任务——设计一个流水线化的Y86-64处理器。首先,对顺序的SEQ处理器做一点小的改动,将PC的计算挪到取指阶段。然后,在各个阶段之间加上流水线寄存器。到这个时候,我们的尝试还不能正确处理各种数据和控制相关。不过,做一些修改,就能实现我们的目标——一个高效的、流水线化的实现Y86-64ISA的处理器。

SEQ+

调整一下SEQ的顺序,使更新PC阶段在一个时钟周期开始时执行,我们称这种修改过的设计为SEQ+。我们移动PC阶段,使得它的逻辑在时钟周期开始时活动,使它计算当前指令的PC值。图给出了SEQ和SEQ+在PC计算上的不同之处。在SEQ中(图4-39a),PC计算发生在时钟周期结束的时候,根据当前时钟周期内计算出的信号值来计算PC寄存器的新值。在SEQ+中(图4-39b),我们创建状态寄存器来保存在一条指令执行过程中计算出来的信号。然后,当一个新的时钟周期开始时,这些信号值通过同样的逻辑来计算当前指令的PC。我们将这些寄存器标号为“pIcode”、“pCnd”等等,来指明在任一给定的周期,它们保存的是前一个周期中产生的控制信号。

PIPE-

在SEQ+的各个阶段之间插入流水线寄存器,并对信号重新排列,得到PIPE-处理器。

流水线寄存器按如下方式标号:

F保存程序计数器的预测值,稍后讨论。

D位于取指和译码阶段之间。它保存关于最新取出的指令的信息,即将由译码阶段进行处理。

E位于译码和执行阶段之间。它保存关于最新译码的指令和从寄存器文件读出的值的信息,即将由执行阶段进行处理。

M位于执行和访存阶段之间。它保存最新执行的指令的结果,即将由访存阶段进行处理。它还保存关于用于处理条件转移的分支条件和分支目标的信息。

W位于访存阶段和反馈路径之间,反馈路径将计算出来的值提供给寄存器文件写,而当完成ret指令时,它还要向PC选择逻辑提供返回地址。

对信号进行重新排列和标号

我们采用的命名机制,通过在信号名前面加上大写的流水线寄存器名字作为前缀,存储在流水线寄存器中的信号可以唯一被标识。在信号名前面加上小写的流水线寄存器名字作为前缀,表示在一个阶段刚计算出来的信号。

SEQ+和PIPE一的译码阶段都产生信号dstE和dstM,它们指明值valE和valM的目的寄存器。在SEQ+中,我们可以将这些信号直接连到寄存器文件写端口的地址输入。在PIPE一中,会在流水线中一直携带这些信号穿过执行和访存阶段,直到写回阶段才送到寄存器文件(如各个阶段的详细描述所示)。我们这样做是为了确保写端口的地址和数据输入是来自同一条指令。否则,会将处于写回阶段的指令的值写入,而寄存器ID却来自于处于译码阶段的指令。作为一条通用原则,我们要保存处于一个流水线阶段中的指令的所有信息。

PIPE一中有一个块在相同表示形式的SEQ+中是没有的,那就是译码阶段中标号为“Select A”的块。我们可以看出,这个块会从来自流水线寄存器D的valP或从寄存器文件A端口中读出的值中选择一个,作为流水线寄存器E的值valA。包括这个块是为了减少要携带给流水线寄存器E和M的状态数量。在所有的指令中,只有cal1在访存阶段需要valP的值。只有跳转指令在执行阶段(当不需要进行跳转时)需要valP的值。而这些指令又都不需要从寄存器文件中读出的值。因此我们合并这两个信号,将它们作为信号valA携带穿过流水线,从而可以减少流水线寄存器的状态数量。这样做就消除了SEQ(图4-23)和SEQ+(图4-40)中标号为“数据”的块,这个块完成的是类似的功能。在硬件设计中,像这样仔细确认信号是如何使用的,然后通过合并信号来减少寄存器状态和线路的数量,是很常见的。

预测下一个PC

如果取出的指令是条件分支指令,要等到几个周期后也就是执行阶段之后,我们才能知道是否要选择分支。为了提高效率,猜测分支方向并根据猜测开始取指的技术称为分支预测。

PIPE-的取指阶段,如图4-41底部所示,负责预测PC的下一个值,以及为取指选择实际的PC。我们可以看到,标号为“Predict PC”的块会从PC增加器计算出的valP和取出的指令中得到的valc中进行选择。这个值存放在流水线寄存器F中,作为程序计数器的预测值。标号为“Select PC”的块类似于SEQ+的PC选择阶段中标号为“PC”的块(图4-40)。它从三个值中选择一个作为指令内存的地址:预测的PC,对于到达流水线寄存器M的不选择分支的指令来说是valP的值(存储在寄存器M_valA中),或是当ret指令到达流水线寄存器W(存储在W_valM中)时返回地址的值。

流水线冒险

当相邻指令间存在相关时会导致出现问题。这些相关有两种形式:1)数据相关,下一条指令会用到这一条指令计算出的结果;2)控制相关,一条指令要确定下一条指令的位置,例如在执行跳转、调用或返回指令时。这些相关可能会导致流水线产生计算错误,称为冒险(hazard)。同相关一样,冒险也可以分为两类:数据冒险(data hazard)和控制冒险(control hazard)。我们首先关心的是数据冒险,然后再考虑控制冒险。

之所以会出现这些冒险,是因为我们的流水线化的处理器是在译码阶段从寄存器文件中读取指令的操作数,而要到三个周期后,指令经过写回阶段时,才会将指令的结果写到寄存器文件中。

避免流水线冒险

用暂停来处理流水线冒险

暂停是避免冒险的一种常用技术,暂停时,处理器会停止流水线中的一条或多条指令,直到冒险条件不再满足。让一条指令停顿在译码阶段,直到产生它的源操作数的指令通过了写回阶段,这样我们的处理器就能避免数据冒险。暂停技术就是让一组指令阻塞在它们所处的阶段,而允许其他指令继续通过流水线。但是会导致流水线暂停几个周期,严重降低整体的吞吐量。

用转发来避免数据冒险

译码阶段从寄存器文件中读入源操作数,但是对于这些源操作数的写可能要在写回阶段才能进行。直接用旁路电路将提供到端口E的数据字作为操作数valb的值,就能避免暂停。为了充分利用数据转发技术,我们还可以将新计算出来的值从执行阶段传到译码阶段,以避免程序prog4所需要的暂停,如图4-51所示。在周期4中,译码阶段逻辑发现在访存阶段中有对寄存器rdx未进行的写,而且执行阶段中ALU正在计算的值稍后也会写入寄存器rax。它可以将访存阶段中的值(信号M_valE)作为操作数valA,也可以将ALU的输出(信号e _valE)作为操作数va1B。注意,使用ALU的输出不会造成任何时序问题。译码阶段只要在时钟周期结束之前产生信号valA和valB,这样在时钟上升开始下一个周期时,流水线寄存器E就能装载来自译码阶段的值了。而在此之前ALU的输出已经是合法的了。

避免控制冒险

当处理器无法根据取指阶段的当前指令来确定下一条指令的地址时,就会出现控制冒险。控制冒险只会发生在ret指令和跳转指令,而且后一种情况只有在条件跳转方向预测错误时才会造成麻烦。在下一个周期往执行阶段和译码阶段插入气泡,并同时取出跳转指令后面的指令,这样就能取消预测错误的指令。在出现特殊情况时,暂停和往流水线中插入气泡的技术可以动态调整流水线的流程。

异常处理

处理器中很多事情都会导致异常控制流,程序执行的正常流程被破坏掉。异常可以由程序执行从内部产生,也可以由某个外部信号从外部产生。我们的指令集体系结构包括三种不同的内部产生的异常:1)halt指令,2)有非法指令和功能码组合的指令,3)取指或数据读写试图访问一个非法地址。一个更完整的处理器设计应该也能处理外部异常。我们把导致异常的指令称为异常指令。

在一个流水线化的系统中,异常处理包括一些细节问题:

首先可能同时会有多条指令引起异常。基本原则是:由流水线中最深的指令引起的异常优先级最高。比如访存阶段的异常应该比取指阶段的异常优先级高,所以只向操作系统报告这个异常。

第二个细节就是,当取出一条指令,开始执行时导致了异常,后来由于分支预测错误,取消了该指令。

第三个细节问题的产生是因为流水线化的处理器会在不同阶段更新系统状态的不同部分。有可能会出现这种状况,一条指令导致了一个异常,而他后面的指令在异常完成前已经改变了部分状态。

一般地,通过在流水线结构中加入异常处理逻辑,我们既能够从各个异常中做出正确的选择,也能够避免出现由于分支预测错误取出的指令造成的异常。这就是为什么我们会在每个流水线寄存器中包括一个状态码stat。如果一条指令在其处理中于某个阶段产生了一个异常,这个状态字段就被设置成指示异常的种类。异常状态和该指令的其他信息一起沿着流水线传播,直到它到达写回阶段。在此,流水线控制逻辑发现出现了异常,并停止执行。

为了避免异常指令之后的指令更新任何程序员可见的状态,当处于访存或写回阶段中的指令导致异常时,流水线控制逻辑必须禁止更新条件码寄存器或是数据内存。在上面的示例程序中,控制逻辑会发现访存阶段中的pushq导致了异常,因此应该禁止addq指令更新条件码寄存器。

 

3.5 Y84-64的流水线实现的更多相关文章

  1. Altera FFT核使用详解

    简介 快速傅里叶变换(Fast Fourier Transform)最为一种高效的算法,被广泛的用于信号处理与数据分析等领域.对于设计工程师来讲,自己动手采样可编程语言来实现一个FFT/IFFT模块, ...

  2. [论文翻译] 分布式训练 Parameter sharding 之 ZeRO

    [论文翻译] 分布式训练 Parameter sharding 之 ZeRO 目录 [论文翻译] 分布式训练 Parameter sharding 之 ZeRO 0x00 摘要 0x01 综述 1.1 ...

  3. 64 计算机图形学入门(1)——OpenGL环境配置与图形流水线(图像管线)

    0 引言 最近想学一下计算机图形学方面的知识,原因如下.目前本人接触了数字图像处理(opencv)以及点云处理(PCL)方面的知识,对从图像和点云中提取特征信息,并将特征转化为底层/中层语义信息有了一 ...

  4. verilog实现16位五级流水线的CPU带Hazard冲突处理

    verilog实现16位五级流水线的CPU带Hazard冲突处理 该文是基于博主之前一篇博客http://www.cnblogs.com/wsine/p/4292869.html所增加的Hazard处 ...

  5. 基于五阶段流水线的RISC-V CPU模拟器实现

    RISC-V是源自Berkeley的开源体系结构和指令集标准.这个模拟器实现的是RISC-V Specification 2.2中所规定RV64I指令集,基于标准的五阶段流水线,并且实现了分支预测模块 ...

  6. 【原创】Linux环境下的图形系统和AMD R600显卡编程(9)——R600显卡的3D引擎和图形流水线

    1. R600 3D引擎 R600核心是AMD一款非常重要的GPU核心,这个核心引入了统一处理器架构,其寄存器和指令集同以前的GPU 都完全不同,对其编程也有比较大的区别. 图1显示了R600 GPU ...

  7. 项目案例之Pipeline流水线及流水线发布PHP项目(二)

    项目案例之Pipeline流水线及流水线发布PHP项目(二) 链接:https://pan.baidu.com/s/1NZZbocZuNwtQS0eGkkglXQ 提取码:z7gj 复制这段内容后打开 ...

  8. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线 学习目标 了解几个用以表达真实场景的标志和2D图像 ...

  9. 【转】gitlab CI流水线配置文件.gitlab-ci.yml详解

    目录 GitLab CI流水线配置文件.gitlab-ci.yml详解 实验环境 GitLab CI介绍 .gitlab-ci.yml 配置参数 参数详解 script image services ...

  10. [源码解析] 深度学习流水线并行Gpipe(1)---流水线基本实现

    [源码解析] 深度学习流水线并行Gpipe(1)---流水线基本实现 目录 [源码解析] 深度学习流水线并行Gpipe(1)---流水线基本实现 0x00 摘要 0x01 概述 1.1 什么是GPip ...

随机推荐

  1. C 语言编程 — 高级数据类型 — 结构体与位域

    目录 文章目录 目录 前文列表 结构体 定义结构体 初始化结构体变量 访问结构体成员 将结构体作为实参传入函数 指向结构体变量的指针 位域 定义位域 使用位域结构体的成员 前文列表 <程序编译流 ...

  2. vmware迁移虚拟机

    迁移 1.打开"VMware",点击"虚拟机详细信息"可以看到虚拟机的储存路径. 2. 按照储存路径找到虚拟机文件位置,将整个虚拟机文件复制,粘贴到需要转移的路 ...

  3. RocketMq开启安全认证ACL-解决服务器系统安全漏洞

    1.为什么要开启ACL 通过之前的文章我们已经知道怎么安装RocketMq了.如果你还不会安装RocketMq可以查看我的这篇文章:快速入门一篇搞定RocketMq-实现微服务实战落地 进行软件安装, ...

  4. Istio(四):创建部署Gateway并使用网关暴露服务

    目录 一.模块概览 二.系统环境 三.Gateway网关 3.1 使用 Gateway 四.实战:使用Gateway发布服务 4.1 创建部署并使用网关暴露 4.2 清理 一.模块概览 在Kubern ...

  5. MySQL查询某个字段含有字母数字的值

    1.正则表达式(REGEXP) 查询MySQL表中某个字段含有字母和数字的值,可以使用正则表达式(REGEXP)来匹配这样的模式.在MySQL中,正则表达式是一个强大的工具,可以用来搜索和匹配字符串中 ...

  6. 阿里巴巴 MySQL 数据库之建表规约(一)

    建表规约 强制部分 [强制] 表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint (1 表示是,0 表示否). 说明:任何字段如果为非负数,必须是 ...

  7. centos7下启动Django项目报错(sqlite错误)

    报错内容如下: [root@localhost project]# python3 manage.py runserver Watching for file changes with StatRel ...

  8. 001. git基础

    目录 1. 持续集成教程 1.1 持续集成的基础概念 1.2 持续集成的一般流程 1.3 认识DevOps 1.3.1 DevOps是啥? 1.3.2 为什么需要DevOps呢? 1.3.3 DevO ...

  9. Swift Copy On Write 多线程下面的资源竞争

    Swift中的String.Array.Dictionary等容器类型默认实现了写时复制,这个操作在多线程下面可能会带来错误 https://bugs.swift.org/browse/SR-6543

  10. C# .NET Unix 时间戳

    10 位时间戳: public static long GetTimeStampTen() { return (DateTime.Now.ToUniversalTime().Ticks - 62135 ...