存器堆。在指令执行过程中,程序计数器的数据放在地址寄存器中,地址寄存器的数据送入增值器。然后将增值后的数据拷贝到寄存器堆的r15(程序计数器),同时还拷贝到地址寄存器,作为下一次取指的地址。
到ARM7为止的ARM处理器使用简单的3级流水线,包括下列流水线级:
· 取指(fetch):从寄存器装载一条指令。
· 译码(decode):识别被执行的指令,并为下一个周期准备数据通路的控制信号。在这一级,指令占有译码逻辑,不占用数据通路。
· 执行(excute):处理指令并将结果写回寄存器。
图2.4显示了3级流水线指令执行过程。
图2.4 3级流水线
| 注意 | 在任一时刻,可能有3种不同的指令占有这3级中的每一级,因此,每一级中的硬件必须能够独立操作。 |
当处理器执行简单的数据处理指令时,流水线使得平均每个时钟周期能完成1条指令。但1条指令需要3个时钟周期来完成,因此,有3个时钟周期的延时(latency),但吞吐率(throughput)是每个周期一条指令。例2.2通过一个简单的例子说明了流水线的机制。
【例2.2】
指令序列为:
ADD r1 r2
SUB r3 r2
CMP r1 r3
流水线指令序列如图2.5所示。
图2.5 流水线指令顺序
在第一个周期,内核从存储器取出指令ADD;在第二个周期,内核取出指令SUB,同时对ADD译码;在第三个周期,指令SUB和ADD都沿流水线移动,ADD被执行,而SUB被译码,同时又取出CMP指令。可以看出,流水线使得每个时钟周期都可以执行一条指令。
当执行多条指令时,流水线的执行不一定会如图2.5那么规则,图2.6显示了有STR指令的流水线状态。
图2.6 含有存储器访问指令的流水线状态
图2.6中在单周期指令ADD后出现了一条数据存储指令STR。访问主存储器的指令用阴影表示,可以看出在每个周期都使用了存储器。同样,在每一个周期也使用了数据通路。在执行周期、地址计算和数据传输周期,数据通路都是被占用的。在译码周期,译码逻辑负责产生下一周期用到的数据通路的控制信号。
| 注意 | 对于STR这种存储器访问指令,实际是在地址计算时由译码逻辑产生下一周期数据传输所需要的数据通路控制信号。 |
在图2.6中的指令序列中,处理器的每个逻辑单元在每个指令都是活动的。可以看出流水线的执行与存储器访问密切相关。存储器访问限制了程序执行必须花费的指令周期数。
ARM的流水线执行模式导致了一个结果,就是程序计数器PC(对使用者而言为r15)必须在当前指令执行前计数。例如,指令在其第一个周期为下下条指令取指,这就意味着PC必须指向当前指令的后8个字节(其后的第2条指令)。
当程序中必须用到PC时,程序员要特别注意这一点。大多数正常情况下,不用考虑这一点,它由汇编器或编译器自动处理这些细节。
例2.3显示了流水线下程序计数器PC的使用情况。
【例2.3】
指令序列为:
0x8000 LDR pc,[pc,#0]
0x8004 NOP
0x8008 DCD jumpAdress
当指令LDR处于执行阶段时,pc=address+8即0x8008。
2.5级流水线ARM组织
所有的处理器都要满足对高性能的要求。直到ARM7为止,在ARM核中使用的3级流水线的性价比是很高的。但是,为了得到更高的性能,需要重新考虑处理器的组织结构。执行一个给定的程序需要的时间由下式决定:
Tprog = (Ninst×CPI)/ fclk
式中:
Ninst:表示在程序中执行的ARM指令数;
CPI:表示每条指令的平均时钟周期;
fclk:表示处理器的时钟频率。
因为对给定程序(假设使用给定的优化集并用给定的编译器来编译)Ninst是常数,所以,仅有两种方法来提供性能。
第一,提高时钟频率。时钟频率的提高,必然引起指令执行周期的缩短,所以要求简化流水线每一级的逻辑,流水线的级数就要增加。
第二,减少每条指令的平均指令周期数CPI。这就要求重新考虑3级流水线ARM中多于1个流水线周期的实现方法,以便使其占有较少的周期,或者减少因指令相关造成的流水线停顿,也可以将两者结合起来。
3级流水线ARM核在每一个时钟周期都访问存储器,或者取指令,或者传输数据。只是抓紧存储器不用的几个周期来改善系统系统性能,效果是不明显的。为了改善CPI,存储器系统必须在每个时钟周期中给出多于一个的数据。方法是在每个时钟周期从单个存储器中给出多于32位数据,或者为指令或数据分别设置存储器。
基于以上原因,较高性能的ARM核使用了5级流水线,而且具有分开的指令和数据存储器。把指令的执行分割为5部分而不是3部分,进而