深入理解计算机系统 第4章 处理器体系结构

指令集体系结构isa。ISA在编译器编写者和处理器设计人员之间提供了一个概念抽象层,编译器编写者只需要知道允许哪些指令,以及它们是如何编码的;而处理器设计者必须建造出执行这些指令的处理器。

Y86-64

程序员可见状态
在这里插入图片描述
Y86-64程序用虚拟地址来引用内存位置。
字:8字节

在这里插入图片描述

立即数(i)、寄存器(r)或内存(m)
第一个字母就表明了源的类型。第二个字母指明了目的的类型

内存引用方式是简单的基址和偏移量形式

OPq有addq、subq、andq和xorq。这些指令会设置3个条件码ZF、SF和OF(零、符号和溢出)

7个跳转指令(图4-2中的jXX)是jmp、jle^ jl、je、jne、jge和jg

有 6 个条件传送指令 cmovle, cmovl、cmove, cmovne、 cmovge和cmovg

call指令将返回地址入栈,然后跳到目的地址。ret指令从这样的调用中返回。

pushq和popq指令实现了入栈和出栈,就像在x86-64中一样。

halt指令停止指令的执行。将状态码设置为HLT

编码

每条指令的第一个字节表明指令的类型。高4位是代码(code)部分,低4位是功能(function)部分

在这里插入图片描述
在这里插入图片描述
没有寄存器操作 数的指令,例如分支指令和call指令,就没有寄存器指示符字节。那些只需要一个寄存器操作数的指令(irmovq> pushq和popq)将另一个寄存器指示符设为0xF。

4字节常数字.这个字能作为irmovq的立即数数据,rmmovq和mrmovq的地址指示符的偏移量,以及分支指令和调用指令的目的地址。

注意,分支指令和调用指令的目的是一个绝对地址

在这里插入图片描述
伪指令(directive)指明应该将代码或数据放在什么位置,以及如何对齐

.pos 0 告诉汇编器应该从地址0处开始产生代码。

irmovq stack, %rsp 初始化栈指针

在这里插入图片描述
YIS 指令集模拟器

pushq %rsp指令时,处理器的行为是不确定的,因为要入栈的寄存器会被同一条指令修改。

两种不同的约定:1)压入%rsp的原始值,2)压入减去8的%rsp的值。

在写之前,pushq应该先将栈指针减去8
popq应该首先读内存,然后再增加栈指针。

HCL 硬件控制语言

AND用&&表示,OR用||表示,而NOT用!表示。我们用这些符号而不用C语言中的位运算符&、|和〜,这是因为逻辑门只对单个位的数进行操作,而不是整个字。

多路复用器mux
在这里插入图片描述
bool out = (s && a) I| (!s && b);
在这里插入图片描述

情况表达式
在这里插入图片描述
顺序求值的,且第一个求值为1的情况会被选中。
在这里插入图片描述
集合关系

iexpr in {iexpr,yiexpr2 ,,,iexprk}

bool s1 = code in { 2, 3 };
bool s0 = code in { 1, 3 };
在这里插入图片描述
时钟寄存器(简称寄存器)
随机访问存储器(简称内存)
在这里插入图片描述
寄存器文件:
在这里插入图片描述
随机访问存储器在这里插入图片描述
我们的处理器还包括一个只读存储器,用来读指令。

在大多数实际系统中,这两个存储器被合并为一个具有双端口的存储器:一个用来读指令,另一个用来读或者写数据。

Y86-64的顺序实现

每个时钟周期上,SEQ执行处理一条完整指令所需的所有步
骤。

创建这样一个框架

取指(fetch) 取指阶段从内存读取指令字节,地址为程序计数器(PC)的值。从指令中抽取出指令指示符字节的两个四位部分,称为icode(指令代码)和ifun(指令功能)。它可能取出一个寄存器指示符字节,指明一个或两个寄存器操作数指示符rA和rB。它还可能取出一个四字节常数字valC。它按顺序方式计算当前指令的下一条指令的地址valPo也就是说,valP等于PC的值加上已取出指令的长度。

