3atv精品不卡视频,97人人超碰国产精品最新,中文字幕av一区二区三区人妻少妇,久久久精品波多野结衣,日韩一区二区三区精品

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ARM汇编指令汇总

發(fā)布時間:2023/12/14 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ARM汇编指令汇总 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
1、ARM匯編的格式:
??? 在ARM匯編里,有些字符是用來標(biāo)記行號的,這些字符要求頂格寫;有些偽碼是需要成對出現(xiàn)的,例如ENTRY和END,就需要對齊出現(xiàn),也就是說他們要么都頂格,要么都空相等的空,否則編譯器將報錯。常量定義需要頂格書寫,不然,編譯器同樣會報錯。
??? 2、字符串變量的值是一系列的字符,并且使用雙引號作為分界符,如果要在字符串中使用雙引號,則必須連續(xù)使用兩個雙引號。
??? 3、在使用LDR時,當(dāng)格式是LDR r0,=0x022248,則第二個參數(shù)表示地址,即0x022248,同樣的,當(dāng)src變量代表一個數(shù)組時,需要將r0寄存器指向src則需要這樣賦值:LDR r0,=src???? 當(dāng)格式是LDR r0,[r2],則第二個參數(shù)表示寄存器,我的理解是[]符號表示取內(nèi)容,r2本身表示一個寄存器地址,取內(nèi)容候?qū)⑵浯嫒0這個寄存器中。
??? 4、在語句:
?????? CMP r0,#num
?????? BHS stop
?????? 書上意思是:如果r0寄存器中的值比num大的話,程序就跳轉(zhuǎn)到stop標(biāo)記的行。但是,實際測試的時候,我發(fā)現(xiàn)如果r0和num相等也能跳轉(zhuǎn)到stop標(biāo)記的行,也就是說只要r0小于num才不會跳轉(zhuǎn)。
???
???? 下面就兩個具體的例子談?wù)凙RM匯編(這是我昨天好不容易看懂的,呵呵)。
???? 第一個是使用跳轉(zhuǎn)表解決分支轉(zhuǎn)移問題的例程,源代碼如下(保存的時候請將文件后綴名改為s):??
????? AREA JumpTest,CODE,READONLY
????? CODE32
?num? EQU? 4

?ENTRY
?
start
????? MOV? r0, #4
????? MOV? r1, #3
????? MOV? r2, #2
????? MOV? r3, #0
?
????? CMP? r0,? #num
????? BHS? stop
?
????? ADR? r4, JumpTable
?
????? CMP? r0, #2
????? MOVEQ? r3, #0
????? LDREQ? pc, [r4,r3,LSL #2]
?
????? CMP? r0, #3
????? MOVEQ? r3, #1
????? LDREQ? pc, [r4,r3,LSL #2]
?
????? CMP? r0, #4
????? MOVEQ? r3, #2
????? LDREQ? pc, [r4,r3,LSL #2]
?
????? CMP? r0, #1
????? MOVEQ? r3, #3
????? LDREQ? pc, [r4,r3,LSL #2]
?
DEFAULT
????? MOVEQ? r0, #0
?
SWITCHEND

stop
????? MOV? r0, #0x18
????? LDR? r1, =0x20026
????? SWI? 0x123456
?
JumpTable
????? DCD? CASE1
????? DCD? CASE2
????? DCD? CASE3
????? DCD? CASE4
????? DCD? DEFAULT
?
CASE1
????? ADD? r0, r1, r2
????? B? SWITCHEND
?
CASE2
????? SUB? r0, r1, r2
????? B? SWITCHEND
?
CASE3
????? ORR? r0, r1, r2
????? B? SWITCHEND
?
CASE4
????? AND? r0, r1, r2
????? B? SWITCHEND
?END
??? 程序其實很簡單,可見我有多愚笨!還是簡要介紹一下這段代碼吧。首先用AREA偽代碼加上CODE,表明下面引出的將是一個代碼段(于此相對的還有數(shù)據(jù)段DATA),ENTRY 和END成對出現(xiàn),說明他們之間的代碼是程序的主體。start段給寄存器初始化。ADR? r4, JumpTable一句是將相當(dāng)于數(shù)組的JumpTable的地址付給r4這個寄存器。

??? stop一段是用來是程序退出的,第一個語句“MOV r0,#0x18”將r0賦值為0x18,這個立即數(shù)對應(yīng)于宏angel_SWIreason_ReportException。表示r1中存放的執(zhí)行狀態(tài)。語句“LDR r1,=0x20026”將r1的值設(shè)置成ADP_Stopped_ApplicationExit,該宏表示程序正常退出。然后使用SWI,語句“SWI 0x123456”結(jié)束程序,將CPU的控制權(quán)交回調(diào)試器手中。

??? 在JumpTable表中,DCD類型的數(shù)組包含四個字,所以,當(dāng)實現(xiàn)CASE跳轉(zhuǎn)的時候,需要將給出的索引乘上4,才是真正前進(jìn)的地址數(shù)。

?

??? 再看一個用匯編實現(xiàn)冒泡排序的例程:

???? AREA Sort,CODE,READONLY
?ENTRY
?
start
???? MOV r4,#0
???? LDR r6,=src
???? ADD r6,r6,#len
?
outer
???? LDR r1,=src
?
inner
???? LDR r2,[r1]
???? LDR r3,[r1,#4]
???? CMP r2,r3
???? STRGT r3,[r1]
???? STRGT r2,[r1,#4]
???? ADD r1,r1,#4
???? CMP r1,r6
???? BLT inner
?
???? ADD r4,r4,#4
???? CMP r4,#len
???? SUBLE r6,r6,#4
???? BLE outer
?
stop
???? MOV r0,#0x18
???? LDR r1,=0x20026
???? SWI 0x123456
?
???? AREA Array,DATA,READWRITE
src DCD 2,4,10,8,14,1,20
len EQU 7*4
???? END
???? 用匯編實現(xiàn)循環(huán)需要跳轉(zhuǎn)指令,但是因為ARM系統(tǒng)只有一個CPSR寄存器,所以要實現(xiàn)雙重循環(huán)還是有些難度。上面這個代碼還是有相當(dāng)大的借鑒意義。程序不難讀懂,和C語言的冒泡排序基本思路是完全一樣的。

?

?

?


Load CodeWarrior from the Start Menu.
Create a new project (File | New), select ARM Executable Image and give it the name "hello".
Create a new assembler source file (File | New Text File) and paste the following code in it.
??????????? ; Hello world in ARM assembler

??????????? AREA text, CODE
??????????? ; This section is called "text", and contains code

??????????? ENTRY

??????????? ; Print "Hello world"

??????????? ; Get the offset to the string in r4.
??????????? adr?????? r4, hello?????????? ;; "address in register"

loop??????? ; "loop" is a label and designates an address
??????????? ; Call putchar to display each character
??????????? ; to illustrate how a loop works

??????????? ldrb????? r0, [r4], #1??????? ; Get next byte and post-index r4
??????????? cmp?????? r0, #0????????????? ; Stop when we hit a null
??????????? beq?????? outputstring??????? ;; "branch if equal" = cond. goto

??????????? bl??????? putchar????????????
??????????? b???????? loop??????????????? ;; "branch" =? goto

outputstring
??????????? ; Alternatively, use putstring to write out the
??????????? ; whole string in one go
??????????? adr?????? r0, hello
??????????? bl??????? putstring?????????? ;; "branch+link" = subroutine call

finish
??????????? ; Standard exit code: SWI 0x123456, calling routine 0x18
??????????? ; with argument 0x20026
??????????? mov?????? r0, #0x18
??????????? mov?????? r1, #0x20000??????? ; build the "difficult" number...
??????????? add?????? r1, r1, #0x26?????? ; ...in two steps
??????????? SWI?????? 0x123456??????????? ;; "software interrupt" = sys call

hello
??????????? DCB?????? "Hello World/n",0

??????????? END

?

?

?

?

?

?

?


??

?


從下面的一個ARM 匯編小程序要弄懂的以下三個問題:

1).在ARM狀態(tài)轉(zhuǎn)到THUNB狀態(tài)和BX的應(yīng)用

2).匯編的架構(gòu)

3).SWI指令的使用

    AREA??? ADDREG,CODE,READONLY

?    ENTRY

MAIN

???   ADR? r0,ThunbProg + 1? ;(為什么要加1呢?因為BX指令跳轉(zhuǎn)到指定的地址執(zhí)行程序?? 時,?? 若   (BX{cond}? Rm)Rm的位[0]為1,則跳轉(zhuǎn)時自動將CPSR中的標(biāo)志T置位即把目標(biāo) 代碼解釋為 Thunb代碼)

???     BX??? r0

???    CODE16

ThunbProg

???    mov r2,#2

?     mov r3,#3

?    add r2,r2,r3

    ADR r0,ARMProg

    BX? ro

    CODE32

ARMProg

?    mov r4,#4

    mov r5,#5

    add? r4,r4,r5

???????????? stop?? mov r0,#0x18

????????????? LDR? r1,=0x20026

???????????? SWI?? 0x123456

???????????? END

SWI--軟中斷指令:

SWI指令用于產(chǎn)生軟中斷,從擁護(hù)模式變換到管理模式,CPSR保存到管理模式的SPSR中.

 SWI{cond}????? immed_24????? ;immed_24為軟中斷號(服務(wù)類型)

使用SWI指令時,通常使用以下兩種方法進(jìn)行傳遞參數(shù),SWI 異常中斷處理程序就可以提供相關(guān)的服務(wù),這兩種方法均是用戶軟件協(xié)定.SWI異常中斷處理程序要通過讀取引起軟中斷的SWI指令,以取得24位立即數(shù).

(1) 指令中的24位立即數(shù)指定了用戶請求的服務(wù)類型,參數(shù)通過通用寄存器傳遞.

 mov?? r0,#34??? ;設(shè)置子功能號位34

?? SWI?? 12???? ;調(diào)用12號軟中斷

(2) 指令中的24位立即數(shù)被忽略,用戶請求的服務(wù)類型有寄存器RO的值決定,參數(shù)通過其他的通用寄存器傳遞.

 mov? r0,#12???????? ;調(diào)用12號軟中斷

 mov r1,#34???????? ;設(shè)置子功能號位34

 SWI  0

在SWI異常中斷處理程序中,取出SWI立即數(shù)的步驟為:首先確定引起軟中斷的SWI指令是ARM指令還是Thunb指令,這可通過對SPSR訪問得到;然后取得該SWI指令的地址,這可通過訪問LR寄存器得到;接著讀出指令,分解出立即數(shù).如如下程序:

T_bit????????????? EQU??????????????????? 0X20

SWI_Handler

??????????????? STMFD????? SP!,{R0-R3,R12,LR}????????????????? ;現(xiàn)場保護(hù)

?????????????? MRS?????????? R0,SPSR?????????????????????????????????? ;讀取SPSR

????????????? STMFD?????? SP!,{R0}???????????????????????????????????? :保存SPSR

????????????? TST???????????? R0,#T_bit???????????????????????

??????????? LDRNEH??????? R0,[LR,#-2]?????????????????????? ;若是Thunb指令,讀取指令碼(16位)

   BICNE???????????? R0,#0XFF00???????????????????? :取得Thunb指令的8位立即數(shù)

   LDREQ?????????? R0,[LR,#-4]????????????????????? ;若是ARM指令,讀取指令碼(32位)

   BICEQ??????????? R0,#0XFF000000?????????? ;取得ARM指令的24位立即數(shù)

   ....

   LDMFD????????? SP!,{R0-R3,R12,PC}^??? ;SWI異常中斷返回

    

?

?


ARM匯編的SWI指令軟中斷

從下面的一個ARM 匯編小程序要弄懂的以下三個問題:

1).在ARM狀態(tài)轉(zhuǎn)到THUNB狀態(tài)和BX的應(yīng)用

2).匯編的架構(gòu)

3).SWI指令的使用

    AREA??? ADDREG,CODE,READONLY

?    ENTRY

MAIN

???   ADR? r0,ThunbProg + 1? ;(為什么要加1呢?因為BX指令跳轉(zhuǎn)到指定的地址執(zhí)行程序?? 時,?? 若   (BX{cond}? Rm)Rm的位[0]為1,則跳轉(zhuǎn)時自動將CPSR中的標(biāo)志T置位即把目標(biāo) 代碼解釋為 Thunb代碼)

???     BX??? r0

???    CODE16

ThunbProg

???    mov r2,#2

?     mov r3,#3

?    add r2,r2,r3

    ADR r0,ARMProg

    BX? ro

    CODE32

ARMProg

?    mov r4,#4

    mov r5,#5

    add? r4,r4,r5

???????????? stop?? mov r0,#0x18

????????????? LDR? r1,=0x20026

???????????? SWI?? 0x123456

???????????? END

SWI--軟中斷指令:

SWI指令用于產(chǎn)生軟中斷,從擁護(hù)模式變換到管理模式,CPSR保存到管理模式的SPSR中.

 SWI{cond}????? immed_24????? ;immed_24為軟中斷號(服務(wù)類型)

使用SWI指令時,通常使用以下兩種方法進(jìn)行傳遞參數(shù),SWI 異常中斷處理程序就可以提供相關(guān)的服務(wù),這兩種方法均是用戶軟件協(xié)定.SWI異常中斷處理程序要通過讀取引起軟中斷的SWI指令,以取得24位立即數(shù).

(1) 指令中的24位立即數(shù)指定了用戶請求的服務(wù)類型,參數(shù)通過通用寄存器傳遞.

 mov?? r0,#34??? ;設(shè)置子功能號位34

?? SWI?? 12???? ;調(diào)用12號軟中斷

(2) 指令中的24位立即數(shù)被忽略,用戶請求的服務(wù)類型有寄存器RO的值決定,參數(shù)通過其他的通用寄存器傳遞.

 mov? r0,#12???????? ;調(diào)用12號軟中斷

 mov r1,#34???????? ;設(shè)置子功能號位34

 SWI  0

在SWI異常中斷處理程序中,取出SWI立即數(shù)的步驟為:首先確定引起軟中斷的SWI指令是ARM指令還是Thunb指令,這可通過對SPSR訪問得到;然后取得該SWI指令的地址,這可通過訪問LR寄存器得到;接著讀出指令,分解出立即數(shù).如如下程序:

T_bit????????????? EQU??????????????????? 0X20

SWI_Handler

??????????????? STMFD????? SP!,{R0-R3,R12,LR}??????????? ;現(xiàn)場保護(hù)

?????????????? MRS?????????? R0,SPSR?????????????????????????? ;讀取SPSR

????????????? STMFD?????? SP!,{R0}??????????????????????????? :保存SPSR

????????????? TST???????????? R0,#T_bit???????????????????????

??????????? LDRNEH??????? R0,[LR,#-2]????????????? ;若是Thunb指令,讀取指令碼(16)

   BICNE???????????? R0,#0XFF00????????????????? :取得Thunb指令的8位立即數(shù)

   LDREQ?????????? R0,[LR,#-4]??????????????? ;若是ARM指令,讀取指令碼(32位)

   BICEQ??????????? R0,#0XFF000000?????????? ;取得ARM指令的24位立即數(shù)

   ....

   LDMFD????????? SP!,{R0-R3,R12,PC}^??? ;SWI異常中斷返回

    

Thu Oct 12 2006

?

軟件中斷SWI的實現(xiàn)
在需要軟件中斷處調(diào)用

__SWI? 0xNum?????????? ;Num為SWI中斷處理模塊的編號,見表SwiFunction


;軟件中斷
SoftwareInterrupt
??????? CMP???? R0, #12???????????????????????? ;R0中的SWI編號是否大于最大值

/* 下面這句語句把 (LDRLO地址+ 8 + R0*4) 的地址裝載到PC寄存器,舉例如果上面的 Num="1",也就是R0 = 1, 假設(shè)LDRLO這條指令的地址是0x00008000,那么根據(jù)ARM體系的2級流水線 PC寄存器里指向是下兩條指令 于是PC = 0x00008008? 也就是偽指令DCD???? TASK_SW 聲明的標(biāo)號TASK_SW? 的地址,注意DCD???? TASK_SW 這條指令本身不是ARM能執(zhí)行的指令,也不會占有地址,這條指令靠匯編器匯編成可執(zhí)行代碼,它的意義就是聲明 TASK_SW的地址,? , [PC, R0, LSL #2] 這個尋址方式就是 PC + R0的值左移2位的值( 0x01<<2? => 0x04 ),這樣PC的值就是0x0000800C, 即ENTER_CRITICAL的地址于是ARM執(zhí)行該標(biāo)號下的任務(wù) */

??????? LDRLO?? PC, [PC, R0, LSL #2]???????
??????? MOVS??? PC, LR

SwiFunction
??????? DCD???? TASK_SW??????????????? ;0
??????? DCD???? ENTER_CRITICAL???????? ;1
??????? DCD???? EXIT_CRITICAL??????????? ;2
??????? DCD???? ISRBegin???????????????? ;3
??????? DCD???? ChangeToSYSMode???????? ;4
??????? DCD???? ChangeToUSRMode???????? ;5
??????? DCD???? __OSStartHighRdy??????? ;6
??????? DCD???? TaskIsARM?????????????? ;7
??????? DCD???? TaskIsTHUMB???????????? ;8
??????? DCD???? OSISRNeedSwap?????????? ;9
??????? DCD???? GetOSFunctionAddr?????? ;10
??????? DCD???? GetUsrFunctionAddr????? ;11

TASK_SW
??????? MRS???? R3, SPSR??????????????????????? ;保存任務(wù)的CPSR
??????? MOV???? R2, LR????????????????????????? ;保存任務(wù)的PC
???????
??????? MSR???? CPSR_c, #(NoInt | SYS32Mode)??? ;切換到系統(tǒng)模式
??????? STMFD?? SP!, {R2}?????????????????????? ;保存PC到堆棧
??????? STMFD?? SP!, {R0-R12, LR}?????????????? ;保存R0-R12,LR到堆棧
??????????????????????????????????????????????? ;因為R0~R3沒有保存有用數(shù)據(jù),所以可以這樣做
??????? B?????? OSIntCtxSw_0??????????????????? ;真正進(jìn)行任務(wù)切換

ENTER_CRITICAL
??????????????????????????????????????????????? ;OsEnterSum++
??????? LDR???? R1, =OsEnterSum
??????? LDRB??? R2, [R1]
??????? ADD???? R2, R2, #1
??????? STRB??? R2, [R1]
??????????????????????????????????????????????? ;關(guān)中斷
??????? MRS???? R0, SPSR
??????? ORR???? R0, R0, #NoInt
??????? MSR???? SPSR_c, R0
??????? MOVS??? PC, LR

?

?

?


批量數(shù)據(jù)加載/存儲指令實驗???? 2007-08-22 12:08:06
大 中 小
標(biāo)簽:arm指令 ldm/stm
這個程序用批量傳輸指令傳輸數(shù)據(jù),一次可傳8個字:

??????? AREA Block, CODE, READONLY????? ; name this block of code

num???? EQU???? 20????????????? ; Set number of words to be copied

??????? ENTRY?????????????????? ; mark the first instruction to call

start
??????? LDR???? r0, =src??????? ; r0 = pointer to source block
??????? LDR???? r1, =dst??????? ; r1 = pointer to destination block
??????? MOV???? r2, #num??????? ; r2 = number of words to copy

??????? MOV???? sp, #0x400????? ; set up stack pointer (r13)
blockcopy?????
??????? MOVS??? r3,r2, LSR #3?? ; number of eight word multiples
??????? BEQ???? copywords?????????????? ; less than eight words to move ?

??????? STMFD?? sp!, {r4-r11}?? ; save some working registers
octcopy
??????? LDMIA?? r0!, {r4-r11}?? ; load 8 words from the source
??????? STMIA?? r1!, {r4-r11}?? ; and put them at the destination
??????? SUBS??? r3, r3, #1????????????? ; decrement the counter
??????? BNE???? octcopy???????? ; ... copy more

??????? LDMFD?? sp!, {r4-r11}?? ; dont need these now - restore originals

copywords
??????? ANDS??? r2, r2, #7????????????? ; number of odd words to copy
??????? BEQ???? stop??????????????????? ; No words left to copy ?
wordcopy
??????? LDR???? r3, [r0], #4??? ; a word from the source
??????? STR???? r3, [r1], #4??? ; store a word to the destination
??????? SUBS??? r2, r2, #1????????????? ; decrement the counter
??????? BNE???? wordcopy??????????????? ; ... copy more

stop
??????? MOV???? r0, #0x18?????????????? ; angel_SWIreason_ReportException
??????? LDR???? r1, =0x20026??? ; ADP_Stopped_ApplicationExit
??????? SWI???? 0x123456??????????????? ; ARM semihosting SWI

?

下面的這個程序?qū)崿F(xiàn)同樣的功能,每次只能傳一個字:


??????? AREA BlockData, DATA, READWRITE

src???? DCD???? 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4
dst???? DCD???? 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

??????? END

?

??????? AREA Word, CODE, READONLY?????? ; name this block of code

num???? EQU???? 20????????????? ; Set number of words to be copied

??????? ENTRY?????????????????? ; mark the first instruction to call

start
??????? LDR???? r0, =src??????? ; r0 = pointer to source block
??????? LDR???? r1, =dst??????? ; r1 = pointer to destination block
??????? MOV???? r2, #num??????? ; r2 = number of words to copy
??????
wordcopy
??????? LDR???? r3, [r0], #4??? ; a word from the source
??????? STR???? r3, [r1], #4??? ; store a word to the destination
??????? SUBS??? r2, r2, #1????? ; decrement the counter
??????? BNE???? wordcopy??????? ; ... copy more

stop
??????? MOV???? r0, #0x18?????? ; angel_SWIreason_ReportException
??????? LDR???? r1, =0x20026??? ; ADP_Stopped_ApplicationExit
??????? SWI???? 0x123456??????? ; ARM semihosting SWI

??????? AREA BlockData, DATA, READWRITE

src???? DCD???? 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4
dst???? DCD???? 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

??????? END

?

?


當(dāng)處理器工作在ARM狀態(tài)時,幾乎所有的指令均根據(jù)CPSR中條件碼的狀態(tài)和指令的條件域有條件的執(zhí)行。當(dāng)指令的執(zhí)行條件滿足時,指令被執(zhí)行,否則指令被忽略。
每一條ARM指令包含4位的條件碼,位于指令的最高4位[31:28]。條件碼共有16種,每種條件碼可用兩個字符表示,這兩個字符可以添加在指令助記符的后面和指令同時使用。例如,跳轉(zhuǎn)指令B可以加上后綴EQ變?yōu)锽EQ表示“相等則跳轉(zhuǎn)”,即當(dāng)CPSR中的Z標(biāo)志置位時發(fā)生跳轉(zhuǎn)。

1、 B指令
B指令的格式為:
B{條件} 目標(biāo)地址
B指令是最簡單的跳轉(zhuǎn)指令。一旦遇到一個 B 指令,ARM 處理器將立即跳轉(zhuǎn)到給定的目標(biāo)地址,從那里繼續(xù)執(zhí)行。注意存儲在跳轉(zhuǎn)指令中的實際值是相對當(dāng)前PC值的一個偏移量,而不是一個絕對地址,它的值由匯編器來計算(參考尋址方式中的相對尋址)。它是 24 位有符號數(shù),左移兩位后有符號擴展為 32 位,表示的有效偏移為 26 位(前后32MB的地址空間)。以下指令:
B Label ;程序無條件跳轉(zhuǎn)到標(biāo)號Label處執(zhí)行
CMP R1,#0 ;當(dāng)CPSR寄存器中的Z條件碼置位時,程序跳轉(zhuǎn)到標(biāo)號Label處執(zhí)行
BEQ Label

3.3.6 批量數(shù)據(jù)加載/存儲指令
ARM微處理器所支持批量數(shù)據(jù)加載/存儲指令可以一次在一片連續(xù)的存儲器單元和多個寄存器之間傳送數(shù)據(jù),批量加載指令用于將一片連續(xù)的存儲器中的數(shù)據(jù)傳送到多個寄存器,批量數(shù)據(jù)存儲指令則完成相反的操作。常用的加載存儲指令如下:
— LDM 批量數(shù)據(jù)加載指令
— STM 批量數(shù)據(jù)存儲指令
LDM(或STM)指令
LDM(或STM)指令的格式為:
LDM(或STM){條件}{類型} 基址寄存器{!},寄存器列表{∧}
LDM(或STM)指令用于從由基址寄存器所指示的一片連續(xù)存儲器到寄存器列表所指示的多個寄存器之間傳送數(shù)據(jù),該指令的常見用途是將多個寄存器的內(nèi)容入棧或出棧。其中,{類型}為以下幾種情況:
IA 每次傳送后地址加1;
IB 每次傳送前地址加1;
DA 每次傳送后地址減1;
DB 每次傳送前地址減1;
FD 滿遞減堆棧;
ED 空遞減堆棧;
FA 滿遞增堆棧;
EA 空遞增堆棧;
{!}為可選后綴,若選用該后綴,則當(dāng)數(shù)據(jù)傳送完畢之后,將最后的地址寫入基址寄存器,否則基址寄存器的內(nèi)容不改變。
基址寄存器不允許為R15,寄存器列表可以為R0~R15的任意組合。
{∧}為可選后綴,當(dāng)指令為LDM且寄存器列表中包含R15,選用該后綴時表示:除了正常的數(shù)據(jù)傳送之外,還將SPSR復(fù)制到CPSR。同時,該后綴還表示傳入或傳出的是用戶模式下的寄存器,而不是當(dāng)前模式下的寄存器。
指令示例:
STMFD R13!,{R0,R4-R12,LR} ;將寄存器列表中的寄存器(R0,R4到R12,LR)存入堆棧。
LDMFD R13!,{R0,R4-R12,PC} ;將堆棧內(nèi)容恢復(fù)到寄存器(R0,R4到R12,LR)。

?

?

?

?

?

ARM匯編的SWI指令軟中斷 [轉(zhuǎn)貼 2007-05-25 11:21:49]??
?
從下面的一個ARM 匯編小程序要弄懂的以下三個問題:

1).在ARM狀態(tài)轉(zhuǎn)到THUNB狀態(tài)和BX的應(yīng)用

2).匯編的架構(gòu)

3).SWI指令的使用

    AREA ADDREG,CODE,READONLY

    ENTRY

MAIN

??????????????? ADR r0,ThunbProg 1 ;(為什么要加1呢?因為BX指令跳轉(zhuǎn)到指定的地址執(zhí)行程序 時, 若   (BX{cond} Rm)Rm的位[0]為1,則跳轉(zhuǎn)時自動將CPSR中的標(biāo)志T置位即把目標(biāo) 代碼解釋為 Thunb代碼)

??????????????? BX r0

??????????????? CODE16

ThunbProg

??????????????? mov r2,#2

    mov r3,#3

    add r2,r2,r3

    ADR r0,ARMProg

    BX ro

    CODE32

ARMProg

    mov r4,#4

    mov r5,#5

    add r4,r4,r5

stop???????? mov r0,#0x18

??????????????? LDR r1,=0x20026
???
??????????????? SWI 0x123456

END

?SWI--軟中斷指令:

?SWI指令用于產(chǎn)生軟中斷,從擁護(hù)模式變換到管理模式,CPSR保存到管理模式的SPSR中.

 SWI{cond} immed_24 ;immed_24為軟中斷號(服務(wù)類型)

使用SWI指令時,通常使用以下兩種方法進(jìn)行傳遞參數(shù),SWI 異常中斷處理程序就可以提供相關(guān)的服務(wù),這兩種方法均是用戶軟件協(xié)定.SWI異常中斷處理程序要通過讀取引起軟中斷的SWI指令,以取得24位立即數(shù).

(1) 指令中的24位立即數(shù)指定了用戶請求的服務(wù)類型,參數(shù)通過通用寄存器傳遞.

??????? mov r0,#34 ;設(shè)置子功能號位34

??????? SWI 12 ;調(diào)用12號軟中斷

(2) 指令中的24位立即數(shù)被忽略,用戶請求的服務(wù)類型有寄存器R0的值決定,參數(shù)通過其他的通用寄存器傳遞.

??????? mov r0,#12 ;調(diào)用12號軟中斷

??????? mov r1,#34 ;設(shè)置子功能號位34

??????? SWI  0

在SWI異常中斷處理程序中,取出SWI立即數(shù)的步驟為:首先確定引起軟中斷的SWI指令是ARM指令還是Thunb指令,這可通過對SPSR訪問得到;然后取得該SWI指令的地址,這可通過訪問LR寄存器得到;接著讀出指令,分解出立即數(shù).如如下程序:

