第5章介绍的单周期处理器和多周期处理器的指令执行都是采用串行方式。串行方式
第 3 版 · OCR 辅助 · 原书检索 · 文字用于定位,公式与图表请回原页核验 · 本次导入快照
<!-- page: 190 -->
指令流水线
(1)若是R-型指令或I型运算类指令,则在 Mem段是“空”操作,只要把相应信息继续
传递到下一个流水段即可。控制信号取值为Branch=Jump=MemWr=0。
(2)若是lw指令,则进行取数操作。在Ex段得到的地址被送到数据存储器 DM的读
地址端RA,经过一段存取时间,数据从DM的输出端Do送到Mem/Wr寄存器的输入端。
控制信号取值为 Branch=Jump=MemWr=0。
(3)若是sw指令,则进行存数操作。在 Ex段得到的地址被送到数据存储器 DM的写
地址端WA,同时把Ex/Mem寄存器送来的要存的数据R[Rt]送 DM的输入端 Di,经过一
段存取时间后,数据被存入DM中。控制信号取值为Branch=Jump=0,MemWr=1。
(4)若是beq指令,当Ex段生成的 Zero为1,则控制多路选择器选择将转移目标地址
Btarg送 PC输入端。控制信号取值为Branch=1,Jump=MemWr=0。
(5)若是j指令,则控制将Ex/Mem流水段寄存器传送过来的转移目标地址 Jtarg 送
PC的输入端。控制信号取值为Branch=0,Jump=1,MemWr=0。
5.Wr段
如图6.5所示,寄存器写口是Wr段的主要功能部件,寄存器堆 RFile的写地址端口Rw
来源于Mem/Wr寄存器的目的寄存器输出,写数据端口Di来源于一个多路选择器的输出,
写使能信号 WE由溢出标志Overflow和控制信号RegWr共同确定。Wr流水段的功能也
由具体指令确定,各条指令在Wr段的执行流程和控制信号取值如下。
(1)若是R-型指令或I型运算类指令,则选择将 ALU的输出结果送寄存器堆的输入
端Di,目的寄存器送写地址端Rw。控制信号取值为MemtoReg=0,RegWr=1。
(2)若是lw指令,则选择将DM读出结果送寄存器堆的输入端Di,目的寄存器送写地
址端Rw。控制信号取值为MemtoReg=1,RegWr=1。
(3)若是sw、beq或j指令,则任何通用寄存器的值都不改变,即不能写寄存器堆。控
制信号取值为 MemtoReg=x,RegWr=0。
6.2.3流水线控制器的设计
从上述分析可以看出,某一时刻每个流水段执行的是不同指令的某个阶段,因而某一时
刻每个流水段中的控制信号应该是正在执行指令的对应功能段的控制信号。
如图6.8所示,假定有3条指令lw、ori和add依次在时钟1、2和3开始进入流水线执
行,则流水线中控制信号的传递情况为:第2时钟对lw指令译码,产生的控制信号在下个
时钟(第3时钟)送到Exec段,在第4时钟送到Mem段,在第5时钟送到Write段;在第3
时钟对ori指令译码,产生的控制信号在第4时钟送Exec段,第5时钟送Mem段,第6时
时钟周期
1
2
3
4
5
6
7
lw指令
Ifetch
Reg/Dec
Exec
Mem
Write
ori指令
Ifetch
Reg/Dec
Exec
Mem
Write
add指令
Ifetch
Reg/Dec
Exec
Mem
Write
第6章
173
图 6.8 流水线执行情况举例
<!-- page: 191 -->
计算机组成与系统结构(第3版)
174
钟送Write 段⋯⋯由此可见,在某个时钟周期,不同的流水段受不同指令的控制信号控制,
执行不同指令的不同功能段。例如,在第5时钟内,Write段由lw指令的信号控制,Mem
段由ori指令的信号控制,Exec段由add指令的信号控制。
从上述例子可看出,在Reg/Dec阶段由控制器产生指令各流水段的所有控制信号,分
别在随后的各个时钟周期内被使用。具体来说,Exec阶段的信号(如 ExtOp、ALUSrc、
ALUop、RegDst、R-type)在下个周期使用;Mem阶段的信号(如 MemWr、Branch)在随后
第二个周期使用;Write阶段的信号(如 MemtoReg、RegWr)在随后第三个周期使用。因
此随后各流水段寄存器中都要保存相应的控制信号,如图6,9所示。
Reg/Dec
Exee
Mem
Write
IF/ID
Main
Control
ExtOp
ALUSre
ALUop
RegDst
R-type
MemWr
Branch
MemtoReg
RegWr
ExtOp
ALUSre
ALUop
RegDst
ID/Ex
R-type
MemWr
Branch
MemtoReg
RegWr
Ex/Mem
Mem Wr
Branch
MemtoReg
RegWr
Mem/Wr
MemtoReg
RegWr
图6.9 控制信号在流水线中的传递
综上所述,每个流水段寄存器中保存的信息包括两类:一类是后面阶段需要用到的所
有数据信息,包括PC+4、指令、立即数、目的寄存器、转移目标地址、ALU运算结果、标志信
息等,它们是前面阶段在数据通路中执行的结果;还有一类是前面传递过来的后面各阶段要
用到的所有控制信号。
## 第5章介绍过单周期处理器和多周期处理器的控制器设计。单周期处理器中,每条指
令的控制信号在指令执行期间不变;而多周期处理器中,每条指令分多个周期执行,因此控
制器的功能采用有限状态机来描述。
流水线处理器中控制信号一旦在Reg/Dec(ID)阶段由控制器生成,就不会改变,并和数
据信息同步地依次传递到后面的流水段中。显然,这和单周期控制器类似,因而流水线控制
器的设计可以完全按照单周期控制器设计的思路进行,故在此不再赘述。
6.3流水线冒险及其处理
指令流水线中,可能会遇到一些情况使得流水线无法正确执行后续指令而引起流水线
阻塞或停顿(stall),这种现象称为流水线冒险(hazard)。根据导致冒险的原因的不同,有结
构冒险、数据冒险和控制冒险3种。以下分别介绍其原因和对策。
6.3.1结构冒险
结构冒险(structural hazards)也称为硬件资源冲突(hardware resource conflicts)。引起结
<!-- page: 192 -->
指令流水线
构冒险的原因在于同一个部件同时被不同指令所用,也就是说它是由硬件资源竞争造成的。
如图6.10(a)所示,若不区分指令存储器和数据存储器而只用一个存储器的话,则在
load指令取数据的同时,随后的指令3(instr3)正好取指令,此时发生访存冲突。同样,如果
不对寄存器堆的写口和读口独立设置的话,load 和随后的指令3也会发生寄存器访问冲突。
解决结构冒险的策略包含两方面:①通过6.2.1节提到过的功能段划分原则(一个部件
每条指令只能使用一次,且只能在特定时钟周期使用),可以避免一部分结构冒险;②通过
设置多个独立的部件来避免硬件资源冲突。例如,对于寄存器访问冲突,可将寄存器读口和
写口独立开来,利用时钟上升沿和下降沿两次触发,使得前半周期使用写口进行寄存器写,
后半周期使用读口进行寄存器读;对于存储器访存冲突,可把指令存储器IM和数据存储器
DM分开,从而使指令和数据的访问各自独立,这样就不会发生结构冒险,如图6.10(b)所
示。事实上,现代计算机都引入了 cache机制,而且 L1 cache通常采用数据 cache 和代码
cache 分离的方式,因而也就避免了结构冒险的发生。
Time (clock cyeles)
IF
ID
Mem
Wr
load
IM
Reg
Men
instr 1
IM
Reg
DM
Reg
instr 2
IM
Reg
DM
Reg
instr 3
Mem
DM
Reg
instr 4
IM
Reg
DM
Reg
(a)有寄存器和存储器访问冲突的流水线
Time (clock cycles)
IF
ID
Ex
Mem
Wr
IM
Reg
DM
沼
IM
Reg
DM
Reg
IM
Reg
DM
Reg
IM
Rk
DM
Reg
IM
Reg
DM
Reg
(b)消除了寄存器和存储器访问冲突的流水线
第6章
175
图6.10 结构冒险的例子
<!-- page: 193 -->
计算机组成与系统结构(第3版)
6.3.2数据冒险
176
数据冒险(data hazards)也称为数据相关(data dependencies)。引起数据冒险的原因在
于后面指令用到前面指令结果时前面指令结果还没产生。图6.11 是一个存在数据冒险的
流水线例子。
Time(clock cycles)
IF
ID
Ex
Mem
Wr
add $1.S2.S3
IM
Reg
DM
eg
sub $4,S1.S3
IM
Re
DM
Reg
or S8,S1,$9
IM
Re
DM
Reg
add $6,S1,$7
IM
Re
DM
Reg
xor $3,$1.S5
IM
cg
DM Reg
图 6.11 存在数据冒险的流水线例子
在图6.11中,第一条指令的目的寄存器$1是后面4条指令的源寄存器。第一条指令
在Wr阶段结束才将结果写到$1中,而第2、3、4条指令分别在第一条指令的 Ex、Mem 和
Wr阶段就要取$1的内容,显然,如果不采取任何措施,那么这几条指令取到的是$1的旧
值,只有第5条指令xor能取到$1的新值。从图6.11可看出,所有的数据冒险都是由于前
面指令写结果之前后面指令就需要读取而造成的,这种数据冒险称为写后读(read after
write,RAW)数据冒险。在非“乱序”执行的基本流水线中,所有数据冒险都属于RAW数
据冒险。
对于RAW数据冒险,可以采取以下措施。
1.插入空操作指令
在软件上采取措施,使相关指令延迟执行。最简单的做法是,在编译时预先插入空操作
指令nop。这样做的好处是硬件控制简单,但浪费了指令存储空间和指令执行时间。如
图6.12 所示,共浪费了3条指令的空间和时间。
2.插入气泡
在硬件上采取措施,使相关指令延迟执行,通过硬件阻塞(stall)方式阻止后续指令执
行。这种硬件阻塞的方式称为插入气泡(bubble),如图6.13所示。
这种方式控制比较复杂,需要修改数据通路。通常要在数据通路中检测哪两条指令发
生了相关,以确定是否进行阻塞。阻塞时,可将控制信号清零来阻止结果的写入;也可将指
令清零使后续指令执行空操作;或让PC写使能信号清零使PC值不变,从而使当前指令重
复执行。这种方式不增加指令条数,但有额外时间开销。
3.采用转发技术
将数据通路中生成的中间数据直接转发到ALU的输入端。如图6.14所示,对于第1
<!-- page: 194 -->
指令流水线
IF
Time (clock cycles)
ID
Ex Mem Wr
add S1,$2,$3
IM
Reg
DM
Reg
nop
IM
Reg
DM Reg
nop
IM
Reg
DM
Reg
nop
IM
Reg
DM Reg
sub $4,S1,$3
IM
Re
DM
Reg
or $8,S1,S9
IM
Reg
DM
图 6.12 用插入 nop 指令方式解决数据冒险
Time(clock cyeles)
IF
ID
Ex
Mem Wr
add $1, S2,$3
IM
Reg
DM
B
stall
IM
气泡
气泡
气泡气泡
stall
IM
气泡气泡
气泡气泡
stall
IM
气泡气泡
气泡气泡
sub $4,S1.S3
IM
Re
DM
Reg
or $8.S1.S9
IM
Reg
DM
图6.13 用流水线阻塞方式解决数据冒险
条add指令和sub指令之间的数据相关情况,add指令在 Ex段结束时已经得到$1的新
值,被存放在 Ex/Mem流水段寄存器中,因此,可以直接从该流水段寄存器中取出数据送到
ALU的输入端,这样,在sub指令执行时ALU中用的就是$1的新值。对于第1条add指
令和or指令之间的数据相关情况,or指令在ALU中用到的$1也可直接从Mem/Wr 流水
段寄存器中取。这种技术称为转发(forwarding)或旁路(bypassing)技术。
对于图6.14中第1和第4条指令之间的数据相关问题,可以通过将寄存器写口和读口
分别控制在前、后半个时钟周期内操作来解决,使前半周期写入$1的值在后半周期马上被
读出。
第6章
177
<!-- page: 195 -->
计算机组成与系统结构(第3版)
178
add $1, S2, $3
sub $4.SL.S3
or $8,$1, 59
add $6,S1.S7
xor $3,$1.S5
IF
IM
Time (clock cycles)
ID
Ex
Mem Wr
Reg
DM
Reeg
IM
Re
DM
IM
Re
IM
Re
IM
Reg
DM
Reg
Reg
DM
Reg
DM
Reg
图6.14 用转发技术解决数据冒险
采用转发技术解决数据冒险必须在硬件上进行相应的改动。如图6.15所示,通过在
ALU的输入端加多路选择器,使Ex段之后的流水段寄存器的值能返送到ALU输入端。
ALU的 A输入端原来只有从ID/Ex寄存器来的busA,B输入端原来只有从ID/Ex寄存器
来的 busB和扩展器的值,采用转发技术后,A端和B端都增加了3个可能的输入。
Ex
Mem
③
lw S3,100(S1)
or S6,$2,S1
①
sub S5,S3,S4
add S3,S2, SI
MUX
sub $5,S3,S4
A
Mem/r
Ex/Mem
ID/Ex
busA
ALU
DM
Adr
busB,
②
Do
MUX
add S3,S2,S1
Di
B
or S6,$2,SI
sub S5,S3,$4
扩展器
图6.15 引入转发技术后数据通路中增加的转发线路
图6.15中有3个指令序列示例,从这3个示例可看出,增加转发线路后,相邻两条
ALU 运算类指令之间(指令序列①)、相隔一条的两个 ALU运算类指令之间(指令序列
②),以及相隔一条的load和ALU运算类指令之间(指令序列③)的数据相关带来的数据冒
险问题就都能解决了。
若前面指令的目的寄存器和随后sw指令的源寄存器发生数据相关,例如,相邻两条指
令为“add $3,$2,$1”和“sw $3,0($1)”,则图6.15中的转发线路不能解决其数据冒险
问题。可以参照图6.15所示方法,在 DM的数据输入端 Di处增加一个多路选择器,当出现
<!-- page: 196 -->
指令流水线
这种数据冒险时,选择上条指令执行阶段产生的ALU结果作为Di的输入值。
从图6.15可看出,采用转发技术的数据通路中,在执行阶段中ALU的两个输入端处,
多路选择器的控制信号需要考虑转发条件,因而需要对图6.7中的执行部件进行以下调整。
(1)原来 ALU的A输入端加一个三选一多路选择器,随之增加一个两位的控制信号
ALUSrcA。
(2)原来ALU的B输入端多路选择器要调整为四选一,原来的一位控制信号ALUSrc
改为两位控制信号 ALUSrcB。
(3)控制信号ALUSrcA和ALUSreB的取值除了考虑原来的控制信号ALUSrc以外,
还要考虑转发条件检测的结果。
(4)对图6.15中的转发线路进行合并,在Wr阶段用一个多路选择器将ALU 输出结果
和数据存储器的输出数据合并成一路数据同时转发到 ALU 的两个输入端。
调整后的部分流水线数据通路如图6.16所示。
Ex
Mem
Mem/Wr.RegWr
Ex/Mem.RegWr
busA
00
MUX
01
A
DM
10
ALU
Adr
Do
Ex/Mem
ID/Ex
Mem/Wr
MUX
busB
Di
00
0
### 01 子
B
10;文
Rs
11
Rt
Rd
0:XnM
Ex/Mem.regRd
转发检测
Mem/Wr.regRd
单元
ALUSrcA
扩展器
ALUSrcB
ExtOp
RegDst
ALUSre
MemtoReg
图6.16 带转发控制的部分流水线数据通路
图6.16中“转发检测单元”的控制逻辑可根据指令的数据相关性来设计。从图6.15可
以看出,发生数据相关的情况有以下两种。
(1)本条指令的目的操作数是随后第一条指令所用的源操作数,对应的转发条件如下:
C1(A):(Ex/Mem.regRd=ID/Ex.Rs)
C1(B):(Ex/Mem.regRd=ID/Ex.Rt)
当C1(A)=1时,ALUSrcA应等于01;当C1(B)=1时,ALUSrcB应等于01。
(2)本条指令的目的操作数是随后第二条指令所用的源操作数,对应的转发条件如下:
C2(A):(Mem/Wr.regRd=ID/Ex.Rs)
C2(B):(Mem/Wr.regRd=ID/Ex.Rt)
第6章
179
<!-- page: 197 -->
计算机组成与系统结构(第 3版)
180
当C2(A)=1时,ALUSrcA应等于10;当C2(B)=1时,ALUSrcB应等于10。
当C1(A)和C2(A)都不等于1时,ALUSrcA应等于00。当C1(B)和C2(B)都不等于
1时,ALUSrcB应根据 ALUSrc的值确定,当 ALUSrc=0时,ALUSrcB等于 00;当
ALUSrc=1时,ALUSrcB等于11。
以上考虑的仅是基本的数据相关情况。实际上,转发条件还要考虑其他一些约束情况,
以下是一些例子。
(1)运算结果不写入目的寄存器。例如,对于beq指令后面紧跟一条ALU运算类指令
的情况,虽然可能满足上述条件,但是beq指令并不改变目的寄存器Rt的值,所以,不能进
行转发。
(2)目的寄存器为$0。例如,对于指令“add$0,$7,$8”,根据图6.16可知,转发的
是$7和$8的内容相加的结果,它可能是一个非0数,但实际上下条指令的操作数应该是
$0的内容0。
(3)多条连续指令关于同一个寄存器数据相关。例如,对于下列指令序列:
add
add
add
⋯⋯
$1,$1,$2
§1,91,§3
$1,§1,$4
按照前述C1(A)和C2(A)的逻辑表达式,可得C1(A)=C2(A)=1,这样,使得
ALUSrcA 的取值不确定而发生错误。显然,这种情况下,应该使C1(A)=1,C2(A)=0,
即,当本条指令源操作数和上条指令的目的操作数一样,则不能转发上上条指令的结果,而
必须转发上条指令的结果。
综合考虑上述各种情况,得到改进的转发条件逻辑表达式如下。
C1(A):Ex/Mem.RegWr66(Ex/Mem.regRd!-0)66(Ex/Mem.regRd==ID/Ex.Rs)
C1(B):Ex/Mem.RegWr 66(Ex/Mem.regRd!=0)66(Ex/Mem.regRd==ID/Ex,Rt)
C2(A):Mem/Wr.RegWr&6(Mem/Wr.regRd!=0)66
(Ex/Mem.regRd!=ID/Ex.Rs)6&(Mem/Wr.regRd==ID/Ex.Rs)
C2(B):Mem/Wr.RegWr 66(Mem/WB.regRd!=0)66
(Ex/Mem.regRd!=ID/Ex.Rt)66(Mem/Wr.regRd=-ID/Ex.Rt)
通过上述转发条件的检测和对相应的转发线路的控制,可以解决大部分RAW数据
冒险。
4.load-use 数据冒险的检测和处理
转发能够解决大部分RAW数据冒险,那么,lw指令随后跟 R-型指令或I-型运算类指
令的相关性问题,能否通过转发来解决呢?如图6.17所示,lw指令只有在Mem段结束时
才能得到 DM中的结果,然后送Mem/Wr寄存器,在Wr段前半周期$1中才能存入新值,
但随后的sub指令在Ex阶段就要取$1的值。因此,得到的是旧值,而根据图6.15的转发
线路,ALU的输入端要么来自上条指令在Ex段生成且存放在Ex/Mem寄存器中的值,要
么来自上上条指令的执行结果。由此可知,用转发线路无法解决图中lw指令和sub指令之
间的数据相关问题。通常把这种情况称为load-use数据冒险。
对于load-use数据冒险,最简单的做法是由编译器在load指令之后插入nop指令来解
<!-- page: 198 -->
指令流水线
Time (clock cycles)
IF
ID
Ex
Mem Wr
1w $1,0(S2)
IM
Reg
DM
Re
sub $4,S1, $3
IM
Re
DN M
Reg
or $8,S1.S9
IM
R
DM Reg
add S6,S1,S7
IM
Re
DM
Reg
图6.17 load-use 数据冒险
决,这样,就无须硬件来处理数据冒险问题了。当然,最好的办法是在程序编译时进行优化,
通过调整指令顺序以避免出现 load-use现象。
例 6.1 以下是某高级语言源程序中的两条赋值语句:
a=b+c;
d=e-f;
假定a、b、c、d、e、f都被分配在内存,其地址分别用[a]、[b]、[c]、[d]、[e]、[f]表示,通
过编译器编译后,生成的汇编目标代码(为方便说明,在第一列加了序号)如下:
1
1w
### 2 1w
3
add
4
sw
5
lw
6
lw
7
sub
8
sw
s2,[b]
§3,[c]
$1, S2,§3
s1,[a]
$5,[e]
s6,[f]
S4,55,S6
s4,[d]
请分析上述目标代码中的数据相关性,并说明哪些相关性引起的数据冒险可通过转发
技术解决,哪些不能?并要求进行代码优化,以尽量减少load-use数据冒险。
解:上述目标代码中,发生数据相关的指令对是1-3、2-3、3-4、5-7、6-7、7-8。其中,2-3
和6-7两个指令对之间出现了load-use数据冒险,它们不能通过转发技术解决,其他指令对
之间的相关性引起的数据冒险都可通过转发技术解决。
可通过调整指令顺序,将一条无关指令插入load和R-型指令之间来优化代码,以避免
load-use 现象。本例中通过将第5条指令和第4条指令分别插入2-3和6-7指令对中间来
进行优化。以下是编译优化得到的目标代码:
1. 1w
§2,[b]
2.1w
§3,[c]
5.1w
55,[e]
第6章
181
3.add
$1,$2,$3
<!-- page: 199 -->
计算机组成与系统结构(第3版)
182
6.1w
$6,[f]
4. sw
s1,[a]
7.sub
§4,$5,§6
B.SW
§4,[d]
显然,优化后的指令序列比优化前的指令序列在流水线中执行速度快。据统计,优化调
度后,load-use冒险引起的阻塞现象大约能降低1/2~1/3。由此可见,编译优化对程序的性
能是非常重要的,而了解指令的功能、指令执行流程和流水线结构等对构造良好的编译器又
是极其必要的。
如果需要硬件来处理load-use冒险,那么必须在流水线数据通路中增加load-use 冒险
检测部件,并在检测到发生 load-use冒险时进行流水线阻塞处理。从图6.17可以看出,
load-use 冒险发生的条件是:上条是 load指令,并且从存储器装入寄存器的数据是当前指
令的源操作数。load-use冒险的检测越早越好,但是,再早也要在load 随后的指令被取出并
译码之后,因此,检测点可安排在其译码(ID)阶段。此时,若是load-use冒险,则load 指令
应处于执行(Ex)阶段。为了能够确定上条是否是load指令,可引入一个新的控制信号
MemRead,load 指令时该信号取值为1,否则取值为0。
根据上述分析,得到 load-use冒险检测条件C为
ID/Ex.MemRead 66((ID/Ex.Rt==IF/ID.Rs)II(ID/Ex.Rt==IF/ID.Rt))
当C=1时,说明发生了load-used数据冒险。检测出load-use数据冒险时,load 指令
后面的第一条指令(如6.17中的 sub指令)正在ID阶段进行译码和取数操作,下个时钟到
来时,译码出来的控制信号和寄存器Rs、Rt的值将被送到 ID/Ex流水段寄存器。同时,
load后面的第二条指令(如图6.17中的or指令)处在IF阶段,正在根据PC的值取指令,下
个时钟到来时,取出的指令将被送到IF/ID流水段寄存器。为了避免load-use数据冒险,必
须使紧随 load后的两条指令停顿一个时钟周期后继续执行。这可通过将这两条指令的执
行结果清除并让它们延迟一个时钟周期来实现。具体来说,就是控制实现以下3个操作:
①将ID/Ex流水段寄存器中的所有控制信号清零(相当于插入了一个气泡),而不是将当时
译码出来的控制信号送ID/Ex流水段寄存器;②保持IF/ID流水段寄存器的值不变,而不
是送当时取出的指令,这样,使load后面的一条指令继续保存在IF/ID流水段寄存器中,在
下个时钟周期,该指令重新译码/取数;③保持PC的值不变,使load后面的第二条指令在
下个时钟周期重新执行取指令操作。图6.18给出了带转发和 load-use 冒险处理的部分流
水线数据通路。从图中可以看出,当检测到存在load-use数据冒险时,load-use 检测单元送
出3个控制信号(图中①、②、③处),分别控制上述3个操作的实现。
6.3.3控制冒险
从图6.5给出的流水线数据通路来看,正常情况下,指令在流水线中总是按顺序执行,
当遇到改变指令执行顺序的情况时,流水线中指令的正常执行会被阻塞。这种由于发生了
指令执行顺序改变而引起的流水线阻塞称为控制冒险(control hazards)。各类转移指令(包
括调用、返回指令等)的执行,以及异常和中断的出现都会改变指令执行顺序,因而都可能会
引发控制冒险。
<!-- page: 200 -->
指令流水线
IF
ID
Ex
Mem
8
load-use
③
检测单元
①
②
ID/Ex.MemRead
Ex/Mem.RegWr
busA
00
MUX
DM
寄存器堆
01
A
103
ALU
Adr
Do
IF/ID
ID/Ex
Ex/Mem
Mem/Wr
IM
busB
XUM
00
Di
01MUX
B
10;
Rs
Rs
11
Rt
Rt
XnM
Rd
Ex/Mem.RegRd
转发Mem/Wr.RegRd
检测
ALUSrcA
单元
扩展器
ALUSrcB
Mem/Wr.RegWr
ExtOp
RegDst
ALUSre
MemtoReg
图6,18 带转发和load-use 冒险处理的部分流水线数据通路
1.分支指令引起的控制冒险
图6.19 是一个由分支指令(条件转移指令)引起的控制冒险的流水线例子。
时钟周期
1
2
3
4
5
6
7
8
9
10
8:sub
IF
ID
Ex
Mem
Wr
12:beq
IF
ID
Ex
Mem
Wr
16:ori
10
Ex
Mem
Wr
20:add
#
10
Ex
Mem
Wr
24:add
ID
Ex
Mem
Wr
1000:1w
IF
ID
Ex
Mem
Wr
图6.19 分支指令引起的控制冒险的流水线例子
图6.19中,假定beq指令的地址为12,条件满足时其转移目标地址为1000。从图6.5
和图6.7可以看出,分支指令beq的转移目标地址计算操作在Ex段,并在 Mem段由标志
Zero 和控制信号 Branch来控制,以确定是否将PC的值更新为转移目标地址 Btarg。因此,
在图6.19所示的例子中,只有当beq指令执行到第5时钟结束才能将转移目标地址1000
送到 PC的输入端。在第6时钟到来后,取出1000号单元开始的指令送流水线中执行。此
时,紧接在beq指令后面的第16、20和24单元的指令已在流水线中被执行了一部分。显
第6章
183
<!-- page: 201 -->
计算机组成与系统结构(第3版)
184
然,正确的执行流程应该是第12单元中的beq指令执行完后转移到第1000单元执行,因
此,如果不采取相应措施则指令流水线的执行便发生问题。
通常把由于流水线阻塞而带来的延迟执行周期数称为延迟损失时间片C。显然,图6.19
中的延迟损失时间片C=3。由于指令分支而引起的控制冒险也称为分支冒险(branch
hazards)。对于分支冒险,可采用和前面解决数据冒险一样的硬件阻塞方式(插入气泡)或
软件阻塞方式(插入空操作指令)。假设延迟损失时间片为C,则在数据通路中检测到分支
指令时,就在分支指令后插入C个气泡,或在编译时在分支指令后填入C条nop指令。
插入气泡和插入空操作指令这两种都是消极的方式,效率较低。结合分支预测可以降
低由于分支冒险带来的时间损失。分支预测有简单(静态)预测和动态预测两种。此外,还
有延迟分支方式也可部分解决分支冒险问题。
1)简单预测
简单预测与指令执行历史无关,因此,它是一种静态预测方式。可以简单预测分支指令
的条件总是不满足(not taken)或总是满足(taken)。对于预测不满足的情况,流水线总是按
顺序继续执行分支指令的后续指令,如果在数据通路中检测到实际条件确实不满足时,则预
测正确,没有任何时间损失;如果检测到实际条件满足时,则预测不正确,此时,将分支指令
后续不该执行的指令(如图6.19中的第16、20、24单元中的指令)的控制信号清零,实际上
只需要将寄存器写信号RegWr和存储器写信号MemWr清零,就能保证不会改变指令执行
结果,相当于执行了空操作。这样,如果分支延迟损失时间片为3,则预测错误时将损失3
个时钟周期。
简单预测方式下,如果转移概率是50则预测正确率仅有50??当然,也可以加一些
启发式规则来提高简单预测准确率。可以进行一些有条件的简单预测,即在有些情况下预
测总是满足,其他情况预测总是不满足。例如,将循环体顶(底)部的分支总是预测为不满足
(满足)。这种方法能达到65??85??预测准确率。
2)动态预测
动态预测(dynamic prediction)的准确率可达90现在几乎所有处理器都采用动态预
测。它利用分支指令发生转移的历史情况来进行预测,并根据实际执行情况动态调整预测
位。转移发生历史情况记录在一个表中,这个表有不同的名称,如分支历史记录表(branch
history table,BHT)、分支预测缓冲(branch prediction buffer,BPB)、分支目标缓冲(branch
target buffer,BTB)等。图 6.20 给出了动态预测和调整过程。
每个表项由分支指令的地址作索引,故在分支指令的IF阶段就可取到预测位。因此,
完全来得及在分支指令进入ID阶段时去取被预测执行的后继指令。首先,根据当前分支指
令的地址低位查找BHT中对应的项;若未找到(即“未命中”),说明该分支指令是第一次执
行,则由控制逻辑加入一个新项,将该分支指令的地址低位、转移目标地址和初始预测位填
入表项中;若找到(即“命中”),则控制逻辑根据预测位,确定是“转移取”还是“顺序取”;在分
支指令执行时,控制逻辑根据实际情况来修改调整预测位。预测位的宽度对动态预测准确
率有影响。有一位预测位或两位预测位,也有的系统采用两位以上预测位。
(1)一位预测位。
采用一位预测位时,总是按上次实际发生的情况来预测下次分支情况,可用1表示最近
一次发生转移(taken),0表示未发生转移(not taken)。
<!-- page: 202 -->
指令流水线
分支
指令
地址
BHT
分支指令地址预测位转移目标地址
①查找
转移取
顺序取
④修正
②预测
加入新项
③选择
控制逻辑
命中与否
实际执行情况
指令预取器
指令执行
图 6.20 动态预测和调整过程
预测时,若预测位为1,则预测下次条件满足,会发生转移;若为0,则预测下次条件不满
足,不会发生转移。实际执行时,若预测错,则预测
位取反;否则,预测位不变。可用一个简单的预测状
态图表示预测位的动态调整过程,如图6.21所示。
、正确
正确
发生
不发生,
不发生 错误,
预测发生
预测不发生
1
0
发生 错误
采用一位预测位的缺点是:当分支情况连续两
次发生改变时,则预测错误。例如,对于循环出口处
图 6.21 一位预测位的状态转换
的分支指令,第一次进循环和最后一次出循环时都
会发生预测错误,因为这两次都会改变分支情况;而在循环中每次预测都不会错,因为预测
和实际的情况都是发生转移。
例6.2 图6.22给出了某个C语言程序段及其对应的MIPS汇编代码。假定该程序在
一个采用一位预测位的流水线处理器上执行,预测位初始为0。试分析当N=10和N=
100时该程序段中各分支指令的预测正确率。
int sum(int N)
)
int 1,3,sum=0;
for(i=0;i<N;i++)
for(j=0;j<N;j++)
sum=sum+1;
return sum;
Loop-i: beq $t1,Sa0,exit-i
*若(i=N)则跳出外循环
add $t2,$zero,$zero #j=0
Loop-j:
beq $t2,Sa0,exit-j
*若(j=N)则跳出内循环
addi st2,$t2,1
#j=j+1
addi st0,st0,1
#sum=sum+1
j loop-j
addi st1,st1,1
*i=i+1
exit-j:
j Loop-i
exit-i:
(a)C语言程序段
(b)汇编程序段
图 6.22 循环中分支指令的预测
解:该程序具有两重循环结构,每层循环中有一个分支指令,位于循环入口处。外循环
中的分支指令共执行N+1次,内循环中的分支指令共执行N×(N+1)次。
第6章
185
<!-- page: 203 -->