
① 合理地分配存儲器資源,將前述的目標系統(tǒng)‘數(shù)據結構模型’表示到各存儲器單元。
(相關資料圖)
② CPU寄存器數(shù)量有限,在程序中,大多數(shù)操作都要使用寄存器;并且有的操作使用特定的寄存器(如堆棧操作使用SP/R13等),程序中要合理分配各寄存器的用途。
用計算機語言,對數(shù)據結構模型和流程圖表示的算法進行準確地描述。
① 語法調試:排除程序中的語法錯誤。
② 功能調試:保證程序的邏輯功能正確性。
用文檔形式記錄說明程序的功能、使用方法、程序結構、算法流程等每一個階段的工作。 把解題的方法、步驟用框圖形式表示。如果問題比較復雜,那么可以逐步細化,直到每一框圖可以容易編程為止。流程圖不僅便于程序的編制,且對程序邏輯正確性也比較容易查找和修改。
順序程序是一種最簡單的程序結構,也稱為直線程序,它的執(zhí)行自始自終按照語句的先后順序進行。這種結構的流程圖,除了有一個起始框,一個終止框外,就是若干執(zhí)行框。
例:試編制一程序,完成10+3的操作。
AREA ARMex, CODE, READONLY ; 代碼段名ARMexENTRY ; 程序的入口CODE 32start MOV R0, #10 ; 將立即數(shù)10存入寄存器R0 MOV R1, #3 ; 將立即數(shù)3存入寄存器R1 ADD R0, R0, R1 ; R0 = R0 + R1stop MOV R0, #0x18 ; 這三條指令是ADS調試環(huán)境特約 LDR R1, =0x20026 ;程序運行結束返回編譯器調試環(huán)境 SWI 0x123456END ; 結束
許多實際問題需要根據不同的情況作出不同的處理。在程序中,針對不同的情況把不同的處理方法編制成各自的處理程序段,運行時由機器根據當時的條件自動作出判斷,選擇執(zhí)行相應的處理程序段。這樣的程序結構中,計算機不再完全按指令存儲的順序執(zhí)行,稱之為分支。分支程序使用轉移指令B、子程序調用指令BL或帶狀態(tài)轉移指令BX來實現(xiàn)。
例:給定以下符號函數(shù):
任意給定值,假定為-25,存放在x單元,函數(shù)值存放在y單元;要求根據x中的值來確定y的值。
AREA symbol, CODE, READONLY ; 代碼段的名字 symbol ENTRY ; 程序的入口 CODE32start LDR R0, =x ; 加載數(shù)據段中的變量x地址,存入R0 LDR R1, =y ; 加載數(shù)據段中的變量y地址,存入R1 LDR R2, [R0] ; 加載變量x的值,存入R2compare CMP R2, #0 ; 將R2的值與0作比較 BEQ ZERO ; 如果R2等于0,那么轉向標號ZERO處 BGT PLUS ; 如果R2大于0,那么轉向標號PLUS處 MOV R3, #-1 ; 否則,R2小于0,將-1存入R3中 B stopZERO MOV R3, #0 ; R2等于0,將0存入R3中 B stopPLUS MOV R3, #1 ; R2大于0,將1存入R3中; 續(xù)上段代碼stop STR R3, [R1] MOV R0, #0x18 LDR R1, =0x20026 SWI 0x123456 AREA Data, DATA, READWRITEx DCD -25y DCD 0 END
順序程序和分支程序中的指令每次運行最多只執(zhí)行一次。在實際應用中重復地做某些事的情況很多,這也是計算機最擅長的工作方式。重復地執(zhí)行某些指令,最好用循環(huán)程序來實現(xiàn)。循環(huán)程序的結構---重復地執(zhí)行同一種運算,直到某種條件滿足。
建立循環(huán)初始值。如設置地址指針、計數(shù)器、其他循環(huán)參數(shù)的起始值等。循環(huán)程序的主體業(yè)務代碼,可以是一個順序程序、分支程序或另一個循環(huán)程序。 為執(zhí)行下一個循環(huán)而修改某些參數(shù),尤其循環(huán)控制變量的修改等。
條件控制循環(huán):通過判斷循環(huán)終止條件是否已成立,控制循環(huán)。判斷循環(huán)結束條件是否成立,決定是否繼續(xù)循環(huán)。
例如:計數(shù)控制循環(huán);通過計數(shù)循環(huán)次數(shù),判斷是否已達到預定次數(shù),控制循環(huán)。對循環(huán)結束進行適當處理;有的循環(huán)程序可以沒有這部分。
用計數(shù)控制循環(huán)適用于已知循環(huán)次數(shù)的循環(huán)程序設計
例:從x單元開始的30個連續(xù)字單元中存放有30個無符號數(shù),從中找出最大者送入y單元中。
分析:
根據題意,把第一個數(shù)先送入Rx寄存器,將Rx中的數(shù)與后面的29個數(shù)逐個進行比較,如果Rx中的數(shù)較小,則將該較大的數(shù)送入Rx ;繼續(xù)與余下的數(shù)據逐個比較。在比較過程中, Rx中始終保持較大的數(shù),共計比較29次,則最終Rx中保留了最大數(shù),最后把Rx中的數(shù)(最大者)送入y單元。
AREA max, CODE, READONLY ; 代碼段的名字 max ENTRY ; 程序的入口 CODE32num EQU 29 ; 比較的次數(shù)start LDR R0, =x ; R0指向源數(shù)據塊x LDR R1, =y ; R1指向單元y LDR R2, =num ; R2作為計數(shù)器 LDR R3, [R0] ; 將源數(shù)據塊x中第一個數(shù)加載到R3中compare ADD R0, R0, #4 ; 每進行一次比較,將R0指針地址加4 LDR R4, [R0] ; 依次將源數(shù)據塊x中下一個數(shù)加載到R4中 CMP R3, R4 ; 比較R3和R4中數(shù)的大小 MOVCC R3, R4 ; 如果R3小于R4,則將較大的數(shù)送入R3中 SUBS R2, R2, #1 ; 計數(shù)器值減1 BNE compare ; 如果不為0,那么繼續(xù)跳到compare執(zhí)行 STREQ R3, [R1] ; 如果為0,那么循環(huán)比較結束,R3是最大的數(shù) ; 并且將R3中的數(shù)加載到R1指向的單元(即y)中 stop MOV r0, #0x18 LDR r1, =0x20026 SWI 0x123456 AREA Data, DATA, READWRITEx DCD 73,59,61,34,81,107,225,231,54,43 DCD 100,35,1,42,222,254,34,71,100,31 DCD 33,119,13,44,18,147,55,244,97,3y DCD 0 END
② 適用于已知循環(huán)條件的循環(huán)程序設計
適用于無法確定循環(huán)次數(shù),但知道循環(huán)結束的條件
例:從自然數(shù)1開始累加,直到累加和大于1000為止,統(tǒng)計被累加的自然數(shù)的個數(shù),并把統(tǒng)計的個數(shù)送入n單元,把累加和送入sum單元。
分析:
根據題意,被累加的自然數(shù)的個數(shù)事先未知,因此不能用計數(shù)方法控制循環(huán)。但題目中給定一個條件,即累加和大于1000則停止累加,因此,可以根據這一條件控制循環(huán)。我們用R3寄存器放累加和,用R4寄存器放每次取得的自然數(shù),其中它的值也是統(tǒng)計自然數(shù)的個數(shù)。
AREA SUM, CODE, READONLY ; 代碼段的名字 SUM ENTRY ; 程序的入口 CODE32start LDR R0, =n ; 將數(shù)據段中自然數(shù)的個數(shù)n的地址加載到R0寄存器 LDR R1, =sum ; 將數(shù)據段中自然數(shù)的累加和sum的地址加載到R1寄存器 LDR R3, =0 ; R3存放自然數(shù)的累加和 LDR R4, =0 ; R4用于循環(huán)個數(shù)的統(tǒng)計/每次取得的自然數(shù) LDR R5, =1000 ; R5用于循環(huán)結束的界限值continue ADD R4, R4, #1 ; 取下一個自然數(shù) ADD R3, R3, R4 ; 累加自然數(shù) CMP R3, R5 ; 比較累加和是否超過了1000 BCC continue ; 如果小于1000,那么跳到compare執(zhí)行 STRCS R3, [R1] ; 如果大于1000,那么將累加和存儲到R1所指向的單元中 STRCS R4, [R0] ; 如果大于1000,那么將已累加的自然數(shù)個數(shù)值存儲 ; 到R0所指向的單元中 stop MOV r0, #0x18 LDR r1, =0x20026 SWI 0x123456 AREA Data, DATA, READWRITEn DCD 0 ; 定義累加的自然數(shù)的個數(shù)sum DCD 0 ; 定義自然數(shù)的累加和 END
子程序概念
如果在一個程序中的多處用到同一段程序代碼,那么可以把這段共同的程序代碼抽取出來,寫成一個相對獨立的程序段,每當需要執(zhí)行這段代碼時,就調用這個程序段,執(zhí)行完這個程序段后,再返回原來調用它的程序。這樣編寫程序時,就不必重復寫這段代碼了,而這樣的程序段稱為子程序或子過程。
子程序的調用與返回
主程序中使用BL指令實現(xiàn)子程序的調用
BL子程序名
在子程序結束處,使用如下指令返回到主程序中。
MOV PC, LR
主程序與子程序之間的參數(shù)傳遞
主程序調用子程序時,可以向子程序傳遞一些參數(shù);同樣,子程序運行后也可把一些結果參數(shù)傳回給主程序。主程序與子程序之間的這種信息傳遞稱為參數(shù)傳遞。
三種參數(shù)傳遞方式
寄存器傳遞參數(shù)方式存儲區(qū)域傳遞參數(shù)方式堆棧傳遞參數(shù)方式例:用子程序實現(xiàn)內存區(qū)里的字符串拷貝功能,即將存儲單元中源字符串對應拷貝到目的字符串中。
技術思想:主程序將待傳遞的數(shù)據直接寫入約定的通用寄存器,在子程序中直接使用;或子程序返回后,主程序直接從約定的通用寄存器中獲得子程序的結果數(shù)據。
應用特點:這種方式適合于傳遞較少參數(shù)的應用場合。
解題思路:
通過設定兩個地址指針,分別指向存儲區(qū)中的源字符串和目的字符串;然后通過加載和存儲指令(LDR和STR)的寄存器間接尋址方式,依次從源字符串讀取一個字符數(shù)據,寫入到目的字符串的對應字符位置中,直到遇到源字符串的結束標志’\0’為止。
AREA StrCopy, CODE, READONLY ENTRY CODE32start LDR R1, =srcstr ; R1指向數(shù)據區(qū)的源字符串 LDR R0, =dststr ; R0指向數(shù)據區(qū)的目的字符串 BL strcopy ; 調用子程序strcopy,完成字符串拷貝stop MOV R0, #0x18 ; 程序結束返回編譯器調試環(huán)境 LDR R1, =0x20026 SWI 0x123456strcopy LDRB R2, [R1], #1 ; 將R1指向的單元內容加載到R2中 STRB R2, [R0], #1 ; 將R2中的數(shù)存儲到R0指向的單元中 CMP R2, #0 ; 檢查R0的值是否等于0 BNE strcopy ; 如果不等于0,那么轉到strcopy處執(zhí)行 MOV PC, LR ; 子程序返回 AREA Strings, DATA, READWRITEsrcstr DCB "First string - source",0 ; 源字符串dststr DCB "Second string - destination",0 ; 目的字符串 END
例:通過設置的入口參數(shù)查找函數(shù)地址表,實現(xiàn)選擇不同的函數(shù)功能。
說明:本題中通過事先將函數(shù)地址存放在存儲單元中,通過查找地址表的方法,實現(xiàn)根據“選擇項(choice)”進入不同的函數(shù)體功能。
技術思想:主程序和子程序約定了某一共享內存塊用于參數(shù)傳遞,主程序在BL調用子程序前,先將要傳遞的參數(shù)寫入到約定的存儲單元,子程序可從約定的內存讀取這些參數(shù);子程序返回時,也可以使用該方式將數(shù)據傳給主程序。
應用特點:這種方式可以傳遞大批量數(shù)據。
實現(xiàn)方法:當主程序與子程序有較多的數(shù)據需要傳遞時,可以通過共享內存區(qū)或傳內存數(shù)據塊地址方式來傳遞批量數(shù)據。
通過偽指令ADR直接裝載近距離數(shù)據塊地址;
通過偽指令ADRL直接裝載中距離數(shù)據塊地址;
通過語句LDR Rd, =Label轉載遠距離的數(shù)據塊地址;
AREA Jump, CODE, READONLY num EQU 4 ; 函數(shù)地址表內容的個數(shù) ENTRY CODE32start LDR R0, =choice ; R0指向存儲區(qū)的choice單元 LDR R0, [R0] ; 設置第一個參數(shù):選擇執(zhí)行哪一個函數(shù) MOV R1, #16 ; 設置第1個操作數(shù) MOV R2, #2 ; 設置第2個操作數(shù) BL arithfunc ; 調用子程序arithfuncstop MOV R0, #0x18 ; 程序結束返回編譯器調試環(huán)境 LDR R1, =0x20026 SWI 0x123456arithfunc CMP R0, #num ; 比較R0的值是否超過函數(shù)地址表的個數(shù) MOVHS PC, LR ; 如果大于,那么就返回到標號stop處 ADR R3, JumpTable ; 將函數(shù)地址表的地址作為基地址 LDR PC, [R3, R0, LSL #2] ; 根據R0參數(shù)進入對應的子程序JumpTable ; 函數(shù)地址表的入口基地址 DCD DoAdd ; 加法子程序 DCD DoSub ; 減法子程序 DCD DoMul ; 乘法子程序 DCD DoDiv ; 除法子程序DoAdd ADD R0, R1, R2 ; R0 = R1 + R2 MOV PC, LR ; 返回DoSub SUB R0, R1, R2 ; R0 = R1 - R2 MOV PC, LR ; 返回DoMul MOV R0, R1, LSL R2 ; R0 = R1 << R2 MOV PC, LR ; 返回DoDiv MOV R0, R1, LSR R2 ; R0 = R1 >> R2 MOV PC, LR ; 返回 AREA NUM, DATA, READWRITEchoice DCD 3 ; 0:表示選擇加法子程序 1:表示選擇減法子程序 ; 2:表示選擇乘法子程序 3:表示選擇除法子程序 END
主程序和子程序使用同一個堆棧,主程序在BL調用子程序前,先將要傳遞的參數(shù)壓入到堆棧中,子程序可從堆棧中讀取傳過來的數(shù)據;子程序返回需要向主程序傳遞參數(shù)時,也可使用此方法。
參考文獻:
孟祥蓮.嵌入式系統(tǒng)原理及應用教程(第2版)[M].北京:清華大學出版社,2017.