?????????? T_bit EQU 0X20
??
??????????? SWI_Handler
??
??????????? STMFD SP!,{R0-R3,R12,LR} ;現(xiàn)場保護(hù)
??
??????????? MRS R0,SPSR ;讀取SPSR
??
??????????? STMFD SP!,{R0} :保存SPSR
??
??????????? TST R0,#T_bit
??
??????????? LDRNEH R0,[LR,#-2] ;若是Thunb指令,讀取指令碼(16位)

   BICNE R0,#0XFF00 :取得Thunb指令的8位立即數(shù)

   LDREQ R0,[LR,#-4] ;若是ARM指令,讀取指令碼(32位)

   BICEQ R0,#0XFF000000 ;取得ARM指令的24位立即數(shù)

   ....

   LDMFD SP!,{R0-R3,R12,PC}^ ;SWI異常中斷返回

?

?

?


基于s3c2410軟中斷服務(wù)的uC/OS-II任務(wù)切換
?
?
?
1.關(guān)于軟中斷指令
? 軟件中斷指令(SWI)可以產(chǎn)生一個軟件中斷異常,這為應(yīng)用程序調(diào)用系統(tǒng)例程提供了一種機制。
語法:
?????? SWI?? {<cond>}? SWI_number
SWI執(zhí)行后的寄存器變化:
lr_svc = SWI指令后面的指令地址
spsr_svc = cpsr
pc = vectors + 0x08
cpsr模式 = SVC
cpsr I = 1(屏蔽IRQ中斷)
?
?? 處理器執(zhí)行SWI指令時,設(shè)置程序計數(shù)器pc為向量表的0x08偏移處,同事強制切換處理器模式到SVC模式,以便操作系統(tǒng)例程可以在特權(quán)模式下被調(diào)用。
?? 每個SWI指令有一個關(guān)聯(lián)的SWI號(number),用于表示一個特定的功能調(diào)用或特性。
【例子】 一個ARM工具箱中用于調(diào)試SWI的例子,是一個SWI號為0x123456的SWI調(diào)用。通常SWI指令是在用戶模式下執(zhí)行的。
SWI執(zhí)行前:
??? cpsr = nzcVqift_USER
??? pc = 0x00008000
??? lr = 0x003fffff?? ;lr = 4
??? r0 = 0x12
?
執(zhí)行指令:
??? 0x00008000?? SWI??? 0x123456
?
SWI執(zhí)行后:
??? cpsr = nzcVqIft_SVC
??? spsr = nzcVqift_USER
??? pc = 0x00000008
??? lr = 0x00008004
??? r0 = 0x12
?? SWI用于調(diào)用操作系統(tǒng)的例程,通常需要傳遞一些參數(shù),這可以通過寄存器來完成。在上面的例子中,r0
用于傳遞參數(shù)0x12,返回值也通過寄存器來傳遞。
?? 處理軟件中斷調(diào)用的代碼段稱為中斷處理程序(SWI Handler)。中斷處理程序通過執(zhí)行指令的地址獲取軟件中斷號,指令地址是從lr計算出來的。
?? SWI號由下式?jīng)Q定:
?? SWI_number = <SWI instruction> AND NOT<0xff000000>
?? 其中SWI instruction就是實際處理器執(zhí)行的32位SWI指令
?
?? SWI指令編碼為:
?? 31 - 28? 27 - 24? 23 - 0
???? cond?? 1 1 1 1? immed24
?? 指令的二進(jìn)制代碼的bit23-bit0是24bit的立即數(shù),即SWI指令的中斷號,通過屏蔽高8bit即可獲得中斷號。lr寄存器保存的是中斷返回指令的地址,所以 [lr - 4] 就是執(zhí)行SWI的執(zhí)行代碼。通過load指令拷貝整個SWI指令到寄存器,使用BIC屏蔽指令的高8位,獲取SWI中斷號。
??
??? ;read the SWI instruction
??? LDR? r10, [lr, #-4]
??? BIC? r10, r10, #0xff000000
?
2. 周立功移植uC/OS-II到s3c2410的軟中斷服務(wù)級的任務(wù)切換
uC/OS-II的任務(wù)調(diào)度函數(shù)
?? uC/OS-II的任務(wù)級的調(diào)度是由函數(shù)OS_Sched( )完成的。
?
void OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
??? OS_CPU_SR cpu_sr;
#endif
??? INT8U y;


??? OS_ENTER_CRITICAL();
??? if ((OSIntNesting == 0) && (OSLockNesting == 0)) { /* Sched. only if all ISRs done & not locked */
??????? y = OSUnMapTbl[OSRdyGrp]; /* Get pointer to HPT ready to run */
??????? OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
??????? if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */
??????????? OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
??????????? OSCtxSwCtr++; /* Increment context switch counter */
??????????? OS_TASK_SW(); /* Perform a context switch */
??????? }
??? }
??? OS_EXIT_CRITICAL();
}
?

?? 詳細(xì)解釋可以參考《嵌入式實時操作系統(tǒng) uC/OS-II》,os_sched函數(shù)在確定所有就緒任務(wù)的最高優(yōu)先級高于當(dāng)前任務(wù)優(yōu)先級時進(jìn)行任務(wù)切換,通過OS_TASK_SW( )宏來調(diào)用。
?? OS_TASK_SW( )宏實際上定義的是SWI軟中斷指令。見OS_CPU.H文件的代碼:

__swi(0x00) void OS_TASK_SW(void); /* 任務(wù)級任務(wù)切換函數(shù) */
__swi(0x01) void _OSStartHighRdy(void); /* 運行優(yōu)先級最高的任務(wù) */
__swi(0x02) void OS_ENTER_CRITICAL(void); /* 關(guān)中斷 */
__swi(0x03) void OS_EXIT_CRITICAL(void); /* 開中斷 */

__swi(0x40) void *GetOSFunctionAddr(int Index); /* 獲取系統(tǒng)服務(wù)函數(shù)入口 */
__swi(0x41) void *GetUsrFunctionAddr(int Index);/* 獲取自定義服務(wù)函數(shù)入口 */
__swi(0x42) void OSISRBegin(void); /* 中斷開始處理 */
__swi(0x43) int OSISRNeedSwap(void); /* 判斷中斷是否需要切換 */

__swi(0x80) void ChangeToSYSMode(void); /* 任務(wù)切換到系統(tǒng)模式 */
__swi(0x81) void ChangeToUSRMode(void); /* 任務(wù)切換到用戶模式 */
__swi(0x82) void TaskIsARM(INT8U prio); /* 任務(wù)代碼是ARM代碼 */
__swi(0x83) void TaskIsTHUMB(INT8U prio); /* 任務(wù)代碼是THUMB */
?

__swi(0x00) void OS_TASK_SW(void); 是與ADS相關(guān)的代碼,通過反匯編可以看到,調(diào)用OS_TASK_SW實際上被替換成swi 0x00 軟中斷指令。執(zhí)行此執(zhí)行,pc會跳轉(zhuǎn)到向量表的0x08偏移處。


中斷向量表:(見Startup.s文件)


CODE32
??????? AREA vectors,CODE,READONLY
; 異常向量表
Reset
??????? LDR PC, ResetAddr
??????? LDR PC, UndefinedAddr
??????? LDR PC, SWI_Addr
??????? LDR PC, PrefetchAddr
??????? LDR PC, DataAbortAddr
??????? DCD IRQ_Addr
??????? LDR PC, IRQ_Addr
??????? LDR PC, FIQ_Addr

ResetAddr???? DCD ResetInit
UndefinedAddr DCD Undefined
SWI_Addr????? DCD SoftwareInterrupt
PrefetchAddr? DCD PrefetchAbort
DataAbortAddr DCD DataAbort
Nouse???????? DCD 0
IRQ_Addr????? DCD IRQ_Handler
FIQ_Addr????? DCD FIQ_Handler
?


執(zhí)行SWI 0x00指令后,pc會跳轉(zhuǎn)到SoftwareInterrupt代碼處開始執(zhí)行:

見Os_cpu_a.s文件的SoftwareInterrupt函數(shù):

?

SoftwareInterrupt
??????? LDR SP, StackSvc ; 重新設(shè)置堆棧指針
??????? STMFD {R0-R3, R12, LR}
??????? MOV R1, SP ; R1指向參數(shù)存儲位置

??????? MRS R3, SPSR
??????? TST R3, #T_bit ; 中斷前是否是Thumb狀態(tài)
??????? LDRNEH R0, [LR,#-2] ; 是: 取得Thumb狀態(tài)SWI指令
??????? BICNE R0, R0, #0xff00
??????? LDREQ R0, [LR,#-4] ; 否: 取得arm狀態(tài)SWI指令
??????? BICEQ R0, R0, #0xFF000000??? ; 如上面所述,此處通過屏蔽SWI指令的高8位來獲取SWI號,r0 = SWI號,R1指向參數(shù)存儲位置
??????? CMP R0, #1
??????? LDRLO PC, =OSIntCtxSw? ;為0時跳轉(zhuǎn)到OSIntCtxSwdi地址處
??????? LDREQ PC, =__OSStartHighRdy ; 為1時,跳轉(zhuǎn)到__OSStartHighRdy地址處。SWI 0x01為第一次任務(wù)切換

??????? BL SWI_Exception? ;進(jìn)入中斷號散轉(zhuǎn)函數(shù)
???????
??????? LDMFD {R0-R3, R12, PC}^
???????
StackSvc DCD (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)

?

以上就是任務(wù)切換軟中斷級服務(wù)的實現(xiàn)。
?
?


?

?

利用arm 組語的PRE-INDEX 與POST-INDEX ADDRESSING,上課時CODING完成的範(fàn)例--1+2+3+...+10之和 分類:IT技術(shù)分享2008/01/30 17:17於今日 97/01/30 上課時實作的程式範(fàn)例,先貼上程式碼。

因是上課當(dāng)場coding完成的,so沒有加上註解^^

範(fàn)例一:使用 POST-INDEX ADDRESSING實作的code
=======================================
??? AREA? ASM6,CODE,READONLY

??? ENTRY
START
??? LDR R0,=ARR1
??? MOV R1,#0
LOOP
??? LDR R2,[R0],#4
??? ADD R1,R1,R2
??? CMP R2,#0
??? BNE LOOP

STOP
??? LDR R0,=0X18
??? LDR R1,=0X20026
??? SWI 0X123456

??? AREA? ARR,DATA,READWRITE
ARR1? DCD?? 1,2,3,4,5,6,7,8,9,10,0
??? END


範(fàn)例二:使用 PRE-INDEX ADDRESSING實作的code
=======================================
AREA??? ASM8,CODE,READONLY

??? ENTRY
START
??? LDR R0,=ARR1
??? MOV R1,#0
??? MOV R3,#0
LOOP
??? LDR R2,[R0,R1,LSL #2]
??? ADD R1,R1,#1
??? ADD R3,R3,R2
??? CMP R2,#0
??? BNE LOOP

STOP
??? LDR R0,=0X18
??? LDR R1,=0X20026
??? SWI 0X123456

??? AREA? ARR,DATA,READWRITE
ARR1? DCD?? 1,2,3,4,5,6,7,8,9,10,0
??? END

?


http://www.akaedu.org/bbs/redirect.php?tid=231&goto=lastpost

?

常用ARM指令
1、??????? 內(nèi)存訪問指令
基本指令:
LDR:memory -> register (memory包括映射到內(nèi)存空間的非通用寄存器)
STR:register? -> memory
語法:
??????? op{cond }{B}{T}??????????????? Rd ,??????????????? [Rn ]
op{cond }{B}??????????????????????? Rd ,??????????????? [Rn ,??????????????? FlexOffset ]{!}
op{cond }{B}??????????????????????? Rd ,??????????????? label
op{cond }{B}{T}??????????????? Rd ,??????????????? [Rn ],??????? FlexOffset
op:基本指令,如LDR、STR
cond:條件執(zhí)行后綴
B:字節(jié)操作后綴
T:用戶指令后綴
Rd:源寄存器,對于LDR指令,Rd將保存從memory中讀取的數(shù)值;對于STR指令,Rd保存著將寫入memory的數(shù)值
Rn:指針寄存器
FlexOffset:偏移量
例子:
ldr??????????????? r0,??????????????? [r1]??????????????????????????????????????? ;r1作為指針,該指針指向的數(shù)存入r0
str??????????????? r0,??????????????? [r1,??????????????? #4]??????????????? ;r1+4作為指針,r0的值存入該地址
??????? str??????????????? r0,??????????????? [r1,??????????????? #4]!??????????????? ;同上,并且r1 = r1 + 4
??????? ldr??????????????? r1,??????????????? =0x08100000??????????????? ;立即數(shù)0x08100000存到r1
??????? ldr??????????????? r1,??????????????? [r2],??????????????? #4??????????????????????? ;r2+4作為指針,指向的值存入r1,并且r2=r2+4
【label的使用】
addr1??????????????????????????????????????????????????????? ;定義一個名為“addr1”的label,addr1 = 當(dāng)前地址
??????? dcd??????????????? 0??????????????????????????????????????? ;在當(dāng)前地址出定義一個32bit的變量
~ ~ ~
??????? ldr??????????????? r1,??????????????? label1??? ;r1 = addr1,r1即可以作為var1的指針
??????? ldr??????????????? r0,??????????????? [r1]
??????? add??????? r0,??????????????? r0,??????????????? #1
??????? str??????????????? r0,??????????????? [r1]??????????????????????? ;變量var1的值加1
【FlexOffset的使用】
??????? FlexOffset可以是立即數(shù),也可以是寄存器,還可以是簡單的表達(dá)式
???????
2、??????? 多字節(jié)存取指令(常用于堆棧操作)
基本指令:
??????? LDM:memory ――> 多個寄存器
??????? STM:多個寄存器 ――> memory
語法:
??????? op{cond }mode??????? Rn{!},??????????????? reglist {^}
??????? mode:指針更新模式,對應(yīng)于不同類型的棧。最常用的是“FD”模式,相當(dāng)于初始棧指針在高位,壓棧后指針值減小。
??????? Rn:指針寄存器
??????? !:最后的指針值將寫入Rn中
??????? reglist:要操作的寄存器列表,如{r0-r8, r10}
??????? ^ :完成存取操作后從異常模式下返回
例子:
;異常處理程序:
??????? sub??????????????? lr,??????????????? lr,??????????????? #4??????????????????????? ; lr – 4是異常處理完后應(yīng)該返回的地方
;保存r0~r12和lr寄存器的值到堆棧并更新堆棧指針。
??????? stmfd??????????????? sp!,??????????????? {r0-r12, lr}???????
;異常處理
??????????????? ldmfd??????? sp!,??????????????? {r0-r12, pc}^???????? ;從堆棧中恢復(fù)r0~r12,返回地址賦給pc指針,使程序返回到異常發(fā)生前所執(zhí)行的地方,^標(biāo)記用來使CPU退出異常模式,進(jìn)入普通狀態(tài)。
???????????????????????????????????????????????????????????????????????????????????????

3、??????? 算術(shù)運算指令
基本指令:
??????? ADD:加
??????? SUB:減
語法:
??????? op{cond }{S}??????????????? Rd,??????????????? Rn,??????????????? Operand2
??????? S:是否設(shè)置狀態(tài)寄存器(CPSR),如:N(有符號運算結(jié)果得負(fù)數(shù))、Z(結(jié)果得0)、C(運算的進(jìn)位或移位)、V(有符號數(shù)的溢出)等等。
??????? Rd:保存結(jié)果的寄存器
??????? Rn:運算的第一個操作數(shù)
??????? Operand2:運算的第二個操作數(shù),這個操作數(shù)的值有一些限定:如可以是8位立即數(shù)(例:0xa8)或一個8為立即數(shù)的移位(例:0xa800,而0xa801就不符合)。也可以是寄存器,或寄存器的移位(如“r2,? lsl? #4”)。
例子:
??????? add??????????????? r0,??????????????? r1,??????????????? r2??????????????????????????????????????? ; r0 = r1 + r2
??????? adds??????????????? r0,??????????????? r1,??????????????? #0x80??????????????????????????????? ; r0 = r1 + 0x80,并設(shè)置狀態(tài)寄存器
??????? subs??????????????? r0,??????????????? r1,??????????????? #2000??????????????????????????????? ; r0 = r1 – 2000,并設(shè)置狀態(tài)寄存器

4、??????? 邏輯運算指令
基本指令:
??????? AND:與
??????? ORR:或
??????? EOR:異或
??????? BIC:位清0
語法:
??????? op{cond }{S}??????????????? Rd,??????????????? Rn,??????????????? Operand2
??????? 語法類似算術(shù)運算指令
例子:
??????? ands??????????????? r0,??????? r1,??????? #0xff00??????????????????????? ; r0 = r1 and 0xff00,并設(shè)置狀態(tài)寄存器
??????? orr??????????????? r0,??????????????? r1,??????????????? r2??????????????????????????????????????? ; r0 = r1 and r2
??????? bics??????????????? r0,??????????????? r1,??????????????? #0xff00??????????????????????? ; r0 = r1 and ! (0xff00)
??????? ands??????????????? r0,??????????????? r1,??????????????? #0xffff00ff??????????????? ; 錯誤

5、??????? MOV指令
語法:
MOV{cond}{S}??????? Rd,??????????????? Operand2
例子:
??????? mov??????????????? r0,??????????????? #8??????????????????????????????????????????????? ; r0 = 8
??????? mov??????????????? r0,??????????????? r1??????????????????????????????????????????????? ; r0 = r1
不同于LDR、STR指令,該指令可以寄存器間賦值

6、??????? 比較指令
基本指令:
??????? CMP:比較兩個操作數(shù),并設(shè)置狀態(tài)寄存器
語法:
??????? CMP{cond }??????????????? Rn,??????????????? Operand2
例子:
??????? cmp??????????????? r0,??????????????? r1??????????????????????????????????????????????? ; 計算r0 – r1,并設(shè)置狀態(tài)寄存器,由狀態(tài)寄存器可以知r0是否大于、小于或等于r1
??????? cmp??????????????? r0,??????????????? #0??????????????????????????????????????????????? ;

7、??????? 跳轉(zhuǎn)指令
基本指令:
??????? B:跳轉(zhuǎn)
??????? BL:跳轉(zhuǎn)并將下一指令的地址存入lr寄存器
語法:
??????? op{cond}??????????????? label
??????? label:要跳向的地址
例子:
loop1
??????? ~ ~ ~
??????? b??????????????? loop1??????????????????????????????? ; 跳到地址loop1處
??????? bl??????????????? sub1??????????????????????????????? ; 將下一指令地址寫入lr,并跳至sub1
??????? ~ ~ ~
sub1
??????? ~ ~ ~
??????? mov??????? pc,??????? lr??????????????????????? ; 從sub1中返回
【使用本地label(local label)】
??????? 本地label可以在一個程序段內(nèi)多次使用,用數(shù)字作為label的名稱,也可以在數(shù)字后面跟一些字母。引用本地label的語法是:??????? %{F|B}{A|T}n{routname},其中F代表向前搜索本地label,B代表向后搜索,A/T不常使用。
例子
100??????? ; 定義本地label,名稱為“100”
~ ~ ~
100??????????????????????????????????????????????????????????????????????????????? ; 第二次定義本地label,名稱為“100”
??????? ~ ~ ~
??????? b??????????????? %f100??????????????????????????????????????????????? ; 向前跳到最近的“100”處
~ ~ ~
??????? b??????????????? %b100??????????????????????????????????????????????? ; 向后跳至最近的“100”處
100??????????????????????????????????????????????????????????????????????????????? ; 第三次定義本地label 100

8、??????? 條件執(zhí)行
條件:狀態(tài)寄存器中某一或某幾個比特的值代表條件,對應(yīng)不同的條件后綴cond,如:
后綴 (cond)???????? 狀態(tài)寄存器中的標(biāo)記???????? 意義
EQ???????????????????????????????????????????????? Z = 1???????????????????????????????????????????????????????????????????????? 相等
NE???????????????????????????????????????????????? Z = 0??????????????????????????????????????????????????????????????????????? 不相等
GE???????????????????????????????????????????????? N和V相同???????????????????????????????????????????????? >=
LT???????????????????????????????????????????????? N和V不同??????????????????????????????????????????????????????? <
GT???????????????????????????????????????????????? Z??????? = 0, 且N和V相同??????????????????????? >
LE??????????????????????????????????????????????? Z = 1, 或N和V不同???????????????? <=
例子:
??????????????? cmp??????????????? r0,??????????????? r1??????????????? ;比較r0和r1
??????????????? blgt??????????????? sub1??????????????????????? ;如果r0>r1,跳轉(zhuǎn)到sub1,否則不操作
;――――――――――――――――――――
??????????????? ;一段循環(huán)代碼
??????????????? ldr??????????????????????? r2,??????????????? =8??????????????? ;r2 = 8
??????? loop
??????????????? ;這里可以進(jìn)行一些循環(huán)內(nèi)的操作
??????????????? subs??????????????? r2,??????????????? r2,??????????????? #1??????????????? ;r2 = r2 –1,并設(shè)置狀態(tài)位
??????????????? bne??????????????? loop??????????????????????????????????????? ;如果r2不等于0,則繼續(xù)循環(huán)
;――――――――――――――――――――
??????????????? mov??????????????? r0,??????????????? #1??????????????????????????????? ; r0 = 1
??????????????? cmp??????????????? r2,??????????????? #8??????????????????????????????? ;??????? 比較r2和8
??????????????? movlt??????? r0,??????????????? #2??????????????????????????????? ; 如果r2<8,r0 = 2
???????
ARM匯編程序結(jié)構(gòu)
;――――――――――――――――――――
AREA? EX2,? CODE,? READONLY
;AREA指令定義一個程序段,名稱為EX2,屬性為:CODE、READONLY
??????? INCLUDE???????? Common.inc??????? ;包含匯編頭文件
??????? IMPORT???????? sub1??????????????????????????????????????? ;引用外部符號
??????? EXPORT??????????????? prog1??????????????????????? ;向外輸出符號
ENTRY???????????????????????????????????????????????????????? ;ENTRY指令定義程序的開始
start??????????????????????????????????????????????????????????????????????????????? ;此處定義了一個label start
MOV???????? r0,??????? #10???????????????????????????????????????
MOV???????? r1,??????? #3
ADD???????? r0,??????? r0,??????? r1???????????????????????????????? ;r0 =r0 +r1
prog1??????????????????????????????????????????????????????????????????????? ;此處定義了一個label prog1
MOV???????? r0,??????? #0x18????????????????????????????????
LDR???????? r1,??????? =0x20026????????????????????????
SWI???????? 0x123456????????????????????????????????
END???????????????????????????????????????????????????????????????? ;END指令表示程序段的結(jié)束
;――――――――――――――――――――
宏的使用
定義宏:
MACRO??????????????????????????????????????????????? ;宏的起始
{label}??????? macroname??????? para1,para2……
;代碼
MEND??????????????????????????????????????????????????????? ;宏結(jié)束
引用宏:
??????????????? marconame???????? para1,para2……
例子
;定義一個宏,完成兩個寄存器內(nèi)容交換
??????????????? MACRO
??????????????? swap??????????????? $w1,??????????????? $w2,??????????????? $w3
??????????????????????? mov??????????????? $w3,??????????????? $w1
??????????????????????? mov??????????????? $w1,??????????????? $w2
??????????????????????? mov??????????????? $w2,??????????????? $w3
??????????????? MEND

;使用這個宏
ldr??????????????????????? r0,??????????????? =1
ldr??????????????????????? r1,??????????????? =2
swap??????????????? r0,??????????????? r1,??????????????? r2??????????????? ;此處調(diào)用了宏swap,運行完后r0、r1的值交換了
一般可以把宏寫在宏文件(.mac文件)中,在程序里用INCLUDE指令包含宏文件

?

?

?

?


?
最超值的ARM7/ARM9開發(fā)板系列
AVR單片機開發(fā)板與仿真器
?
本章節(jié)主要介紹ARM 處理器的基本程序設(shè)計方法,包含ARM 指令實驗,Thumb 指令實驗和ARM 處理器工作模式實驗。

4.1 ARM 指令實驗
4.1.1 實驗說明
? 實驗?zāi)康?#xff1a;??? 透過實驗掌握ARM 組譯指令的使用方法。


???????? 實驗設(shè)備: 硬件使用PC 主機,軟件使用Embest IDE 2003 整合開發(fā)環(huán)境,Windows 98/2000/NT/XP。

???????? 實驗內(nèi)容:??? 使用簡單ARM 組譯指令,操作寄存器和內(nèi)存區(qū)作互相的數(shù)據(jù)交換。

4.1.2 實驗原理
ARM 處理器共有37個寄存器:31個通用寄存器,包括程序計數(shù)器(PC)。這些寄存器都是32 位的。6個狀態(tài)寄存器。這些寄存器也是32 位的,但是只是使用了其中的12 位。

ARM 通用寄存器

通用寄存器(R0~R15)可分為3 類:

不分組寄存器R0~R7;

分組寄存器R8~R14;

程序計數(shù)器R15。

?

1)不分組寄存器R0~R7

R0~R7 是不分組寄存器。這意味著在所有處理器模式下,它們都存取一樣的32 位寄存器。它們是真正的通用寄存器,沒有架構(gòu)所隱含的特殊用途。

?

2)分組寄存器R8~R14

R8~R14 是分組寄存器。它們存取的物理寄存器取決于當(dāng)前的處理器模式。若要存取特定的物理寄存器而不依賴當(dāng)前的處理器模式,則要使用規(guī)定的各字。

寄存器R8~R12 各有兩組物理寄存器:一組為FIQ 模式,另一組為除了FIQ以外的所有模式。寄存器R8~R12 沒有任何指定的特殊用途。只是使用R8~R14來簡單地處理中斷。寄存器R13,R14 各有6 個分組的物理寄存器。1 個用于用戶模式和系統(tǒng)模式,其它5 個分別用于5 種異常模式。寄存器R13 通常用做堆迭指標(biāo),稱為SP。每種異常模式都有自己的R13。寄存器R14 用作子程序鏈接寄存器,也稱為LR。

?

3) 程序計數(shù)器R15

寄存器R15 用做程序計數(shù)器(PC)。程序狀態(tài)寄存器在所有處理器模式下都可以存取當(dāng)前的程序狀態(tài)寄存器CPSR。CPSR 包含條件碼標(biāo)志位,中斷禁止位,當(dāng)前處理器模式以及其它狀態(tài)和控制信息。每種異常模式都有一個程序狀態(tài)保存寄存器SPSR。當(dāng)例外出現(xiàn)時,SPSR 用于保留CPSR的狀態(tài)。

CPSR 和SPSR 的格式如下:

31
?30
?29
?28
?27
?26???????? 8
?7
?6
?5
?4
?3
?2
?1
?0
?
N
?Z
?C
?V
?Q
?DNM(RAZ)
?I
?F
?T
?M
?M
?M
?M
?M
?

?

條件碼標(biāo)志:N,Z,C,V 大多數(shù)指令可以測試這些條件碼標(biāo)志以決定程序指令如何執(zhí)行

控制位:最低8 位I,F,T 和M 位用做控制位。當(dāng)異常出現(xiàn)時改變控制位。當(dāng)處理器在特權(quán)模式下也可以由軟件改變。

中斷禁止位:I 置1 則禁止IRQ 中斷。F 置1 則禁止FIQ 中斷。T 位:T=0 指示ARM 執(zhí)行。T=1 指示Thumb 執(zhí)行。在這些架構(gòu)系統(tǒng)中,可自由地使用能在ARM 和Thumb 狀態(tài)之間切換的指令。

模式位:M0, M1, M2, M3 和M4 (M[4:0]) 是模式位.這些位

決定處理器的工作模式.如表2-1 所示。

表4-1 ARM 工作模式M[4:0]

M[4:0]
?模式
?可存取的寄存器
?
0b10000
?用戶模式
?PC, R14~R0,CPSR
?
0b10001
?FIQ模式
?PC, R14_fiq~R8_fiq,R7~R0,CPSR,SPSR_fiq
?
0b10010
?IRQ模式
?PC, R14_irq~R8_fiq,R12~R0,CPSR,SPSR_irq
?
0b10011
?管理模式
?PC, R14_svc~R8_svc,R12~R0,CPSR,SPSR_svc
?
0b10111
?中止
?PC, R14_abt~R8_abt,R12~R0,CPSR,SPSR_abt
?
0b11011
?未定義
?PC, R14_und~R8_und,R12~R0,CPSR,SPSR_und
?
0b11111
?系統(tǒng)
?PC, R14~R0,CPSR
?

其它位程序狀態(tài)寄存器的其它位保留,用作以后的擴充。

?

4.1.3. 實驗操作步驟
1. 執(zhí)行ADS1.2開發(fā)環(huán)境,打開實驗系統(tǒng)例程目錄下ARMcode_test 子目錄下的ARMcode.mcp 工程文件。

2. 透過操作菜單欄或使用快捷命令編譯鏈接項目。

3. 選擇Debug 菜單Remote Connect 進(jìn)行連接軟件仿真器,執(zhí)行Download命令下載程序,并打開寄存器窗口。

4. 單步執(zhí)行程序并觀察和記錄寄存器R0-R15 的值變化。

5. 結(jié)合實驗內(nèi)容和相關(guān)數(shù)據(jù),觀察程序執(zhí)行,透過實驗加深理解ARM指令的使用。

?

?

?

4.1.4? 試驗程序代碼
;本程序?qū)?shù)據(jù)區(qū)從數(shù)據(jù)區(qū)SRC復(fù)制到目標(biāo)數(shù)據(jù)區(qū)DST。復(fù)制時,以8個字節(jié)為單位進(jìn)行。對于

;最后所剩不足的8個字節(jié)的數(shù)據(jù),以字為單位進(jìn)行復(fù)制,這時程序跳轉(zhuǎn)到copywords處執(zhí)行。

;在進(jìn)行以8個字為單位的數(shù)據(jù)復(fù)制時,保存了所有的8個工作寄存器。

?

;設(shè)置本段程序的名稱(Block)及屬性

?AREA Block,CODE,READONLY

?

????????????????????

;設(shè)置將要復(fù)制的字?jǐn)?shù)(定義變量num,并賦值為20)

num EQU 20????????????????

?

;程序入口標(biāo)志

?????? ENTRY

start

?

;r0寄存器指向源數(shù)據(jù)區(qū)(SRC 標(biāo)識的地址放入R0)

?????? LDR?????? r0,=src???

?

;r1寄存器指向目標(biāo)數(shù)據(jù)區(qū)(DST 標(biāo)識的地址放入R1)??????

?????? LDR?????? r1,=dst???

??????

;r2指定將要復(fù)制的字?jǐn)?shù)(裝載num 的值到R2)??

?????? MOV????? r2, #num

?????????????

;設(shè)置數(shù)據(jù)棧指針(R13),用于保存工作寄存器數(shù)值(設(shè)定SP堆棧開始地址為0x400)

?????? MOV????? sp, #0x400