译码(decode):译码阶段从寄存器文件读入最多两个操作数,得到值valA和/或valB。通常,它读入指令rA和rB字段指明的寄存器,不过有些指令是读寄存器%rsp的。

执行(execute):在执行阶段,算术/逻辑单元(ALU)要么执行指令指明的操作(根据ifun的值),计算内存引用的有效地址,要么增加或减少栈指针。得到的值我们称为valE。在此,也可能设置条件码。对一条条件传送指令来说,这个阶段会检验条件码和传送条件(由ifun给出),如果条件成立,则更新目标寄存器。同样,对一条跳转指令来说,这个阶段会决定是不是应该选择分支。

访存(memory):访存阶段可以将数据写入内存,或者从内存读出数据。读出的值为 valM

写回(write back):写回阶段最多可以写两个结果到寄存器文件。

更新PC(PC update):将PC设置成下一条指令的地址。

在这里插入图片描述
在这里插入图片描述
popq rA的访存应该写错了,valE应为valM
在这里插入图片描述
对指令call,我们要将valP,也就是call指令后紧跟着的那条指令的地址,
压入栈中。在更新PC阶段,将PC设为valC,也就是调用的目的地。对指令ret,在更新PC阶段,我们将valM,即从栈中取出的值,赋值给PC。
在这里插入图片描述
取指:将程序计数器寄存器作为地址,指 令内存读取指令的字节。PC增加器(PC incre-menter)计算valP,即增加了的程序计数器。

译码:寄存器文件有两个读端口 A和B,从这两个端口同时读寄存器值valA和valB

执行:执行阶段会根据指令的类型,将算术/逻辑单元(ALU)用于不同的目的。对整数操作,它要执行指令所指定的运算。对其他指令,它会作为一个加法器来计算增加或减少栈指针,或者计算有效地址,或者只是简单地加0,将一个输入传递到输出。
条件码寄存器(CC)有三个条件码位。ALU负责计算条件码的新值。当执行条件传送指令时,根据条件码和传送条件来计算决定是否更新目标寄存器。同样,当执行一条跳转指令时,会根据条件码和跳转类型来计算分支信号Cnd。
访存:在执行访存操作时,数据内存读出或写入一个内存字。指令和数据内存访问的是相同的内存位置,但是用于不同的目的。

PC更新:程序计数器的新值选择自:valP,下一条指令的地址;valC,调用指令或跳转指令指定的目标地址;valM,从内存读取的返回地址。
在这里插入图片描述
白色方框表示时钟寄存器。浅蓝色方框表示硬件单元。控制逻辑块用灰色圆角矩形表示。

srcA, valA的源;srcB, valB的源;dstE,写入valE的寄存器;以及dstM,写入valM的寄存器。

原则:从不回读
处理器从来不需要为了完成一条指令的执行而去读由该指令更新了的状态。

读操作沿着这些单元传播,就好像它们是组合逻辑,而写操作是由时钟控制的。

取指阶段
423
instr_valid:这个字节对应于一个合法的Y86-64指令吗?
need_regids:这个指令包括一个寄存器指示符字节吗?
need_valC:这个指令包括一个常数字吗?
在这里插入图片描述

译码和写回阶段
它们都要访问寄存器文件。
在这里插入图片描述
在这里插入图片描述
执行阶段
在这里插入图片描述
在这里插入图片描述
访存阶段
在这里插入图片描述
在这里插入图片描述
更新PC阶段
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

流水线

流水线化的一个重要特性就是提高了系统的吞吐量(throughput),也就是单位时间内服务的顾客总数,不过它也会轻微地增加延迟(latency),也就是服务一个用户所需要的时间。
在这里插入图片描述
在这里插入图片描述
每秒千兆条指令(GIPS),也就是每秒十亿条指令,为单位来描述吞吐量。
在这里插入图片描述
不一致的划分
在这里插入图片描述
流水线过深,收益反而下降
在这里插入图片描述
带反馈的流水线系统
在这里插入图片描述
数据相关

指令控制流造成的顺序相关
在这里插入图片描述

