首先介绍前置知识
arm7采用三级流水
(1)取指(fetch)
取指级的任务是从程序存储器中读取指令。
(2)译码(decode)
译码级完成对指令的分析,并为下一个周期准备数据路径需要的控制信号。在这一级,指令占用译码逻辑,不占用数据通路。
(3)执行(excute)
完成指令要求的操作,并根据需要将结果写回寄存器。指令占用数据路径,寄存器堆被读取,操作数在桶行移位器中被移位。运算器产生运算结果并回写到目的寄存器中,运算器根据指令需求和运输结果更改状态寄存器的条件位。
arm9采用五级流水
(1)取指(fetch)
从存储器中取出指令,并将其放入指令流水线。
(2)译码(decode)
指令被译码,从寄存器堆中读取寄存器操作数。在寄存器堆中有3个操作数读端口,因此大多数ARM指令能在1个周期内读取其操作数。
(3)执行(execute)
将其中一个操作数移位,并在ALU中产生结果。如果指令是Load或Store指令,则在ALU中计算存储器的地址。
(4)缓冲/数据(buffer/data)
如果需要则访问数据存储器,否则ALU只是简单地缓冲一个时钟周期,以便是所有的指令具有同样的流水线流程。
(5)回写(write-back)寄存器堆
------------------------------------------------
注意,arm7中执行和取指是隔了一级译码级,那一级不读取数据,当前PC=原PC+8, 正常
arm9中执行和取指之间的译码级不再老实,译码级已经开始从寄存器堆中读取寄存器操作数,这样的话,
读取到得就是PC+4,不是PC+8,执行级又不会再读一次,那将导致执行级的PC还是=PC+4
为了保持向下兼容,在ARM9的5级流水线上,取指级增加的PC值被直接送到译码级的寄存器,穿过了两级之间的流水线寄存器,这样译码级得到的PC值就是下一条指令的PC+4,等于当前指令的PC+8,
等到了执行级时,PC寄存器的值=当前指令地址+8
当使用指令STR或STM对R15进行保存时,保存的可能是当前指令地址加8或当前指令地址加12。
到底是哪种方式,取决于芯片的具体设计方式。当然,在同一个芯片中,只能采用一种方式。要么保存当前指令地址加8,要么保存当前指令地址加12。程序开发人员应尽量避免使用STR或STM指令来对R15进行操作。当不可避免要使用这种方式时,可以先通过一小段程序来确定所使用的芯片是使用哪种方式实现的。例如:
SUB R1,PC, #4 ;R1中存放STR指令地址
STR PC,[R0] ;用STR指令将PC保存到R0指向的地址单元中,
;PC=STR指令地址+偏移量(偏移量为8或者12)。
LDR R0,[R0] ;读取STR指令地址+偏移量的值
SUB R0,R0,R1 ; STR指令地址+偏移量的值减去STR指令的地址,
;得到偏移量值(8或者12)。
=============================
ARM7采用三级流水线的冯·诺伊曼结构,ARM9采用五级流水线的哈佛结构。
ARM7流水线包括取指(fetch)、译码(decode)、执行(excute)。ARM7流水线在译码阶段不读取操作数寄存器,因此执行阶段的PC值和取指阶段的PC值关系为:PC(excute)=PC(fetch)+8。
ARM9流水线包括取指(fetch)、译码(decode)、执行(excute)、缓冲/数据(buffer/data)、回写(write-back)寄存器堆。ARM9流水线在译码阶段已经开始读取操作数寄存器,因此译码阶段的PC值和取指阶段的PC值关系为:PC(decode)=PC(fetch)+4。因此执行阶段的PC值和译码阶段的PC值关系为:PC(excute)=PC(decode)+4。
为了保证ARM9流水线和ARM7流水线兼容,ARM9流水线将取指阶段的PC值跨过取指和译码流水线寄存器,直接送往译码阶段寄存器,这样仍然保证执行阶段的PC值和取指阶段的PC值关系为:PC(excute)=PC(fetch)+8。
下面对每一个指令周期,CPU做了哪些事情,分别详细进行阐述:
在看下面具体解释之前,有一句话要牢记,那就是:
PC不是指向你正在运行的指令,而是
PC始终指向你要取的指令的地址。
认识清楚了这个前提,后面的举例讲解,就容易懂了。
指令周期Cycle1
(1)取指:
PC总是指向将要读取的指令的地址(即我们常说的,指向下一条指令的地址),而当前PC=4,
所以去取物理地址为4对对应的指令“ldr pc, [pc, #20]”,其对应二进制代码为e59ff014。
此处取指完之后,自动更新PC的值,即PC=PC+4(单个指令占4字节,所以加4)=4+4=8
指令周期Cycle2
(1)译指:翻译指令e59ff014;
(2)同时再去取指:
PC总是指向将要读取的指令的地址(即我们常说的,指向下一条指令的地址),而当前PC=8,
所以去物理地址为8所对应的指令“ldr pc, [pc, #20]” 其对应二进制代码为e59ff014。
此处取指完之后,自动更新PC的值,即PC=PC+4=8+4=12=0xc
指令周期Cycle3
(1)执行(指令):执行“e59ff014”,即“ldr pc,[pc, #20]”所对表达的含义,即
PC
= PC + 20
= 12 + 20
= 32
= 0x20
此处,只是计算出待会要赋值给PC的值是0x20,这个0x20还只是放在执行单元中内部的缓冲中。
(2)译指:翻译e59ff014。
(3)取指:
此步骤由于是和上面(1)中的执行同步做的,所以,未受到影响,继续取指,而取指的那一时刻,PC为上一Cycle
更新后的值,即PC=0xc,所以是去取物理地址为0xc所对应的指令” ldr pc, [pc, #20]”,对应二进制为e59ff014。