?

?????????????

;進(jìn)行以8個字節(jié)為單位的數(shù)據(jù)復(fù)制

blockcopy

?

;需要進(jìn)行的以8個字為單位的復(fù)制次數(shù)( R2 右移3 位后的值放入R3)

?????? MOVS r3,r2, LSR #3????

;對于剩下的不足8個字的數(shù)據(jù),跳轉(zhuǎn)到copywords,以字為單位復(fù)制(判斷是否為0,為0 跳移)

??????

?????? BEQ copywords??????????????????

;保存工作寄存器(把R4 到R11 的值保存到SP 標(biāo)識的堆棧中)

?????? STMFD sp!, {r4-r11}?????????

?

octcopy

;從數(shù)據(jù)區(qū)讀取8個字節(jié)的數(shù)據(jù),放到8個寄存器中,并更新目標(biāo)數(shù)據(jù)區(qū)指針r0(把R0 中的地址標(biāo)識的內(nèi)容順序裝載到R4 到R11 中)

?

?????? LDMIA r0!, {r4-r11}??????????

;將這8個字?jǐn)?shù)據(jù)寫入到目標(biāo)數(shù)據(jù)區(qū),并更新目標(biāo)數(shù)據(jù)區(qū)指針r1(把R4 到R11 的值順序保存到以R1 起始地址的內(nèi)存中)

?????? STMIA r1!, {r4-r11}???????????

?

;將塊的復(fù)制次數(shù)減1 (R3 -1 計數(shù))

?????? SUBS r3, r3, #1??????????????????

?

;循環(huán),直到完成以8個字為單位的塊復(fù)制

?????? BNE octcopy??????????????????????

?

;需要注意的是,LDMIA 或者STMIA 指令執(zhí)行后,R0,R1 的值產(chǎn)生變化,每一次寄存器操作,R0 或者R1 的值會自動增加一個字節(jié)的量,這里操作了8 個寄存器,R0 或者R1 的值也相應(yīng)增加了8 個字節(jié)

?

?

;恢復(fù)工作寄存器值(把剛才保存的SP 堆棧中的值恢復(fù)到R4 到R11 中)

?????? LDMFD sp!, {r4-r11}??

???????

copywords

;剩下不足8個字的數(shù)據(jù)的字?jǐn)?shù)(邏輯與,把R2 前7 位扔掉)

?????? ANDS r2, r2, #7??????????

?

;數(shù)據(jù)復(fù)制完成(判斷是否為0,為0 跳移)

?????? BEQ stop???????????????????????????

?

wordcopy

;從源數(shù)據(jù)區(qū)讀取18個字的數(shù)據(jù),放到r3寄存器中,并更新目標(biāo)數(shù)據(jù)區(qū)指針r0(把R0 表示地址的內(nèi)容的后4 位全部拷貝到R3)

?????? LDR r3, [r0], #4???

?

;將這r3中數(shù)據(jù)寫入到目標(biāo)數(shù)據(jù)區(qū)中,并更新目標(biāo)數(shù)據(jù)區(qū)指針r1 (把R3 的內(nèi)容,放入以R1 為起始地址的4 位內(nèi)存中)??????

?????? STR r3, [r1], #4???????????

??????

;將字?jǐn)?shù)減1;(R2 -1 放回R2)

?????? SUBS r2, r2, #1???????????

?

;循環(huán),直到完成以字為單位的數(shù)據(jù)復(fù)制(判斷是否為0,不為0 跳移,同樣的,這里R0,R1 操作后,R0,R1 會自動加上便宜量)???

?????? BNE wordcopy??????????????????

?????????????????????????????????????????

stop

;從應(yīng)用程序中退出

?????? MOV????? r0,?? #0x18

?????? LDR?????? r1,?? =0x20026

?????? SWI 0x123456

;定義數(shù)據(jù)區(qū)bloackdata

?

?????? AREA???? Bloackdata,???? DATA,??? READWRITE

;定義源數(shù)據(jù)區(qū)src及目標(biāo)數(shù)據(jù)區(qū)dst

src?? DCD?????? 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4

dst?? DCD?????? 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

?

;結(jié)束匯編

?????? END

4.1.5 實驗練習(xí)題
1. 撰寫程序循環(huán)對R4~R11 進(jìn)行8 次累加,R4~R11 起始值為1~8,每次加操作后把R4~R11 的內(nèi)容放入SP 堆棧中,SP 初始設(shè)定為0x800。最后把R4~R11 用LDMFD 指令清空值為0。

2. 對于每一種ARM 的尋址方法,簡短的寫出相對的應(yīng)用程序片段。

4.2 ARM 處理器工作模式實驗
4.2.1. 實驗說明
???????? 實驗?zāi)康?#xff1a;透過實驗掌握ARM 處理器工作模式的切換。

???????? 實驗設(shè)備:軟件需要ADS1.2開發(fā)環(huán)境,Windows 98/2000/NT/XP。

???????? 實驗內(nèi)容:透過ARM 組譯指令,在各種處理器模式下切換并觀察各種模式下緩存器的區(qū)別;掌握ARM 不同模式的進(jìn)入與退出。

4.2.2. 實驗原理
ARM 處理器模式

ARM 架構(gòu)支持下表2-2 所列的7 種處理器模式。

工作模式
?描述
?
用戶模式(User,usr)
?正常程序執(zhí)行的模式
?
快速中斷模式(FIQ,fig)
?用于高速數(shù)據(jù)傳輸和數(shù)據(jù)處理
?
外部中斷模式(IRQ,irq)
?用于通常的中斷處理
?
特權(quán)模式(管理模式)(Supervisor,sve)
?共操作系統(tǒng)使用的一種模式
?
數(shù)據(jù)訪問中止模式(Abort,abt)
?用于虛擬存儲及存儲保護(hù)
?
未定義指令中斷模式(Undefind,und)
?用于支持通過軟件方針的協(xié)處理器
?
系統(tǒng)模式(System,sys)
?用于運行特權(quán)的操作系統(tǒng)任務(wù)
?

?

?

大多數(shù)應(yīng)用程序在用戶模式下執(zhí)行。當(dāng)處理器工作在用戶模式時,正在執(zhí)行的程序不能存取某些被保護(hù)的系統(tǒng)資源,也不能改變模式,除非例外(exception)發(fā)生。這允許適當(dāng)撰寫操作系統(tǒng)來控制系統(tǒng)資源的使用。

除用戶模式外的其它模式稱未特權(quán)模式。它們可以自由的存取系統(tǒng)資源和改變模式。其中的5 種稱為異常模式,即

n???????? FIQ(Fash Interrupt request);

n???????? IRQ(Interrupt ReQuest);

n???????? 管理(Supervisor);

n???????? 中止(Abort) ;

n???????? 未定義(Underfined) 。

當(dāng)特定的異常出現(xiàn)時,進(jìn)入相應(yīng)的模式。每種模式都有某些附加的寄存器,以避免異常出現(xiàn)時用戶模式的狀態(tài)不可靠。

剩下的模式是系統(tǒng)模式。僅ARM 架構(gòu)V4 以及以上的版本有該模式。不能由于任何異常而進(jìn)入該模式。它與用戶模式有完全相同的寄存器。然而它是特權(quán)模式,不受用戶模式的限制。它供需要存取系統(tǒng)資源的操作系統(tǒng)工作使用,單希望避免使用與例外模式有關(guān)的附加寄存器。避免使用附加寄存器保證了當(dāng)任何異常出現(xiàn)時,都不會使工作的狀態(tài)不可靠。

4.2.3. 實驗操作步驟
1.開發(fā)環(huán)境,打開實驗系統(tǒng)例程目錄下ARMMode_test/ARMMode.MCP 項目,并編譯鏈接項目。

3. 單步執(zhí)行程序并觀察和記錄CPSP 和SPSR 緩存器值的變化;并觀察在相應(yīng)模式下執(zhí)行程序后對應(yīng)緩存器值的變化。

4. 結(jié)合實驗內(nèi)容和相關(guān)數(shù)據(jù),觀察程序執(zhí)行,透過實驗加深理解和掌握

4.2.4? 試驗程序代碼
;設(shè)置本段程序的名稱(Block)及屬性

?AREA Block,CODE,READONLY

?

;程序入口標(biāo)志

?????? ENTRY

start

?

?????? B???? Reset_Handler

??????

Undefined_Handler

?????? B Undefined_Handler

?????? B SWI_Handler

??????

Prefetch_Handler

?????? B Prefetch_Handler

??????

Abort_Handler

?????? B Abort_Handler

?????? NOP ;空操作

??????

IRQ_Handler

?????? B IRQ_Handler

??????

FIQ_Handler

?????? B FIQ_Handler

??????

SWI_Handler

?????? mov pc, lr

;前面部分是處理程序,主要處理各種模式的入端口跳移

?

Reset_Handler

?

;into System mode

?????? MRS R0,CPSR????? ;復(fù)制CPSR 到R0

?????? BIC R0,R0,#0x1F ;清除R0 的后5 位

?????? ORR R0,R0,#0x1F?????? ;設(shè)定R0 的最后5 位為11111

?????? MSR?????? CPSR_c,R0??? ;把R0 裝載到CPSR,切換到系統(tǒng)模式

?????? MOV R0, #1???????? ;對系統(tǒng)模式下的R0 賦值,下面的R1~R15 一樣

?????? MOV R1, #2

?????? MOV R2, #3

?????? MOV R3, #4

?????? MOV R4, #5

?????? MOV R5, #6

?????? MOV R6, #7

?????? MOV R7, #8

?????? MOV R8, #9

?????? MOV R9, #10

?????? MOV R10, #11

?????? MOV R11, #12

?????? MOV R12, #13

?????? MOV R13, #14

?????? MOV R14, #15

;into FIQ mode

?????? MRS R0,CPSR

?????? BIC R0,R0,#0x1F

?????? ORR R0,R0,#0x11 ;設(shè)定R0 的最后5 位為10001

?????? MSR CPSR_c,R0 ;把R0 裝載到CPSR,切換到Fiq 模式

?????? MOV R8, #16 ;給Fiq 模式的特有緩存器R8 賦值, 下面的R9~R14 一樣

?????? MOV R9, #17

?????? MOV R10, #18?????

?????? MOV R11, #19

?????? MOV R12, #20

?????? MOV R13, #21

?????? MOV R14, #22

;into SVC mode

?????? MRS R0,CPSR

?????? BIC R0,R0,#0x1F

?????? ORR R0,R0,#0x13 ;設(shè)定R0 的最后5 位為10011

?????? MSR CPSR_c,R0?? ;把R0 裝載到CPSR,切換到Svc 模式

?????? MOV R13, #23????? ;給SVC 模式的特有緩存器R13 賦值, 下面的R14 一樣

?????? MOV R14, #24

;into Abort mode

?????? MRS R0,CPSR

?????? BIC R0,R0,#0x1F

?????? ORR R0,R0,#0x17 ;設(shè)定R0 的最后5 位為10111

?????? MSR CPSR_c,R0 ;把R0 裝載到CPSR,切換到Abort 模式

?????? MOV R13, #25 ;給Abort 模式的特有緩存器R13 賦值, 下面的R14 一樣

?????? MOV R14, #26

;into IRQ mode

?????? MRS R0,CPSR

?????? BIC R0,R0,#0x1F

?????? ORR R0,R0,#0x12 ;設(shè)定R0 的最后5 位為10010

?????? MSR CPSR_c,R0 ;把R0 裝載到CPSR,切換到IRQ 模式

?????? MOV R13, #27 ;給IRQ 模式的特有緩存器R13 賦值, 下面的R14一樣

?????? MOV R14, #28

;into UNDEF mode

?????? MRS R0,CPSR

?????? BIC R0,R0,#0x1F

?????? ORR R0,R0,#0x1b??????? ;設(shè)定R0 的最后5 位為11011

?????? MSR CPSR_c,R0???????????????? ;把R0 裝載到CPSR,切換到UNDEF 模式

?????? MOV R13, #29???????????? ;給UNDEF 模式的特有緩存器R13 賦值, 下面的R14 一樣

?????? MOV R14, #30

?????? B Reset_Handler ;跳移到最開始地方循環(huán)

?????? END

4.2.5. 實驗練習(xí)題
1. 參考例子,把其中系統(tǒng)模式程序更改為使用者模式程序,編譯除錯,觀察執(zhí)行結(jié)果,檢查是否正確,如果有有錯誤分析其原因。(提示:不能從使用者模式直接切換到其它模式,可以先使用SWI 指令切換到管理模式)。

?

?

?

?

?

?

?

?


? 山東大學(xué)嵌入式系統(tǒng)原理與接口技術(shù)課程試卷(A)?????????????????????? 2007——2008 學(xué)年???? 1? 學(xué)期

題號 一 二 三 四 五 六 七 八 九 十 總分
得分??????????????????????


?
?

得分 閱卷人
???


?
?
?
?

單項選擇題(每空2分,共10分)
?
1、對寄存器R1的內(nèi)容乘以4的正確指令是( )。
?? ①LSR R1,#2??????? ②LSL R1,#2??

?? ③MOV R1,R1, LSL #2????????? ④MOV R1,R1, LSR #2

2、下面指令執(zhí)行后,改變R1寄存器內(nèi)容的指令是(???? )。

?? ①TST R1,#2? ②ORR? R1,R1,R1?? ③CMP R1,#2??? ④EOR? R1,R1,R1

3、? MOV?? R1,#0x1000??

???? LDR?? R0,[R1],#4

執(zhí)行上述指令序列后,R1寄存器的值是(??? )。

①0x1000???? ②0x1004???? ③0x0FFC????? ④0x4

4、當(dāng)進(jìn)行數(shù)據(jù)寫操作時,可能Cache未命中,根據(jù)Cache執(zhí)行的操作不同,將Cache分為兩類(?????????? )

①數(shù)據(jù)Cache和指令Cache?? ②統(tǒng)一Cache和獨立Cache? ③寫通Cache和寫回Cache? ④讀操作分配Cache和寫操作分配Cache

5、一個異步傳輸過程:設(shè)每個字符對應(yīng)8個信息位、偶校驗、2個停止位,如果波特率為2400,那么每秒鐘能傳輸?shù)淖畲笞址麛?shù)為(???????????????? )個。

① 200,② 218,③ 240,④ 2400
?得分 閱卷人
???


?
?
?
?
二、填空(共18分)
1、嵌入式處理器可分為以下4類:(???????????????????????????????????????? )。

2、ARM處理器總共有(? )個寄存器,這些寄存器按其在用戶編程中的功能可劃分為:(????????? )和(??????? ),這些寄存器根據(jù)ARM處理器不同工作模式,可將全部寄存器分成( )組,在使用中有(?????????????????????????????????????? )特點。

3、ARM 4種存儲周期的基本類型分別為:(???????????????????????????????????? )。

4、S3C44B0X UART單元發(fā)送器能夠檢測的四種異步串行通信數(shù)據(jù)錯誤為(????????????????????????????????????????????????????????????????????????? )。


得分 閱卷人
???


?
?

簡答題:(每空6分,共30分)
1、從硬件系統(tǒng)來看,嵌入式系統(tǒng)由哪幾部分組成?畫出簡圖。

?

?

?

?

?

?

?

?

?


基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
基于ARM的嵌入式系統(tǒng)程序開發(fā)要點(一)
—— 嵌入式程序開發(fā)過程
ARM 系列微處理器作為全球16/32位RISC處理器市場的領(lǐng)先者,在許多領(lǐng)
域內(nèi)得到了成功的應(yīng)用.近年來,ARM在國內(nèi)的應(yīng)用也得到了飛速的發(fā)展,越
來越多的公司和工程師在基于ARM的平臺上面開發(fā)自己的產(chǎn)品.
與傳統(tǒng)的4/8位單片機相比,ARM的性能和處理能力當(dāng)然是遙遙領(lǐng)先的,但
與之相應(yīng),ARM的系統(tǒng)設(shè)計復(fù)雜度和難度,較之傳統(tǒng)的設(shè)計方法也大大提升了.
本文旨在通過討論系統(tǒng)程序設(shè)計中的幾個基本方面,來說明基于ARM的嵌入式
系統(tǒng)程序開發(fā)的一些特點,并提出和解決了一些常見的問題.
文章分成幾個相對獨立的章節(jié)刊載.第一部分討論基于ARM的嵌入式程序
開發(fā)和移植過程中的一些基本概念.
1.嵌入式程序開發(fā)過程
不同于通用計算機和工作站上的軟件開發(fā)工程,一個嵌入式程序的開發(fā)過程
具有很多特點和不確定性.其中最重要的一點是軟件跟硬件的緊密耦合特性.
(不帶操作系統(tǒng)支持) (帶操作系統(tǒng)支持)
圖-1:兩類不同的嵌入式系統(tǒng)結(jié)構(gòu)模型
這是兩類簡化的嵌入式系統(tǒng)層次結(jié)構(gòu)圖.由于嵌入式系統(tǒng)的靈活性和多樣
性,上面圖中各個層次之間缺乏統(tǒng)一的標(biāo)準(zhǔn),幾乎每一個獨立的系統(tǒng)都不一樣.
這樣就給上層的軟件設(shè)計人員帶來了極大地困難.第一,在軟件設(shè)計過程中過多
地考慮硬件,給開發(fā)和調(diào)試都帶來了很多不便;第二,如果所有的軟件工作都需
要在硬件平臺就緒之后進(jìn)行,自然就延長了整個的系統(tǒng)開發(fā)周期.這些都是應(yīng)該
從方法上加以改進(jìn)和避免的問題.
為了解決這個問題,工程和設(shè)計人員提出了許多對策.首先在應(yīng)用與驅(qū)動(或
API)這一層接口,可以設(shè)計成相對統(tǒng)一的一些接口函數(shù),這對于具體的某一個
開發(fā)平臺或在某個公司內(nèi)部,是完全做得到的.這樣一來,就大大提高了應(yīng)用層
應(yīng)用(Application)
驅(qū)動/板級支持包
(Driver/BSP)
硬件(Hardware)
應(yīng)用(Application)
硬件抽象層(HAL)
硬件(Hardware)
操作系統(tǒng)(OS)
標(biāo)準(zhǔn)接口函數(shù)(API)
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
軟件設(shè)計的標(biāo)準(zhǔn)化程度,方便了應(yīng)用程序在跨平臺之間的復(fù)用和移植.
對于驅(qū)動/硬件抽象這一層,因為直接驅(qū)動硬件,其標(biāo)準(zhǔn)化變得非常困難甚至
不太可能.但是為了簡化程序的調(diào)試和縮短開發(fā)周期,我們可以在特定的EDA
工具環(huán)境下面進(jìn)行開發(fā),通過后再進(jìn)行移植到硬件平臺的工作.這樣既可以保證
程序邏輯設(shè)計的正確性,同時使得軟件開發(fā)可平行甚至超前于硬件開發(fā)進(jìn)程.
我們把脫離于硬件的嵌入式軟件開發(fā)階段稱之為"PC軟件"的開發(fā),可以
用下面的圖來示意一個嵌入式系統(tǒng)程序的開發(fā)過程.
"PC軟件"開發(fā) 移植,測試 產(chǎn)品發(fā)布
圖-2:嵌入式系統(tǒng)產(chǎn)品的開發(fā)過程
在"PC軟件"開發(fā)階段,可以用軟件仿真,即指令集模擬的方法,來對用
戶程序進(jìn)行驗證.在ARM公司的開發(fā)工具中,ADS 內(nèi)嵌的ARMulator和
RealView 開發(fā)工具中的ISS,都提供了這項功能.在模擬環(huán)境下,用戶可以設(shè)
置ARM處理器的型號,時鐘頻率等,同時還可以配置存儲器訪問接口的時序參
數(shù).程序在模擬環(huán)境下運行,不但能夠進(jìn)行程序的運行流程和邏輯測試,還能夠
統(tǒng)計系統(tǒng)運行的時鐘周期數(shù),存儲器訪問周期數(shù),處理器運行時的流水線狀態(tài)(有
效周期,等待周期,連續(xù)和非連續(xù)訪問周期)等信息.這些寶貴的信息是在硬件
調(diào)試階段都無法取得的,對于程序的性能評估非常有價值.
為了更加完整和真實地模擬一個目標(biāo)系統(tǒng),ARMulator和ISS還提供了一個
開放的API編程環(huán)境.用戶可以用標(biāo)準(zhǔn)C來描述各種各樣的硬件模塊,連同工
具提供的內(nèi)核模塊一起,組成一個完整的"軟"硬件環(huán)境.在這個環(huán)境下面開發(fā)
的軟件,可以更大程度地接近最終的目標(biāo).
利用這種先進(jìn)的EDA工具環(huán)境,極大地方便了程序開發(fā)人員進(jìn)行嵌入式開
發(fā)的工作.當(dāng)完成一個"PC軟件"的開發(fā)之后,只要進(jìn)行正確的移植,一個真
正的嵌入式軟件就開發(fā)成功了.而移植過程是相對比較容易形成一套規(guī)范的流程
的,其中三個最重要的方面是:
考慮硬件對庫函數(shù)的支持
移植
移植
開發(fā)/實驗/
測試平臺
最終產(chǎn)品
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
符合目標(biāo)系統(tǒng)上的存儲器資源分布
應(yīng)用程序運行環(huán)境的初始化
2.開發(fā)工具環(huán)境里面的庫函數(shù)
如果用戶程序里調(diào)用了跟目標(biāo)相關(guān)的一些庫函數(shù),則在應(yīng)用前需要裁剪這些
函數(shù)以適合在目標(biāo)上允許的要求.主要需要考慮以下三類函數(shù):
訪問靜態(tài)數(shù)據(jù)的函數(shù)
訪問目標(biāo)存儲器的函數(shù)
使用semihosting(半主機)機制實現(xiàn)的函數(shù)
這里所指的C庫函數(shù),除了ISO C標(biāo)準(zhǔn)里面定義的函數(shù)以外,還包括由編
譯工具提供的另外一些擴展函數(shù)和編譯輔助函數(shù).
2.1 裁剪訪問靜態(tài)數(shù)據(jù)的函數(shù)
庫函數(shù)里面的靜態(tài)數(shù)據(jù),基本上都是在頭文件里面加以定義的.比如CTYPE
類庫函數(shù),其返回值都是通過預(yù)定義好的CTYPE屬性表來獲得的.比如,想要
改變isalpha() 函數(shù)的缺省判斷,則需要修改對應(yīng)CTYPE屬性表里對字符屬性的
定義.
2.2 裁減訪問目標(biāo)存儲器的函數(shù)
有一類動態(tài)內(nèi)存管理函數(shù),如malloc() 等,其本身是獨立于目標(biāo)系統(tǒng)而運行
的;但是它所使用的存儲器空間需要根據(jù)目標(biāo)來確定.所以malloc() 函數(shù)本身
并不需要裁剪或移植,但那些設(shè)置動態(tài)內(nèi)存區(qū)(地址和空間)的函數(shù)則是跟目標(biāo)
系統(tǒng)的存儲器分布直接相關(guān)的,需要進(jìn)行移植.例如堆棧的初始化函數(shù)
__user_initial_stackheap(),是用來設(shè)置堆(heap)和棧(stack)地址的函數(shù),顯
然針對每一個具體的目標(biāo)平臺,該函數(shù)都需要根據(jù)具體的目標(biāo)存儲器資源進(jìn)行正
確移植.
下面是對示例函數(shù)__user_initial_stackheap() 進(jìn)行移植的一個例子:
__value_in_regs struct __initial_stackheap __user_initial_stackheap(
unsigned R0, unsigned SP, unsigned R2, unsigned SL)
{
struct __initial_stackheap config;
config.heap_base = (unsigned int) 0x11110000;
// config.stack_base = SP; // optional
return config;
}
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
請注意上面的函數(shù)體并不完全遵循標(biāo)準(zhǔn)C的關(guān)鍵字和語法規(guī)范,使用了ARM
公司編譯器(ADS 或RealView Compilation tool) 里的C語言擴展特性.關(guān)于編譯
器特定的C語言擴展,請參考相關(guān)的編譯器說明,這里簡單介紹函數(shù)
__user_initial_stackheap() 的功能,它主要是返回堆和棧的基地址.上面的程序中
只對堆(heap) 的基地址進(jìn)行了設(shè)置(設(shè)成了0x11110000),也就是說用戶把
0x11110000開始的存儲器地址用作了動態(tài)內(nèi)存分配區(qū)(heap區(qū)).具體地址的確
定是要由用戶根據(jù)自己的目標(biāo)系統(tǒng)和應(yīng)用情況來確定的,至少要滿足以下條件:
0x11110000開始的地址空間有效且可寫(是RAM)
該存儲器空間不與其它功能區(qū)沖突(比如代碼區(qū),數(shù)據(jù)區(qū),stack區(qū)等)
因為__user_initial_stackheap() 函數(shù)的全部執(zhí)行效果就是返回一些數(shù)值,所
以只要符合接口的調(diào)用標(biāo)準(zhǔn),直接用匯編來實現(xiàn)看起來更加直觀一些:
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR r0,0x11110000
MOV pc,lr
如果不對這個函數(shù)進(jìn)行移植,編譯過程中將使用缺省的設(shè)置,這個設(shè)置適用
于ARM公司的Integrator系列平臺.
(注意:ARM的編譯/連接工具鏈也提供了繞過庫函數(shù)來設(shè)置運行時存儲器模型
的方法,請參閱ARM公司其他的相關(guān)文檔.)
2.3 裁剪使用semihosting(半主機)機制實現(xiàn)的函數(shù)
庫函數(shù)里有一大部分函數(shù)是涉及到輸入/輸出流設(shè)備的,比如文件操作函數(shù)需
要訪問磁盤I/O,打印函數(shù)需要訪問字符輸出設(shè)備等.在嵌入式調(diào)試環(huán)境下,所
有的標(biāo)準(zhǔn)C庫函數(shù)都是有效且有其缺省行為的,很多目標(biāo)系統(tǒng)硬件不能支持的
操作,都通過調(diào)試工具來完成了.比如printf() 函數(shù),缺省的輸出設(shè)備是調(diào)試器
里面的信息輸出窗口.
但是一個真實的系統(tǒng)是需要脫離調(diào)試工具而獨立運行的,所以在程序的移植
過程當(dāng)中,需先對這些庫函數(shù)的運行機制作一了解.
下圖說明了在ADS下面這類C庫函數(shù)的結(jié)構(gòu).
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
圖-3:C庫函數(shù)實現(xiàn)過程中的層次調(diào)用
如圖中例子所示,函數(shù)printf() 最終是調(diào)用了底層的輸入/輸出函數(shù)
_sys_write() 來實現(xiàn)輸出操作的,而_sys_write() 使用了調(diào)試工具的內(nèi)部機制來把
信息輸出到調(diào)試器.
顯然這樣的函數(shù)調(diào)用過程在一個真實的嵌入式系統(tǒng)里是無法實現(xiàn)的,因為獨
立運行的嵌入式系統(tǒng)將不會有調(diào)試器的參與.如果在最終系統(tǒng)中仍然要保留
printf() 函數(shù),而且在系統(tǒng)硬件中具備正確的輸出設(shè)備(如LCD等),則在移植
過程中,需要把printf() 調(diào)用的輸出設(shè)備進(jìn)行重新定向.
考察printf() 函數(shù)的完整調(diào)用過程:
圖-4:printf() 的調(diào)用過程
單純考慮printf() 的輸出重新定向,可以有三種途徑實現(xiàn):
改寫printf() 本身
改寫 fput()
改寫 _sys_write()
需要注意的是,越底層的函數(shù),被其他上層函數(shù)調(diào)用的可能性越大,改變了
一個底層函數(shù)的實現(xiàn),則所有調(diào)用該函數(shù)的上層函數(shù)的行為都被改變了.
以fputc() 的重新實現(xiàn)為例,下面是改變fputc() 輸出設(shè)備到系統(tǒng)串行通信端
口的實例:
int fputc(int ch, FILE *f)
ANSI C
Input/
output
Error
handling
Stack &
heap setup
Other
Semihosting Support
應(yīng)用程序調(diào)用的
函數(shù),如printf()
設(shè)備驅(qū)動程序級
使用semihosting
機制
如_sys_write()
由調(diào)試系統(tǒng)執(zhí)行
printf() fput() _sys_wite()輸出設(shè)備
其他函數(shù) 其他函數(shù)
C 庫函數(shù)
調(diào)試輔助環(huán)境
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
{ /* e.g. write a character to an UART */
char tempch = ch;
sendchar(&tempch); // UART driver
return ch;
}
代碼中的函數(shù)sendchar() 假定是系統(tǒng)的串口設(shè)備驅(qū)動函數(shù).只要新建函數(shù)
fput() 的接口符合標(biāo)準(zhǔn),經(jīng)過編譯連接后,該函數(shù)實現(xiàn)就覆蓋了原來缺省的函數(shù)
體,所有對該函數(shù)的調(diào)用,其行為都被新實現(xiàn)的函數(shù)所重新定向了.
具體哪些庫函數(shù)是跟目標(biāo)相關(guān)的,這些函數(shù)之間的相互調(diào)用關(guān)系等,請參考
具體的編譯器說明.
3.Semihosting (半主機) 機制
上面提到許多庫函數(shù)在調(diào)試環(huán)境下的實現(xiàn)都調(diào)用了一種叫semihosting的機
制.Semihosting具體來講是指一種讓代碼在ARM 目標(biāo)上運行,但使用運行了
ARM 調(diào)試器的主機上I/O 設(shè)備的方法;也就是讓ARM 目標(biāo)將輸入/ 輸出請求
從應(yīng)用程序代碼傳遞到運行調(diào)試器的主機的一種機制.通常這些輸入/輸出設(shè)備
包括鍵盤,屏幕和磁盤I/O.
半主機由一組已定義的SWI 操作來實現(xiàn).庫函數(shù)調(diào)用相應(yīng)的SWI(軟件中
斷),然后調(diào)試代理程序處理SWI 異常,并提供所需的與主機之間的通訊.
圖-5:Semihosting的實現(xiàn)過程
多數(shù)情況下,半主機SWI 是由庫函數(shù)內(nèi)的代碼調(diào)用的.但是應(yīng)用程序也可
以直接調(diào)用半主機SWI.半主機SWI 的接口函數(shù)是通用的.當(dāng)半主機操作在硬
件仿真器,指令集仿真器,RealMonitor或Angel下執(zhí)行時,不需要進(jìn)行移植處
理.
使用單個SWI 編號請求半主機操作.其它的SWI 編號可供應(yīng)用程序或操
printf()
printf("Hello world! ");
SWI
調(diào)試器
Hello world!
C 庫代碼
應(yīng)用程序代碼
與運行在主機上的調(diào)試器通信
主機屏幕上顯示的文本
目標(biāo)
主機
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
作系統(tǒng)使用.用于半主機的SWI號是:
在ARM 狀態(tài)下:0x123456
在Thumb 狀態(tài)下:0xAB
SWI 編號向調(diào)試代理程序指示該SWI 請求是半主機請求.要辨別具體的操
作類型,用寄存器r0 作為參數(shù)傳遞.r0 傳遞的可用半主機操作編號分配如下:
0x00-0x31:這些編號由ARM 公司使用,分別對應(yīng)32個具體的執(zhí)行函
數(shù).
0x32-0xFF:這些編號由ARM 公司保留,以備將來用作函數(shù)擴展.
0x100-0x1FF:這些編號保留給用戶應(yīng)用程序.但是,如果編寫自己的
SWI 操作,建議直接使用SWI指令和SWI編號,而不要使用半主機
SWI 編號加這些操作類型編號的方法.
0x200-0xFFFFFFFF:這些編號未定義.當(dāng)前未使用并且不推薦使用這
些編號.
半主機SWI使用的軟件中斷編號也可以由用戶自定義,但若是改變了缺省
的軟中斷編號,需要:
更改系統(tǒng)中所有代碼(包括庫代碼)的半主機SWI 調(diào)用
重新配置調(diào)試器對半主機請求的捕捉與相應(yīng)
這樣才能使用新的SWI 編號.
有關(guān)半主機SWI處理函數(shù)實現(xiàn)的更詳細(xì)信息,請參考ARM編譯器的相關(guān)
文檔.
4.應(yīng)用環(huán)境的初始化和根據(jù)目標(biāo)系統(tǒng)資源進(jìn)行的移植
在下一期中介紹應(yīng)用環(huán)境和目標(biāo)系統(tǒng)的初始化.
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
基于ARM的嵌入式系統(tǒng)程序開發(fā)要點(二)
—— 系統(tǒng)的初始化過程
基于ARM的芯片多數(shù)為復(fù)雜的片上系統(tǒng)集成(SoC),這種復(fù)雜的系統(tǒng)里多
數(shù)的硬件模塊都是可配置的,需要由軟件來設(shè)置其需要的工作狀態(tài).因此在用戶
的應(yīng)用程序啟動之前,需要有專門的一段啟動代碼來完成對系統(tǒng)的初始化.由于
這類代碼直接面對處理器內(nèi)核和硬件控制器進(jìn)行編程,一般都使用匯編語言.系
統(tǒng)啟動程序所執(zhí)行的操作跟具體的目標(biāo)系統(tǒng)和開發(fā)系統(tǒng)相關(guān),一般通用的內(nèi)容包
括:
中斷向量表
初始化存儲器系統(tǒng)
初始化堆棧
初始化有特殊要求的端口,設(shè)備
初始化應(yīng)用程序執(zhí)行環(huán)境
改變處理器模式
呼叫主應(yīng)用程序
1.中斷向量表
ARM要求中斷向量表必須放置在從0地址開始,連續(xù)8×4字節(jié)的空間內(nèi)
(ARM720T和ARM9/10及以后的ARM處理器也支持從0xFFFF0000開始的高
地址向量表,在本文的其他地方對此不再另加說明).各個中斷矢量在向量表中
的位置分配如下圖:
圖1:中斷向量表
每當(dāng)一個中斷發(fā)生以后,ARM處理器便強制把PC指針置為向量表中對應(yīng)中
Reset 復(fù)位中斷 0x00
Undef 未定義指令中斷 0x04
Software Interrupt 軟件中斷 0x08
Prefetch Abort 指令預(yù)取異常 0x0C
Data Abort 數(shù)據(jù)異常 0x10
(Reserved) 保留 0x14
IRQ 普通外部中斷 0x18
FIQ 外部快速中斷 0x1C
… …
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
斷類型的地址值.因為每個中斷只占據(jù)向量表中1個字的存儲器空間,只能放置
1條ARM指令,所以通常在向量表中放的是跳轉(zhuǎn)指令,使程序能從向量表里跳
轉(zhuǎn)到存儲器里的其他地方,再執(zhí)行中斷處理.
中斷向量表的程序?qū)崿F(xiàn)通常如下所示:
AREA Boot, CODE, READONLY
ENTRY
B Reset_Handler ; Reset_Handler is a label
B Undef_Handler
B SWI_Handler
B PreAbort_Handler
B DataAbort_Handler
B . ; for reserved interrupt, stop here
B IRQ_Handler
B FIQ_Handler
其中的關(guān)鍵字ENTRY是指定編譯器保留這段代碼,因為編譯器可能會認(rèn)為
這是一段冗余代碼而加以優(yōu)化.連接的時候要確保這段代碼被鏈接在0地址處,
并且作為整個程序的入口點(關(guān)鍵字ENTRY并非總是用來設(shè)置程序入口點,所
以通常需要在連接選項里顯式地指定程序入口點).
2.初始化存儲器系統(tǒng)
初始化存儲器系統(tǒng)的編程對象是系統(tǒng)的存儲器控制器.存儲器控制器并不是
ARM內(nèi)核的一部分,不同的系統(tǒng)其設(shè)計不盡相同,所以應(yīng)該針對具體的要求來
完成這部分的程序設(shè)計.一般來說,下面這兩個方面是比較通用的.
2.1.存儲器類型和時序配置
一個復(fù)雜的系統(tǒng)可能存在多種存儲器類型的接口,需要根據(jù)實際的系統(tǒng)設(shè)計
對此加以正確配置.對同一種存儲器類型來說,也因為訪問速度的差異,需要不
同的時序設(shè)置.
通常Flash 和SRAM同屬于靜態(tài)存儲器類型,可以合用同一個存儲器端口;
而DRAM 因為動態(tài)刷新和地址線復(fù)用等特性,通常配有專用的存儲器端口.
存儲器端口的接口時序優(yōu)化是非常重要的,影響到整個系統(tǒng)的性能.因為一
般系統(tǒng)運行的速度瓶頸都存在于存儲器訪問,所以存儲器訪問時序應(yīng)盡可能地
快;但同時又要考慮由此帶來的穩(wěn)定性問題.只有根據(jù)具體選定的芯片,進(jìn)行多
次的測試之后,才能確定最佳的時序配置.
2.2.存儲器地址分布(memory map)
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
有些系統(tǒng)具有非常靈活的存儲器地址分配特性,進(jìn)行存儲器初始化設(shè)計的時
候一定要根據(jù)應(yīng)用程序的具體要求來完成地址分配.
一種典型的情況是啟動ROM的地址重映射(remap).如前面第1節(jié)所述,
當(dāng)一個系統(tǒng)上電后程序?qū)⒆詣訌?地址處開始執(zhí)行,因此在系統(tǒng)的初始狀態(tài),必
須保證在0地址處存在正確的代碼,即要求0地址開始處的存儲器是非易性的
ROM或Flash等.但是因為ROM或Flash的訪問速度相對較慢,每次中斷發(fā)生
后都要從讀取ROM或Flash上面的向量表開始,影響了中斷響應(yīng)速度.因此有
的系統(tǒng)便提供一種靈活的地址重映射方法,可以把0地址重新指向到RAM中去.
在這種地址映射的變化過程當(dāng)中,程序員需要仔細(xì)考慮的是程序的執(zhí)行流程不能
被這種變化所打斷.比如下面這種情況:
圖2:啟動ROM的地址重映射對程序執(zhí)行流程的影響
系統(tǒng)上電后從Flash內(nèi)的0地址開始執(zhí)行,啟動代碼位于地址0x100開始的
空間,當(dāng)執(zhí)行到地址0x200時,完成了一次地址的重映射,把原來0開始的地址
空間由Flash轉(zhuǎn)給了RAM.接下去執(zhí)行的指令(這里為了簡化起見,忽略流水
線指令預(yù)取的模型)將來自從0x204開始的RAM空間.如果預(yù)先沒有對RAM
內(nèi)容進(jìn)行正確的設(shè)置,則里面的數(shù)據(jù)都是隨機的,這樣處理器在執(zhí)行完0x200
地址處的指令之后,再往下取指執(zhí)行就會出錯.解決的方法就是要使RAM在使
用之前準(zhǔn)備好正確的內(nèi)容,包括開頭的向量表部分.
有的系統(tǒng)不具備存儲器地址重映射的功能,所有的空間地址就相對簡單一
些,不需要考慮這方面的問題.
3.初始化堆棧
因為ARM處理器有7種執(zhí)行狀態(tài),每一種狀態(tài)的堆棧指針寄存器(SP)都
Flash
0x0100
(Reset_Handler)
B Reset_Handler
… …
.
.
.
(boot code)
.
.
(remap)
0x0000
0x0200
RAM
0x0200
remap 0x0204
Vector Table
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
是獨立的(System和User模式使用相同的SP寄存器).因此對程序中需要用到
的每一種模式都要給SP寄存器定義一個堆棧地址.方法是改變狀態(tài)寄存器CPSR
內(nèi)的狀態(tài)位,使處理器切換到不同的狀態(tài),然后給SP賦值.注意不要切換到User
模式進(jìn)行User模式的堆棧設(shè)置,因為進(jìn)入User模式后就不能再操作CPSR回到
別的模式了.可能會對接下去的程序執(zhí)行造成影響.
一般堆棧的大小要根據(jù)需要而定,但是要盡可能給堆棧分配快速和高帶寬的
存儲器.堆棧性能的提高對系統(tǒng)整體性能的影響是非常明顯的.
這是一段堆棧初始化的代碼示例,其中只定義了三種模式的SP指針:
MRS R0, CPSR ; CPSR -> R0
BIC R0, R0, #MODEMASK ; 安全起見,屏蔽模式位以外的其它位
ORR R1, R0, #IRQMODE ; 把設(shè)置模式位設(shè)置成需要的模式
MSR CPSR_cxsf, R1 ; 轉(zhuǎn)到IRQ模式
LDR SP, =UndefStack ; 設(shè)置 SP_irq
ORR R1,R0,#FIQMODE
MSR CPSR_cxsf, R1 ; FIQMode
LDR SP, =FIQStack
ORR R1, R0, #SVCMODE
MSR CPSR_cxsf, R1 ; SVCMode
LDR SP, =SVCStack
注意上面的程序中使用到的3個SP寄存器是不同的物理寄存器:SP_irq,
SP_fiq和SP_svc.引用的幾個標(biāo)號假設(shè)已經(jīng)正確定義.
4.初始化有特殊要求的端口,設(shè)備
這要由具體的系統(tǒng)和用戶需求而定.一般的外設(shè)初始化可以在系統(tǒng)初始化之
后進(jìn)行.
比較典型的應(yīng)用是驅(qū)動一些簡單的輸出設(shè)備,如LED等,來指示系統(tǒng)啟動
的進(jìn)程和狀態(tài).
5.初始化應(yīng)用程序執(zhí)行環(huán)境
一個簡單的可執(zhí)行程序的映像結(jié)構(gòu)通常如下:
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
圖3:程序映像的結(jié)構(gòu)
映像一開始總是存儲在ROM/Flash里面的,其RO部分既可以在ROM/Flash
里面執(zhí)行,也可以轉(zhuǎn)移到速度更快的RAM中去;而RW和ZI這兩部分必須是
需要轉(zhuǎn)移到可寫的RAM里去的.所謂應(yīng)用程序執(zhí)行環(huán)境的初始化,就是完成必
要的從ROM到RAM的數(shù)據(jù)傳輸和內(nèi)容清零.
不同的工具鏈會提供一些不同的機制和方法幫助用戶完成這一步操作,主要
是跟鏈接器(Linker)相關(guān).下面是在ARM開發(fā)工具環(huán)境(ADS或RVCT)下,
一種常用存儲器模型的直接實現(xiàn):
LDR r0, =|Image