SEQ+

更新PC阶段在一个时钟周期开始时执行,而不是结束时才执行。
在这里插入图片描述

PIPE-

流水线寄存器分隔开这些阶段。
在这里插入图片描述
F 保存程序计数器的预测值,稍后讨论。
D 位于取指和译码阶段之间。它保存关于最新取出的指令的信息,即将由译码阶段 进行处理。
E 位于译码和执行阶段之间。它保存关于最新译码的指令和从寄存器文件读出的值的信息,即将由执行阶段进行处理。
M 位于执行和访存阶段之间。它保存最新执行的指令的结果,即将由访存阶段进行处理。它还保存关于用于处理条件转移的分支条件和分支目标的信息。
W 位于访存阶段和反馈路径之间,反馈路径将计算出来的值提供给寄存器文件写,而当完成ret指令时,它还要向PC选择逻辑提供返回地址。

译码阶段 “Select A”的块。这个块是为了减少要携带给流水线寄存器E和M的状态数量。

只有call在访存阶段需要valP的值。只有跳转指令在执行阶段(当不需要进行跳转时)需要valP的值。而这些指令又都不需要从寄存器文件中读出的值。因此我们合并这两个信号,将它们作为信号valA携带穿过流水线,从而可以减少流水线寄存器的状态数量。

分支预测
预测下一个 PC
预测PC的新值为valC。我们的设计只使用了简单的策略,即总是预测选择了条件分支,因而预测PC的新值为valC。
ret 在设计中,我们不会试图对返回地址做任何预测。只是简单地暂停处理新指令,直到ret指令通过写回阶段

数据冒险

用暂停来避免数据冒险
在这里插入图片描述

用转发来避免数据冒险

PIPE

在这里插入图片描述
加载 /使用数据冒险
有一类数据冒险不能单纯用转发来解决,因为内存读在流水线发生的比较晚。

可以将暂停和转发结合起来,避免加载/使用数据冒险
在这里插入图片描述
避免控制冒险
控制冒险只会发生在ret指令和跳转指令。
ret在这里插入图片描述
跳转
在这里插入图片描述
异常处理

把导致异常的指令称为异常指令
1)halt 指令
2)有非法指令和功能码组合的指令
3)取指或数据读写试图访问一个非法地址。

基本原则是:由流水线中最深的指令引起的异常,优先级最高。

细节问题:1当首先取出一条指令,开始执行时,导致了一个异常,而后来由于分支预测错误,取消了该指令。2因为流水线化的处理器会在不同的阶段更新系统状态的不同部分。

当处于访存或写回阶段中的指令导致异常时,流水线控制逻辑必须禁止更新条件码寄存器或是数据内存

在这里插入图片描述
当一条预测错误的分支进入访存阶段时,会从流水线寄存器M(信号M_valA)中读出该指令valP的值(指明下一条指令的地址)当mt指令进入写回阶段时,会从流水线寄存器W(信号W_valM)中读出返回地址。其他情况会使用存放在流水线寄存器F(信号F_predPC)中的PC的预测值
pc选择逻辑在这里插入图片描述

当取出的指令为函数调用或跳转时,PC预测逻辑会选择vale,否则就会选择vaM:
pc预测
在这里插入图片描述
译码和写回阶段
在这里插入图片描述
Sel + FwdA扮演两个角色。它为后面的阶段将valP信号合并到valA信号。valA的转发逻辑。
在这里插入图片描述
如果不满足任何转发条件,这个块就应该选择d_rvalA作为它的输出
在这里插入图片描述
5个转发源的优先级是非常重要的。给处于最早流水线阶段中的转发源以较高的优先级。因为它保持着程序序列中设置该寄存器的最近的指令。

