比較有用的是MOV B BL LDR STR
@ disable watch dog timer
mov r1, #0x53000000 //立即數尋址方式
mov r2, #0x0
str r2, [r1]
MOV沒有什麼好說的,只要掌握幾個尋址方式就可以了,而且ARM的尋址方式比386的簡單很多。立即數尋址方式,立即數要求以“#”作前綴,對於十六進制的數,還要求在#後面加上0x或者&。0x大家很好理解。有一次我碰到了&ff這個數,現在才明白跟0xff是一樣的。
STR是比較重要的指令了,跟它對應的是LDR。ARM指令集是加載/存儲型的,也就是說它只處理在寄存器中的數據。那麼對於系統存儲器的訪問就經常用到STR和LDR了。STR是把寄存器上的數據傳輸到指定地址的存儲器上。它的格式我個人認爲很特殊:
STR(條件) 源寄存器,<存儲器地址>
比如 STR R0, [R1] ,意思是R0-> [R1],它把源寄存器寫在前面,跟MOV、LDR都相反。
LDR應該是非常常見了。LDR就是把數據從存儲器傳輸到寄存器上。而且有個僞指令也是LDR,因此我有個百思不得其解的問題。看這段代碼:
mov r1, #GPIO_CTL_BASE
add r1, r1, #oGPIO_F
ldr r2,=0x55aa // 0x55aa是個立即數啊,前面加個=幹什麼?
str r2, [r1, #oGPIO_CON]
mov r2, #0xff
str r2, [r1, #oGPIO_UP]
mov r2, #0x00
str r2, [r1, #oGPIO_DAT]
對於當中的ldr 那句,我就不明白了,如果你把=去掉,是不能通過編譯的。我查了一些資料,個人感覺知道了原因:這個=應該表示LDR不是ARM指令,而是僞指令。作爲僞指令的時候,LDR的格式如下:
LDR 寄存器, =數字常量/Label
它的作用是把一個32位的地址或者常量調入寄存器。嗬嗬,那大家可能會問,
“MOV r2,#0x55aa”也可以啊。應該是這樣的。不過,LDR是僞指令啊,也就是說編譯時編譯器會處理它的。怎麼處理的呢?——規則如下:如果該數字常量在MOV指令範圍內,彙編器會把這個指令作爲MOV。如果不在MOV範圍中,彙編器把該常量放在程序後面,用LDR來讀取,PC和該常量的偏移量不能超過4KB。
這麼一說,雖然似懂非懂,但是能夠解釋這個語句了。
僞指令LDR{cond} register, ={expr|label-expr}
expr爲32位常量。編譯器根據expr的取值情況來處理這條僞指令:
1、當expr表示的地址沒有超過mov或mvn指令中地址的取值範圍時,編譯器用合適的mov指令或mvn指令代替該LDR僞指令。
2、當expr表示的地址超過了mov或mvn指令中地址的取值範圍時,編譯器將該常數放在緩衝區中,同時用一條基於PC的LDR指令讀取該常數。
...............................
通過上面兩種可以得出僞指令LDR和ARM指令LDR的區別,具體使用時,可以不用考慮二者的區別,由編譯器決定的,看源碼時,你只要搞清楚它的功能就行。
然後說一下跳轉指令。ARM有兩種跳轉方式。
(1) mov pc <跳轉地址〉
這種向程序計數器PC直接寫跳轉地址,能在4GB連續空間內任意跳轉。
(2)通過 B BL BLX BX 可以完成在當前指令向前或者向後32MB的地址空間的跳轉(爲什麼是32MB呢?寄存器是32位的,此時的值是24位有符號數,所以32MB)。
B是最簡單的跳轉指令。要注意的是,跳轉指令的實際值不是絕對地址,而是相對地址——是相對當前PC值的一個偏移量,它的值由彙編器計算得出。
BL非常常用。它在跳轉之前會在寄存器LR(R14)中保存PC的當前內容。BL的經典用法如下:
bl NEXT ; 跳轉到NEXT
……
NEXT
……
mov pc, lr ; 從子程序返回。
最後提一下Thumb指令。ARM體系結構還支持16位的Thumb指令集。Thumb指令集是ARM指令集的子集,它保留了32位代碼優勢的同時還大大節省了存儲空間。由於Thumb指令集的長度只有16位,所以它的指令比較多。它和ARM各有自己的應用場合。對於系統性能有較高要求,應使用32位存儲系統和ARM指令集;對於系統成本和功耗有較高要求,應使用16位存儲系統和ARM指令集。
###################################################################################################
###################################################################################################
指令格式:
LDR/STR{cond}{T} Rd,<地址>
LDR/STR{cond}B{T} Rd,<地址>
LDR{cond}{T} Rd,<地址> 加載指定地址的字數據到Rd中;
STR{cond}{T} Rd,<地址> 存儲Rd中的字數據到指定的地址單元中;
- 零偏移(zero offset)
[Rn] ,Rn的值作爲傳送數據的地址。如:
LDR R0,[R1]; - 前索引偏移(pre-indexed offset)
[Rn,Flexoffset]{!}
在數據傳送之前,將偏移量Flexoffset加到Rn
中。其結果作爲傳送數據的存儲器地址。若使用後綴“!”,則結果寫回到Rn
中,且Rn 不允許是R15,如:
LDRB R0,[R1,#8]
LDR R0,[R1,#8]! - 程序相對偏移(program relative)
label(label 必須是在當前指令的土4KB 範圍內) 。
程序相對偏移是前索引形式的另一種版本。從PC 計算偏移量,並將PC 作爲Rn 生成前索引指令,不能使用後綴“!”,如:
LDR R0,place ;
place地址裝入R0 - 後索引偏移(post-indexed offset)
[Rn],Flexoffset。在數據傳送後,將偏移量Flexoffset 加到Rn 中,結果寫回到Rn,Rn 不允許是R15,如:
LDR R0,[R1],R2,LSL#2 ;
將存儲器地址爲R1 的字數據讀入寄存器R0,並將新地址R1+R2×4寫入R1。
偏移量Flexoffset可以是下兩種形式之:
1) 取值範圍是-4095 到+4095 的整數的表達式,經常是數字常量,如:
STR R5,[R7],#--8
2) 一個寄存器再加上移位(移位由立即數指定),如:
{-}Rm{,shift}
其中:
- :可選負號。若帶符號“一”,則從Rn 中減去偏移量。否則,將偏移量加到Rn 中。
Rm :內含偏移量的寄存器。Rm 不允許是R15。
Shift:Rm 的可選移位方法。可以是下列形式的任何一種:
ASR n :算術右移n 位(1<=n<=32)
LSL n :邏輯左移n 位(1<=n<=31)
LSR n :邏輯右移n 位(1<=n<=32)
ROR n :循環右移n 位(1<=n<=31)
RRX :循環右移1 位,帶擴展。
指令格式:
ANDS R1,R1,R2 ;R1=R1&R2,並根據運算的結果更新標誌位
AND R0,R0,#0x0F ;R0=R0&0x0F,取出R0最低4位數據。
指令格式:ORR{cond}{S} Rd,Rn,operand2 ORR指令將操作數operand2 與Rn 的值按位邏輯"或",結果存放到目的寄存器Rd 中。指令示例:
ORRS R1,R1,R2 ;R1=R1|R2,並根據運算的結果更新標誌位
指令格式:
BIC{cond}{S} Rd,Rn,operand2
cmp R0,R1 ;比較R0,R1
beq stop ;R0=R1跳到stop
blt less ;R0<R1跳到Less
.
.
.
.
.
Stop:
指令格式:
SUB{cond}{S} Rd,Rn,operand2 SUB指令用Rn 的值減去操作數operand2 ,並將結果存放到目的寄存器Rd 中。 指令示例:
助記符 |
說明 |
操作 |
B{cond} lable |
分支指令 |
PC← lable |
BL{cond} lable |
帶鏈接的分支指令 |
LR← PC-4 ,PC←lable |
BX{cond} Rm |
帶狀態切換的分支指令 |
PC← Rm,切換處理器狀態 |
條件碼 | 助記符後綴 | 標誌 | 含義 |
0000 | EQ | Z置位(Z=1) | 相等 |
0001 | NE | Z清零(Z=0) | 不相等 |
0010 | CS | C置位 | 無符號數大於等於 |
0011 | CC | C清零 | 無符號數小於 |
0100 | MI | N置位 | 負數 |
0101 | PL | N清零 | 整數或0 |
0110 | VS | V置位 | 溢出 |
0111 | VC | V清零 | 未溢出 |
1000 | HI | C置位且Z清零 | 無符號數大於 |
1001 | LS | Z置位且C清零 | 無符號數小於等於 |
1010 | GE | N等於V(N=V=1或N=V=0) | 帶符號數大於或等於 |
1011 | LT | N不等於V | 帶符號數小於 |
1100 | GT | Z清零且N等於V | 帶符號數大於 |
1101 | LE | Z置位或N不等於V | 帶符號數小於或等於 |
1110 | AL | 忽略 | 無條件執行 |
;GPIO寄存器宏定義
GPFCON EQU 0x56000050
GPFDAT EQU 0x56000054
GPFUP EQU 0x56000058
EXPORT LEDTEST
AREA LEDTESTASM,CODE,READONLY
;該僞指令定義了一個代碼段,段名爲LEDTESTASM,屬性只讀
LEDTEST
;設置GPF4-GPF7爲output
ldr r0,=GPFCON
ldr r1,[r0]
bic r1,r1,#0xff00
orr r1,r1,#0x5500
str r1,[r0]
;禁止GPF4-GPF7端口的上拉電阻
ldr r0,=GPFUP
ldr r1,[r0]
orr r1,r1,#0xf0
str r1,[r0]
looptest
;將數據端口F的數據寄存器的地址附給寄存器r2
ldr r2,=GPFDAT
ldr r3,[r2]
bic r3,r3,#0xf0
orr r3,r3,#0xb0
str r3,[r2]
;GPF6 output 0
ldr r0,=0x2fffff
bl delay ;調用延遲子程序
ldr r3,[r2]
bic r3,r3,#0xf0
orr r3,r3,#0x70
str r3,[r2]
;GPF7 output 0
ldr r0,=0x2fffff
;初始計數值
bl delay ;調用延遲子程序
ldr r3,[r2]
bic r3,r3,#0xf0
orr r3,r3,#0xd0
str r3,[r2]
;GPF5 output 0
ldr r0,=0x2fffff
bl delay ;調用延遲子程序
ldr r3,[r2]
bic r3,r3,#0xf0
orr r3,r3,#0xe0
str r3,[r2]
;GPF4 output 0
ldr r0,=0x2fffff
bl delay ;調用延遲子程序
b looptest
delay
sub r0,r0,#1
;r0=r0-1
cmp r0,#0x0
;將r0的值與0相比較
bne delay ;比較的結果不爲0(r0不爲0),繼續調用delay,否則執行下一條語句
mov pc,lr
;返回
END ;程序結束符