RO Limit ; Get pointer to ROM data
LDR r1, =|Image RW Base| ; RAM copy address
LDR r3, =|Image ZI Base| ; Zero init base => top of initialised data
CMP r0, r1 ; Check that they are different
BEQ %F1
0
CMP r1, r3 ; Copy init data
LDRCC r2, [r0], #4 ; ([r0] -> r2) and (r0+4)
STRCC r2, [r1], #4 ; (r2 -> [r1]) and (r1+4)
BCC %B0
1
LDR r1, =|Image ZI Limit| ; Top of zero init segment
MOV r2, #0
2
CMP r3, r1
STRCC r2, [r3], #4 ; (0 -> [r3]) and (r3+4)
BCC %B2
程序?qū)崿F(xiàn)了RW數(shù)據(jù)的拷貝和ZI區(qū)域的清零功能.其中引用到的4個符號
是由連接器(linker)定義輸出的:
|Image RO Limit|:表示RO區(qū)末地址后面的地址,即RW數(shù)據(jù)源的起始地址.
|Image RW Base|:RW區(qū)在RAM里的執(zhí)行區(qū)起始地址,也就是編譯選項
RW_Base指定的地址;程序里是RW數(shù)據(jù)拷貝的目標(biāo)地址.
ZI (Zero initialized R/W Data)
RW (R/W Data)
RO (Code + RO Data)
編譯結(jié)果
定義時帶初始值的全局變量
只定義了變量名的全局變量
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
|Image ZI Base|:ZI區(qū)在RAM里面的起始地址.
|Image ZI Limit|:ZI區(qū)在RAM里面的結(jié)束地址后面的一個地址.
程序先把ROM里 |Image RO Limit| 開始的RW初始數(shù)據(jù)拷貝到RAM里
|Image RW Base| 開始的地址,當(dāng)RAM這邊的目標(biāo)地址到達(dá)
|Image ZI Base| 后就表示RW區(qū)的結(jié)束和ZI區(qū)的開始,接下去就對這片ZI
區(qū)進(jìn)行清零操作,直到遇到結(jié)束地址 |Image ZI Limit|.
6.改變處理器模式
ARM處理器(V4架構(gòu)以后的版本)一共有7種執(zhí)行模式:
User: 用戶模式
FIQ: 快速中斷響應(yīng)模式
IRQ: 一般中斷響應(yīng)模式
Supervisor:超級模式
Abort: 出錯處理模式
Undef: 未定義模式
System: 系統(tǒng)模式
除用戶模式以外,其他6種模式都是特權(quán)模式.因為在初始化過程中許多操
作需要在特權(quán)模式下才能進(jìn)行(比如CPSR的修改),所以要特別注意不能過早
地進(jìn)入用戶模式.一般地,在初始化過程中會經(jīng)歷以下一些模式變化:
圖4:處理器模式變換過程
在最后階段才把模式轉(zhuǎn)換到最終應(yīng)用程序運行所需的模式,一般是用戶模
式.
內(nèi)核級的中斷使能(CPSR的I,F位狀態(tài))也可以考慮在這一步進(jìn)行.如果
系統(tǒng)中另外存在一個專門的中斷控制器(多數(shù)情況下是這樣的),這么做總是安
全的,否則就需要考慮過早地打開中斷可能帶來的問題,比如在系統(tǒng)初始化完成
之前就觸發(fā)了有效中斷,導(dǎo)致系統(tǒng)的死機.
7.呼叫主應(yīng)用程序
當(dāng)所有的系統(tǒng)初始化工作完成之后,就需要把程序流程轉(zhuǎn)入主應(yīng)用程序.最
簡單的一種情況是:
復(fù)位后的缺省模式 注意不要進(jìn)入用戶模式 用戶選擇
(堆棧初始化階段)
超級模式
(Supervisor)
多種特權(quán)模式
變化
設(shè)置成用戶程
序運行模式
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
IMPORT main ; get the label main if main() is defined in other files
B man ; jump to main()
直接從啟動代碼跳入應(yīng)用程序主函數(shù)入口,主函數(shù)名字可由用戶自己定義.
在ARM ADS環(huán)境中,還另外提供了一套系統(tǒng)級的呼叫機制.
IMPORT __main
B __main
__main()
圖5:在應(yīng)用程序主函數(shù)之前插入__main
__main() 是編譯系統(tǒng)提供的一個函數(shù),負(fù)責(zé)完成庫函數(shù)的初始化和第5節(jié)中
所描述的功能,最后自動跳向main() 函數(shù).這種情況下用戶程序的主函數(shù)名字
必須得是main.
用戶可以根據(jù)需要選擇是否使用__main().如果想讓系統(tǒng)自動完成系統(tǒng)調(diào)用
(如庫函數(shù))的初始化過程,可以直接使用__main();如果所有的初始化步驟都
是由用戶自己顯式地完成,則可以跳過__main().
當(dāng)然,使用__main() 的時候,可能會涉及到一些庫函數(shù)的移植和重定向問
題.在__main() 里面的程序執(zhí)行流程如下圖所示:
圖6:有系統(tǒng)調(diào)用參與的程序執(zhí)行流程
關(guān)于在__main() 里面調(diào)用到的庫函數(shù)說明,可以參閱相關(guān)的編譯器文檔,
庫函數(shù)移植和重定向的方法,可以參考上一期文章里面的相關(guān)章節(jié).
Image Entry Point
__main
·copy code and data
·zero initialize
__rt_entry
·initialize library functions
·call top-level constructors
(C++)
·Exit from application
·
Reset handler
·user boot code
User application
·main
__User_initial_stackheap
·set up stack & heap
啟動代碼 應(yīng)用程序初始化用戶應(yīng)用程序main()
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
基于ARM的嵌入式系統(tǒng)程序開發(fā)要點(三)
—— 如何滿足嵌入式系統(tǒng)的靈活需求
因為嵌入式應(yīng)用領(lǐng)域的多樣性,每一個系統(tǒng)都具有各自的特點.在進(jìn)行系統(tǒng)
程序設(shè)計的時候,一定要進(jìn)行具體分析,充分利用這些特點,揚長避短.
結(jié)合ARM架構(gòu)本身的一些特點,在這里討論幾個常見的要點.
1.ARM還是Thumb
在討論ARM還是Thumb之前,先說明ARM內(nèi)核型號和ARM結(jié)構(gòu)體系之
間的區(qū)別和聯(lián)系.
圖-1 ARM結(jié)構(gòu)體系和處理器家族的演變發(fā)展
如圖-1所示,ARM的結(jié)構(gòu)體系主要從版本4開始,發(fā)展到了現(xiàn)在的版本6,
結(jié)構(gòu)體系的變化,對程序員而言最直接的影響就是指令集的變化.結(jié)構(gòu)體系的演
變意味著指令集的不斷擴展,值得慶幸的是ARM結(jié)構(gòu)體系的發(fā)展一直保持了向
上兼容,不會造成老版本程序在新結(jié)構(gòu)體系上的不兼容.
在圖中的橫坐標(biāo)上,顯示了每一個體系結(jié)構(gòu)上都含有眾多的處理器型號,這
是在同一體系結(jié)構(gòu)下根據(jù)硬件配置和存儲器系統(tǒng)的不同而作的進(jìn)一步細(xì)分.需要
注意的是通常我們用來區(qū)分ARM處理器家族的ARM7,ARM9或ARM10,可
能跨越不同的體系結(jié)構(gòu).
在ARM的體系結(jié)構(gòu)版本4與5中,還可以再細(xì)分出幾個小的擴展版本:V4T,
V5TE和V5TEJ,其區(qū)別如圖-2中所示,這些后綴名也反映在各自擁有的處理器
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
型號上面,可以進(jìn)行直觀的分辨.V6結(jié)構(gòu)體系因為包含了以前版本的所有特性,
所以不需要再進(jìn)行分類.
圖-2 結(jié)構(gòu)體系特征
上面介紹了整個ARM處理器家族的分布,主要是說明在一個特定的平臺上
編寫程序的時候,一定要先弄清楚目標(biāo)的特性和一些細(xì)微的差別,特別是需要具
體優(yōu)化特征的時候.
從ARM體系結(jié)構(gòu)V4T以后,最大的變化是增加了一套16位的指令集——
Thumb.到底在一個具體應(yīng)用中要否采用Thumb呢 首先我們來分析一下ARM
和Thumb各自的特點和優(yōu)勢.先看下面一張性能分析圖:
圖-3 ARM和Thumb指令集的比較
圖中的縱坐標(biāo)是測試向量Dhrystone在20MHz頻率下運行1秒鐘的結(jié)果,其
值越大表明性能越好;橫坐標(biāo)是系統(tǒng)存儲器系統(tǒng)的數(shù)據(jù)總線寬度.結(jié)果表明:
(a) 當(dāng)系統(tǒng)具有32位的數(shù)據(jù)總線寬度時,ARM比Thumb有更好的性能表現(xiàn).
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
(b) 當(dāng)系統(tǒng)的數(shù)據(jù)總線寬度小于32位時,Thumb比ARM的性能更好.
由此可見,并不是32位的ARM指令集性能一定強于16位的Thumb指令集,
要具體情況具體分析.考察個中的原因,其實不難發(fā)現(xiàn),因為當(dāng)在一個16位存
儲器系統(tǒng)里面取1條32位指令的時候,需要耗費2個存儲器訪問周期;比之32
位的系統(tǒng),其速度正好大概下降一半左右.而16位指令在32位存儲器系統(tǒng)或
16位存儲器系統(tǒng)里的表現(xiàn)基本相同.正是存儲器造成的系統(tǒng)瓶頸導(dǎo)致了這個有
趣的差別.
除了在窄帶寬系統(tǒng)里面的性能優(yōu)勢外,Thumb指令的另外一個好處是代碼尺
寸.同樣一段C代碼,用Thumb指令編譯的結(jié)果,其長度大約只占ARM編譯
結(jié)果的65%左右,可以明顯地節(jié)省存儲器空間.在大多數(shù)情況下,緊湊的代碼和
窄帶寬的存儲器系統(tǒng),還會帶來功耗上的優(yōu)勢.
當(dāng)然,如果在32位的系統(tǒng)上面,并且對系統(tǒng)性能要求很高的情況下,ARM
是一個更好的選擇.畢竟在這種情況下,只有32位的指令集才能完全發(fā)揮32
位處理器的優(yōu)勢來.
因此,選擇ARM還是Thumb,需要從存儲器開銷和性能要求兩方面加以權(quán)
衡考慮.
2.堆棧的分配
在圖-3中,橫坐標(biāo)上還有一種情況,就是16位的存儲器寬度,但是堆棧空
間是32位的.這種情況下無論ARM還是Thumb,其性能表現(xiàn)都比單純的16位
存儲器系統(tǒng)情況下要好.這是因為ARM和Thumb其指令集雖然分32位和16
位,但是堆棧全部是采用32位的.因此在16位堆棧和32位堆棧的不同環(huán)境下,
其性能當(dāng)然都會相差很多.這種差別還跟具體的應(yīng)用程序密切相關(guān),如果一個程
序堆棧的使用頻率相當(dāng)高,則這種性能差異很大;反之則要小一些.
在基于ARM的系統(tǒng)中,堆棧不僅僅被用來進(jìn)行諸如函數(shù)調(diào)用,中斷響應(yīng)等
時候的現(xiàn)場保護(hù),還是程序局部變量和函數(shù)參數(shù)傳遞(如果大于4個)的存儲空
間.所以出于系統(tǒng)整體性能考慮,要給堆棧分配相對訪問速度最快,數(shù)據(jù)寬度最
大的存儲器空間.
一個嵌入式系統(tǒng)通常存在多種多樣的存儲器類型.設(shè)計的時候一定要先清楚
每一種存儲器的訪問速度,地址分配和數(shù)據(jù)線寬度.然后根據(jù)不同程序和目標(biāo)模
塊對存儲器的不同要求進(jìn)行合理分配,以期達(dá)到最佳配置狀態(tài).
3.ROM還是RAM在0地址處
顯然當(dāng)系統(tǒng)剛啟動的時候,0地址處肯定是某種類型的ROM,里面存儲了系
統(tǒng)的啟動代碼.但是很多靈活的系統(tǒng)設(shè)計中,0地址處的存儲器類型是可映射的.
也就是說,可以通過軟件的方法,把別的存儲器(主要是快速的RAM)分配以
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
0起始的地址.
這種做法的最主要目的之一是提高系統(tǒng)對中斷的反應(yīng)速度.因為每一個中斷
發(fā)生的時候,ARM都需要從0地址處的中斷向量表開始其中斷響應(yīng)流程,顯然
把中斷向量表放在RAM里,比放在ROM里有更快的訪問速度.因此,如果系
統(tǒng)提供了這一類的地址重映射功能,軟件設(shè)計者一定要加以利用.
下面是一個典型的經(jīng)過0地址重映射之后的存儲空間分布圖,注意盡可能把
速度要求最高的部分放置在系統(tǒng)里面訪問速度最快,帶寬最寬的RAM里面.
圖-4 系統(tǒng)存儲器分布的實例
4.存儲器地址重映射(memory remap)
存儲器地址重映射是當(dāng)前很多先進(jìn)控制器所具有的功能.在上一節(jié)中已經(jīng)提
到了0地址處存儲器重映射的例子,簡而言之,地址重映射就是可以通過軟件配
置來改變一塊存儲器物理地址的一種機制或方法.
當(dāng)一段程序?qū)\行自己的存儲器進(jìn)行重映射的時候,需要特別注意保證程序
執(zhí)行流程在重映射前后的承接關(guān)系.下面是一種典型的存儲器地址重映射情況:
Peripherals
RO
Reset Handler
Heap
RW/ZI
Stack
Exception Handlers
Vector Table
Fast32-bit RAM
16-bit RAM
Flash
0x0000 0000
0x0000 4000
0x0001 0000
0x0001 8000
0x2400 0000
0x2800 0000
0x4000 0000
可以在ROM 里運行的代碼
外設(shè)寄存器
變量區(qū)和動態(tài)內(nèi)存分配區(qū)
需要快速響應(yīng)的代碼和數(shù)據(jù)
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
圖-5 存儲器重映射舉例1
系統(tǒng)上電后的缺省狀態(tài)是0地址上放有ROM,這塊ROM有兩個地址:從0
起始和從0x10000起始,里面存儲了初始化代碼.當(dāng)進(jìn)行地址remap以后,從0
起始的地址被定向到了RAM上,ROM則只保留有唯一的從0x10000起始的地
址了.
如果存儲在ROM 里的Reset_Handler一直在0 - 0x4000的地址上運行,則
當(dāng)執(zhí)行完remap以后,下面的指令將從RAM里預(yù)取,必然會導(dǎo)致程序執(zhí)行流程
的中斷.根據(jù)系統(tǒng)特點,可以用下面的辦法來解決這個問題:
(1) 上電后系統(tǒng)從0地址開始自動執(zhí)行,設(shè)計跳轉(zhuǎn)指令在remap發(fā)生前使PC
指針指向0x10000開始的ROM地址中去,因為不同地址指向的是同一塊
ROM,所以程序能夠順利執(zhí)行.
(2) 這時候0 - 0x4000的地址空間空閑,不被程序引用,執(zhí)行remap后把RAM
引進(jìn).因為程序一直在0x10000起始的ROM空間里運行,remap對運行
流程沒有任何影響.
(3) 通過在ROM里運行的程序,對RAM進(jìn)行相應(yīng)的代碼和數(shù)據(jù)拷貝,完成
應(yīng)用程序運行的初始化.
下面是一段實現(xiàn)上述步驟的例程:
-------------------------------------------------------------------------------------------------------
ENTRY
;啟動時,從0開始,設(shè)法跳轉(zhuǎn)到"真"的ROM地址(0x10000開始的空間里)
LDR pc, =start
;insert vector table here

