4.1 Y86-64 指令集体系结构
1.指令体系结构:处理器支持的指令和指令的字节级编码。
2.与 X86-64 相比,Y86-64 指令集的数据类型、指令和寻址方式要少一些,字节级编码也比较简单,机器代码没有 Y86-64 紧凑,虽简单但足够完整。
3.定义一个指令集体系结构与包括定义各种状态单元、指令集和它们的编码、一组编程规范和异常事件处理。
4.Y86-64 有8个程序寄存器:%rax,%rcx,%rdx,%rbx,%rsi,%rdi,%rsp,%rbp 和 %r8 到 %r14(少了 %r15)。%rsp 被入栈、出栈、调用和返回指令作为栈指针,其它寄存器没有固定的含义或固定值。
5.下图是 Y86-64 指令集。指令编码长度从1~10个字节不等。字段 fn 指明是某个整数操作(OPL)、数据移动条件(cmovXX)或分支条件(jXX)。
- 除了不允许从内存传到内存,还不允许将立即数传送到内存
- OPq 是 addq、subq、andq、xorq,只对寄存器数据进行操作,而 X86-64 还允许对内存数据进行此类操作
- jXX代表 jmp、jle、jl、je、jne、jge、jg。
6.每条指令的第一个字节表面指令的类型。本字节分为两部分,高4位是代码部分,低4位是功能部分。rrmovq 与条件传送的指令代码都为2,可以把它看作是一个“无条件传送”。
15个程序寄存器中每个都有一个相对应的范围在0
~0xE之间的寄存器标识符。程序寄存器存在CPU中的寄存器文件(以寄存器id作为地址的随机访问存储器)中,当需要指明不应访问任何寄存器时用 0xF 表示。
7.没有寄存器操作数的指令(分支指令和call指令)没有寄存器指示符字节;只需要一个寄存器操作数的指令(irmovl,pushl,popl)将另一个寄存器指示符设为0xF;有些指令需要附加的4字节常数字,可作 irmovl 的立即数数据,rmmol 和 mrmovl 的地址指示符的偏移量、分支指令和调用指令的目的地址。注意: 分支指令和调用指令的目的地址是一个绝对地址,所有整数采用小端法编码。
8.rmmovq %rsp,0x123456789abcd(%rdx)
中偏移量要放在8字节的常数字中,所以得先填充0变成8字节,然后再按反序输出,最后字节编码为 4042cdab896745230100。
9.状态码 Stat 描述程序执行的总体状态。ADR 表示处理器试图从一个非法内存地址读或者向一个非法内存地址写。INS 表示遇到了非法的指令代码。
- x86-64 和 Y86-64 由 GCC 编译器产生的代码有不同:
- Y86-64 将 常数加载到寄存器,因为它在算术指令中不能使用立即数
- 实现从内存读取一个数并将其与一个寄存器相加,Y86-64 代码需要两条指令(先放到寄存器中再加),而 x86-64 只需要一条 addq 指令
- Y86-64 实现 subq 指令同时还设置了条件码
11.pushq %rsp
压入 %rsp 的原始值,popq %rsp
将 %rsp 设置为从内存中读出来的值。
4.2 逻辑设计和硬件控制语言HCL
1.数字系统需要三个主要组成部分:
- 计算对位进行操作的函数的组合逻辑
- 存储位的存储器单元
- 控制存储器单元更新的时钟信号
2.C语言中符号运算符的逻辑门下面是对应的HCL表达式:AND用&&表示,OR用||表示,而NOT用!表示。逻辑门只对单个位的数进行操作。逻辑门总是活动的,输入变化输出很快就跟着变化。
用HCL来写这个网的函数:bool eq = (a && b) || (!a && !b)
多路复用器(根据s的值选择是输出a或者b)用HCL来描述:out = (s && a) || (!s && b)
3.将很多的逻辑门组合成一个网,就能构建计算块,称为组合电路。构建这些网时,两个或多个逻辑门的输出不能连在一起且这个网必须是无环的。通常设计的是能对字进行操作的电路:
在HCL中,所有字级的信号都声明为int,不指定字的大小。此电路的函数在字级上表达成 bool Eq = ( A == B )
4.在处理器设计中,很多时候需要将一个信号与许多可能匹配的信号做比较,以此来检验正在处理的信号是否属于某一类指令代码:
此电路中,两位信号code可控制对4个数据字A、B、C、D做选择,根据code值,可以用相等测试来表示信号 s1 和 s0 的产生:bool si = code in { 2, 3 };bool s0 = code in { 1, 3 };
5.组合电路本身不能存储信息。为了产生时序电路,必须引入按位存储信息的设备。一类是时钟寄存器(简称寄存器),储存单个位或字。另一类是随机访问储存器(简称储存器):储存多个字,用地址选择该读/写哪个字,例子包括处理器的虚拟内存系统和寄存器文件。
6.寄存器文件有内部存储,不是组合电路。有A、B两个读端口,和一个W写端口。允许同时进行多个读写操作,可以同时读两个寄存器,同时更新第三个寄存器的状态。两个读端口有地址输入srcA、srcB和数据输入valA和valB。写端口有地址输入dstW,数据输入valW。向寄存器文件写入字是由时钟信号控制的,每次时钟上升时,输入valW上的值会被写入输入dstW上的寄存器ID指示的程序寄存器。
7.随机访问存储器从内存中读的操作方式类似于组合逻辑,写内存时由时钟控制的。
4.3 Y86-64的顺序实现
1.处理一条指令包含很多操作,将它们组织成某个特殊的阶段序列。分为以下几个阶段:
- 取指:取指阶段从存储器读取指令字节,地址为程序计数器(PC)的值
- 译码:译码阶段从寄存器文件读入最多两个操作数,得到val A 和 / 或 val B
- 执行:执行阶段,算术/逻辑单元要么执行指令明确的操作(根据ifun的值),计算存储器引用的有效地址,要么增加或减少栈指针。得到的值为valE
- 访存:访存阶段可将数据写入存储器或从存储器读出数据
- 写回:最多可写两个结果到寄存器文件
- 更新PC:将PC设置成下一指令的地址
2.以下是各个 Y86-64 指令在顺序实现中的计算:
jXX Dest
在执行阶段,检查条件码和跳转条件来确定是否要选择分支,产生出一个一位信号 Cnd 。在更新 PC 阶段,检查这个标志,如果标志为1,就将PC设为valC(跳转目标),如果为0,就设为valP(下一条指令的地址)。
3.我们要将上述计算映射到硬件上,就是要实现逻辑控制,它能在不同硬件单元之间传送数据,以及操作这些单元,使得对每个不同的指令执行指定的运算。SEQ 硬件结构中灰色圆角方框表示的就是控制逻辑块:
4.要控制处理器中活动的时序,只需要寄存器和内存的时钟控制。通过时钟周期来控制元素的更新,通过组合逻辑来传播,每次时钟周期由低到高时,处理器开始执行一条新指令。处理器从来不需要为了完成一条指令的执行而去读该指令更新了的状态。
4.4 流水线的通用原理
1.非流水线化的硬件系统:
2.流水线化的硬件系统:
流水线阶段之间的指令转移是由时钟信号来控制的。每隔120ps信号从0上升至1,开始下一组流水线阶段的计算。
3.流水线的局限性:
- 不一致的划分:由于阶段的延迟并不一样,这样空闲的空间就增加了延迟
- 流水线过深,收益反而下降
4.5 Y86-64 的流水线实现
1.对 SEQ 中五个阶段的顺序进行调整,使得更新 PC 阶段在一个时钟周期开始时执行,而不是在结束时才执行。这种修改过的设计为“SEQ+”。SEQ+中没有单独的硬件寄存器来存放pc,而是通过pIconde、pCnd等寄存器(保存的是前一个周期中产生的控制信号),在一个新的时钟周期开始时用同样的逻辑来计算 pc 值。
- 在 SEQ+ 的各个阶段之间插入流水线寄存器,并对信号重新排列,得到PIPE-处理器。
- F : 保存pc预测值
- D :位于取指和译码之间,保存最新的指令信息,即将由译码阶段处理
- E :位于译码和执行之间,保存最新译码指令和从寄存器读出的值,即将由执行阶段处理
- M :位于执行和访存之间,保存最新执行指令的结果,条件分支和分支目标,即将由访存处理
- W :位于访存和反馈之间,提供给寄存器文件写,完成ret指令,向pc提供返回地址
3.D_stat、E_stat、M_stat、W_stat指的是流水线寄存器的状态码字段,而小写的 f、d、e、m、w指的是流水线阶段,是为了引用某些在一个阶段内刚刚计算出来的信号。
4.数据相关和控制相关可能会导致流水线产生计算错误,成为冒险。首先关心数据冒险,然后再考虑控制冒险。
5.避免数据冒险的方法:
- 暂停:将指令阻滞在译码阶段,相当于加入一条nop指令,直到产生它的源操作数指令通过了写会阶段。
- 转发:将结果值直接从一个流水线阶段传到较早阶段。不是在被动的等待 irmovq 执行完毕,而是在addq指令需要用到rax值时将 irmovq 的W阶段的中间值 W_valE 转发到 addq 指令中作为源操作数 valB :
- 使用暂停和转发相结合的方法来避免加载/使用数据冒险。
6.异常处理方法:
- 由流水线最深的指令引起的异常,优先级最高
- 多条分支中有异常,取消预测指令
- 根据状态码stat发现异常,禁止其他指令更新程序状态
7.PIPE 是使用了转发技术的流水线化的 Y86-64 处理器:
- PC选择和取指阶段:当预测错误分支进入访存阶段,PC选择逻辑会选择M_valA中读出该指令valP的值(下一条指令的地址);当ret指令进入写回阶段时从W _valM中读出的返回地址;其他情况下选择F_predPC。
- 译码和写回阶段:提供给写端口的寄存器ID来自于写回阶段(W_dstE和W_dstM),而不是译码阶段。“Sel+Fwd A”实现 select A 和对 valA 的转发逻辑,“Fwd B”实现对 valB 的转发逻辑:
- 执行阶段:
- 访存阶段:PIPE 中用“Sel+Fwd A”执行SEQ中的“Data”块:
8.流水线控制逻辑根据来自流水线寄存器和流水线阶段的信号,控制逻辑产生流水线寄存器的暂停和气泡控制信号,同时也决定是否要更新条件码寄存器。PIPE流水线控制逻辑覆盖了通过流水线的正常指令流,以处理特殊条件,例如过程返回、预测错误的分支、加载/使用冒险和程序异常:
9.通过确定往流水线中插入气泡的频率来衡量效率的损失。一条返回指令会产生三个气泡,一个加载/使用冒险会产生一个,一个预测错误的分支会产生两个。通过计算PIPE执行一条指令所需要的平均时钟周期数的估计值来量化处罚对整体性能的影响(CPI)。CPI = 1.0 + lp + mp + rp
。
算出CPI的值为1.27。我们的目标是设计一个每个周期发射一条指令的流水线,即CPII为1.0。要想降低CPI,要集中注意力预测错误的分支。
10.实现多周期指令可以简单扩展执行阶段逻辑的功能,添加一些整数和浮点算术运算单元;用暂停来处理短时间的高速缓存不命中和用异常处理来处理长时间的缺页结合起来能够顾及到存储器访问时由于存储器层次结构引起的所有不可预测性。