ARM3级流水和5级流水为什么都是PC=PC+8
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。以下面uboot中的start.S的最开始的汇编代码为例来进行解释:
00000000 <_start>:
0: ea000014 b 58
4: e59ff014 ldr pc, [pc, #20] ; 20 <_undefined_instruction>
8: e59ff014 ldr pc, [pc, #20] ; 24 <_software_interrupt>
c: e59ff014 ldr pc, [pc, #20] ; 28 <_prefetch_abort>
10: e59ff014 ldr pc, [pc, #20] ; 2c <_data_abort>
14: e59ff014 ldr pc, [pc, #20] ; 30 <_not_used>
18: e59ff014 ldr pc, [pc, #20] ; 34 <_irq>
1c: e59ff014 ldr pc, [pc, #20] ; 38 <_fiq>
00000020 <_undefined_instruction>:
20: 00000120 .word0x00000120
复制代码
下面对每一个指令周期,CPU做了哪些事情,分别详细进行阐述:
在看下面具体解释之前,有一句话要牢记,那就是:
PC不是指向你正在运行的指令,而是
PC始终指向你要取的指令的地址。
认识清楚了这个前提,后面的举例讲解,就容易懂了。
指令周期Cycle1
(1)取指:
PC总是指向将要读取的指令的地址(即我们常说的,指向下一条指令的地址),而当前PC=4,
所以去取物理地址为4对对应的指令“ldr pc,[pc,#20]”,其对应二进制代码
ARM3级流水5级流 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)