Start ;Begin of Reset_Handler
; 進(jìn)行remap設(shè)置
remap
0x10000
0x4000
=
0x4000
0x0000
Reset Handler
Vectors
0x4000
0x0000
RAMROM
0x10000
0x10400
ROM ROM
0x10400
Vectors
Reset Handler
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
LDR r1, =Ctrl_reg ;假定控制remap的寄存器
LDR r0, [r1]
ORR r0, r0, #Remap_bit ;假定對控制寄存器進(jìn)行remap設(shè)置
STR r0, [r1]
;接下去可以進(jìn)行從ROM到RAM的代碼和數(shù)據(jù)拷貝
-------------------------------------------------------------------------------------------------------
除此之外,還有另外一種常見的remap方式,如下圖:
圖-6 存儲器重映射舉例2
原來RAM和ROM各有自己的地址,進(jìn)行重映射以后RAM和ROM的地址
都發(fā)生了變化,這種情況下,可以采用以下的方案:
(1) 上電后,從0地址的ROM開始往下執(zhí)行.
(2) 根據(jù)映射前的地址,對RAM進(jìn)行必要的代碼和數(shù)據(jù)拷貝.
(3) 拷貝完成后,進(jìn)行remap操作.
(4) 因為RAM在remap前準(zhǔn)備好了內(nèi)容,使得PC指針能繼續(xù)在RAM里取
到正確的指令.
不同的系統(tǒng)可能會有多種靈活的remap方案,根據(jù)上面提到的兩個例子,可
以總結(jié)出最根本的考慮是:要使程序指針在remap以后能繼續(xù)往下得到正確的指
令.
5. 根據(jù)目標(biāo)存儲器系統(tǒng)分散加載映像(scatterloading)
Scatterloading文件是ARM的工具鏈里面的一個特性,作為程序編譯過程中
給連接器使用的一個參數(shù),用來指定最終生成的目標(biāo)映像文件運行時的分布狀
態(tài).如果用戶程序映像只是如圖7所示的最簡狀態(tài),所有的可執(zhí)行代碼都集合放
置在一起,那么可以不使用Scatterloading文件,直接用連接器的命令行選項就
remap
0x20000
0x4000
=
0x4000
0x0000
Reset Handler
Vectors
0x4000
0x0000
RAMROM
0x10000
0x10400
RAM ROM
0x20400
Vectors
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
能夠完成設(shè)置:
RO = 0x00000:表示映像的第一條指令開始地址;
RW = 0x10000:表示變量區(qū)的起始地址,變量區(qū)一定要位于RAM區(qū).
圖-7 簡單的映像分布舉例
但是一個復(fù)雜的系統(tǒng)可能會把映像分割成幾個部分.如圖8,系統(tǒng)中存在多
種類型的存儲器,不能的代碼部分根據(jù)執(zhí)行性能優(yōu)化的考慮分布與不同的地方.
圖-8 復(fù)雜的映像分布舉例
這時候不能通過簡單的RO,RW參數(shù)來完成實現(xiàn)上述配置,就要用到
scatterloading文件了.在scatterloading文件里,可以給編譯出來的各個目標(biāo)模塊
RO
RW
ZI
Stack
Heap
RAM
Flash 代碼區(qū)
變量區(qū)
0x00000
0x10000
Exception Handler
RO
Reset Handler
Heap
RW & ZI
Stack
Vector table
0x0000
0x4000
0x10000
0x18000
0x20000
0x28000
32-bit fast RAM
16-bit RAM
Flash
性能要求最苛刻的部分
變量區(qū)和動態(tài)內(nèi)存分配區(qū)
普通程序區(qū)
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
指定運行地址,下面的例子是針對圖8的.
FLASH 0x20000 0x8000
{
FLASH 0x20000 0x8000
{
init.o (Init, +First)
* (+RO)
}
32bitRAM 0x0000
{
vectors.o (Vect, +First)
handlers.o (+RO)
}
STACK 0x1000 UNINIT
{
stackheap.o (stack)
}
:
:
16bitRAM 0x10000
{
* (+RW,+ZI)
}
HEAP 0x15000 UNINIT
{
stackheap.o (heap)
}
}
關(guān)于scatterloading文件的詳細(xì)語法,請參閱ARM公司的相關(guān)手冊.
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
基于ARM的嵌入式系統(tǒng)程序開發(fā)要點(四)
—— 異常處理機制的設(shè)計
異常或中斷是用戶程序中最基本的一種執(zhí)行流程或形態(tài),這部分對ARM架
構(gòu)下異常處理程序的編寫作一個全面的介紹.
ARM一共有7種類型的異常,按優(yōu)先級從高到低排列如下:
Reset
Data Abort
FIQ
IRQ
Prefetch Abort
SWI
Undefined instruction
請注意在ARM的文檔中,使用術(shù)語exception 來描述異常.Exception主要
是從處理器被動接受異常的角度出發(fā)描述,而interrupt帶有向處理器主動申請的
色彩.在本文中,對"異常"和"中斷"不作嚴(yán)格區(qū)分,都是指請求處理器打斷
正常的程序執(zhí)行流程,進(jìn)入特定程序循環(huán)的一種機制.
1.異常響應(yīng)流程
如以前介紹異常向量表時所提到過的,每一個異常發(fā)生時,總是從異常向量
表開始起跳的,最簡單的一種情況是:
圖-1 異常向量表
B
B
(Reserved)
B B
B
B
B
B
0x1C
0x18
0x14
0x10
0x0C
0x08
0x04
0x00
FIQ_Handler()
IRQ_Handler()
DataAbt_Handler()
PreAbt_Handler()
SWI_Handler()
Undef_Handler()
Reset_Handler()
中斷處理函數(shù)
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
向量表里面的每一條指令直接跳向?qū)?yīng)的異常處理函數(shù).其中FIQ_Handler()
可以直接從地址0x1C處開始,省下一條跳轉(zhuǎn)指令.
但是當(dāng)執(zhí)行跳轉(zhuǎn)的時候有2個問題需要討論:跳轉(zhuǎn)范圍和異常分支.
1.1 跳轉(zhuǎn)范圍
我們知道ARM的跳轉(zhuǎn)指令(B)是有范圍限制的(±32MB),但很多情況
下不能保證所有的異常處理函數(shù)都定位在向量表的32MB范圍內(nèi),需要大于
32MB的長跳轉(zhuǎn),而且因為向量表空間的限制只能由一條指令完成.這可以通過
下面二種方法實現(xiàn).
(a) MOV PC, #imme_value
把目標(biāo)地址直接賦給PC寄存器.
但是這條指令受格式限制并不能處理任意立即數(shù),只有當(dāng)這個立即數(shù)能夠
表示為一個8-bit數(shù)值通過循環(huán)右移偶數(shù)位而得到,才是合法的.例如:
MOV PC, #0x30000000 是合法的,因為0x300000000可以通過0x03循
環(huán)右移4位而得到.
而 MOV PC, #30003000 就是非法指令.
(b) LDR PC, [PC+offset]
把目標(biāo)地址先存儲在某一個合適的地址空間,然后把這個存儲器單元上的32
位數(shù)據(jù)傳送給PC來實現(xiàn)跳轉(zhuǎn).
這種方法對目標(biāo)地址值沒有要求,可以是任意有效地址.但是存儲目標(biāo)地址
的存儲器單元必須在當(dāng)前指令的±4KB空間范圍內(nèi).
注意在計算指令中引用的offset數(shù)值的時候,要考慮處理器流水線中指令預(yù)
取對PC值的影響,以圖-2的情況為例:
offset = address location - vector address - pipeline effect
= 0xFFC - 0x4 - 0x8
= 0xFF0
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
圖-2 利Literal pool實現(xiàn)跳轉(zhuǎn)
1.2 異常分支
ARM內(nèi)核只有二個外部中斷輸入信號nFIQ和nIRQ,但對于一個系統(tǒng)來說,
中斷源可能多達(dá)幾十個.為此,在系統(tǒng)集成的時候,一般都會有一個異常控制器
來處理異常信號.
圖-3 中斷系統(tǒng)
這時候,用戶程序可能存在多個IRQ/FIQ的中斷處理函數(shù),為了從向量表
開始的跳轉(zhuǎn)最終能找到正確的處理函數(shù)入口,需要設(shè)計一套處理機制和方法.
圖-4 中斷分支
LDR PC, [PC, 0xFF0]
0x30003000
Undef_Handler()
0x00
0x04
0xFFC
32MB
0x30003000
n
1
2 多
中斷源
中斷
控制器
ARM
內(nèi)核
nIRQ
nFIQ
外設(shè)通信
配置/獲取信息
IRQ 0x14
IRQ_Handler_1()
IRQ_Handler_2()
...
...
IRQ_Handler_n()

基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
(a) 硬件處理
有的系統(tǒng)在ARM的異常向量表之外,又增加了一張由中斷控制器控制的特
殊向量表.當(dāng)由外設(shè)觸發(fā)一個中斷以后,PC能夠自動跳到這張?zhí)厥庀蛄勘碇腥?
特殊向量表中的每個向量空間對應(yīng)一個具體的中斷源.
舉例來說,下面的系統(tǒng)一共有20個外設(shè)中斷源,特殊向量表被直接放置在
普通向量表后面.
圖-5 額外的硬件異常向量表
當(dāng)某個外部中斷觸發(fā)之后,首先觸發(fā)ARM的內(nèi)核異常,中斷控制器檢測到
ARM的這種狀態(tài)變化,再通過識別具體的中斷源,使PC自動跳轉(zhuǎn)到特殊向量
表中的對應(yīng)地址,從而開始一次異常響應(yīng).需要檢查具體的芯片說明,是否支持
這類特性.
(b) 軟件處理
多數(shù)情況下是用軟件來處理異常分支.因為軟件可以通過讀取中斷控制器來
獲得中斷源的詳細(xì)信息.
圖-6 軟件控制中斷分支
Int_20
.
.
.
Int_2
Int_1
FIQ
IRQ
.
.
Reset
0x70
0x6C
.
.
.
0x24
0x20
0x1C
0x18
.
.
0x00
Int_20_Handler()



Int_2_Handler()
Int_1_Handler()
(獲取狀態(tài)信息)
IRQ
… …

中斷控制器
IRQ_Handler:
Switch(int_source)
{
case 1:
case 2:

}
Int_1_Handler()
Int_2_Handler()
… …
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
因為軟件設(shè)計的靈活性,用戶可以設(shè)計出比上圖更好的流程控制方法來.下
面是一個例子:
圖-7 靈活的軟件分支設(shè)計
Int_vector_table是用戶自己開辟的一塊存儲器空間,里面按次序存放異常處
理函數(shù)的地址.IRQ_Handler()從中斷控制器獲取中斷源信息,然后再從
Int_verctor_table中的對應(yīng)地址單元得到異常處理函數(shù)的入口地址,完成一次異
常響應(yīng)的跳轉(zhuǎn).這種方法的好處是用戶程序在運行過程中,能夠很方便地動態(tài)改
變異常服務(wù)內(nèi)容.
2.異常處理函數(shù)的設(shè)計
2.1 異常發(fā)生時處理器的動作
當(dāng)任何一個異常發(fā)生并得到響應(yīng)時,ARM內(nèi)核自動完成以下動作:
拷貝 CPSR 到 SPSR_
Address of Int_n_Handler()
.
.
.
Address of Int_2_Handler()
Address of Int_1_Handler()
(獲取狀態(tài)信息)
IRQ
… …

中斷控制器
IRQ_Handler():
Switch(int_source)
{
case 1:
case 2:

case n:
}
Int_1_Handler()
Int_2_Handler()
… …
Int_vector_table
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
設(shè)置適當(dāng)?shù)?CPSR 位:
改變處理器狀態(tài)進(jìn)入 ARM 狀態(tài)
改變處理器模式進(jìn)入相應(yīng)的異常模式
設(shè)置中斷禁止位禁止相應(yīng)中斷
更新 LR_
設(shè)置 PC 到相應(yīng)的異常向量
注意當(dāng)響應(yīng)異常后,不管異常發(fā)生在ARM還是Thumb狀態(tài)下,處理器都將
自動進(jìn)入ARM狀態(tài).另一個需要注意的地方是中斷使能被自動關(guān)閉,也就是說
缺省情況下中斷是不可重入的.單純的把中斷使能位打開接受重入的中斷會帶來
新的問題,在第3部分中對此會有詳細(xì)介紹.
除這些自動完成的動作之外,如果在匯編級進(jìn)行手動編程,還需要注意保存
必要的通用寄存器.
2.2 進(jìn)入異常處理循環(huán)后軟件的任務(wù)
進(jìn)入異常處理程序以后,用戶可以完全按照自己的意愿來進(jìn)行程序設(shè)計,包
括調(diào)用Thumb狀態(tài)的函數(shù),等等.但是對于絕大多數(shù)的系統(tǒng)來說,有一個步驟
必須處理,就是要把中斷控制器中對應(yīng)的中斷狀態(tài)標(biāo)識清掉,表明該中斷請求已
經(jīng)得到響應(yīng).否則等退出中斷函數(shù)以后,又馬上會被再一次觸發(fā),從而進(jìn)入周而
復(fù)始的死循環(huán).
2.3 異常的返回
當(dāng)一個異常處理返回時,一共有3件事情需要處理:通用寄存器的恢復(fù),狀
態(tài)寄存器的恢復(fù)以及PC指針的恢復(fù).
通用寄存器的恢復(fù)采用一般的堆棧操作指令,而PC和CPSR的恢復(fù)可以通
過一條指令來實現(xiàn),下面是3個例子:
MOVS pc, lr 或 SUBS pc, lr, #4 或LDMFD sp!, {pc}^
這幾條指令都是普通的數(shù)據(jù)處理指令,特殊之處就是把PC寄存器作為了目
標(biāo)寄存器,并且?guī)Я颂厥獾暮缶Y"S"或"^",在特權(quán)模式下,"S"或"^"的作
用就是使指令在執(zhí)行時,同時完成從SPSR到CPSR的拷貝,達(dá)到恢復(fù)狀態(tài)寄存
器的目的.
異常返回時另一個非常重要的問題是返回地址的確定.在2.1節(jié)中提到進(jìn)入
異常時處理器會有一個保存LR的動作,但是該保存值并不一定是正確中斷的返
回地址.下面以一個簡單的指令執(zhí)行流水狀態(tài)圖來對此加以說明.
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
圖-8 ARM狀態(tài)下3級指令流水線執(zhí)行示例
我們知道在ARM架構(gòu)里,PC值指向當(dāng)前執(zhí)行指令的地址加8處.也就是說,
當(dāng)執(zhí)行指令A(yù)(地址0x8000)時,PC等于指令C的地址(0x8008).假如指令
A是"BL"指令,則當(dāng)執(zhí)行時,會把PC(=0x8008)保存到LR寄存器里面,但
是接下去處理器會馬上對LR進(jìn)行一個自動的調(diào)整動作:LR=LR-0x4.這樣,最
終保存在LR里面的是B指令的地址,所以當(dāng)從BL返回時,LR里面正好是正
確的返回地址.
同樣的調(diào)整機制在所有LR自動保存操作中都存在,比如進(jìn)入中斷響應(yīng)時處
理器所做的LR保存中,也進(jìn)行了一次自動調(diào)整,并且調(diào)整動作都是LR=LR-0x4.
由此我們來對不同異常類型的返回地址進(jìn)行依次比較:
假設(shè)在指令B處(地址0x8004)發(fā)生了中斷響應(yīng),進(jìn)入中斷響應(yīng)后LR上經(jīng)
過調(diào)整保存的地址值應(yīng)該是C的地址0x8008.
(a) 如果發(fā)生的是軟件中斷,即B是"SWI"指令
從SWI中斷返回后下一條執(zhí)行指令就是C,正好是LR寄存器保存的地址,
所以只要直接把LR恢復(fù)給PC.
(b) 如果發(fā)生的是"IRQ"或"FIQ"等指令
因為外部中斷請求中斷了B指令的執(zhí)行,當(dāng)中斷返回后,需要重新回到B
指令的執(zhí)行,也就是返回地址應(yīng)該是B(0x8004),需要把LR減4.
(c) 如果發(fā)生的是"Data Abort"
在B上進(jìn)入數(shù)據(jù)異常的響應(yīng),但導(dǎo)致數(shù)據(jù)異常的原因卻應(yīng)該是上一條指令A(yù).
當(dāng)中斷處理程序修復(fù)數(shù)據(jù)異常以后,要回到A上重新執(zhí)行導(dǎo)致數(shù)據(jù)異常的指令,
因此返回地址應(yīng)該是LR減8.
如果原來的指令執(zhí)行狀態(tài)是Thumb,異常返回地址的分析與此類似,對LR
的調(diào)整正好與ARM狀態(tài)完全一致.
2.4 ARM編譯器對異常處理函數(shù)編寫的擴展
F D E
F D E
F D E
F D E
0x8000 A
0x8004 B
0x8008 C
0x800C D
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
考慮到異常處理函數(shù)在現(xiàn)場保護(hù)和返回地址的處理上與普通函數(shù)的不同之
處,不能直接把普通函數(shù)體連接到異常向量表上,需要在上面加一層封裝,下面
是一個例子:
IRQ_Handler ;中斷響應(yīng),從向量表直接跳來
STMFD SP!, {R0-R12, LR} ;保護(hù)現(xiàn)場,一般只需保護(hù){r0-r3,lr}即可
BL IrqHandler ;進(jìn)入普通處理函數(shù),C或匯編均可
LDMFD SP!, {R0-R12, LR} ;恢復(fù)現(xiàn)場
SUBS PC, LR, #4 ;中斷返回,注意返回地址
為了方便使用高級語言直接編寫異常處理函數(shù),ARM編譯器對此作了特定
的擴展,可以使用函數(shù)聲明關(guān)鍵字__irq,這樣編譯出來的函數(shù)就滿足異常響應(yīng)
對現(xiàn)場保護(hù)和恢復(fù)的需要,并且自動加入對LR進(jìn)行減4的處理,符合IRQ和
FIQ中斷處理的要求.
__irq void IRQ_Handler (void)
{…}
2.5 軟件中斷處理
軟件中斷由專門的軟中斷指令SWI觸發(fā),SWI指令后面跟一個中斷編號,
以標(biāo)識可能共存的多個軟件中斷程序.
圖-9 軟件中斷處理流程
在C程序中調(diào)用軟件中斷需要用到編譯器的擴展功能,使用關(guān)鍵字"__swi"
來聲明中斷函數(shù).注意軟中斷號碼同時在函數(shù)定義時指定.
__swi(0x24) void my_swi (void);
這樣當(dāng)調(diào)用函數(shù)my_swi的時候,就會用"SWI 0x24"來代替普通的函數(shù)調(diào)
用"BL my_swi".
分析圖9的流程,可以發(fā)現(xiàn)軟件中斷同樣存在著中斷分支的問題,即需要根
據(jù)中斷號碼來決定調(diào)用不同的處理程序.軟中斷號碼只存在于SWI指令碼當(dāng)中,
因此需要在中斷處理程序中讀取觸發(fā)中斷的指令代碼,然后提取中斷號信息,再


SWI 0x01


用戶程序(C或匯編)

CMP swi_num
BEQ …
(Optional)
異常向量表 SWI處理程序(匯編)
SWI處理程序(C)
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
進(jìn)行進(jìn)一步處理.下面是軟中斷指令的編碼格式:
ARM狀態(tài)下的SWI指令編碼格式,32位長度,其中低24位是中斷編號.
Thumb狀態(tài)下的SWI指令編碼格式,16位長度,其中低8位是中斷編號.
圖-10 SWI指令編碼格式
為了在中斷處理程序里面得到SWI 指令的地址,可以利用LR寄存器.每
當(dāng)響應(yīng)一次SWI的時候,處理器都會自動保存并調(diào)整LR寄存器,使里面的內(nèi)
容指向SWI下一條指令的地址,所以把LR里面的地址內(nèi)容上溯一條指令就是
所需的SWI指令地址.需要注意的一點是當(dāng)SWI指令的執(zhí)行狀態(tài)不同時,其指
令地址間隔不一樣,如果進(jìn)入SWI執(zhí)行前是在ARM狀態(tài)下,需要通過LR-4來
獲得SWI指令地址,如果是在Thumb狀態(tài)下進(jìn)入,則只要LR-2就可以了.
下面是一段提取SWI中斷號碼的例程:
MRS R0, SPSR ;檢查進(jìn)入SWI響應(yīng)前的狀態(tài)
TST R0, #T_bit ;是ARM還是Thumb #T_bit=0x20
LDRNEH R0, [LR, #-2] ;是Thumb,讀回SWI指令碼
BICNE R0, R0, #0xff00 ;提取低8位
LDREQ R0, [LR, #-4] ;是ARM,讀回SWI指令碼
BICEQ R0, R0, #0xff000000 ;提取低24位
;寄存器R0中的內(nèi)容是正確的軟中斷編號了
3.可重入中斷設(shè)計
如2.1節(jié)所述,缺省情況下ARM中斷是不可重入的,因為一旦進(jìn)入異常響
應(yīng)狀態(tài),ARM自動關(guān)閉中斷使能.如果在異常處理過程中簡單地打開中斷使能
而發(fā)生中斷嵌套,顯然新的異常處理將破壞原來的中斷現(xiàn)場而導(dǎo)致出錯.但有時
候中斷的可重入又是需要的,因此要能夠通過程序設(shè)計來解決這個問題.其中有
二點是這個問題的關(guān)鍵:
(a) 新中斷使能之前必須要保護(hù)好前一個中斷的現(xiàn)場信息,比如LR_irq和
SPSR_irq等,這一點容易想到也容易做到.
(b) 中斷處理過程中對BL的保護(hù)
28 24 27
SWI number
23
15 8 7 0
1 1 0 1 1 1 1 1 SWI number
31
Cond 1 1 1 1
0
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
在中斷處理函數(shù)中發(fā)生函數(shù)調(diào)用(BL)是很常見的,假設(shè)有下面一種情況:
IRQ_Handler:

BL Foo -----------> Foo:
ADD … STMFD SP!, {R0-R3, LR}
… …
LDMFD SP!, {R0-R3, PC}
上述程序,在IRQ處理函數(shù)IRQ_Handler() 中調(diào)用了函數(shù)Foo(),這是一個
普通的異常處理函數(shù).但若是在IRQ_Handler() 里面中斷可重入的話,則可能發(fā)
生問題,考察下面的情況:
當(dāng)新的中斷請求恰好在"BL Foo"指令執(zhí)行完成后發(fā)生.
這時候LR寄存器(因在IRQ模式下,是LR_irq)的值將調(diào)整為BL指令的
下一條指令(ADD)地址,以期能從Foo() 正確返回;但是因為這時候發(fā)生了
中斷請求,接下去要進(jìn)行新中斷的響應(yīng),處理器為了能使新中斷處理完成后能正
確返回,也將進(jìn)行LR_irq保存.因為新中斷是在指令流
BL Foo --> STMFD SP!, {R0-R3, LR}
執(zhí)行過程中插入的,完成跳轉(zhuǎn)操作后,進(jìn)行流水線刷新,最后LR_irq保存的是
STMFD后面一條指令的地址;這樣當(dāng)新中斷利用(PC = LR - 4)操作返回時,
正好可以繼續(xù)原來的流程執(zhí)行STMFD指令.這二次對LR_irq的操作發(fā)生了沖
突,當(dāng)新中斷返回后往下執(zhí)行STMFD指令,這時候壓棧的LR已不是原來需要
的ADD指令的地址,從而使子程序Foo() 無法正確返回.
這個問題無法通過增加額外的現(xiàn)場保護(hù)指令來解決.一個巧妙的辦法是在重
新使能中斷之前改變處理器的模式,也就是使上面程序中的"BL Foo"指令不
要運行在IRQ模式下.這樣當(dāng)新中斷發(fā)生時就不會造成LR寄存器的沖突了.考
慮ARM的所有運行模式,采用System模式是最恰當(dāng)?shù)?因為它既是特權(quán)模式,
又與中斷響應(yīng)無關(guān).
所以一個完整的可重入中斷應(yīng)該遵循以下流程:
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
圖-11 可重入中斷處理流程
下面是一段實現(xiàn)的例程:
保護(hù)寄存器:LR,SPSR等
與中斷控制器通信(需要的話)
切換到System狀態(tài),開中斷使能
中斷處理(現(xiàn)在中斷可重入)
關(guān)閉中斷使能,切換回IRQ狀態(tài)
恢復(fù)寄存器:PC,CPSR等
進(jìn)入普通不可重入中斷處理
結(jié)束一次可重入中斷處理
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
基于ARM的嵌入式系統(tǒng)程序開發(fā)要點(五)
—— ARM/Thumb的交互工作
在前面的文章中提到過,很多情況下應(yīng)用程序需要在ARM跟Thumb狀態(tài)之
間相互切換,這部分就討論交互工作的實現(xiàn)方法和一些注意問題.
1. 需要交互的原因
前面提到過Thumb指令在某些特殊情況下具有比ARM指令更為出色的表
現(xiàn),主要是在代碼長度和窄帶寬存儲器系統(tǒng)性能兩方面.正因為Thumb指令在
特定環(huán)境下面的優(yōu)勢,它在很多方面得到了廣泛的應(yīng)用.但是因為下面一些原因,
Thumb又不可能獨立地組成一個應(yīng)用系統(tǒng),所以不可避免地會產(chǎn)生ARM與
Thumb之間交互的問題.
Thumb指令集在功能上只是ARM指令集的一個子集,某些功能只能在
ARM狀態(tài)下執(zhí)行,如CPSR和協(xié)處理器的訪問.
進(jìn)行異常響應(yīng)時,處理器會自動進(jìn)入ARM狀態(tài).
從系統(tǒng)優(yōu)化考慮,在寬帶存儲器上不應(yīng)該放置Thumb代碼,很多窄帶
系統(tǒng)具有寬帶的內(nèi)部存儲器.
即使是一個單純的Thumb應(yīng)用系統(tǒng),也必須加一個匯編的交互頭程序,
因為系統(tǒng)總是自動從ARM開始啟動.
2. 狀態(tài)切換的實現(xiàn)
處理器在ARM/Thumb之間的狀態(tài)切換是通過一條專用的跳轉(zhuǎn)交換指令BX
來實現(xiàn)的.BX指令以通用寄存器(R0-R15)為操作數(shù),通過拷貝Rn到PC來
實現(xiàn)4GB空間范圍內(nèi)的一個絕對跳轉(zhuǎn). BX利用Rn寄存器中存儲的目標(biāo)地址值
的最后一位來判斷跳轉(zhuǎn)后的狀態(tài).
圖-1 BX指令實現(xiàn)狀態(tài)切換
0 31
Rn
PC
BX
ARM/Thumb選擇位:
0 - ARM
1 - Thumb
BX Rn
當(dāng)前狀態(tài)是Thumb時
BX{Cond.} Rn
當(dāng)前狀態(tài)是ARM時
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
無論ARM還是Thumb,其指令存儲在存儲器中都是邊界對齊的(4-Byte或
2-Byte對齊),所以在執(zhí)行跳轉(zhuǎn)過程中,PC寄存器中的最低位肯定被舍棄,不起
作用.在BX指令的執(zhí)行過程中,最低位正好被用作狀態(tài)判斷的標(biāo)識,不會造成
存儲器訪問不對齊的錯誤.
圖2中是一段直接進(jìn)行狀態(tài)切換的例程:
圖-2 ARM/Thumb交互工作的例子
我們知道ARM的狀態(tài)寄存器CPSR中,bit-5是狀態(tài)控制位T-bit,決定當(dāng)前
處理器的運行狀態(tài).如果直接修改CPSR的狀態(tài)位,也能夠達(dá)到改變處理器運行
狀態(tài)的目的,但是會帶來一個問題.因為ARM采用了多級流水線的結(jié)構(gòu),所以
在程序執(zhí)行過程中指令流水線上會存在幾條預(yù)取指令(具體數(shù)目視流水線級數(shù)而
不同).當(dāng)修改CPSR的T-bit以后,狀態(tài)的轉(zhuǎn)變會造成流水線上預(yù)取指令執(zhí)行的
錯誤.而如果用BX指令,則執(zhí)行后會進(jìn)行流水線刷新動作,清除流水線上的殘
余指令,在新的狀態(tài)下重新開始指令預(yù)取,從而保證狀態(tài)轉(zhuǎn)變時候指令流的正確
銜接.
3. ARM/Thumb之間的函數(shù)調(diào)用
在無交互的子程序調(diào)用中,其過程比較簡單.實現(xiàn)調(diào)用通常只需要一條指
令:
BL function
實現(xiàn)返回也只需要從LR恢復(fù)PC即可:
MOV PC, LR
;從ARM狀態(tài)開始
CODE32 ;匯編關(guān)鍵字
ADR R0, Into_Thumb+1 ;得到目標(biāo)地址,末位置1,轉(zhuǎn)向Thumb
BX R0 ;執(zhí)行
… ;其他代碼
CODE16 ;匯編關(guān)鍵字
Into_Thumb ;Thumb代碼段起始地址
… ;Thumb代碼
ADR R5, Back_to_ARM ;得到目標(biāo)地址,末位缺省為0,轉(zhuǎn)向ARM
BX R5 ;執(zhí)行
… ;其他代碼
CODE32 ;匯編關(guān)鍵字
Back_to_ARM ;ARM代碼段起始地址

基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
如下圖所示:
圖-3 普通函數(shù)調(diào)用
如果子函數(shù)和父函數(shù)不是在同一種狀態(tài)下執(zhí)行的,因為狀態(tài)切換,需要對
函數(shù)調(diào)用作更多的考慮.
(a) BL不能完成狀態(tài)切換,需要由BX來切換狀態(tài).
(b) BX不能自動保存返回地址到LR,需要在BX之前先保存好LR.
(c) 用"BX LR"來返回,不能使用"MOV PC, LR",因為這條指令同
樣不能實現(xiàn)狀態(tài)切換.返回時要仔細(xì)考慮保存的LR中最低位內(nèi)容是否
正確.
假如用戶直接使用匯編進(jìn)行狀態(tài)交互跳轉(zhuǎn),上述的幾個問題都需要用手工
編碼加以處理.如果用戶使用高級語言進(jìn)行開發(fā),不需要為ARM/Thumb之間的
相互調(diào)用增加額外的編碼,但是最好要對其調(diào)用過程加以了解.下面以ARM ADS
中的編譯工具為例進(jìn)行說明(圖4).
(a) 兩個函數(shù)func1()和func2()被編譯成了不同的指令集(ARM或Thumb).
注意func1()和func2()在這里位于二個不同的源文件.
(b) 編譯時必須告訴編譯器和連接器足夠的信息,一方面讓編譯器能夠使用
正確的指令碼進(jìn)行編譯,另一方面這樣當(dāng)在不同的狀態(tài)之間發(fā)生函數(shù)調(diào)
用時,連接器將插入一段連接代碼(veneers)來實現(xiàn)狀態(tài)轉(zhuǎn)換.
圖-4 不同狀態(tài)間函數(shù)調(diào)用的示例
func1
連接器生成
連接代碼
File2.c File1.c
Void func1(void)
{

func2();

}
.
.
.
BL
.
.
.
.
.
BX
func2
. .
.
BX
Void func2(void)
{


}
func2
func1
Void func1(void)
{

func2();

}
.
.
.
BL func2
.
.
.
.
.
MOV PC, LR
基于ARM的嵌入式程序開發(fā)要點
ARM-CHINA-040415A
上述過程中的一個特點是func1還是使用通常的BL指令來進(jìn)行子程序調(diào)用,
而func2返回時則直接使用"BX LR",沒有對LR進(jìn)行判斷和最低位的設(shè)置.
這是因為當(dāng)執(zhí)行BL指令對LR進(jìn)行保存時,其最低位會被自動設(shè)置,以滿足返
回時狀態(tài)切扼/td>

用并且不推薦使用這
些編號。
半主機SWI 使用的軟件中斷編號也可以由用戶自定義,但若是改變了缺省
的軟中斷編號,需要:
?? 更改系統(tǒng)中所有代碼(包括庫代碼)的半主機SWI 調(diào)用
?? 重新配置調(diào)試器對半主機請求的捕捉與相應(yīng)
這樣才能使用新的SWI 編號。
有關(guān)半主機SWI 處理函數(shù)實現(xiàn)的更詳細(xì)信息,請參考ARM 編譯器的相關(guān)
文檔。
4.應(yīng)用環(huán)境的初始化和根據(jù)目標(biāo)系統(tǒng)資源進(jìn)行的移植
在下一期中介紹應(yīng)用環(huán)境和目標(biāo)系統(tǒng)的初始化。
?
?
基于s3c2410軟中斷服務(wù)的uC/OS-II任務(wù)切換
?
?
?
1.關(guān)于軟中斷指令
? 軟件中斷指令(SWI)可以產(chǎn)生一個軟件中斷異常,這為應(yīng)用程序調(diào)用系統(tǒng)例程提供了一種機制。
語法:
?????? SWI?? {<cond>}? SWI_number
SWI執(zhí)行后的寄存器變化:
lr_svc = SWI指令后面的指令地址
spsr_svc = cpsr
pc = vectors + 0x08
cpsr模式 = SVC
cpsr I = 1(屏蔽IRQ中斷)
?
?? 處理器執(zhí)行SWI指令時,設(shè)置程序計數(shù)器pc為向量表的0x08偏移處,同事強制切換處理器模式到SVC模式,以便操作系統(tǒng)例程可以在特權(quán)模式下被調(diào)用。
?? 每個SWI指令有一個關(guān)聯(lián)的SWI號(number),用于表示一個特定的功能調(diào)用或特性。
【例子】 一個ARM工具箱中用于調(diào)試SWI的例子,是一個SWI號為0x123456的SWI調(diào)用。通常SWI指令是在用戶模式下執(zhí)行的。
SWI執(zhí)行前:
??? cpsr = nzcVqift_USER
??? pc = 0x00008000
??? lr = 0x003fffff?? ;lr = 4
??? r0 = 0x12
?
執(zhí)行指令:
??? 0x00008000?? SWI??? 0x123456
?
SWI執(zhí)行后:
??? cpsr = nzcVqIft_SVC
??? spsr = nzcVqift_USER
??? pc = 0x00000008
??? lr = 0x00008004
??? r0 = 0x12
?? SWI用于調(diào)用操作系統(tǒng)的例程,通常需要傳遞一些參數(shù),這可以通過寄存器來完成。在上面的例子中,r0
用于傳遞參數(shù)0x12,返回值也通過寄存器來傳遞。
?? 處理軟件中斷調(diào)用的代碼段稱為中斷處理程序(SWI Handler)。中斷處理程序通過執(zhí)行指令的地址獲取軟件中斷號,指令地址是從lr計算出來的。
?? SWI號由下式?jīng)Q定:
?? SWI_number = <SWI instruction> AND NOT<0xff000000>
?? 其中SWI instruction就是實際處理器執(zhí)行的32位SWI指令
?
?? SWI指令編碼為:
?? 31 - 28? 27 - 24? 23 - 0
???? cond?? 1 1 1 1? immed24
?? 指令的二進(jìn)制代碼的bit23-bit0是24bit的立即數(shù),即SWI指令的中斷號,通過屏蔽高8bit即可獲得中斷號。lr寄存器保存的是中斷返回指令的地址,所以 [lr - 4] 就是執(zhí)行SWI的執(zhí)行代碼。通過load指令拷貝整個SWI指令到寄存器,使用BIC屏蔽指令的高8位,獲取SWI中斷號。
??
??? ;read the SWI instruction
??? LDR? r10, [lr, #-4]
??? BIC? r10, r10, #0xff000000
?
2. 周立功移植uC/OS-II到s3c2410的軟中斷服務(wù)級的任務(wù)切換
uC/OS-II的任務(wù)調(diào)度函數(shù)
?? uC/OS-II的任務(wù)級的調(diào)度是由函數(shù)OS_Sched( )完成的。
?
void OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
??? OS_CPU_SR cpu_sr;
#endif
??? INT8U y;


??? OS_ENTER_CRITICAL();
??? if ((OSIntNesting == 0) && (OSLockNesting == 0)) { /* Sched. only if all ISRs done & not locked */
??????? y = OSUnMapTbl[OSRdyGrp]; /* Get pointer to HPT ready to run */
??????? OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
??????? if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */
??????????? OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
??????????? OSCtxSwCtr++; /* Increment context switch counter */
??????????? OS_TASK_SW(); /* Perform a context switch */
??????? }
??? }
??? OS_EXIT_CRITICAL();
}
?

