EDA365电子论坛网
标题: ARM条件执行 [打印本页]
作者: monsterscvb 时间: 2021-5-6 13:56
标题: ARM条件执行
条件执行指令格式6 h3 q$ e$ ]8 |! X- V
ARM 处理器的一个非常特殊的特征是它的条件执行。我们指的不是基本的如果进位则分支,ARM 使这个逻辑阶段进一步深化为如果进位则 XXX - 这里的 XXX 是任何东西。6 e" b6 p" ^5 u4 M% ?; e4 L
为了举例,下面是 Intel 8086 处理器分支指令的一个列表:
8 u; [1 c1 W p7 f6 aJA Jump if Above( P6 s/ k4 x: ? W1 L! x
JAE Jump if Above or Equal0 n* H# T' X0 y: e' s
JB Jump if Below, n! e( N4 L4 \# z% A0 r
JBE Jump if Below or Equal0 w A# q' b9 q2 H; u$ U
JC Jump if Carry( J) u2 o7 s' r) W2 [+ m
JCXZ Jump if CX Zero (CX is a register that can be used for loop counts)* R) w% v9 x$ J, u, E
JE Jump if Equal
! D/ r$ Z' U( a K4 U" y0 hJG Jump if Greater than# ]/ e; \6 C- Y7 F
JGE Jump if Greater than or Equal
p/ E+ n! l, r N: @( OJL Jump if Less than
% A1 K& X, Z$ p1 |8 |6 S1 RJLE Jump if Less Than or Equal2 J) s6 u( j! d; e, G
JMP JuMP* ~' E& k) D6 V' B/ s
JNA Jump if Not Above8 \9 Z0 r' s. r
JNAE Jump if Not Above or Equal# s! d- v) G* H* f9 @
JNB Jump if Not Below
6 @3 D8 ~1 [0 r5 o1 E2 `JNBE Jump if Not Below or Equal# q ^; n9 Y! n5 U9 I0 i4 f
JNC Jump if No Carry
# Y* }) U6 Y! Q( l# \3 q1 xJNE Jump if Not Equal
8 B) n+ g D# d' T; K$ p! AJNG Jump if Not Greater than
7 H: p; P! J% {- B; kJNGE Jump if Not Greater than or Equal
: l: B+ V& a# @JNL Jump if Not Less than
5 B% j0 L1 u2 e$ r- q) E" Y6 @5 IJNLE Jump if Not Less than or Equal% }" U- I2 Q; _; X* S3 o I+ C
JNO Jump if Not Overflow3 p( P1 c% U$ T
JNP Jump if Not Parity' d( X: i8 ~+ e
JNS Jump if Not Sign
( R W* ^, i7 K9 IJNZ Jump if Not Zero
' E+ @# @# \# V. k2 w, S& ~3 kJO Jump if Overflow% V: O1 n% A3 e( w
JP Jump if Parity
/ O0 a( R+ @2 X: `+ Z: u& ~JPE Jump if Parity Even6 a6 }8 J. u. e: }* l# R$ D
JPO Jump if Parity Odd, ^/ N3 Q2 O! O4 Q
JS Jump if Sign" A6 G: ~, R) K6 X7 o. ]' o9 Q
JZ Jump if Zero8 K. C& U$ j0 ^1 P2 y* h, p4 W
80386 添加了:
. P" b& ^& h2 h0 u7 I% YJECXZ Jump if ECX Zero
1 Q- O, A. w. Z o作为对比,ARM 处理器只提供了:1 s5 J$ w2 G5 h
B 分支6 `, }8 y; c( z' _. W1 m. N2 L# r
BL 带连接的分支
. T8 B5 @9 G& c# D& ~6 T但 ARM 提供了条件执行,你可以不受这个表面上不灵活的方式的限制:. k+ r! U/ z- \3 d/ b6 ]' A
BEQ Branch if EQual! R& i, {" {5 r, D7 J
BNE Branch if Not Equal
- a+ U5 v& q- x. s" {) Z3 nBVS Branch if oVerflow Set
+ W( s0 @ t* L) x2 p" v/ R9 {BVC Branch if oVerflow Clear9 |: ` Q$ C n# p9 |
BHI Branch if HIgher
6 {& l+ j1 J" U. t! c0 |BLS Branch if Lower or the Same& P$ p/ p8 q& u
BPL Branch if PLus2 Q8 _6 e E3 S1 \. m
BMI Branch if MInus$ P' x8 {3 f, p
BCS Branch if Carry Set
, e5 N) f7 O/ F" mBCC Branch if Carry Clear! {& [% z7 @# Y. S2 U4 V% K
BGE Branch if Greater than or Equal
& F! K9 a- _7 _/ Q- d5 Z8 W& IBGT Branch if Greater Than
) R: Y" ?, w. _* M+ J9 {BLE Branch if Less than or Equal
' E6 K! F2 e6 q/ gBLT Branch if Less Than
5 W" Z5 a c& TBLEQ Branch with Link if EQual2 x' R4 g; F4 ~) } }
....
~" `% i$ T* S# u9 U5 RBLLT Branch with Link if Less Than* y' m v: t- h
还有两个代码,7 k$ M1 u( x" A/ D2 a
AL - ALways,缺省条件所以不须指定! S: ~! k# a$ s. Q: T
NV - NeVer,不是非常有用。你无论如何不要使用这个代码...! f! q; G$ [. ~ R
当你发现所有 Bxx 指令实际上是同一个指令的时候,紧要关头就到了。接着你会想,如果你可以在一个分支指令上加上所有这些条件,那么对一个寄存器装载指令能否加上它们? 答案是可以。
" r* |3 c% c# v: b6 e# ^; b& {下面是可获得的条件代码的列表:4 J: |, A5 I; S: ?& Z2 @
EQ : 等于
' }! P; y6 Y, r4 i$ u如果一次比较之后设置了 Z 标志。8 X% R3 M9 c4 T: N
NE : 不等于
! _6 I7 \4 x7 F; [5 y7 h5 K如果一次比较之后清除了 Z 标志。
& \$ A( F& M% u yVS : 溢出设置3 U- E& a8 l2 z: H
如果在一次算术操作之后设置了 V 标志,计算的结果不适合放入一个 32bit 目标寄存器中。
* E. F2 M( w6 f9 ^, e1 l( i+ ^VC : 溢出清除
+ W6 W, N n! F: }如果清除了 V 标志,与 VS 相反。# ^) D& L8 w, k
HI : 高于(无符号)
0 x) E! d7 Y2 U+ g# {2 @如果一次比较之后设置了 C 标志并清除了 Z 标志。
) Q- o5 F% \( o* R WLS : 低于或同于(无符号)
- J, A6 e, I5 H) B+ s如果一次比较操作之后清除了 C 标志或设置了 Z 标志。
( F6 ?6 _7 ^( y9 b; q0 C; b$ K3 q$ GPL : 正号
% b. D' f J/ w1 H% a5 B如果一次算术操作之后清除了 N。出于定义‘正号’的目的,零是正数的原因是它不是负数...* {' | X, R' R6 o F% d0 l" h
MI : 负号
# S3 r) L& ?' Y; B1 K9 Q如果一次算术操作之后设置了 N 标志。6 ? k* P: m7 N
CS : 进位设置7 N+ h; d8 M' C h4 t6 Y. T. Z
如果一次算术操作或移位操作之后设置了 C 标志,操作的结果不能表示为 32bit。你可以把 C 标志当作结果的第 33 位。
- r, R( X& n' F: }CC : 进位清除
# u# A8 c w0 s; Z5 ~与 CS 相反。
2 p: r6 ?7 N" b7 rGE : 大于或等于(有符号)6 h3 E( Z% m; v& u; s) z; M8 I
如果一次比较之后...4 g `$ z X2 N7 [; N& ~- ^
设置了 N 标志并设置了 V 标志: r1 a' _- n' }
或者...6 ^0 C$ H' S+ `2 s% H, V' n
清除了 N 标志并清除了 V 标志。! w0 m2 D% N; l' B
GT : 大于(有符号)
# `' y& b. W% l2 ]( Z如果一次比较之后...2 C# v1 G& R* ^8 j' Y
设置了 N 标志并设置了 V 标志+ l: V- A# Q. j( x; J
或者...
1 G: V6 c) X5 n3 M9 ?9 i清除了 N 标志并清除了 V 标志
. Z x% L2 {! @0 U* o) b并且...
) N# l7 j* n& \% U2 T# ~& T5 t5 @清除了 Z 标志。
* t: q1 N, |: L6 J; @, R3 d7 M$ u/ |LE : 小于或等于(有符号)" Z* n! O& `6 @1 l* o7 k
如果一次比较之后...
0 K: o V7 `3 c) u$ F, m# I设置了 N 标志并清除了 V 标志0 h7 u, |6 h' h1 J# _9 N
或者...
6 N" f% {) O; J, u清除了 N 标志并设置了 V 标志7 f" S" k0 \0 }# w3 }4 E0 o: a1 z+ P
并且..." v6 z2 C1 o0 w+ _7 q$ o
设置了 Z 标志。
& |+ C5 b {9 G& SLT : 小于(有符号)
6 E1 D s6 F4 }" A! }: Z如果一次比较之后...
2 S; W# `, A+ P* f4 P设置了 N 标志并清除了 V 标志。6 ^& b" ?- _; k3 H
或者...8 h: V( @$ Y: T) }" c k
清除了 N 标志并设置了 V 标志。+ B( ]4 t+ H: L% C# ~5 W5 g
AL : 总是
2 V9 `; I) [0 `4 V7 f5 F缺省条件,所以不用明显声明。9 O6 b7 o% q- m; s4 @
NV : 从不
2 q# `+ ?$ l: [3 t% f. T不是特别有用,它表示应当永远不执行这个指令。是穷人的 NOP。& @& G: N& d4 I Z/ R( Y
包含 NV 是为了完整性(与 AL 相对),你不应该在你的代码中使用它。
7 k' V/ R1 ~0 Q" w有一个在最后的条件代码 S,它以相反的方式工作。当用于一个指令的时候,导致更改状态标志。这不是自动发生的 - 除非这些指令的目的是设置状态。例如:6 P+ {; t$ n& J3 Q: P0 s* W, l
ADD R0, R0, R1
" W- C4 n* ]5 H! sADDS R0, R0, R1" Y5 ]) o3 s4 l
ADDEQS R0, R0, R1
' \+ E9 I- \7 n% {第一个例子是一个基本的加法(把 R1 的值增加到 R0),它不影响状态寄存器。
) z: h* y, @: Q' W8 x- N第二个例子是同一个加法,只不过它导致更改状态寄存器。
. ?8 G6 A; p6 ~/ S; ~' P最后一个例子是同一个加法,更改状态寄存器。不同在于它是一个有条件的指令。只有前一个操作的结果是 EQ (如果设置了 Z 标志)的时候它才执行。5 u( J/ {- n& U3 X# d
下面是条件执行的一个工作中的例子。你把寄存器 0 与存储在寄存器 10 中内容相比较。如果不等于 R10,则调用一个软件中断,增加它并分支回来再次做这些。否则清除 R10 并返回到调用它的那部分代码(它的地址存储在 R14)。: k$ J* k3 z# u3 d
\ 条件执行的一个例子) V4 }2 L+ m4 b$ d6 ]+ A: i$ }. ?# ?
.loop ; 标记循环开始位置6 c2 N" K* A' ]+ F5 G/ k
CMP R0, R10 ; 把 R0 与 R10 相比较- [. n; B7 j: m3 y- v5 k5 g
SWINE &40017 ; 不等于: 调用 SWI &40017/ C9 d# ~4 f" G' Y
ADDNE R0, R0, #1 ; 向 R0 加 1
+ g- ~( I! h3 c, k, @2 nBNE loop ; 分支到 loop1 W% s: p4 I% F* ?8 J, D' H4 L
MOV R10, #0 ; 等于 : 设置 R10 为零4 k: z3 j \2 z5 x
LDMFD R13!, {R0-R12,PC} ; 返回到调用者
" Z, T8 ^2 c* H注解:
$ d0 d8 t: Y: j/ n( e4 z( Z% tSWI 编号就象我写的这样。在 RISC OS 下,它是给 Econet_DoImmediate 的编号。不要字面的接受它,这只是一个例子!
: {5 v6 z" v) E5 f6 N8 l$ p& g( e你可能以前没见过 LDMFD,它从栈中装载多个寄存器。在这个例子中,我们从一个完全正式的栈中装载 R0 至 R12 和 R14。关于寄存器装载和存储的更多信息请参阅 str.html。 p. Y& J ]9 J' h8 ?6 @8 b7 A
我说要装载 R14。那么为什么要把它放入 PC 中? 原因是此时 R14 存储的值包含返回地址。我们也可以采用:+ o2 H5 D0 E+ k9 Q4 B
LDMFD R13!, {R0-R12,R14}
' e2 I; `7 `# r+ H3 `MOV PC, R14
" F. G& V0 R! u5 R但是直接恢复到 PC 中可以省略这个 MOV 语句。# u8 k- l5 C5 G8 M$ \2 u
最后,这些寄存器很有可能被一个 SWI 调用所占用(依赖于在调用期间执行的代码),所以你最好把你的重要的寄存器压入栈中,以后在恢复它们。
) Y9 c+ U1 ]) c
作者: nevadaooo 时间: 2021-5-6 14:43
本帖最后由 nevadaooo 于 2021-5-6 17:52 编辑
. K \. ^. H! e: P7 }, [7 l. b, `* C1 {; h" K
很详细,先收了,后面练练
作者: Memory00 时间: 2021-5-6 15:24
ARM条件执行云集
7 u" Z- `/ c1 f
作者: modengxian111 时间: 2021-5-6 17:16
很实用,收藏了
| 欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/) |
Powered by Discuz! X3.2 |