持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天
设计现代高端微处理器的过程包括两个主要步骤:微体系结构设计和逻辑设计(组合逻辑和时序逻辑) ;
Ø 微体系结构: 包括为获得预期性能而对关键技术进行的研究与确定。通常用性能模型作为评估这些技术有效性的分析工。性能模型在时钟周期的粒度上准确地模拟了处理器地行为,能够计算执行一个测试程序(bench mark) 所需要的时钟周期数目。
微体系结构设计的最终结果是微处理器的高级描述,这种描述一般使用寄存器传输语言(RTL)来定义处理器内部结构中所有主要的模块以及这些模块之间的互连。在进行逻辑设计时,通过加入实现细节来对RTL描述进行精化,最终生成实际硬件设计的HDL描述。
Ø 体系结构、逻辑实现和物理实现
体系结构规定了处理器的功能性行为;逻辑实现是实现体系结构和组织;物理实现是逻辑实现的物理结构和具体表现形式。
体系结构对指令集处理器的指令集合进行说明。为了能被处理器执行,所有的软件都必须与指令集匹配,或者用该指令集进行编码。每个程序都被编译成这个指令集的一个指令序列。
逻辑实现就是体系结构的具体设计,也称为微体系结构。某种体系结构在它的ISA生命周期内可以有很多逻辑实现。对于在这个ISA上编写的任何程序,同一体系结构的所有逻辑实现都可以执行,与逻辑实现相关的一些概念包括流水线设计,Cache存储器和分支预测器。【Cache:高速缓存存储器】
物理实现是设计的具体物理表现形式,通常是单芯片或多芯片的封装。对于一个逻辑实现,可以有许多不同的物理实现,按时钟频率、cache存储容量、总线接口、结构技术及封装等方面的差异而具有不同的形式。
流水线设计
基于上述的理想流水线的考量,推导出流水线设计的三个途径:
- 一致的运算分量 => 保持流水段均衡
- 重复的运算 => 统一指令类型
- 独立的运算分量 => 尽量减少流水线停顿
在典型的现代RISC体系结构中,计算机指令需要完成三类任务:
ALU指令,完成算术和逻辑运算
Load/store指令: 完成在数据在寄存器及存储器间的移动
分支指令:控制指令执行的顺序
Load/store指令和分支指令都采用了比较简单的寻址模式,通常只支持带偏移的寄存器间接寻址模式。对于分支指令,还支持PC相对寻址。
Step1 : 分析各类指令的处理内容
对于上述三类指令,按照IF,ID,OF,EX和OS五个阶段进行划分,可以整理出每一类指令在各个阶段所进行的处理内容:
- ALU 指令处理内容分析
![表格
中度可信度描述已自动生成]()****
- load/store 指令处理内容分析
![表格
描述已自动生成]()
- 分支指令处理内容分析
![表格
描述已自动生成]()****
可见通过上面的划分,能够将各类指令处理过程映射到流水线的每个处理阶段。
Step2 :资源需求整合
资源整合的过程包含以下三个方面:
![文本
描述已自动生成]()****
在理想流水线假设中,需要设计的流水线满足重复的运算原则,即保持所有指令处理的形式上统一。因此对上述的各类指令的处理过程进行微调,包括以下几个方面:
- 将所有指令的计算操作都统一到执行环节,统一使用ALU单元来进行计算,涉及的调整包括load/store和Branch指令的生成地址处理
- 流水线中增加MEM环节,在该环节来处理Load/Store指令的访存操作,以及Branch指令的更新PC操作;
- ALU指令和Load指令的写寄存器环节统一放到流水线最后一个环节进行处理。
相应的处理规范如下图所示:
![图示
描述已自动生成]()
流水线技术是一项可以应用于任何ISA的微体系结构技术,RISC体系结构的特性确实能够使流水线设计更加容易,更加高效。
流水线处理器性能的主要障碍是指令相关引起的流水线停顿。
其中,控制相关引起的分支开销是最主要的部分,动态分支预测(第四章)能够减少这一部分的开销,只有当分支预测失误时才会带来分支开销,当分支预测正确时,流水线没有停顿,然而,当检测失误时,必须清空流水线。
随着流水线深度增加,分支开销也会增大并成为主要的挑战。解决策略:
1. 通过减少流水线前端的段数来减少分支开销,流水线前端指的是从取指段到完成分支指令的相应段距离
2. 增加动态分支预测算法的准确性,从而降低预测失误的频率,因此引入分支开销的频率也得到了降低。
第三章:超标量结构
超标量处理器的本质特点:
1. 能够同时发射多条指令,克服单指令流水线每周期只能发射一条指令的限制,增强了并行执行能力,提高了吞吐量
2. 支持“乱序执行”,当指令由于相关性而被阻塞时可以从后续指令中找出不相关的指令进行执行
标量流水线的局限性:****
1. 标量流水线最大的吞吐率不会超过每周期一条指令。
2. 将不同类型的指令放在一条流水线中处理,效率低下。
3. 为了保证流水线的步调一致而插入的停顿使流水线产生很多气泡
第一个限制比较明显,标量处理器每个周期只能发一条指令,因此IPC(平均每条指令执行的周期数)
采用深流水线(超流水线)可以提高主频,深流水通过减少每段的逻辑门级数降低时钟周期,从而提高主频。
深流水线是以增加流水线的硬件开销为代价的。同时,在解决指令相关时增加了损失的时钟周期数,潜在地降低了处理器的CPI(平均每条指令执行的周期数),这样主频提高带来的好处就被抵消了。为了提高吞吐率,需要使IPC大于1,
因此这时很有必要设计一种能够在同一周期启动多条指令执行的方案,因此需要增加流水线的宽度以适应多条指令同时位于同一流水段的情况。这种流水线称为并行流水线。
低效的统一流水线
标量流水线中,对于所有指令都采用了统一的流水段划分,即:IF,ID,RD,EXE,MEM和WB;但是每个指令都只需要使用其中部分流水段;同时不同指令在各个阶段的操作不同,例如,浮点运算和整数运算的处理复杂度差距悬殊,(因为它们的执行需要多个时钟周期,执行延迟不定或较长的指令很难和延迟为一个周期的指令同一在一条流水线上),使得这些指令难以使用同一的流水线格式。
严格流水线导致的性能损失
标量流水线中要所有指令保持步调一致,指令按照程序的顺序流入流水线,并依次经过流水线的各个环节,一旦一条指令的某个环节出现了停顿,则会导致整个流水线停顿。
标量流水线中的停顿将向后传递并导致了不必要的气泡,从而使某些流水段空闲。
在标量流水线中也将同一流水段处理不同的指令设置了不同的时钟周期,例如无符号整数加减运算一个周期就完成,浮点乘运算则需要多个时钟周期完成。这样设计之后虽然能够提高时钟频率,但还是会导致流水线中产生了大量的停顿。如下面的例子
![表格
描述已自动生成]()
但是如图,如果多条指令可以绕过停顿的流水段,就可以减少多个周期的开销,从而使得流水线表面上看起来一致在执行有效指令。理论上,所有的停顿开销都可以被消除。这种允许后续指令绕过停顿指令的技术称为指令的乱序执行。严格的标量流水线不支持指令的乱序执行,为了解决指令之间的相关,必须插入不必要的停顿周期。支持乱序执行的并行流水线称为动态流水线。
![图示
描述已自动生成]()****
从标量流水线到超标量流水线
标量流水线的性能极限是每周期一条指令,要再进一步提高性能,简单的方式就是设置多条并行的流水线。(实现并行流水需要大量增加硬件资源)例如,设置S条并行的流水线,理性情况下能够将性能提升到每周期s条指令。实现这一效果的代价是流水线的硬件资源需要增加s倍;同时需要指令存储器和数据存储器每个周期内能够进行s次的访问,如下是Pentium中s=2的并行流水线。
\
在前面的标量流水线的设计过程中可以看到,不同的指令处理所需要的功能单元是不同的,在超标量流水线追求形式的统一,将不同指令的处理的功能单元合并到流水线的某一个处理环节中。在并行流水线中可以将这些部分进行分解,例如定点运算操作,浮点运算操作,访存操作,分支操作等功能模块进行拆分,这些模块可以互相独立的处理不同的指令,从而能够实现不增加硬件成本的情况下提升流水线的处理能力。如下图所示的s=3的并行流水线,IF/ID/RD等模块增加硬件使同时能够处理三条指令,之后在RD模块根据不同指令所需的功能模块,分派到对应的流水线。
![图示
描述已自动生成]()
这样的流水线形式被称作多配置并行流水线。 在该架构中EX环节的每个流水线可以根据其设计的目标处理进行针对性优化,以提高硬件效率。
CDC 6600 CPU就是基于多配置并行流水架构进行设计的CPU
![图示, 示意图
描述已自动生成]()****
在多配置并行流水线,多条指令到达RD环节后需要检查各个流水线的状态,只有在指令处理所需的流水线是空闲的情况下才能够分派指令进行执行。这样执行的状态就同指令的顺序强相关,例如程序中连续几条指令都是浮点运算的指令,那么RD只能依次排队处理这些指令,无法获得并行的收益。例如下述的场景,这个场景中是由于流水线硬件的限制,无法避免。
![表格
描述已自动生成]()
为了保证指令的执行结果能够按照原始程序的顺序作用到结果硬件(写入物理寄存器),同时确保指令异常时能够准确的分离已执行和未执行的指令,在此仍然约束指令顺序的完成(结果提交)。即流水线对指令的执行策略是乱序发射,顺序完成。
![表格
描述已自动生成]()****
相应的流水线中需要进行如下调整:
![图示, 工程绘图
描述已自动生成]()
上述结构形式的处理器就是超标量流水线。
超标量流水线同标量流水线之间的一个关键区别是:超标量流水线使用复杂的多记录缓冲存放正在执行的指令。
基于这个多记录缓冲,就可以实现指令的乱序调度,支持乱序执行的并行流水线又称为动态流水线。
超量流水线的两个关键问题:
1. 超标量流水线结构设计:引入保留站
2. 超标量流水线动态调度:采用Tamasulo算法,使用寄存器重命名来解决数据相关,使用硬件分支预测来解决控制相关。
超标量流水线综述
取指 : 设计目标设计增大取指段的宽度,因为取指段能够维持的吞吐率直接影响到整个超标量流水线的吞吐率,后续几个流水段的吞吐率取决于取指的吞吐率,并且不能超过它。
指令译码:指令译码段 对从cache取出但还没有分派到功能部件的指令进行译码,这主要包括指令的识别、指令类型的确定以及指令间相关性的检测。
指令译码的复杂度受两个因素:ISA(指令集架构)和并行流水线的宽度
对于典型的RISC指令集,指令是定长的且格式简单,因此译码操作比较简洁,无需确定每条指令的起止字节。相对较少的指令格式和寻址方式使得指令类型的辨别相对容易,只需对很少的几个字段进行译码(如操作码)就可以确定指令类型和格式,其他字段的意义也可以很快确定。因此,使用RISC指令集可以简化指令译码操作。
指令分派:指令在超标量流水线中必须经过分派才能开始执行。标量流水线中,所有类型的指令均在同一条流水线中执行,因此不存在分派阶段。
超标量属于多配置流水线,其执行段使用了很多不同类型的执行部件,不同类型的指令要在不同部件中执行。指令的类型在译码段一旦确定,指令就必须被发射到相应的部件执行,这就是指令分派所做的工作。
超标量技术
上述介绍了超标量流水线的结构设计,解决了指令在处理时遇到的一般问题。
本章重点是超标量处理器执行指令时的动态行为,以及针对某些特殊指令的处理技术。
三条流通路大致上对应三种主要指令的处理,即分支指令,ALU指令,和load/store指令。因此,要增大三条流通路的吞吐率就必须减少分支指令、ALU指令和load/store指令的开销。
指令流:分支指令处理
寄存器数据流:ALU指令处理
存储器数据流:load/store指令处理
分支造成的性能损失
分支指令对流水线对流水线性能的影响体现在从分支指令进入流水线,到获得分支的目标PC的k个指令周期内,流水线都需要暂停,从而导致流水线效率下降;特别对于超标量流水线,有s条指令并行处理,则造成的影响就会放大。例如分支造成的流水线停顿3个周期,同时流水线支持4条指令并行,则分支就会造成流水线产生12个气泡。
分支造成的开销可以分成两个方面:
条件判断引起的开销
生成目标PC引起的开销
条件判断引起的开销只有条件分支才有,无条件分支不需要进行条件判断。
对于条件判断分支,基于不同的条件方式,造成的延迟影响也不同。若使用条件码来判断,则在指令分派环节完成寄存器读取操作后即可完成分支判断,需要2个周期的延迟;若使用通用比较器,则需要在指令执行环节,完成寄存器数值的比较之后才能够完成分支判断,则需要3个周期的延迟。
![图示, 工程绘图
描述已自动生成]()
其中生成目标PC引起的开销又同目标分支的寻址方式相关,由于不同的寻址方式生成环节不同,从而造成的影响也不同;其中:
PC相对寻址,目标PC在指令译码阶段就可以确定,只有一个周期的开销;
寄存器间接寻址,目标PC需要在指令分派环节,完成寄存器访问后才能够确定,有两个周期的开销;
带偏移量的寄存器间接寻址,目标PC需要在指令执行环节完成偏移量的运算后才能够确定,有三个周期的开销。
![图示
描述已自动生成]()
对于每个分支指令,对流水线造成的影响需要取条件判断和分支目标地址生成两个延迟的最大值作为条件分支的延迟。
为了减少分支指令造成的影响,就期望能够在取到一条指令时能够直接获得这个指令的分支目标地址,然后从分支目标地址上开始取指令,实现零暂停的目标。
分支预测技术
分支预测分为两部分:
分支目标地址的预测
分支条件的预测
分支目标地址预测可以通过设置分支目标缓冲(BTB,Branch Target Buffer)来实现。BTB中每个记录包含两个字段:BIA(分支指令地址)和BTA(分支目标地址)。预测过程描述如下:
初始时,BTB是空的;当处理器第一次执行到一条分支指令,且处理下来确定该指令需要跳转时,就将指令的PC地址和分支的目标地址组成一条记录存放到BTB中;
处理器每次拿到一个PC时,就会将其与BTB中所有记录的BIA进行比对,判断当前指令是否为一条分支指令,若是则直接从BTA字段取出分支目标地址进行下一条指令的取指。
处理器对分支指令后续的计算的目标地址进行跟踪,若目标地址与预测地址不一致,则需要清空这个期间进行的流水线的指令,并恢复PC,同时清楚BTB中对应的记录项;若一致则不需要任何操作。
使用上述的分支预测技术,在循环指令的处理中能够发挥很大的威力,即只有循环的第一次和最后一次会导致流水线产生气泡,中间的每次循环都可以使用正确的预测分支进行处理。
不过在上述的分支预测技术中,处理器执行到一条指令,且该指令需要跳转时就会加入到BTB中;若指令不需要跳转则不加入BTB或从BTB清除。所以BTB中的所有指令都是需要跳转的指令,因此称为静态分支预测技术。
与之相对的就是动态分支预测技术,即可以记录分支运行的历史信息基于历史是否跳转信息来进行动态分支预测。 该预测方法中除了给出分支目标地址外,还会给出分支是否跳转的指示。该方法对每个分支设置一个状态机,用来保存分支的历史信息,相应的BTB会做如下调整。
![图示, 示意图
描述已自动生成]()****
在分支动态预测技术中,状态机的bit数则对应于记录的历史分支状态的数目。
一种常用的状态机是使用两个bit位来表示历史的分支跳转清空,包含四种状态:NN,NT,TT,TN;相应的状态机运行情况如下图所示:
\
基于上述的分支预测状态机,在第一次走到一个循环操作时会出现两次分支预测错误,后续再次走到该循环时就只有退出的那次分支预测出错,能够提升分支预测的成功率。
分支预测失败的恢复(不重要)
在上述的分支预测技术中,需要关注的一点是一旦预测了分支跳转时,就会使用预测的分支目标地址来覆盖处理器的PC寄存器;但是预测可能存在失败,如果预测失败时需要将处理器的PC寄存器恢复。此时从哪里恢复PC寄存器呢?
书中没有将现有技术如何实现,不过一种比较简单的方式就是借助BTB,当前的分支指令在BTB中的是有记录的,且该记录里面是保存了PC值的,那么将该值取出加4就可以得到原先顺序执行地址
先进的分支预测技术 (简约看看)
考虑以下代码:
if (aa==2)
aa = 0;
if (bb==2);
bb = 0;
if (aa==bb) {
}
上述C语言代码变异的汇编代码段为:
DADDIU R3,R1,#-2
BNEZ R3,L1 ; if(aa!=2)
DADD R1,R0,R0 ; aa = 0
L1: DADDIU R3,R2,#-2
BNEZ R3,L2 ; if(bb!=2)
DADD R2,R0,R0 ; bb = 0
L2: DSUBU R3,R1,R2
BEQZ R3,L3 ; if(aa==bb)
上述代码段的第三个分支指令的跳转状态时依赖前两个分支的状态,即如果分支1和分支2都未发生跳转,则分支3必定会进行跳转。因此挖掘分支之间的关联,能够增加分支预测的准确性。
针对这一特点,Yeh和Patt提出了两级自适应分支预测算法,主要区别在于,针对每个分支指令,除了维护一个分支的历史信息表,还维护一个模式历史信息表。
![图示, 工程绘图
描述已自动生成]()
寄存器数据流技术
主要是指在ALU(寄存器到-寄存器型)指令在处理器执行执行部件中的有效执行。
寄存器重命名:处理假数据相关的一种更有效的方法是为同一体系结构寄存器中的多个定义动态分配不同的名字。
寄存器重命名: 读取源寄存器;
分配目的寄存器;更新寄存器
核心在于Tamasulo算法;
**存储器数据流技术
**存储器指令负责在存储器和寄存器文件之间的传递数据,从而支持ALU指令的执行。ALU指令的寄存器操作数必须首先从存储器载入进来才能使用。
存储器访问指令有以下步骤:
生成存储器地址、存储器地址转换和数据访问
cache的映射方式有三种,分别是直接映射、全相联映射和组映射。
存储器访问排序
保存存储器数据相关最直接的方法就是按程序的顺序执行load/store指令。
载入旁路和载入定向
将load指令乱序执行是提高性能的一种主要措施。
有两种乱序执行load指令的技术:载入旁路和载入定向