?? 詳細(xì)解釋可以參考《嵌入式實時操作系統(tǒng) uC/OS-II》,os_sched函數(shù)在確定所有就緒任務(wù)的最高優(yōu)先級高于當(dāng)前任務(wù)優(yōu)先級時進(jìn)行任務(wù)切換,通過OS_TASK_SW( )宏來調(diào)用。
?? OS_TASK_SW( )宏實際上定義的是SWI軟中斷指令。見OS_CPU.H文件的代碼:

__swi(0x00) void OS_TASK_SW(void); /* 任務(wù)級任務(wù)切換函數(shù) */
__swi(0x01) void _OSStartHighRdy(void); /* 運行優(yōu)先級最高的任務(wù) */
__swi(0x02) void OS_ENTER_CRITICAL(void); /* 關(guān)中斷 */
__swi(0x03) void OS_EXIT_CRITICAL(void); /* 開中斷 */

__swi(0x40) void *GetOSFunctionAddr(int Index); /* 獲取系統(tǒng)服務(wù)函數(shù)入口 */
__swi(0x41) void *GetUsrFunctionAddr(int Index);/* 獲取自定義服務(wù)函數(shù)入口 */
__swi(0x42) void OSISRBegin(void); /* 中斷開始處理 */
__swi(0x43) int OSISRNeedSwap(void); /* 判斷中斷是否需要切換 */

__swi(0x80) void ChangeToSYSMode(void); /* 任務(wù)切換到系統(tǒng)模式 */
__swi(0x81) void ChangeToUSRMode(void); /* 任務(wù)切換到用戶模式 */
__swi(0x82) void TaskIsARM(INT8U prio); /* 任務(wù)代碼是ARM代碼 */
__swi(0x83) void TaskIsTHUMB(INT8U prio); /* 任務(wù)代碼是THUMB */
?

__swi(0x00) void OS_TASK_SW(void); 是與ADS相關(guān)的代碼,通過反匯編可以看到,調(diào)用OS_TASK_SW實際上被替換成swi 0x00 軟中斷指令。執(zhí)行此執(zhí)行,pc會跳轉(zhuǎn)到向量表的0x08偏移處。


中斷向量表:(見Startup.s文件)


CODE32
??????? AREA vectors,CODE,READONLY
; 異常向量表
Reset
??????? LDR PC, ResetAddr
??????? LDR PC, UndefinedAddr
??????? LDR PC, SWI_Addr
??????? LDR PC, PrefetchAddr
??????? LDR PC, DataAbortAddr
??????? DCD IRQ_Addr
??????? LDR PC, IRQ_Addr
??????? LDR PC, FIQ_Addr

ResetAddr???? DCD ResetInit
UndefinedAddr DCD Undefined
SWI_Addr????? DCD SoftwareInterrupt
PrefetchAddr? DCD PrefetchAbort
DataAbortAddr DCD DataAbort
Nouse???????? DCD 0
IRQ_Addr????? DCD IRQ_Handler
FIQ_Addr????? DCD FIQ_Handler
?


執(zhí)行SWI 0x00指令后,pc會跳轉(zhuǎn)到SoftwareInterrupt代碼處開始執(zhí)行:

見Os_cpu_a.s文件的SoftwareInterrupt函數(shù):

?

SoftwareInterrupt
??????? LDR SP, StackSvc ; 重新設(shè)置堆棧指針
??????? STMFD {R0-R3, R12, LR}
??????? MOV R1, SP ; R1指向參數(shù)存儲位置