执行阶段
在这里插入图片描述
访存阶段
在这里插入图片描述
加载/使用冒险:在一条从内存中读出一个值的指令和一条使用该值的指令之间,流水线必须暂停一个周期。
处理ret:流水线必须暂停直到ret指令到达写回阶段。
预测错误的分支:在分支逻辑发现不应该选择分支之前,分支目标处的几条指令已经进入流水线了。必须取消这些指令,并从跳转指令后面的那条指令开始取指。
异常:当一条指令导致异常,我们想要禁止后面的指令更新程序员可见的状态,并且异常指令到达写回阶段时,停止执行。
在这里插入图片描述
在这里插入图片描述
同时出现多个特殊情况的情形。
在这里插入图片描述
组合A中执行阶段中有一条不选择分支的跳转指令,而译码阶段中有一条ret指令。 出现这种组合要求ret位于不选择分支的目标处。流水线控制逻辑应该发现分支预测错误,因此要取消ret指令。
在这里插入图片描述
组合B包括一个加载/使用冒险,其中加载指令设置寄存器%rsp,然后ret指令用这个寄存器作为源操作数,因为它必须从栈中弹出返回地址。流水线控制逻辑应该将ret指令阻塞在译码阶段。

合并得到
在这里插入图片描述
这些分析表明组合B需要特殊处理。实际上,PIPE控制逻辑原来的实现并没有正确处理这种组合情况。
在这里插入图片描述
CPI(Cycles Per Instruction,每指令周期数)
如果这个阶段一共处理了Ci条指令和Cb个气泡,那 么处理器总共需要大约Ci+Cb个时钟周期来执行Ci条指令。
在这里插入图片描述
CPI = 1.0 + lp+ mp + rp
lp(load penalty,加载处罚)是当由于加载/使用冒险造成暂停时插入气泡的平均数
mp(mispredicted branch penalty,预测错误分支处罚)是当由于预测错误取消指令时插入气泡的平均数
rp(return penalty,返回处罚)是当由于mt指令造成暂停时插入气泡的平均数。
在这里插入图片描述

未完成的工作

多周期指令
在一个更完整的指令集中,我们还将实现一些需要更为复杂操作的指令,例如,整数乘法和除法,以及浮点运算。
采用独立于主流水线的特殊硬件功能单元来处理较为复杂的操作

与存储系统的接口
忽略了由自我修改代码造成的可能冒险,一条指令对一个存储区域进行写,而后面又从这个区域中读取指令。

处理器有两个第一层高速缓存,一个用于读指令,一个用于读和写数据。高速缓存(cache)存储器。翻译后备缓冲器(TLB):提供了从虚拟地址到物理地址的快速翻译。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本书是一本将计算机软件和硬件理论结合讲述的经典教程,内容覆盖计算机导论、体系结构处理器设计等多门课程。本书的最大优点是为程序员描述计算机系统的实现细节,通过描述程序是如何映射到系统上,以及程序是如何执行的,使读者更好地理解程序的行为为什么是这样的,以及造成效率低下的原因。 相对于第1版,本版主要是反映了过去十年间硬件技术和编译器的变化,具体更新如下: 1. 对系统的介绍(特别是实际使用部分)做了增加和修改。例如,既保持了原有的针对32位系统的说明,又增加了对64位系统的描述。 2. 增加了很多关于由算术运算溢出以及缓冲区溢出造成安全漏洞的内容。 3. 更详细讲述了处理器对异常的发现和处理。 4. 描述了基于Intel Core i7处理器的存储器层次结构,还增加了固态硬盘的内容。 5. 强调并发性,增加了关于并发性一般原则的内容。 【编辑推荐】 “2005年,我开始采用Bryant和O’Hallaron的这本书作为本科生计算机系统课程的教材。三年后,这本书仍然是我的计算机系统课程教科书的首选。” —— Mirela Damian,维拉诺瓦大学 “本书表述清晰、恰到好处——举重若轻地呈现了那些非常复杂的内容。” —— Ibrahim Matta, 波士顿大学 “这是一本学习计算机硬件和软件如何‘真正’协同工作的好书,还教会你为什么了解这些知识会使你成为一个更有价值的程序员。本书还帮你为学习像操作系统和编译器这样的高级课程做好准备。在本书中,我最喜欢的节是关于缓存的,当我第一次发现缓存有多重要时,真是难以置信!” —— Vishal Shah,Ask.com总架构师

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值