??????? MRS R3, SPSR
??????? TST R3, #T_bit ; 中斷前是否是Thumb狀態(tài)
??????? LDRNEH R0, [LR,#-2] ; 是: 取得Thumb狀態(tài)SWI指令
??????? BICNE R0, R0, #0xff00
??????? LDREQ R0, [LR,#-4] ; 否: 取得arm狀態(tài)SWI指令
??????? BICEQ R0, R0, #0xFF000000??? ; 如上面所述,此處通過屏蔽SWI指令的高8位來獲取SWI號,r0 = SWI號,R1指向參數(shù)存儲位置
??????? CMP R0, #1
??????? LDRLO PC, =OSIntCtxSw? ;為0時跳轉(zhuǎn)到OSIntCtxSwdi地址處
??????? LDREQ PC, =__OSStartHighRdy ; 為1時,跳轉(zhuǎn)到__OSStartHighRdy地址處。SWI 0x01為第一次任務(wù)切換

??????? BL SWI_Exception? ;進(jìn)入中斷號散轉(zhuǎn)函數(shù)
???????
??????? LDMFD {R0-R3, R12, PC}^
???????
StackSvc DCD (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)

?

以上就是任務(wù)切換軟中斷級服務(wù)的實現(xiàn)。
?
?淺析arm匯編中指令使用學(xué)習(xí)
本帖被 smd801124 設(shè)置為精華(2008-05-08)
macro restore_user_regs
? ldr r1,[sp, #S_PSR]
? ldr lr,[sp, #S_PC]!? @ !用來控制基址變址尋址的最終新地址是否進(jìn)行回寫操作,
????????????????????? @ 執(zhí)行l(wèi)dr之后sp被回寫成sp+#S_PC基址變址尋址的新地址
? msr spsr,r1????????? @ 把cpsr的值保存到spsr中
? ldmdb sp,{r0 - lr}^? @ lr=[sp-1*4],r13=[sp-2*4],r12=[sp-3*4],......,r0=[sp-15*4]
????????????????????? @ 因為沒對pc賦值,所以^的表示將數(shù)據(jù)恢復(fù)到User模式的[r0-lr]寄存器組中[gliethttp]
? mov r0,r0
? add sp,sp,#S_FRAME_SIZE - S_PC
? movs pc,lr
.endm

其他指令正在學(xué)習(xí)中[隨時補充gliethttp]
-----------------------------
1.ldr ip,[sp],#4 將sp中內(nèi)容存入ip,之后sp=sp+4;
? ldr ip,[sp,#4] 將sp+4這個新地址下內(nèi)容存入ip,之后sp值保持不變
? ldr ip,[sp,#4]!將sp+4這個新地址下內(nèi)容存入ip,之后sp=sp+4將新地址值賦給sp
? str ip,[sp],#4 將ip存入sp地址處,之后sp=sp+4;
? str ip,[sp,#4] 將ip存入sp+4這個新地址,之后sp值保持不變
? str ip,[sp,#4]!將ip存入sp+4這個新地址,之后sp=sp+4將新地址值賦給sp
-----------------------------
2.movs r1,#3 ;movs將導(dǎo)致ALU被更改,因為r1賦值非0,即操作結(jié)果r0非0,所以ALU的Z標(biāo)志清0
? bne 1f??? ;因為Z=0,說明不等,所以向前跳到標(biāo)號1:所在處繼續(xù)執(zhí)行其他語句
-----------------------------
3.LDM表示裝載,STM表示存儲.
? LDMED LDMIB 預(yù)先增加裝載
? LDMFD LDMIA 過后增加裝載
? LDMEA LDMDB 預(yù)先減少裝載
? LDMFA LDMDA 過后減少裝載

? STMFA STMIB 預(yù)先增加存儲
? STMEA STMIA 過后增加存儲
? STMFD STMDB 預(yù)先減少存儲
? STMED STMDA 過后減少存儲

注意ED不同于IB;只對于預(yù)先減少裝是相同的.在存儲的時候,ED是過后減少的.
FD、ED、FA、和 EA 指定是滿棧還是空棧,是升序棧還是降序棧.
對于存儲STM而言
先加后存 FA 姑且這么來記,先加(first add),存數(shù)據(jù)
后加先存 EA 姑且這么來記,存數(shù)據(jù),后加end add
先減后存 FD 姑且這么來記,先減first dec,存數(shù)據(jù)
后減先存 ED 姑且這么來記,存數(shù)據(jù),后減end dec
然后記憶LDM,LDM是STM的反相彈出動作,所以
因為是先加后存,所以后減先取 FA 就成了與STM對應(yīng)的取數(shù)據(jù),后減
因為是后加先存,所以先減后取 EA 就成了與STM對應(yīng)的先減,取數(shù)據(jù)
因為是先減后存,所以后加先取 FD 就成了與STM對應(yīng)的取數(shù)據(jù),后加
因為是后減先存,所以先加后取 ED 就成了與STM對應(yīng)的先加,取數(shù)據(jù)
我想通過上面的變態(tài)方式可以比較容易的記住這套指令[gliethttp]
一個滿棧的棧指針指向上次寫的最后一個數(shù)據(jù)單元,而空棧的棧指針指向第一個空閑單元.
一個降序棧是在內(nèi)存中反向增長(就是說,從應(yīng)用程序空間結(jié)束處開始反向增長)而升序棧在內(nèi)存中正向增長.
其他形式簡單的描述指令的行為,意思分別是
IA過后增加(Increment After)、
IB預(yù)先增加(Increment Before)、
DA過后減少(Decrement After)、
DB預(yù)先減少(Decrement Before).

RISC OS使用傳統(tǒng)的滿降序棧.在使用符合APCS規(guī)定的編譯器的時候,它通常把你的棧指針設(shè)置在應(yīng)用程序空間的
結(jié)束處并接著使用一個FD(滿降序-Full Descending)棧.如果你與一個高級語言(BASIC或C)一起工作,你將別無選擇.
棧指針(傳統(tǒng)上是R13)指向一個滿降序棧.你必須繼續(xù)這個格式,或則建立并管理你自己的棧.

4.
teq r1,#0??? //r1-0,將結(jié)果送入狀態(tài)標(biāo)志,如果r1和0相減的結(jié)果為0,那么ALU的Z置位,否則Z清0
bne reschedule//ne表示Z非0,即:不等,那么執(zhí)行reschedule函數(shù)
-----------------------------
5.使用tst來檢查是否設(shè)置了特定的位
tst r1,#0x80 //按位and操作,檢測r1的0x1<<7,即第7位是否置1,按位與之后結(jié)果為0,那么ALU的Z置位
beq reset??? //如果Z置位,即:以上按位與操作結(jié)果是0,那么跳轉(zhuǎn)到reset標(biāo)號執(zhí)行
-----------------------------
6.'^'的理解
'^'是一個后綴標(biāo)志,不能在User模式和Sys系統(tǒng)模式下使用該標(biāo)志.該標(biāo)志有兩個存在目的:
6.1.對于LDM操作,同時恢復(fù)的寄存器中含有pc(r15)寄存器,那么指令執(zhí)行的同時cpu自動將spsr拷貝到cpsr中
如:在IRQ中斷返回代碼中[如下為ads環(huán)境下的代碼gliethttp]
ldmfd {r4}????????? //讀取sp中保存的的spsr值到r4中
msr spsr_cxsf,r4??? //對spsr的所有控制為進(jìn)行寫操作,將r4的值全部注入spsr
ldmfd {r0-r12,lr,pc}^//當(dāng)指令執(zhí)行完畢,pc跳轉(zhuǎn)之前,將spsr的值自動拷貝到cpsr中[gliethttp]
6.2.數(shù)據(jù)的送入、送出發(fā)生在User用戶模式下的寄存器,而非當(dāng)前模式寄存器
如:ldmdb sp,{r0 - lr}^;表示sp棧中的數(shù)據(jù)回復(fù)到User分組寄存器r0-lr中,而不是恢復(fù)到當(dāng)前模式寄存器r0-lr? 當(dāng)然對于User,System,IRQ,SVC,Abort,Undefined這6種模式來說[gliethttp]r0-r12是共用的,只是r13和r14
? 為分別獨有,對于FIQ模式,僅僅r0-r7是和前6中模式的r0-r7共用,r8-r14都是FIQ模式下專有.
7.spsr_cxsf,cpsr_cxsf的理解
c - control field mask byte(PSR[7:0])
x - extension field mask byte(PSR[15:8])
s - status field mask byte(PSR[23:16)
f - flags field mask byte(PSR[31:24]).
老式聲明方式:cpsr_flg,cpsr_all在ADS中已經(jīng)不在支持
cpsr_flg對應(yīng)cpsr_f
cpsr_all對應(yīng)cpsr_cxsf

需要使用專用指令對cpsr和spsr操作:mrs,msr
mrs tmp,cpsr????? //讀取CPSR的值
bic tmp,tmp,#0x80 //如果第7位為1,將其清0
msr cpsr_c,tmp??? //對控制位區(qū)psr[7:0]進(jìn)行寫操作
-----------------------------
8.cpsr的理解
CPSR = Current Program Status Register
SPSR = Saved Program Status Registers
CPSR寄存器(和保存它的SPSR寄存器)
本文來自: 電子論壇[url]http://www.eehome.cn[/url]電子工程師之家!

?

?

?

?

?

?

?

?

?

ARM的堆棧學(xué)習(xí)筆記
來源:
http://www.hzlitai.com.cn/?? 作者:藍(lán)石頭
字體大小:[大][中][小]

  以下是我在學(xué)習(xí)ARM指令中記錄的關(guān)于堆棧方面的知識:

  1、寄存器 R13 在 ARM 指令中常用作堆棧指針

  2、對于 R13 寄存器來說,它對應(yīng)6個不同的物理寄存器,其中的一個是用戶模式與系統(tǒng)模式共用,另外5個物理寄存器對應(yīng)于其他5種不同的運行模式。采用以下的記號來區(qū)分不同的物理寄存器: R13_<mode> 其中,mode為以下幾種模式之一:usr、fiq、irq、svc、abt、und。

  3、寄存器R13在ARM指令中常用作堆棧指針,但這只是一種習(xí)慣用法,用戶也可使用其他的寄存器作為堆棧指針。而在Thumb指令集中,某些指令強制性的要求使用R13作為堆棧指針。由于處理器的每種運行模式均有自己獨立的物理寄存器R13,在用戶應(yīng)用程序的初始化部分,一般都要初始化每種模式下的R13,使其指向該運行模式的棧空間,這樣,當(dāng)程序的運行進(jìn)入異常模式時,可以將需要保護(hù)的寄存器放入R13所指向的堆棧,而當(dāng)程序從異常模式返回時,則從對應(yīng)的堆棧中恢復(fù),采用這種方式可以保證異常發(fā)生后程序的正常執(zhí)行。

  4、有四種類型的堆棧:

  堆棧是一種數(shù)據(jù)結(jié)構(gòu),按先進(jìn)后出(First In Last Out,FILO)的方式工作,使用一個稱作堆棧指針的專用寄存器指示當(dāng)前的操作位置,堆棧指針總是指向棧頂。

  當(dāng)堆棧指針指向最后壓入堆棧的數(shù)據(jù)時,稱為滿堆棧(Full Stack),而當(dāng)堆棧指針指向下一個將要放入數(shù)據(jù)的空位置時,稱為空堆棧(Empty Stack)。

  同時,根據(jù)堆棧的生成方式,又可以分為遞增堆棧(Ascending Stack)和遞減堆棧(DecendingStack),當(dāng)堆棧由低地址向高地址生成時,稱為遞增堆棧,當(dāng)堆棧由高地址向低地址生成時,稱為遞減堆棧。這樣就有四種類型的堆棧工作方式,ARM 微處理器支持這四種類型的堆棧工作方式,即: ◎ Full descending 滿遞減堆棧堆棧首部是高地址,堆棧向低地址增長。棧指針總是指向堆棧最后一個元素(最后一個元素是最后壓入的數(shù)據(jù))。 ARM-Thumb過程調(diào)用標(biāo)準(zhǔn)和ARM、Thumb C/C++ 編譯器總是使用Full descending 類型堆棧。

  ◎ Full ascending 滿遞增堆棧堆棧首部是低地址,堆棧向高地址增長。棧指針總是指向堆棧最后一個元素(最后一個元素是最后壓入的數(shù)據(jù))。

  ◎ Empty descending 空遞減堆棧堆棧首部是低地址,堆棧向高地址增長。棧指針總是指向下一個將要放入數(shù)據(jù)的空位置。

  ◎ Empty ascending 空遞增堆棧堆棧首部是高地址,堆棧向低地址增長。棧指針總是指向下一個將要放入數(shù)據(jù)的空位置。

  5、操作堆棧的匯編指令堆棧類型 入棧指令 出棧指令 Full descending STMFD (STMDB) LDMFD (LDMIA) Full ascending STMFA (STMIB) LDMFA (LDMDA) Empty descending STMED (STMDA) LDMED (LDMIB) Empty ascending STMEA (STMIA) LDMEA (LDMDB)

  例子: STMFD r13!, {r0-r5} ; Push onto a Full Descending Stack LDMFD r13!, {r0-r5} ; Pop from a Full Descending Stack.

總結(jié)

以上是生活随笔為你收集整理的ARM汇编指令汇总的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

性色欲情网站iwww九文堂 | 全球成人中文在线 | 99久久久无码国产精品免费 | 亚洲无人区午夜福利码高清完整版 | 国产精品久久久一区二区三区 | 国产精品无码成人午夜电影 | 亚洲日韩av一区二区三区中文 | 丰满人妻被黑人猛烈进入 | 日日噜噜噜噜夜夜爽亚洲精品 | 国产在线精品一区二区高清不卡 | 国产三级久久久精品麻豆三级 | 日韩人妻系列无码专区 | 中文字幕人妻无码一夲道 | 亚洲の无码国产の无码影院 | 日韩人妻无码一区二区三区久久99 | 亚洲爆乳大丰满无码专区 | 久久精品人妻少妇一区二区三区 | 国产精华av午夜在线观看 | 国产香蕉尹人视频在线 | 日本精品少妇一区二区三区 | 无码国模国产在线观看 | 久久人妻内射无码一区三区 | 国内少妇偷人精品视频免费 | 日韩在线不卡免费视频一区 | 久久午夜夜伦鲁鲁片无码免费 | 强开小婷嫩苞又嫩又紧视频 | 亚洲综合精品香蕉久久网 | 久久人妻内射无码一区三区 | 4hu四虎永久在线观看 | 国产精品无码一区二区桃花视频 | 欧美大屁股xxxxhd黑色 | 欧美丰满熟妇xxxx | 少妇一晚三次一区二区三区 | 香港三级日本三级妇三级 | 精品无码成人片一区二区98 | 亚洲成色在线综合网站 | 久久久久免费看成人影片 | 国产精品久久久久9999小说 | 精品一区二区三区波多野结衣 | 亚洲国产精品毛片av不卡在线 | 国产香蕉尹人综合在线观看 | 中文无码成人免费视频在线观看 | 亚洲综合精品香蕉久久网 | 亚洲a无码综合a国产av中文 | 麻豆成人精品国产免费 | 在教室伦流澡到高潮hnp视频 | 亚洲综合伊人久久大杳蕉 | 国产精品毛片一区二区 | 久久天天躁夜夜躁狠狠 | 熟女体下毛毛黑森林 | 亚洲精品久久久久avwww潮水 | 日韩 欧美 动漫 国产 制服 | 无码精品人妻一区二区三区av | 九九在线中文字幕无码 | 欧美肥老太牲交大战 | 国产精品欧美成人 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 国产内射爽爽大片视频社区在线 | 激情内射亚州一区二区三区爱妻 | 东京热一精品无码av | 国产免费无码一区二区视频 | 欧美人与牲动交xxxx | 丁香花在线影院观看在线播放 | 1000部夫妻午夜免费 | 好爽又高潮了毛片免费下载 | 捆绑白丝粉色jk震动捧喷白浆 | 麻豆国产丝袜白领秘书在线观看 | 国产一区二区三区四区五区加勒比 | 好男人社区资源 | 国产精品多人p群无码 | 少妇久久久久久人妻无码 | 成人一在线视频日韩国产 | 澳门永久av免费网站 | 婷婷五月综合缴情在线视频 | 欧美黑人巨大xxxxx | 亚洲日韩中文字幕在线播放 | 精品国产麻豆免费人成网站 | 亚洲s色大片在线观看 | 强辱丰满人妻hd中文字幕 | 成人性做爰aaa片免费看不忠 | 国产精品久久久久影院嫩草 | 欧美人与禽zoz0性伦交 | 日韩精品久久久肉伦网站 | 97精品国产97久久久久久免费 | 亚洲高清偷拍一区二区三区 | 骚片av蜜桃精品一区 | 国产97人人超碰caoprom | 精品久久久久久人妻无码中文字幕 | 中文字幕av日韩精品一区二区 | 人人妻人人澡人人爽人人精品 | 久久午夜夜伦鲁鲁片无码免费 | 日本又色又爽又黄的a片18禁 | 国产凸凹视频一区二区 | 国产成人无码一二三区视频 | 国产在线精品一区二区高清不卡 | 国产亚洲精品久久久久久久 | 中文字幕人妻丝袜二区 | 国产亚洲美女精品久久久2020 | 国产做国产爱免费视频 | 亚洲色大成网站www国产 | 国产av无码专区亚洲awww | 中文字幕+乱码+中文字幕一区 | 欧美人与禽zoz0性伦交 | 国产成人综合在线女婷五月99播放 | 99在线 | 亚洲 | 国产舌乚八伦偷品w中 | 男人和女人高潮免费网站 | av小次郎收藏 | 欧美变态另类xxxx | 午夜精品一区二区三区在线观看 | 亚洲国产精品一区二区第一页 | 久久天天躁夜夜躁狠狠 | 国产精品手机免费 | 久久久婷婷五月亚洲97号色 | 久久精品国产一区二区三区 | 狠狠cao日日穞夜夜穞av | 亚洲精品成a人在线观看 | 日韩精品久久久肉伦网站 | 欧美精品免费观看二区 | 成人动漫在线观看 | 午夜熟女插插xx免费视频 | 免费观看的无遮挡av | 成在人线av无码免观看麻豆 | 亚洲国产精品一区二区美利坚 | 无码人妻丰满熟妇区毛片18 | 少妇无码吹潮 | 日产精品高潮呻吟av久久 | 人妻夜夜爽天天爽三区 | 久久久久成人片免费观看蜜芽 | 久久久精品国产sm最大网站 | 亚洲中文字幕无码一久久区 | 国产精品亚洲一区二区三区喷水 | 十八禁真人啪啪免费网站 | 成在人线av无码免观看麻豆 | 久久 国产 尿 小便 嘘嘘 | 久久综合狠狠综合久久综合88 | 欧洲极品少妇 | 中文字幕人妻无码一区二区三区 | 亚洲自偷精品视频自拍 | 2020最新国产自产精品 | 成人欧美一区二区三区 | 美女扒开屁股让男人桶 | а天堂中文在线官网 | 精品无码成人片一区二区98 | 四虎永久在线精品免费网址 | 综合人妻久久一区二区精品 | 丰满诱人的人妻3 | 久久人人爽人人爽人人片ⅴ | 丰满肥臀大屁股熟妇激情视频 | 色一情一乱一伦一视频免费看 | 国产精品二区一区二区aⅴ污介绍 | а天堂中文在线官网 | 香港三级日本三级妇三级 | 午夜福利一区二区三区在线观看 | 国产精品无码永久免费888 | 中文亚洲成a人片在线观看 | 欧美老人巨大xxxx做受 | 久久综合网欧美色妞网 | 野外少妇愉情中文字幕 | 国产亚洲欧美日韩亚洲中文色 | 亚洲一区二区三区含羞草 | 丰满护士巨好爽好大乳 | 亚洲精品国偷拍自产在线麻豆 | 网友自拍区视频精品 | 国产麻豆精品精东影业av网站 | 中文字幕无码视频专区 | 亚洲成a人片在线观看无码3d | 国产偷国产偷精品高清尤物 | 在线看片无码永久免费视频 | 国产成人无码一二三区视频 | 精品亚洲成av人在线观看 | 成人免费视频在线观看 | 日日躁夜夜躁狠狠躁 | 亚洲狠狠色丁香婷婷综合 | 丰满人妻翻云覆雨呻吟视频 | 国产精品久久精品三级 | 国产激情艳情在线看视频 | 亚洲 欧美 激情 小说 另类 | 国产免费观看黄av片 | 日产精品高潮呻吟av久久 | 亚洲中文字幕av在天堂 | 久久综合网欧美色妞网 | www国产亚洲精品久久久日本 | 成人片黄网站色大片免费观看 | 少妇厨房愉情理9仑片视频 | 无遮挡啪啪摇乳动态图 | 美女黄网站人色视频免费国产 | 鲁一鲁av2019在线 | 久久久久久a亚洲欧洲av冫 | 国产精品久久久av久久久 | 蜜桃av抽搐高潮一区二区 | 性色欲情网站iwww九文堂 | 午夜成人1000部免费视频 | 自拍偷自拍亚洲精品10p | 亚洲精品一区二区三区四区五区 | 99在线 | 亚洲 | 无码人妻av免费一区二区三区 | 国产精品久久久午夜夜伦鲁鲁 | 美女扒开屁股让男人桶 | 亚洲 a v无 码免 费 成 人 a v | 欧美第一黄网免费网站 | 美女扒开屁股让男人桶 | 精品人妻人人做人人爽夜夜爽 | 999久久久国产精品消防器材 | 国内揄拍国内精品人妻 | 麻豆国产97在线 | 欧洲 | 久久精品99久久香蕉国产色戒 | 国产成人人人97超碰超爽8 | 十八禁真人啪啪免费网站 | 大屁股大乳丰满人妻 | 大地资源网第二页免费观看 | 兔费看少妇性l交大片免费 | 国产精品第一国产精品 | 国产精品毛多多水多 | 国产色视频一区二区三区 | √8天堂资源地址中文在线 | 大屁股大乳丰满人妻 | 日本欧美一区二区三区乱码 | 我要看www免费看插插视频 | 国产乱人无码伦av在线a | 大肉大捧一进一出好爽视频 | 欧美成人午夜精品久久久 | 日日天干夜夜狠狠爱 | 捆绑白丝粉色jk震动捧喷白浆 | 无码一区二区三区在线 | 国产免费久久精品国产传媒 | 岛国片人妻三上悠亚 | 思思久久99热只有频精品66 | 日日天干夜夜狠狠爱 | 大乳丰满人妻中文字幕日本 | 永久黄网站色视频免费直播 | 一个人看的www免费视频在线观看 | 久久婷婷五月综合色国产香蕉 | 亚洲国产欧美日韩精品一区二区三区 | 国产另类ts人妖一区二区 | 熟女少妇在线视频播放 | 性生交大片免费看l | 欧美熟妇另类久久久久久不卡 | 国产亚洲欧美日韩亚洲中文色 | 国产一区二区三区日韩精品 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 丰满少妇女裸体bbw | 久久精品国产亚洲精品 | 偷窥日本少妇撒尿chinese | 精品国产青草久久久久福利 | 亚洲国产精品无码久久久久高潮 | 国产精品嫩草久久久久 | 日本高清一区免费中文视频 | 捆绑白丝粉色jk震动捧喷白浆 | 亚洲第一无码av无码专区 | 爆乳一区二区三区无码 | 国产在线无码精品电影网 | 国产精品igao视频网 | 国产又粗又硬又大爽黄老大爷视 | 自拍偷自拍亚洲精品被多人伦好爽 | 亚洲成av人影院在线观看 | 天天摸天天透天天添 | 免费无码肉片在线观看 | 少妇被黑人到高潮喷出白浆 | 国产成人无码a区在线观看视频app | 男女超爽视频免费播放 | 亚洲理论电影在线观看 | 日产精品99久久久久久 | 精品无人区无码乱码毛片国产 | 99精品久久毛片a片 | 成人毛片一区二区 | 大肉大捧一进一出好爽视频 | 国产成人精品久久亚洲高清不卡 | 亚洲一区av无码专区在线观看 | 亚洲日韩乱码中文无码蜜桃臀网站 | 久久久久久久久蜜桃 | 丰满岳乱妇在线观看中字无码 | 精品一二三区久久aaa片 | 精品偷拍一区二区三区在线看 | 樱花草在线社区www | 小泽玛莉亚一区二区视频在线 | 真人与拘做受免费视频一 | 国产福利视频一区二区 | 永久黄网站色视频免费直播 | 午夜精品久久久内射近拍高清 | 国产成人精品一区二区在线小狼 | 国产三级精品三级男人的天堂 | 亚洲日韩一区二区 | 久久精品国产日本波多野结衣 | 亚洲码国产精品高潮在线 | 最近中文2019字幕第二页 | 人人妻人人澡人人爽精品欧美 | 国产午夜福利100集发布 | 中文字幕日韩精品一区二区三区 | 伊在人天堂亚洲香蕉精品区 | 亚洲精品成人av在线 | 久久国产36精品色熟妇 | 亚洲s色大片在线观看 | 婷婷六月久久综合丁香 | 亚洲色欲色欲天天天www | 日本一区二区三区免费高清 | 亚洲精品中文字幕 | 俺去俺来也www色官网 | 国产国语老龄妇女a片 | 一本加勒比波多野结衣 | 久久天天躁狠狠躁夜夜免费观看 | 亚洲日本一区二区三区在线 | 久久人人爽人人爽人人片ⅴ | 国产xxx69麻豆国语对白 | 任你躁国产自任一区二区三区 | 亚洲精品国产精品乱码视色 | 99久久精品无码一区二区毛片 | 男女超爽视频免费播放 | 国内精品九九久久久精品 | 桃花色综合影院 | 国产猛烈高潮尖叫视频免费 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 日韩无码专区 | 成熟人妻av无码专区 | 久久久久久久人妻无码中文字幕爆 | 99riav国产精品视频 | 人人爽人人澡人人人妻 | 伊人久久大香线焦av综合影院 | 毛片内射-百度 | 国产精品手机免费 | 人妻aⅴ无码一区二区三区 | 妺妺窝人体色www在线小说 | 午夜福利一区二区三区在线观看 | 亚洲国产精品无码久久久久高潮 | 日本精品人妻无码免费大全 | 欧美日韩色另类综合 | 国产精品va在线观看无码 | 国内精品久久久久久中文字幕 | 国产另类ts人妖一区二区 | 久久亚洲精品成人无码 | 日韩亚洲欧美精品综合 | 精品国产一区二区三区四区在线看 | 4hu四虎永久在线观看 | 欧美阿v高清资源不卡在线播放 | 国产热a欧美热a在线视频 | 国产绳艺sm调教室论坛 | 日日摸夜夜摸狠狠摸婷婷 | 中文字幕 亚洲精品 第1页 | 妺妺窝人体色www婷婷 | 国产福利视频一区二区 | 99精品视频在线观看免费 | 精品厕所偷拍各类美女tp嘘嘘 | 国产乱人无码伦av在线a | √8天堂资源地址中文在线 | 老太婆性杂交欧美肥老太 | 日韩成人一区二区三区在线观看 | 麻豆国产人妻欲求不满 | 中文字幕av日韩精品一区二区 | 樱花草在线播放免费中文 | 亚洲精品久久久久avwww潮水 | 亚洲成色在线综合网站 | 女人被男人爽到呻吟的视频 | 人人妻人人澡人人爽欧美一区 | 亚洲色欲色欲天天天www | 成年女人永久免费看片 | 欧美国产日产一区二区 | 牲欲强的熟妇农村老妇女视频 | 色综合视频一区二区三区 | √8天堂资源地址中文在线 | 两性色午夜免费视频 | 欧美成人午夜精品久久久 | 亚洲成av人综合在线观看 | 日本欧美一区二区三区乱码 | 性生交大片免费看l | 久久久久久九九精品久 | 国产乱子伦视频在线播放 | 四虎4hu永久免费 | 伊人久久大香线蕉av一区二区 | 高清无码午夜福利视频 | 国产精品久久久久久久影院 | 国产真实乱对白精彩久久 | 国产成人精品视频ⅴa片软件竹菊 | 在线成人www免费观看视频 | 免费无码一区二区三区蜜桃大 | 国产精品嫩草久久久久 | 国产精品-区区久久久狼 | 国产午夜视频在线观看 | 老太婆性杂交欧美肥老太 | 国产激情无码一区二区app | 久久99精品国产麻豆 | 亚洲精品午夜无码电影网 | 亚洲中文字幕久久无码 | 亚洲人成影院在线无码按摩店 | 十八禁真人啪啪免费网站 | 狠狠综合久久久久综合网 | 久久久成人毛片无码 | 成人欧美一区二区三区 | 中文字幕中文有码在线 | 国产成人精品无码播放 | 熟女体下毛毛黑森林 | 亚洲欧美综合区丁香五月小说 | 欧美自拍另类欧美综合图片区 | 亚洲色欲久久久综合网东京热 | av人摸人人人澡人人超碰下载 | 又色又爽又黄的美女裸体网站 | 久久久久国色av免费观看性色 | 玩弄人妻少妇500系列视频 | 野外少妇愉情中文字幕 | 日日噜噜噜噜夜夜爽亚洲精品 | 在线观看国产一区二区三区 | 又色又爽又黄的美女裸体网站 | 亚洲а∨天堂久久精品2021 | 色婷婷av一区二区三区之红樱桃 | 免费无码的av片在线观看 | аⅴ资源天堂资源库在线 | 久久国产自偷自偷免费一区调 | 亚洲国产av美女网站 | 中文字幕无线码免费人妻 | 99久久精品午夜一区二区 | 狠狠色噜噜狠狠狠狠7777米奇 | 2020久久超碰国产精品最新 | 日本又色又爽又黄的a片18禁 | 国产精品多人p群无码 | 久久精品99久久香蕉国产色戒 | 毛片内射-百度 | 国产在线精品一区二区高清不卡 | 天天做天天爱天天爽综合网 | 国产真实乱对白精彩久久 | 少妇邻居内射在线 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 麻花豆传媒剧国产免费mv在线 | 国内精品久久久久久中文字幕 | 西西人体www44rt大胆高清 | 西西人体www44rt大胆高清 | 1000部啪啪未满十八勿入下载 | 天海翼激烈高潮到腰振不止 | 内射欧美老妇wbb | 亚洲国产av精品一区二区蜜芽 | 乌克兰少妇性做爰 | 妺妺窝人体色www在线小说 | 无码人妻出轨黑人中文字幕 | 国产真人无遮挡作爱免费视频 | 日产国产精品亚洲系列 | 国产成人精品视频ⅴa片软件竹菊 | 白嫩日本少妇做爰 | 男人的天堂2018无码 | 国产成人精品无码播放 | 丝袜足控一区二区三区 | 精品乱码久久久久久久 | 久久综合色之久久综合 | 1000部夫妻午夜免费 | 熟女体下毛毛黑森林 | 亚洲精品中文字幕 | 亚洲精品午夜无码电影网 | 丁香啪啪综合成人亚洲 | 久久99久久99精品中文字幕 | 国产97人人超碰caoprom | 久久久久免费精品国产 | 玩弄中年熟妇正在播放 | 东京热一精品无码av | 日本精品少妇一区二区三区 | 荡女精品导航 | 亚洲乱亚洲乱妇50p | 日韩在线不卡免费视频一区 | 人人妻人人澡人人爽欧美一区九九 | 动漫av网站免费观看 | 亚洲人成人无码网www国产 | 成熟女人特级毛片www免费 | 正在播放东北夫妻内射 | 伊在人天堂亚洲香蕉精品区 | 欧美乱妇无乱码大黄a片 | 中文字幕乱码中文乱码51精品 | 久久精品成人欧美大片 | 日韩精品无码免费一区二区三区 | 亚洲一区二区三区偷拍女厕 | 大色综合色综合网站 | 波多野结衣乳巨码无在线观看 | 老司机亚洲精品影院无码 | 97无码免费人妻超级碰碰夜夜 | 丝袜 中出 制服 人妻 美腿 | 亚洲精品久久久久久久久久久 | 六月丁香婷婷色狠狠久久 | 亚洲一区二区三区在线观看网站 | 暴力强奷在线播放无码 | 一本一道久久综合久久 | 亚洲精品鲁一鲁一区二区三区 | 天堂无码人妻精品一区二区三区 | 狠狠综合久久久久综合网 | 精品国产一区二区三区四区在线看 | 精品国产一区二区三区av 性色 | 国产精品手机免费 | 亚洲综合色区中文字幕 | 无遮无挡爽爽免费视频 | 成熟人妻av无码专区 | 中文字幕无码热在线视频 | 国产va免费精品观看 | 荫蒂被男人添的好舒服爽免费视频 | 亚洲欧美精品伊人久久 | 午夜福利不卡在线视频 | 国内综合精品午夜久久资源 | 久久伊人色av天堂九九小黄鸭 | 国产欧美精品一区二区三区 | 国内丰满熟女出轨videos | 亚洲国产日韩a在线播放 | 亚洲爆乳精品无码一区二区三区 | 日韩人妻系列无码专区 | 老熟妇仑乱视频一区二区 | 日韩少妇内射免费播放 | 日本精品久久久久中文字幕 | 久久久精品成人免费观看 | 亚洲熟妇色xxxxx欧美老妇y | 牛和人交xxxx欧美 | 成人毛片一区二区 | 未满小14洗澡无码视频网站 | 大胆欧美熟妇xx | 亚洲午夜久久久影院 | 欧美丰满少妇xxxx性 | 国产精品人人妻人人爽 | 久久国产精品偷任你爽任你 | 久久五月精品中文字幕 | 波多野结衣av在线观看 | 狠狠色噜噜狠狠狠狠7777米奇 | 国产偷国产偷精品高清尤物 | 性生交大片免费看女人按摩摩 | 少妇愉情理伦片bd | 亚洲 欧美 激情 小说 另类 | 欧美zoozzooz性欧美 | 精品无码国产一区二区三区av | 日日噜噜噜噜夜夜爽亚洲精品 | 奇米影视7777久久精品人人爽 | 国产又爽又黄又刺激的视频 | 国产精品久久国产三级国 | 成人免费视频视频在线观看 免费 | 久久午夜无码鲁丝片秋霞 | 天天躁日日躁狠狠躁免费麻豆 | 夜先锋av资源网站 | 色五月五月丁香亚洲综合网 | 婷婷综合久久中文字幕蜜桃三电影 | 国产两女互慰高潮视频在线观看 | 奇米影视7777久久精品 | 天堂亚洲免费视频 | √天堂资源地址中文在线 | 国内少妇偷人精品视频 | 亚洲欧美国产精品久久 | 国产成人亚洲综合无码 | 亚洲精品久久久久久久久久久 | 国产亚洲欧美在线专区 | 人人妻人人澡人人爽欧美一区九九 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 天天av天天av天天透 | 欧美乱妇无乱码大黄a片 | 欧美国产亚洲日韩在线二区 | 亚洲第一网站男人都懂 | 国产99久久精品一区二区 | 熟女俱乐部五十路六十路av | 精品无码一区二区三区爱欲 | 人妻少妇被猛烈进入中文字幕 | 秋霞成人午夜鲁丝一区二区三区 | 女人被男人爽到呻吟的视频 | 伊人久久大香线焦av综合影院 | 免费人成网站视频在线观看 | 精品久久综合1区2区3区激情 | 女人被男人躁得好爽免费视频 | 一二三四社区在线中文视频 | 亚洲熟妇色xxxxx欧美老妇y | 精品一区二区三区无码免费视频 | 亚洲精品综合一区二区三区在线 | 精品久久久久久人妻无码中文字幕 | 国产精品内射视频免费 | 少妇无码一区二区二三区 | 98国产精品综合一区二区三区 | 性啪啪chinese东北女人 | 亚洲色欲色欲天天天www | 日本一区二区三区免费播放 | 久久无码专区国产精品s | 精品午夜福利在线观看 | 久久99精品久久久久婷婷 | 久久无码专区国产精品s | 扒开双腿疯狂进出爽爽爽视频 | 国产热a欧美热a在线视频 | 国产一区二区三区精品视频 | 成人精品天堂一区二区三区 | 亚洲一区二区三区在线观看网站 | 国产尤物精品视频 | 草草网站影院白丝内射 | 天海翼激烈高潮到腰振不止 | 国产精品亚洲综合色区韩国 | 国产一区二区三区精品视频 | 国产av剧情md精品麻豆 | 亚洲午夜久久久影院 | 天天躁夜夜躁狠狠是什么心态 | 久久精品人妻少妇一区二区三区 | 免费观看又污又黄的网站 | 亚洲午夜无码久久 | 嫩b人妻精品一区二区三区 | 欧美午夜特黄aaaaaa片 | 成年女人永久免费看片 | 亚洲 另类 在线 欧美 制服 | 熟妇激情内射com | 国产色视频一区二区三区 | 中文字幕av伊人av无码av | 丰满护士巨好爽好大乳 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 国产亚洲人成a在线v网站 | 国产精品高潮呻吟av久久 | 黑人巨大精品欧美黑寡妇 | 双乳奶水饱满少妇呻吟 | 久久精品丝袜高跟鞋 | 亚洲国产精品久久久久久 | 久久 国产 尿 小便 嘘嘘 | 中文字幕乱码中文乱码51精品 | 国内精品人妻无码久久久影院 | 国内精品久久久久久中文字幕 | 亚洲无人区午夜福利码高清完整版 | 精品国产av色一区二区深夜久久 | 日韩精品乱码av一区二区 | 漂亮人妻洗澡被公强 日日躁 | 一二三四在线观看免费视频 | 久精品国产欧美亚洲色aⅴ大片 | 女人被男人爽到呻吟的视频 | 国产精品igao视频网 | 无码人妻出轨黑人中文字幕 | 国产精品久久久久影院嫩草 | 亚洲阿v天堂在线 | 又黄又爽又色的视频 | 日韩av无码中文无码电影 | 99久久婷婷国产综合精品青草免费 | 亚洲熟妇色xxxxx欧美老妇y | 成人试看120秒体验区 | 美女扒开屁股让男人桶 | 亚洲熟女一区二区三区 | 天下第一社区视频www日本 | 性欧美videos高清精品 | 国产亚洲欧美在线专区 | 国产色在线 | 国产 | 国产舌乚八伦偷品w中 | 99久久久国产精品无码免费 | 国产成人无码av片在线观看不卡 | 国产成人无码av片在线观看不卡 | 国产午夜福利100集发布 | 无码中文字幕色专区 | 天天做天天爱天天爽综合网 | 国产亚洲精品精品国产亚洲综合 | 精品久久8x国产免费观看 | 激情综合激情五月俺也去 | yw尤物av无码国产在线观看 | 免费乱码人妻系列无码专区 | 亚洲男人av天堂午夜在 | 日本一卡二卡不卡视频查询 | 久久精品成人欧美大片 | 亚洲中文字幕乱码av波多ji | 中文字幕乱码中文乱码51精品 | 亚洲伊人久久精品影院 | 久久精品成人欧美大片 | 在线精品亚洲一区二区 | 999久久久国产精品消防器材 | 亚洲日韩中文字幕在线播放 | 久久久久成人精品免费播放动漫 | 国内揄拍国内精品少妇国语 | 日本丰满熟妇videos | 国产精品第一区揄拍无码 | 久久精品中文闷骚内射 | 天海翼激烈高潮到腰振不止 | 国产超碰人人爽人人做人人添 | 亚洲自偷精品视频自拍 | 国产av剧情md精品麻豆 | 国产成人无码午夜视频在线观看 | 亚洲精品一区二区三区在线观看 | 国产一区二区三区影院 | 亚洲 日韩 欧美 成人 在线观看 | 精品厕所偷拍各类美女tp嘘嘘 | 麻花豆传媒剧国产免费mv在线 | 国产特级毛片aaaaaaa高清 | 久久视频在线观看精品 | 51国偷自产一区二区三区 | 一本久道久久综合狠狠爱 | 午夜精品一区二区三区在线观看 | 欧美丰满少妇xxxx性 | 国产成人精品一区二区在线小狼 | 在线成人www免费观看视频 | 嫩b人妻精品一区二区三区 | 国产精品高潮呻吟av久久 | 最近免费中文字幕中文高清百度 | 国内丰满熟女出轨videos | 亚洲国产日韩a在线播放 | 国产精品久久久久久亚洲影视内衣 | 成人免费视频在线观看 | 在线а√天堂中文官网 | 欧美人与禽zoz0性伦交 | 亚洲色大成网站www | 野狼第一精品社区 | 免费人成网站视频在线观看 | 无码人妻av免费一区二区三区 | 少妇无码av无码专区在线观看 | 国产成人无码区免费内射一片色欲 | 婷婷五月综合缴情在线视频 | 久久久久成人精品免费播放动漫 | 2020久久香蕉国产线看观看 | 色五月丁香五月综合五月 | 午夜精品久久久久久久 | 中文字幕av日韩精品一区二区 | 牲欲强的熟妇农村老妇女 | 久久久久人妻一区精品色欧美 | 成熟人妻av无码专区 | 99久久人妻精品免费一区 | 亚洲欧美国产精品专区久久 | 中文字幕av日韩精品一区二区 | 中文字幕无码av波多野吉衣 | 少妇被黑人到高潮喷出白浆 | 东京一本一道一二三区 | 国产精品美女久久久久av爽李琼 | 欧美精品一区二区精品久久 | 欧美熟妇另类久久久久久多毛 | 欧美激情综合亚洲一二区 | 亚洲成熟女人毛毛耸耸多 | 亚洲自偷精品视频自拍 | 亚洲第一网站男人都懂 | 精品国产一区av天美传媒 | 国产色视频一区二区三区 | 夜夜高潮次次欢爽av女 | 国产亚洲人成在线播放 | 久久婷婷五月综合色国产香蕉 | 人妻互换免费中文字幕 | 色综合久久88色综合天天 | 久久人人97超碰a片精品 | 国产无遮挡又黄又爽免费视频 | 久久久精品成人免费观看 | 国内精品人妻无码久久久影院 | 天天躁日日躁狠狠躁免费麻豆 | 国内揄拍国内精品少妇国语 | 麻豆蜜桃av蜜臀av色欲av | 日韩av无码一区二区三区不卡 | 国产sm调教视频在线观看 | 三级4级全黄60分钟 | 国产精品爱久久久久久久 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 国产精品久久久久7777 | 性欧美疯狂xxxxbbbb | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 亚洲 a v无 码免 费 成 人 a v | 亚洲春色在线视频 | 青春草在线视频免费观看 | 大肉大捧一进一出视频出来呀 | 天堂一区人妻无码 | 亚洲人成网站在线播放942 | 国产成人精品三级麻豆 | 日本爽爽爽爽爽爽在线观看免 | 久久精品国产99久久6动漫 | 青青青手机频在线观看 | 妺妺窝人体色www婷婷 | 老司机亚洲精品影院无码 | 中文无码精品a∨在线观看不卡 | 欧洲极品少妇 | 亚洲人成网站色7799 | 性欧美videos高清精品 | 狠狠躁日日躁夜夜躁2020 | 欧美一区二区三区 | 无套内射视频囯产 | 国产亚洲人成a在线v网站 | 一本大道伊人av久久综合 | 国产熟女一区二区三区四区五区 | www国产亚洲精品久久久日本 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 色欲av亚洲一区无码少妇 | 中文字幕无码视频专区 | 亚洲高清偷拍一区二区三区 | 婷婷五月综合激情中文字幕 | 日韩精品a片一区二区三区妖精 | 国产亚洲视频中文字幕97精品 | 久久午夜夜伦鲁鲁片无码免费 | 国产成人精品三级麻豆 | 欧美老妇交乱视频在线观看 | 亚洲欧美日韩成人高清在线一区 | 中国女人内谢69xxxx | 成人欧美一区二区三区黑人免费 | 人妻少妇精品无码专区动漫 | 精品无码国产自产拍在线观看蜜 | 香港三级日本三级妇三级 | 动漫av一区二区在线观看 | 国产成人无码av片在线观看不卡 | 久久午夜夜伦鲁鲁片无码免费 | 无码免费一区二区三区 | 理论片87福利理论电影 | 亚洲一区二区三区国产精华液 | 精品无人区无码乱码毛片国产 | 日本乱人伦片中文三区 | 精品久久综合1区2区3区激情 | 久久精品国产亚洲精品 | 爱做久久久久久 | 欧洲熟妇色 欧美 | 国产精华av午夜在线观看 | 国产乱人无码伦av在线a | 麻豆md0077饥渴少妇 | 搡女人真爽免费视频大全 | 色欲人妻aaaaaaa无码 | а√资源新版在线天堂 | 成人免费无码大片a毛片 | 色婷婷久久一区二区三区麻豆 | 综合激情五月综合激情五月激情1 | 天堂亚洲免费视频 | 99久久精品无码一区二区毛片 | 成人免费视频视频在线观看 免费 | 国产成人综合在线女婷五月99播放 | 内射后入在线观看一区 | 久久精品国产一区二区三区肥胖 | 特大黑人娇小亚洲女 | 日韩精品一区二区av在线 | 国产亚洲视频中文字幕97精品 | 成人av无码一区二区三区 | 又色又爽又黄的美女裸体网站 | 亚洲成在人网站无码天堂 | 国产精品久久久久9999小说 | 亚洲区小说区激情区图片区 | 一本久道高清无码视频 | 国产av一区二区精品久久凹凸 | 思思久久99热只有频精品66 | 亚洲春色在线视频 | 夜夜影院未满十八勿进 | 大乳丰满人妻中文字幕日本 | 人人妻人人澡人人爽欧美一区 | 香港三级日本三级妇三级 | 国产在线aaa片一区二区99 | 高中生自慰www网站 | 日本一卡2卡3卡四卡精品网站 | 成人无码影片精品久久久 | 99久久无码一区人妻 | av无码不卡在线观看免费 | 精品日本一区二区三区在线观看 | 网友自拍区视频精品 | 九九久久精品国产免费看小说 | 国产热a欧美热a在线视频 | 亚洲综合伊人久久大杳蕉 | 国产精品免费大片 | 免费观看又污又黄的网站 | 性色欲情网站iwww九文堂 | 波多野42部无码喷潮在线 | 精品无人国产偷自产在线 | 国产精品亚洲综合色区韩国 | 国产又爽又黄又刺激的视频 | 亚洲人成网站色7799 | 特级做a爰片毛片免费69 | 麻豆国产人妻欲求不满谁演的 | 玩弄人妻少妇500系列视频 | 在线精品亚洲一区二区 | 亚洲综合在线一区二区三区 | 狠狠色丁香久久婷婷综合五月 | 欧美日韩视频无码一区二区三 | 好男人www社区 | 强奷人妻日本中文字幕 | 377p欧洲日本亚洲大胆 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 一本一道久久综合久久 | 亚洲自偷自拍另类第1页 | 熟妇人妻无乱码中文字幕 | 青青久在线视频免费观看 | 国产精品无码一区二区桃花视频 | 欧美性黑人极品hd | 免费无码av一区二区 | 午夜精品一区二区三区在线观看 | 三上悠亚人妻中文字幕在线 | 国产乱人偷精品人妻a片 | 暴力强奷在线播放无码 | 欧美三级不卡在线观看 | 欧美日韩久久久精品a片 | 亚洲精品国产精品乱码视色 | 丰满少妇高潮惨叫视频 | 欧美亚洲国产一区二区三区 | 青草视频在线播放 | 美女黄网站人色视频免费国产 | 国产精品永久免费视频 | 无码免费一区二区三区 | 亚洲日韩av一区二区三区中文 | 亚洲s码欧洲m码国产av | 久久www免费人成人片 | 少妇性l交大片欧洲热妇乱xxx | 麻豆av传媒蜜桃天美传媒 | 三上悠亚人妻中文字幕在线 | 久久国产36精品色熟妇 | 中文字幕乱码亚洲无线三区 | 中文字幕精品av一区二区五区 | 婷婷色婷婷开心五月四房播播 | 国产区女主播在线观看 | 色综合久久久久综合一本到桃花网 | 青青草原综合久久大伊人精品 | 成人综合网亚洲伊人 | 国产精品第一区揄拍无码 | 熟妇人妻无乱码中文字幕 | 国产成人无码av一区二区 | 亚洲一区二区三区播放 | 色欲综合久久中文字幕网 | 久久综合给久久狠狠97色 | 亚洲精品午夜无码电影网 | 午夜精品一区二区三区的区别 | 精品成在人线av无码免费看 | 成人综合网亚洲伊人 | 国产97色在线 | 免 | 性生交片免费无码看人 | 精品一区二区三区无码免费视频 | 国产肉丝袜在线观看 | 亚洲色成人中文字幕网站 | 精品亚洲韩国一区二区三区 | 麻豆蜜桃av蜜臀av色欲av | 欧美性猛交内射兽交老熟妇 | 欧美丰满少妇xxxx性 | 国内丰满熟女出轨videos | 亚洲欧洲中文日韩av乱码 | 国产亚洲视频中文字幕97精品 | 国产亚洲人成a在线v网站 | 国产特级毛片aaaaaa高潮流水 | 中文字幕无码热在线视频 | 日韩亚洲欧美中文高清在线 | 色婷婷香蕉在线一区二区 | 少妇性俱乐部纵欲狂欢电影 | 男女性色大片免费网站 | 亚洲日韩乱码中文无码蜜桃臀网站 | 天天躁夜夜躁狠狠是什么心态 | 亚洲午夜福利在线观看 | 国产精品久久久久7777 | 日韩精品无码一区二区中文字幕 | 天堂亚洲2017在线观看 | 亚洲中文字幕在线无码一区二区 | 精品人妻av区 | 国产三级久久久精品麻豆三级 | 国产成人综合色在线观看网站 | 无码成人精品区在线观看 | 双乳奶水饱满少妇呻吟 | 日本乱人伦片中文三区 | 日韩人妻少妇一区二区三区 | 波多野结衣乳巨码无在线观看 | 中文精品无码中文字幕无码专区 | 欧美丰满熟妇xxxx | 国产精品欧美成人 | 国产真实夫妇视频 | 国产又粗又硬又大爽黄老大爷视 | 999久久久国产精品消防器材 | 又色又爽又黄的美女裸体网站 | 久久精品人人做人人综合试看 | 麻豆md0077饥渴少妇 | 久久综合网欧美色妞网 | 日本精品少妇一区二区三区 | 国产精华av午夜在线观看 | 亚洲乱码日产精品bd | 老太婆性杂交欧美肥老太 | 日本高清一区免费中文视频 | 丰满妇女强制高潮18xxxx | 亚洲精品中文字幕乱码 | 无遮挡国产高潮视频免费观看 | 无码精品国产va在线观看dvd | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 色窝窝无码一区二区三区色欲 | 久久国内精品自在自线 | 99久久无码一区人妻 | 色诱久久久久综合网ywww | 午夜成人1000部免费视频 | 国产精品无码一区二区桃花视频 | а天堂中文在线官网 | 久久久国产精品无码免费专区 | 日韩精品无码一本二本三本色 | 亚洲欧美日韩综合久久久 | 精品欧美一区二区三区久久久 | 福利一区二区三区视频在线观看 | 亚洲欧美综合区丁香五月小说 | 久久精品99久久香蕉国产色戒 | 亚洲精品久久久久avwww潮水 | 国产片av国语在线观看 | 国产精品高潮呻吟av久久 | 天堂久久天堂av色综合 | 无码av中文字幕免费放 | 国产精品怡红院永久免费 | 久久精品女人天堂av免费观看 | 久久久婷婷五月亚洲97号色 | 国产一区二区三区影院 | 亚洲成av人影院在线观看 | 澳门永久av免费网站 | 亚洲国产欧美国产综合一区 | 水蜜桃亚洲一二三四在线 | 欧美精品无码一区二区三区 | 亚洲日本在线电影 | 久久综合久久自在自线精品自 | 国产精品亚洲一区二区三区喷水 | 亚洲午夜福利在线观看 | 欧美亚洲日韩国产人成在线播放 | 男人和女人高潮免费网站 | 国产精品福利视频导航 | 久久精品成人欧美大片 | 成年女人永久免费看片 | 国产精品二区一区二区aⅴ污介绍 | 精品国产精品久久一区免费式 | 乱码午夜-极国产极内射 | 一二三四社区在线中文视频 | 精品国产一区二区三区四区在线看 | 中文字幕无线码免费人妻 | 乱人伦人妻中文字幕无码久久网 | 伊人久久大香线焦av综合影院 | 中文字幕人妻无码一区二区三区 | 成人精品一区二区三区中文字幕 | av人摸人人人澡人人超碰下载 | 最近的中文字幕在线看视频 | 国产美女精品一区二区三区 | 亚洲成av人综合在线观看 | 99久久久国产精品无码免费 | 精品久久久久香蕉网 | 色婷婷av一区二区三区之红樱桃 | 国产网红无码精品视频 | 少妇无套内谢久久久久 | 欧美色就是色 | 性色欲情网站iwww九文堂 | 日韩精品无码一本二本三本色 | 国产性生大片免费观看性 | 天下第一社区视频www日本 | 麻豆av传媒蜜桃天美传媒 | 亚洲精品中文字幕久久久久 | 日本精品少妇一区二区三区 | 国产精品国产三级国产专播 | 99精品无人区乱码1区2区3区 | 亚洲区欧美区综合区自拍区 | 国产成人无码午夜视频在线观看 | 99久久99久久免费精品蜜桃 | 国产成人综合色在线观看网站 | 撕开奶罩揉吮奶头视频 | 伊在人天堂亚洲香蕉精品区 | 动漫av网站免费观看 | 人人澡人人妻人人爽人人蜜桃 | 精品一区二区三区无码免费视频 | 成人一区二区免费视频 | 麻豆果冻传媒2021精品传媒一区下载 | 亚洲小说春色综合另类 | 国产亚洲精品久久久闺蜜 | 亚洲精品久久久久avwww潮水 | 国产亚av手机在线观看 | 日欧一片内射va在线影院 | 精品国产国产综合精品 | 小sao货水好多真紧h无码视频 | 国产综合在线观看 | 久久久久免费精品国产 | 中文无码精品a∨在线观看不卡 | 中文字幕无码视频专区 | 免费中文字幕日韩欧美 | 国产亚洲精品久久久久久国模美 | 人人妻人人澡人人爽欧美精品 | 国语精品一区二区三区 | 男人和女人高潮免费网站 | 一本加勒比波多野结衣 | 少妇被粗大的猛进出69影院 | 国语精品一区二区三区 | 免费观看黄网站 | 妺妺窝人体色www在线小说 | 欧美人妻一区二区三区 | 午夜成人1000部免费视频 | 久久久久se色偷偷亚洲精品av | 国产精品久久久久久无码 | 免费观看又污又黄的网站 | 亚洲日韩av一区二区三区中文 | 狠狠躁日日躁夜夜躁2020 | 久久国产精品精品国产色婷婷 | 久久伊人色av天堂九九小黄鸭 | 欧美丰满熟妇xxxx | 久久久久av无码免费网 | 亚洲中文字幕在线观看 | 真人与拘做受免费视频 | 骚片av蜜桃精品一区 | 日本成熟视频免费视频 | 中文无码成人免费视频在线观看 | 内射老妇bbwx0c0ck | 极品尤物被啪到呻吟喷水 | 亚洲爆乳精品无码一区二区三区 | 亚洲国产一区二区三区在线观看 | 国产精品久久久午夜夜伦鲁鲁 | 永久免费观看美女裸体的网站 | 精品久久久久久人妻无码中文字幕 | 国产精品成人av在线观看 | 久久这里只有精品视频9 | 强伦人妻一区二区三区视频18 | 日本精品人妻无码77777 天堂一区人妻无码 | 综合激情五月综合激情五月激情1 | 波多野结衣一区二区三区av免费 | 熟女少妇在线视频播放 | 成人欧美一区二区三区黑人免费 | 波多野结衣 黑人 | 精品国产av色一区二区深夜久久 | 亚洲熟悉妇女xxx妇女av | 久久久精品欧美一区二区免费 | 伊人久久大香线蕉午夜 | av人摸人人人澡人人超碰下载 | 巨爆乳无码视频在线观看 | 精品无码一区二区三区的天堂 | 亚洲成av人在线观看网址 | 少妇太爽了在线观看 | 色综合视频一区二区三区 | 久久久精品成人免费观看 | 国产suv精品一区二区五 | 无码毛片视频一区二区本码 | 99精品视频在线观看免费 | 女人和拘做爰正片视频 | 久久人人爽人人爽人人片ⅴ | 国产精品理论片在线观看 | 亚洲熟女一区二区三区 | 亚洲の无码国产の无码步美 | 欧美 丝袜 自拍 制服 另类 | www国产亚洲精品久久久日本 | 男女超爽视频免费播放 | 国产成人综合美国十次 | 久久久精品国产sm最大网站 | 国产国产精品人在线视 | 国产精品久久国产精品99 | 国产精品毛多多水多 | 国产猛烈高潮尖叫视频免费 | 亚洲综合无码一区二区三区 | 欧美性猛交xxxx富婆 | 日本一区二区更新不卡 | 装睡被陌生人摸出水好爽 | 四虎国产精品一区二区 | 国产又粗又硬又大爽黄老大爷视 | 亚洲精品午夜国产va久久成人 | 日本熟妇乱子伦xxxx | 无套内谢老熟女 | 麻豆精产国品 | 99久久亚洲精品无码毛片 | 欧美丰满熟妇xxxx性ppx人交 | 国产精品第一区揄拍无码 | 福利一区二区三区视频在线观看 | 精品午夜福利在线观看 | 熟女少妇在线视频播放 | 内射白嫩少妇超碰 | 国产乱子伦视频在线播放 | 久久熟妇人妻午夜寂寞影院 | 亚洲日本va中文字幕 | 成在人线av无码免观看麻豆 | 高清不卡一区二区三区 | 老子影院午夜精品无码 | ass日本丰满熟妇pics | 日韩人妻系列无码专区 | 真人与拘做受免费视频 | 欧洲欧美人成视频在线 | 色 综合 欧美 亚洲 国产 | 国产两女互慰高潮视频在线观看 | 国产精品久久久久久久影院 | 在线天堂新版最新版在线8 | 奇米影视7777久久精品人人爽 | www国产亚洲精品久久久日本 | 国产电影无码午夜在线播放 | 亚洲国产午夜精品理论片 | 精品无人国产偷自产在线 | 日本大香伊一区二区三区 | 少妇性俱乐部纵欲狂欢电影 | 亚洲а∨天堂久久精品2021 | 中文字幕av无码一区二区三区电影 | 大肉大捧一进一出好爽视频 | 日本精品高清一区二区 | 亚洲乱亚洲乱妇50p | 日本免费一区二区三区最新 | 国产一区二区三区影院 | 日韩少妇白浆无码系列 | 久久99精品国产麻豆蜜芽 | 国产成人精品一区二区在线小狼 | 欧美兽交xxxx×视频 | 疯狂三人交性欧美 | 377p欧洲日本亚洲大胆 | 国产精品香蕉在线观看 | 亚洲乱码中文字幕在线 | 无遮挡国产高潮视频免费观看 | 国产精品亚洲综合色区韩国 | 亚洲 激情 小说 另类 欧美 | 国产激情无码一区二区 | 亚洲成av人片在线观看无码不卡 | 色诱久久久久综合网ywww | 成人片黄网站色大片免费观看 | 又湿又紧又大又爽a视频国产 | 色婷婷香蕉在线一区二区 | 荫蒂添的好舒服视频囗交 | 无码精品人妻一区二区三区av | 全黄性性激高免费视频 | 日日鲁鲁鲁夜夜爽爽狠狠 | 无码国内精品人妻少妇 | 最近免费中文字幕中文高清百度 | 久久久精品人妻久久影视 | 熟女少妇人妻中文字幕 | 伊人久久大香线焦av综合影院 | 国产午夜精品一区二区三区嫩草 | 99久久人妻精品免费一区 | 日本熟妇乱子伦xxxx | 久久久久久久女国产乱让韩 | 一本色道婷婷久久欧美 | 欧美黑人性暴力猛交喷水 | 99麻豆久久久国产精品免费 | 国产 浪潮av性色四虎 | 亚洲 a v无 码免 费 成 人 a v | 精品人妻人人做人人爽夜夜爽 | 51国偷自产一区二区三区 | 日本又色又爽又黄的a片18禁 | 欧美丰满熟妇xxxx | 国产三级精品三级男人的天堂 | 岛国片人妻三上悠亚 | 午夜精品久久久久久久久 | 国产精品香蕉在线观看 | 内射白嫩少妇超碰 | 妺妺窝人体色www在线小说 | 亚洲一区二区三区 | 99久久精品国产一区二区蜜芽 | 女人被男人躁得好爽免费视频 | 樱花草在线社区www | 亚洲欧美国产精品久久 | 久久久国产一区二区三区 | 天天爽夜夜爽夜夜爽 | 无码人妻出轨黑人中文字幕 | 美女极度色诱视频国产 | 夜夜躁日日躁狠狠久久av | 成人免费视频在线观看 | 无码成人精品区在线观看 | 在线观看免费人成视频 | 久久国产精品萌白酱免费 | 无码人妻精品一区二区三区不卡 | 欧美 亚洲 国产 另类 | 青青久在线视频免费观看 | 成人一区二区免费视频 | 国产熟妇另类久久久久 | 女人和拘做爰正片视频 | 国产网红无码精品视频 | 人妻互换免费中文字幕 | 77777熟女视频在线观看 а天堂中文在线官网 | 正在播放老肥熟妇露脸 | 国产精品亚洲综合色区韩国 | 99国产精品白浆在线观看免费 | 亚洲阿v天堂在线 | 国产精品嫩草久久久久 | 婷婷六月久久综合丁香 | 国产精品办公室沙发 | 国产97人人超碰caoprom | 美女极度色诱视频国产 | 荫蒂被男人添的好舒服爽免费视频 | аⅴ资源天堂资源库在线 | 欧美人与禽zoz0性伦交 | 动漫av一区二区在线观看 | 人妻aⅴ无码一区二区三区 | 影音先锋中文字幕无码 | 亚洲欧美精品aaaaaa片 | 少妇性荡欲午夜性开放视频剧场 | 玩弄少妇高潮ⅹxxxyw | 美女扒开屁股让男人桶 | 无码一区二区三区在线 | 国产精品内射视频免费 | 一本色道婷婷久久欧美 | 国产人妻精品午夜福利免费 | 国产精品久久久久久久9999 | 精品人妻人人做人人爽夜夜爽 | 久久久精品国产sm最大网站 | 妺妺窝人体色www在线小说 | 天天拍夜夜添久久精品 | 国产精品va在线播放 | 久久综合给合久久狠狠狠97色 | 鲁一鲁av2019在线 | 日日碰狠狠躁久久躁蜜桃 | 欧洲欧美人成视频在线 | 久久午夜夜伦鲁鲁片无码免费 | 中文字幕乱妇无码av在线 | 性欧美熟妇videofreesex | 国产人妻精品一区二区三区不卡 | 3d动漫精品啪啪一区二区中 | 久久久久亚洲精品男人的天堂 | 国产亚洲人成a在线v网站 | 色窝窝无码一区二区三区色欲 | 波多野42部无码喷潮在线 | 大乳丰满人妻中文字幕日本 | 欧美成人家庭影院 | 日韩人妻无码一区二区三区久久99 | 精品久久8x国产免费观看 | 装睡被陌生人摸出水好爽 | 欧美 亚洲 国产 另类 | 国产午夜福利亚洲第一 | 午夜肉伦伦影院 | 亚洲综合色区中文字幕 | 在线亚洲高清揄拍自拍一品区 | 国产熟妇另类久久久久 | 国产人妻精品一区二区三区 | 日产精品99久久久久久 | 久久精品中文闷骚内射 | 亚洲爆乳精品无码一区二区三区 | 欧洲vodafone精品性 | 日本丰满熟妇videos | 久久久中文字幕日本无吗 | 装睡被陌生人摸出水好爽 | 天天拍夜夜添久久精品大 | 久久aⅴ免费观看 | 人妻无码久久精品人妻 | 色 综合 欧美 亚洲 国产 | 乱码午夜-极国产极内射 | 国产超碰人人爽人人做人人添 | 中文字幕无线码免费人妻 | 亚欧洲精品在线视频免费观看 | 无码国产乱人伦偷精品视频 | av无码久久久久不卡免费网站 | 亚洲色在线无码国产精品不卡 | 又大又黄又粗又爽的免费视频 | 丰满人妻一区二区三区免费视频 | 国产婷婷色一区二区三区在线 | 欧洲极品少妇 | 亚洲色欲色欲欲www在线 | 呦交小u女精品视频 | 精品国产麻豆免费人成网站 | 日产国产精品亚洲系列 | 精品国产麻豆免费人成网站 | 成人免费视频视频在线观看 免费 | 伊人久久大香线焦av综合影院 | 又大又黄又粗又爽的免费视频 | 女人被男人爽到呻吟的视频 | 精品国偷自产在线 | 131美女爱做视频 | 丰满人妻被黑人猛烈进入 | 欧美一区二区三区视频在线观看 | 亚洲欧美中文字幕5发布 | 日本成熟视频免费视频 | 黑人巨大精品欧美一区二区 | 在线天堂新版最新版在线8 | 激情亚洲一区国产精品 | 欧美 亚洲 国产 另类 | 红桃av一区二区三区在线无码av | 久久久精品国产sm最大网站 | 精品久久8x国产免费观看 | 99精品无人区乱码1区2区3区 | 国内精品九九久久久精品 | 亚洲精品国产品国语在线观看 | 久久久久se色偷偷亚洲精品av | 日韩无套无码精品 | 国产麻豆精品一区二区三区v视界 | 精品国产福利一区二区 | 日韩亚洲欧美精品综合 | 欧美 丝袜 自拍 制服 另类 | 少女韩国电视剧在线观看完整 | 强奷人妻日本中文字幕 | 中国大陆精品视频xxxx | 亚洲精品午夜国产va久久成人 | 亚洲va中文字幕无码久久不卡 | 无码一区二区三区在线观看 | 欧美人与善在线com | 又粗又大又硬又长又爽 | 美女极度色诱视频国产 | 少妇性荡欲午夜性开放视频剧场 | 久久成人a毛片免费观看网站 | √天堂中文官网8在线 | 国产亚洲美女精品久久久2020 | 性欧美牲交xxxxx视频 | 欧美熟妇另类久久久久久多毛 | 精品国产aⅴ无码一区二区 | 色一情一乱一伦一区二区三欧美 | 最近的中文字幕在线看视频 | 日韩人妻无码一区二区三区久久99 | 久久久国产精品无码免费专区 | 中文字幕无码视频专区 | 国产黄在线观看免费观看不卡 | 国产深夜福利视频在线 | 日韩精品乱码av一区二区 | 亚洲性无码av中文字幕 | 国产精品高潮呻吟av久久4虎 | 狠狠cao日日穞夜夜穞av | 天天综合网天天综合色 | 国产精品高潮呻吟av久久4虎 | 亚洲の无码国产の无码影院 | 中文字幕乱妇无码av在线 | 中文字幕无码日韩专区 | 人妻体内射精一区二区三四 | 人妻插b视频一区二区三区 | 成人毛片一区二区 | 无码人妻av免费一区二区三区 | 国产精品丝袜黑色高跟鞋 | 欧美怡红院免费全部视频 | 男人扒开女人内裤强吻桶进去 | 水蜜桃亚洲一二三四在线 | 国产午夜手机精彩视频 | 中文字幕乱妇无码av在线 | 免费无码av一区二区 | 日产国产精品亚洲系列 | 超碰97人人射妻 | 国语精品一区二区三区 | 97色伦图片97综合影院 | aⅴ在线视频男人的天堂 | 77777熟女视频在线观看 а天堂中文在线官网 | 四十如虎的丰满熟妇啪啪 | 日韩人妻无码一区二区三区久久99 | 又大又黄又粗又爽的免费视频 | 人妻插b视频一区二区三区 | 日韩精品无码一本二本三本色 | 国产成人精品视频ⅴa片软件竹菊 | 精品久久久无码人妻字幂 | 亚洲国产精品成人久久蜜臀 | 国产凸凹视频一区二区 | 久久综合九色综合97网 | 亚洲一区二区三区四区 | 久久综合网欧美色妞网 | 九月婷婷人人澡人人添人人爽 | 中文字幕人妻丝袜二区 | 国产69精品久久久久app下载 | 装睡被陌生人摸出水好爽 | 亲嘴扒胸摸屁股激烈网站 | 国产精品沙发午睡系列 | 久久99久久99精品中文字幕 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 人妻少妇精品无码专区动漫 | 中文毛片无遮挡高清免费 | 久久无码人妻影院 | 嫩b人妻精品一区二区三区 | 女人和拘做爰正片视频 | 日欧一片内射va在线影院 | 欧美激情一区二区三区成人 | 亚洲午夜久久久影院 | 人人澡人人妻人人爽人人蜜桃 | 牲欲强的熟妇农村老妇女视频 | www一区二区www免费 | 国产精品亚洲五月天高清 | 人人妻人人澡人人爽人人精品 | 欧美熟妇另类久久久久久不卡 | 精品无码成人片一区二区98 | 色偷偷人人澡人人爽人人模 | 亚洲精品中文字幕乱码 | 76少妇精品导航 | 久久亚洲精品中文字幕无男同 | 奇米影视7777久久精品 | 国产激情艳情在线看视频 | 亚洲中文字幕av在天堂 | 久久亚洲国产成人精品性色 | 熟女少妇人妻中文字幕 | 伊人久久大香线蕉av一区二区 | 中文字幕久久久久人妻 | 亚洲精品久久久久久一区二区 | 国产内射爽爽大片视频社区在线 | 欧美国产亚洲日韩在线二区 | 久久午夜无码鲁丝片秋霞 | 亚洲日韩av一区二区三区四区 | 亚洲精品午夜无码电影网 | 丰满少妇人妻久久久久久 | 国产精品久久久久久亚洲毛片 | 丰满人妻精品国产99aⅴ | 中文字幕亚洲情99在线 | 精品水蜜桃久久久久久久 | 天天拍夜夜添久久精品 | 图片区 小说区 区 亚洲五月 | 十八禁视频网站在线观看 | 日本熟妇大屁股人妻 | 国产乱子伦视频在线播放 | 亚洲精品中文字幕久久久久 | 18禁黄网站男男禁片免费观看 | 西西人体www44rt大胆高清 | 无遮无挡爽爽免费视频 | 精品国产青草久久久久福利 | 亚洲午夜无码久久 | 老子影院午夜伦不卡 | 亚洲男人av香蕉爽爽爽爽 | √8天堂资源地址中文在线 | 大屁股大乳丰满人妻 | 日韩在线不卡免费视频一区 | 亚洲乱亚洲乱妇50p | 国产精品成人av在线观看 | 亚洲呦女专区 | 一二三四在线观看免费视频 | 精品少妇爆乳无码av无码专区 | 女人被爽到呻吟gif动态图视看 | 亚洲精品国偷拍自产在线观看蜜桃 | 久久精品国产99久久6动漫 | 精品无人区无码乱码毛片国产 | 人妻少妇被猛烈进入中文字幕 | 中文字幕av日韩精品一区二区 | 午夜福利不卡在线视频 | 曰韩少妇内射免费播放 | 亚洲日韩av一区二区三区四区 | 亚洲欧美中文字幕5发布 | 成人av无码一区二区三区 | 精品熟女少妇av免费观看 | 无码乱肉视频免费大全合集 | 日本xxxx色视频在线观看免费 | 最近免费中文字幕中文高清百度 | 欧美成人免费全部网站 | 蜜桃臀无码内射一区二区三区 | 人人妻人人澡人人爽欧美一区 | 樱花草在线播放免费中文 | 中文字幕日产无线码一区 | 国产精品亚洲lv粉色 | 日韩欧美群交p片內射中文 | 久久久中文字幕日本无吗 | 久久国产精品精品国产色婷婷 | 国产乱子伦视频在线播放 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 性色欲情网站iwww九文堂 | 亚洲一区二区三区四区 | 一二三四在线观看免费视频 | 亚洲精品综合一区二区三区在线 | 国产另类ts人妖一区二区 | 久久精品国产日本波多野结衣 | 女人被男人躁得好爽免费视频 | 欧美精品一区二区精品久久 | 成熟人妻av无码专区 | 无码国内精品人妻少妇 | 88国产精品欧美一区二区三区 | 精品无码av一区二区三区 | 欧美日韩亚洲国产精品 | 亚洲无人区午夜福利码高清完整版 | 极品嫩模高潮叫床 | 高中生自慰www网站 | 精品一区二区三区波多野结衣 | 在教室伦流澡到高潮hnp视频 | a片免费视频在线观看 | av在线亚洲欧洲日产一区二区 | 老司机亚洲精品影院无码 | 性欧美videos高清精品 | 久久精品女人天堂av免费观看 | 丰满岳乱妇在线观看中字无码 | 日本护士xxxxhd少妇 | 无码中文字幕色专区 | 亚洲色欲久久久综合网东京热 | 久久综合色之久久综合 | 久青草影院在线观看国产 | 欧美真人作爱免费视频 | 精品偷自拍另类在线观看 | 又粗又大又硬又长又爽 | 熟妇人妻无乱码中文字幕 | 男人扒开女人内裤强吻桶进去 | 免费乱码人妻系列无码专区 | 成熟人妻av无码专区 | 97se亚洲精品一区 | 蜜桃av抽搐高潮一区二区 | 波多野结衣av在线观看 | 久久久久久久女国产乱让韩 | 久久精品人妻少妇一区二区三区 | 久久国内精品自在自线 | 天下第一社区视频www日本 | 亚洲日本va午夜在线电影 | 久久成人a毛片免费观看网站 | 国产两女互慰高潮视频在线观看 | 欧美日韩人成综合在线播放 | 色情久久久av熟女人妻网站 | 久久久精品成人免费观看 | 强奷人妻日本中文字幕 | 国产真实伦对白全集 | 国产精品igao视频网 | 国产免费观看黄av片 | 精品久久久久久亚洲精品 | 中文字幕无码乱人伦 | 成熟人妻av无码专区 | 亚洲热妇无码av在线播放 | 日日天干夜夜狠狠爱 | 宝宝好涨水快流出来免费视频 | 少妇性荡欲午夜性开放视频剧场 | 天干天干啦夜天干天2017 | 国产肉丝袜在线观看 | 国产精品久久精品三级 | 日韩精品乱码av一区二区 | 欧美日韩综合一区二区三区 | 欧美丰满熟妇xxxx | 激情国产av做激情国产爱 | 激情五月综合色婷婷一区二区 | 国产精品99爱免费视频 | 人人澡人人妻人人爽人人蜜桃 | 亚洲精品国产品国语在线观看 | 精品久久久中文字幕人妻 | 大乳丰满人妻中文字幕日本 | 成人无码视频在线观看网站 | 国产精品久久久久影院嫩草 | 国产麻豆精品一区二区三区v视界 | 国产精品久久久久久亚洲影视内衣 | 亚洲午夜无码久久 | 久久aⅴ免费观看 | a片在线免费观看 | 国模大胆一区二区三区 | 亚洲s色大片在线观看 | 在线观看国产一区二区三区 | 丰满人妻被黑人猛烈进入 | 色情久久久av熟女人妻网站 | 丰满少妇熟乱xxxxx视频 | 婷婷丁香六月激情综合啪 | 亚洲午夜福利在线观看 | 亚洲精品综合五月久久小说 | 偷窥日本少妇撒尿chinese | 国产亚洲精品精品国产亚洲综合 | 国产精品永久免费视频 | 狂野欧美激情性xxxx | 大地资源网第二页免费观看 | 熟妇人妻中文av无码 | 国产精品久久久久影院嫩草 | 无码人妻av免费一区二区三区 | 国产一区二区三区影院 | 内射老妇bbwx0c0ck | 亚洲自偷精品视频自拍 | 久9re热视频这里只有精品 | 国产亚洲精品久久久闺蜜 | 国产精品久久久久久亚洲影视内衣 | 在线播放无码字幕亚洲 | 2019nv天堂香蕉在线观看 | 日本乱人伦片中文三区 | 亚洲精品国产品国语在线观看 | 国产国产精品人在线视 | 久久精品国产一区二区三区 | 人妻人人添人妻人人爱 | 久久久久国色av免费观看性色 | 狂野欧美性猛xxxx乱大交 | 又大又黄又粗又爽的免费视频 | 日本一卡2卡3卡四卡精品网站 | 纯爱无遮挡h肉动漫在线播放 | 六月丁香婷婷色狠狠久久 | 东京一本一道一二三区 | 色婷婷av一区二区三区之红樱桃 | 亚洲aⅴ无码成人网站国产app | 久精品国产欧美亚洲色aⅴ大片 | 国产亚洲精品久久久ai换 | 国产口爆吞精在线视频 | 国产av一区二区三区最新精品 | 97夜夜澡人人爽人人喊中国片 | 亚洲人成网站色7799 | 好爽又高潮了毛片免费下载 | 免费乱码人妻系列无码专区 | 亚洲熟女一区二区三区 | 亚洲色在线无码国产精品不卡 | 少妇高潮喷潮久久久影院 | 老子影院午夜精品无码 | 国产成人精品一区二区在线小狼 | 亚洲乱码国产乱码精品精 | 亚洲码国产精品高潮在线 | 人妻少妇被猛烈进入中文字幕 | 一本色道婷婷久久欧美 | 一本大道久久东京热无码av | 午夜丰满少妇性开放视频 | 精品国产乱码久久久久乱码 | 国产精品久久久av久久久 | 国产精品99爱免费视频 | 欧美午夜特黄aaaaaa片 | 亚洲阿v天堂在线 | 国产人妻大战黑人第1集 | 日日夜夜撸啊撸 | 无码一区二区三区在线观看 | 欧美精品一区二区精品久久 | 国产成人精品必看 | 亚洲自偷精品视频自拍 | 日韩精品a片一区二区三区妖精 | 色窝窝无码一区二区三区色欲 | 最近免费中文字幕中文高清百度 | 无码纯肉视频在线观看 | 欧美丰满熟妇xxxx性ppx人交 | 中文字幕av伊人av无码av | 乱人伦人妻中文字幕无码 | 国产69精品久久久久app下载 | 精品厕所偷拍各类美女tp嘘嘘 | 无码av中文字幕免费放 | 国精产品一品二品国精品69xx | 亚洲精品一区国产 | 青青草原综合久久大伊人精品 | 18无码粉嫩小泬无套在线观看 | 日韩人妻无码中文字幕视频 | 内射欧美老妇wbb | 欧美真人作爱免费视频 | 无码人妻av免费一区二区三区 | www国产亚洲精品久久网站 | 高潮喷水的毛片 | 欧美老人巨大xxxx做受 | 精品国产成人一区二区三区 | 亚洲成av人综合在线观看 | 99麻豆久久久国产精品免费 | 好屌草这里只有精品 | 无遮无挡爽爽免费视频 | 亚洲综合无码久久精品综合 | 人人妻人人藻人人爽欧美一区 | 无码一区二区三区在线 | 国产在线无码精品电影网 | 5858s亚洲色大成网站www | 黑人巨大精品欧美一区二区 | 国产成人综合在线女婷五月99播放 | 国产在线aaa片一区二区99 | 国产真实夫妇视频 | 亚洲国产精品久久久天堂 | 一本色道久久综合狠狠躁 | 精品国产麻豆免费人成网站 | 国产精品亚洲综合色区韩国 | 一区二区传媒有限公司 | 成人试看120秒体验区 | 天堂亚洲2017在线观看 | 在线看片无码永久免费视频 | 西西人体www44rt大胆高清 | 国产成人精品视频ⅴa片软件竹菊 | 丰满护士巨好爽好大乳 | 亚洲阿v天堂在线 | 曰韩少妇内射免费播放 | 欧美真人作爱免费视频 | 国产精品.xx视频.xxtv | 人人超人人超碰超国产 | 久久亚洲a片com人成 | 免费播放一区二区三区 | 一个人免费观看的www视频 | 野狼第一精品社区 | 精品久久久无码中文字幕 | 国内精品人妻无码久久久影院蜜桃 |