




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
《嵌入式系統原理與開發》
第11講南京大學計算機系俞建新主講2008年春季2008年10月23日1第5章ARM指令集和匯編語言程序本章主要介紹以下內容:ARM指令集的根本特點與Thumb指令集的區別與x86處理器的區別ARM指令格式ARM尋址方式ARM指令集分類詳解ARM匯編語句格式和程序格式ARM匯編語言的指示符ARM匯編程序標準與標準典型ARM匯編語言程序舉例2008年10月23日2本講主要參考文獻ARM公司英文資料:ADS_AssemblerGuide_B.pdfDDI0100E_ARM_ARM.pdf中文圖書《ARM體系結構與編程》,清華大學出版社《嵌入式系統根底教程》,機械工業出版社2008年10月23日3講授內容ATPCS和AAPCS標準要點ARM編譯器保有的特定關鍵字典型ARM匯編語言程序舉例ARM匯編程序根本結構C程序和CPP程序調用ARM匯編子程序ARM匯編程序調用ARM匯編子程序整數除法子程序S3C44B0X處理器的啟動代碼44BInit.s、option.s、memcfg.s2008年10月23日45.7ARM匯編程序標準存放器的使用規那么堆棧使用規那么參數傳遞規那么2008年10月23日5ATPCSATPCS〔ARM-ThumbProcedureCallStandard〕規定了一些子程序間調用的根本規那么,這些規那么包括子程序調用過程中存放器的使用規那么,數據棧的使用規那么,參數的傳遞規那么。有了這些規那么之后,單獨編譯的C語言程序就可以和匯編程序相互調用。使用ADS的C語言編譯器編譯的C語言子程序滿足用戶指定的ATPCS類型。而對于匯編語言來說,那么需要用戶來保證各個子程序滿足ATPCS的要求。2008年10月23日6AAPCS2007年ARM公司正式推出了AAPCS標準ARMArchtectureProcedureCallStandardAAPCS是ATPCS的改進版目前,AAPCS和ATPCS都是可用的標準2008年10月23日7存放器的使用規那么子程序間通過存放器R0~R3來傳遞參數。這時,存放器R0~R3可記作a0~a3。被調用的子程序在返回前無需恢復存放器R0~R3的內容。在子程序中,使用存放器R4~R11來保存局部變量。這時,存放器R4~R11可以記作v1~v8。如果在子程序中使用了存放器v1~v8中的某些存放器,那么子程序進入時必須保存這些存放器的值,在返回前必須恢復這些存放器的值。在Thumb程序中,通常只能使用存放器R4~R7來保存局部變量。存放器R12用作過程調用中間臨時存放器,記作IP。在子程序之間的連接代碼段中常常有這種使用規那么。2008年10月23日8存放器的使用規那么〔續〕存放器R13用作堆棧指針,記作SP。在子程序中存放器R13不能用作其他用途。存放器SP在進入子程序時的值和退出子程序時的值必須相等。存放器R14稱為連接存放器,記作LR。它用于保存子程序的返回地址。如果在子程序中保存了返回地址,存放器R14那么可以用作其他用途。存放器R15是程序計數器,記作PC。它不能用作其它用途。2008年10月23日9堆棧使用規那么ATPCS規定堆棧為FD類型,即滿遞減堆棧,并且對堆棧的操作是8字節對齊。對于匯編程序來說,如果目標文件中包含了外部調用,那么必須滿足以下條件:〔1〕外部接口的堆棧必須是8字節對齊的。〔2〕在匯編程序中使用PRESERVE8偽指令告訴連接器,本匯編程序數據是8字節對齊的。2008年10月23日10參數傳遞規那么根據參數個數是否固定,可以將子程序分為參數個數固定的子程序和參數個數可變化的子程序。這兩種子程序的參數傳遞規那么是不一樣的。2008年10月23日11參數個數可變子程序參數傳遞規那么對于參數個數可變的子程序,當參數個數不超過4個時,可以使用存放器R0~R3來傳遞參數;當參數超過4個時,還可以使用堆棧來傳遞參數。在傳遞參數時,將所有參數看作是存放在連續的內存字單元的字數據。然后,依次將各字數據傳遞到存放器R0,R1,R2和R3中。如果參數多于4個,那么將剩余的字數據傳遞到堆棧中。入棧的順序與參數傳遞順序相反,即最后一個字數據先入棧。2008年10月23日12參數個數固定子程序參數傳遞規那么如果系統不包含浮點運算的硬件部件,浮點參數會通過相應的規那么轉換成整數參數〔假設沒有浮點參數,此步省略〕,然后依次將各字數據傳送到存放器R0~R3中。如果參數多于4個,將剩余的字數據傳送堆棧中,入棧的順序與參數順序相反,即最后一個字數據先入棧。在參數傳遞時,將所有參數看作是存放在連續的內存字單元的字數據。2008年10月23日13子程序結果返回規那么子程序中結果返回的規那么如下:結果為一個32位整數時,可以通過存放器R0返回;結果為一個64位整數時,可以通過存放器R0和Rl返回;結果為一個浮點數時,可以通過浮點運算部件的存放器f0、d0或s0來返回;結果為復合型浮點數〔如復數〕時,可以通過存放器f0~fn或d0~dn來返回;對于位數更多的結果,需要通過內存來傳遞。2008年10月23日145.7.2ARM編譯器保有的特定關鍵字ARM編譯器支持一些對ANSIC進行擴展的關鍵詞。這些關鍵詞用于聲明變量、聲明函數、對特定的數據類型進行一定的限制。2008年10月23日15用于聲明函數的關鍵詞
〔雙下劃線起頭〕__asm,內嵌匯編__inline,內聯展開__irq,聲明IRQ或FIQ的ISR__pure,函數不修改該函數之外的數據__softfp,使用軟件的浮點連接件__swi,軟中斷函數__swi_indirect,軟中斷函數2008年10月23日16用于聲明變量的關鍵詞register聲明一個變量,告訴編譯器盡量保存到存放器中。_int64該關鍵詞是longlong的同義詞。_global_reg將一個已經聲明的變量分配到一個全局的整數存放器中。2008年10月23日175.8典型ARM匯編語言程序舉例請參看本課程教材《嵌入式系統根底教程》中第151頁開始的第5.2節。2008年10月23日185.8.1條件執行舉例求a和b兩整數最大公約數的C程序Whilea!=b){ If(a>b)a-=b;elseb-=a;}2008年10月23日19條件執行舉例〔續〕如果用ARM匯編子程序來實現,就是求r1和r2兩個存放器中的兩個整數的最大公約數。使用條件執行指令表示只有以下4句代碼: gcd cmp r1,r2 ;cmp與subs功能類似但不存結果 subgt r1,r1,r2 ;如果r1>r2執行此指令 sublt r2,r2,r1 ;如果r1<r2執行此指令 bne gcd ;如果r1<>r2那么轉gcd標號 注:函數結束時r1=r2,都可以用作返回值。2008年10月23日205.8.232位地址送入一個存放器中下面指令段中的load指令根據輸入參數決定調用那個函數。具體做法是將函數的絕對地址通過LDR指令存入在r4存放器中,由于是32的絕對地址,LDR會被解釋成以下操作:將函數的絕對地址放入一個文字池〔Literalpool,嵌入在代碼中的用以存放常數的區域〕。產生一條形如:LDRrn[pc,#offsettoliteralpool]的指令來將這個絕對地址讀入到指定的存放器中。類似地LDR指令也通過上述方法讀入一個32位的絕對數。在下例中,LDR指令將32位絕對數0x11552634讀入到r0存放器中,用作調用routine1或者routine2的參數。2008年10月23日2132位地址送入一個存放器中〔續〕;voidload(inti);voidroutine1(int1);;voidroutine2(int2); AREALOAD,CODE,READONLY IMPORTroutine1 IMPORTroutine2 EXPORTloadload stmfd r13!,{r4,r14} ldr r4,=routine1 ;首先將32位地址存放在附近的區域 cmps r0,#1 ldrne r4,=routine2 ldr r0=0x11552634 ;函數的第1個int參數 bx r4 ldmfd r13!,{r4,r14} bx r142008年10月23日225.8.3從IRQ和FIQ異常處理程序返回從IRQ和FIQ異常處理程序返回時,返回地址應該是LR-4。有三種不同的編程方法,分別列出如下:返回方式1INT_HANDLER <異常處理代碼> ……… SUBSPC,LR,#4 ;PC=R14-42008年10月23日23從IRQ和FIQ異常處理程序返回〔2〕返回方式2INT_HANDLER SUBR14,R14,#4 ;R14-=4 ……… <異常處理代碼> ……… MOVSPC,LR2008年10月23日24從IRQ和FIQ異常處理程序返回〔3〕返回方式3INT_HANDLER SUBR14,R14,#4 ;R14=R14–4 STMFDR13!,{R0-R3,R14} ……… <異常處理代碼> ……… LDMFDR13!,{R0-R3,R15}2008年10月23日255.8.4調用ARM匯編語言子程序在ARM匯編語言中,子程序調用是通過BL指令完成的。BL指令的語法格式如下:BLsubname其中,subname是調用的子程序的名稱。BL指令完成兩個操作:將子程序的返回地址放在LR存放器中,同時將PC存放器值設置成目標子程序的第一條指令地址。在子程序返回時可以通過將LR存放器的值傳送到PC存放器中來實現。子程序調用時通常使用存放器R0~R3來傳遞參數和返回結果。2008年10月23日26調用匯編子程序舉例子程序DOADD完成加法運算,操作數放在R0和R1存放器中,結果放在R0中。 AREA EXAMPLE2,CODE,READONLY ENTRYstart MOVr0,#10 ;R0設置輸入參數 MOVr1,#3 ;R1設置輸入參數 BL doadd ;調用子程序doadddoadd ADDr0,r0,r1 ;子程序實體 MOV pc,lr ;從子程序中返回 END2008年10月23日275.8.5循環結構在ARM匯編中,沒有專門的指令用來實現循環,一般通過跳轉指令加條件碼的形式來實現。可以采用比較指令CMP或者減法指令SUB等實現。參看下面的指令段:LOOP ADD R4,R4,R0 ADD R0,R0,#1 CMP R0,R1 BLE LOOP;R0小于等于R1場合跳轉在做完了兩次加法操作后,比較R0,R1的值,影響條件標志。最后的條件跳轉語句根據CMP指令執行的結果來決定是否進行循環。2008年10月23日285.8.6數據塊復制示范程序本程序將數據從源數據區復制到目標數據區復制時,以8個字為單位進行。對于最后所剩缺乏8個字的數據,以字為單位進行復制,這時程序跳轉到copywords處執行。在進行以8個字為單位的數據復制時,保存了所用的8個工作存放器。程序清單如下面所示。2008年10月23日29數據塊復制示范程序〔1〕;設置本段程序的名稱(Block)及屬性AREABlock,CODE,READONLY;設置將要復制的字數numEQU20;標識程序入口點ENTRYStart;r0存放器指向源數據區src LDRr0,=src;r1存放器指向目標數據區dst LDRr1,=dst2008年10月23日30數據塊復制示范程序〔2〕;r2指定將要復制的字數 MOVr2,#num;設置數據棧指針(r13),用于保存工作存放器數值 MOVsp,#0x400;進行以8個字為單位的數據復制blockcopy;需要進行的以8個字為單位的復制次數 MOVSr3,r2,LSR#3;對于剩下缺乏8個字的數據,跳轉到copywords,以字為單位復制 BEQcopywords;保存工作存放器,壓棧 STMFDsp!,{r4~r11}2008年10月23日31數據塊復制示范程序〔3〕octcopy;從源數據區讀取8個字的數據,放到8個存放器中,并更新目標數據區指針r0 LDMIAr0!,{r4-r11};將這8個字數據寫入到目標數據區中,并更新目標數據區指針r1 STMIAr1!,{r4-r11};將塊復制次數減1 SUBSr3,r3,#1;循環,直到完成以8個字為單位的塊復制 BNEoctcopy;恢復工作存放器值,出棧 LDMFDsp!,{r4-r11}2008年10月23日32數據塊復制示范程序〔4〕copywords;剩下缺乏8個字的數據的字數 ANDSr2,r2,#7;數據復制完成 BEQstopwordcopy;從源數據區讀取1個字的數據,放到r3存放器中,并更新目標數據區指針r0,后索引偏移 LDRr3,[r0],#4;將這r3中數據寫入到目標數據區中,并更新目標數據區指針r1,后索引偏移 STRr3,[r1],#42008年10月23日33數據塊復制示范程序〔5〕;將字數減1 SUBSr2,r2,#l;循環,直到完成以字為單位的數據復制 BNEwordcopy;定義數據區BlockDataAREABlockData,DATA,READWRITE;定義源數據區src及目標數據區dstsrcDCD1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4dstDCD0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;結束匯編 END2008年10月23日345.8.7內嵌匯編內嵌匯編〔inlineassembly〕的語法如下:__asm{ 指令[;指令]/*注釋*/ … [指令]}2008年10月23日35內嵌匯編的指令用法內嵌在C或者C++程序中的ARM匯編指令與普通〔ADS〕格式的ARM匯編指令有所不同。其主要原因在于C/C++編譯器在編譯C/C++源代碼的同時要兼顧處理內嵌匯編程序,因此CPU的內部存放器資源使用有額外約束。以下講解內嵌ARM匯編指令的用法。2008年10月23日36ARM內嵌匯編程序的操作數內嵌匯編指令中作為操作數的存放器和常量可以是表達式。這些表達式可以是char,short或int類型,而且這些表達式都是作為無符號數進行操作。假設需要帶符號,用戶需要自己處理與符號有關的操作。編譯器將會計算這些表達式的值,并為其分配存放器。2008年10月23日37ARM內嵌匯編程序的物理存放器內嵌匯編程序中使用物理存放器有以下限制。不能直接向PC存放器賦值,程序跳轉只能使用B或BL指令實現不要使用過于復雜的C表達式,因為將會需要較多的物理存放器,這將導致與其他指令中用到的物理存放器產生使用沖突。編譯器可能會使用R12或R13存放編譯的中間結果,在計算表達式的值時可能會將存放器R0~R3,R12和R14用于子程序調用。因此在內嵌的匯編指令中不要將這些存放器同時指定為指令中的物理存放器。通常內嵌的匯編指令中不要指定物理存放器,因為這可能會影響編譯器分配存放器,進而影響代碼的效率。2008年10月23日38其他內嵌匯編程序的編寫注意點常量:在內嵌匯編指令中,常量前面的“#”可以省略。指令展開:內嵌匯編指令中,如果包含常量操作數,該指令可能被內嵌匯編器展開成幾條指令。標號:C程序中的標號可以被內嵌的匯編指令使用,但是只有指令B可以使用C程序中的標號,而指令BL那么不能使用。內存單元的分配:所有的內存分配均由C編譯器完成,分配的內存單元通過變量供內嵌匯編器使用。內嵌匯編器不支持內嵌程序中用于內存分配的偽指令。2008年10月23日39內嵌匯編程序中的SWI和BL指令SWI和BL指令:在兩個指令使用到內嵌匯編中,除了正常的操作數域外,還必須增加以下3個可選的存放器列表:
用于輸入參數的存放器列表。
用于存儲返回結果的存放器列表。
用于表示那些存放器將有可能會被修改的存放器列表。2008年10月23日40內嵌匯編代碼舉例字符串復制〔1〕#include<stdio.h>voidstr_cpy(constchar*src,char*dst){ intch; __asm { loop://普通ARM匯編代碼中的標號后面不能跟冒號。C程序中 //的標號可以被內嵌的匯編指令使用。ARM內嵌匯編代碼中 //只有B指令可以使用C的標號,而BL指令不能夠使用C代碼 //的標號。C程序的標號后面跟冒號,由Goto語句轉向標號處。 LDRB ch,[src],#1 STRB ch,[dst],#1 CMP ch, #0 BNE loop }}2008年10月23日41內嵌匯編代碼舉例字符串復制〔2〕intmain(void){ constchar*a="Helloworld!\n"; charb[20]; //doinlineassemblyroutinestr_cpy(a,b) __asm { MOVR0,a//將串a的串首地址送到R0存放器 MOVR1,b//將串b的串首地址送到R1存放器 BLstr_cpy,{R0,R1}//調用C函數str_cpy() } printf("Originalstring:%s\n",a); printf("Copiedstring:%s\n",b);//半主機方式顯示復制前后的兩個串 return(0);}2008年10月23日425.8.8ARM匯編、C和C++混合編程在C/C++程序中如果必須使用匯編指令來完成某些操作,可以采用兩種方法:1.采用內嵌匯編,即在C/C++源程序中嵌入一塊匯編代碼,讓這塊匯編代碼來完成特定的操作;2.將必須使用匯編代碼的局部獨立編寫成在一個文件中,形成一個子程序,C/C++程序可以調用這些匯編程序來完成特定的操作。2008年10月23日43C/C++程序與ARM匯編語言程序的相互調用C/C++程序與匯編程序相互調用時,應遵守相應的ATPCS,主要有五種調用。ARM匯編子程序調用C語言子程序ARM匯編子程序調用C++語言子程序C語言程序調用ARM匯編語言子程序C++語言程序調用ARM匯編語言子程序C語言程序調用C++語言子程序下面就每種具體情況逐一舉例說明。2008年10月23日44C/C++程序調用ARM匯編子程序要點設計匯編程序必須遵守ATPCS,保證程序調用時參數的正確傳遞。在匯編程序中使用EXPORT指示符聲明本程序可以被別的程序調用。在C語言程序中使用extern關鍵詞聲明該匯編程序可以被調用,C++語言程序使用extern“C”來聲明該匯編程序可以被調用。2008年10月23日45例1C程序調用ARM匯編子程序/*main_0522.csemihostingoutputmode*/#include<stdio.h>externintasmfile(intarg1,intarg2,intarg3);intmain(void){inta1=1,a2=2,a3=4;printf("ExampleofCProgramcallingAssemblyprogram!\n");printf("(%d+%d+%d)*600=%d\n",a1,a2,a3,asmfile(a1,a2,a3));}2008年10月23日46C程序調用ARM匯編子程序〔續〕;ASM_0522.sEXPORTasmfileAREAMy_pro,CODE,READONLYasmfile STMFDSP!,{R4-R6,R8,R7} addr0,r0,r1 addr0,r0,r2 mov r4,#600 mulr3,r0,r4 mov r0,r3 LDMFDSP!,{R4-R6,R8,R7} movpc,lr END2008年10月23日47例2ARM匯編程序調用C語言子程序本案例程序比較兩個IP地址的大小,a1~a4存放IP地址1的值〔按照ATPCS傳遞參數〕,b1~b4存放IP地址2的值〔通過棧傳遞參數〕,如果IP地址1的值大于IP地址2的值那么返回1,如果IP地址1的值小于IP地址2的值那么返回-1,如果兩者相等那么返回零。IP地址1取值:192,168,1,152,IP地址2取值:172,0,0,1512008年10月23日48例2ARM匯編程序調用C子程序〔續〕/*C代碼局部*/#include<stdio.h>externintfunction(void);/*聲明function是外部函數*/intcompare_ip(inta1,inta2,inta3,inta4,intb1,intb2,intb3,intb4){ if(a1!=b1) returna1>b1?1:-1; if(a2!=b2) returna2>b2?1:-1; if(a3!=b3) returna3>b3?1:-1; if(a4!=b4) returna4>b4?1:-1; return0;}intmain(){ printf("Thisisaexampleofsemihosting\n"); printf("resultis%d\n",function());}2008年10月23日49例2ARM匯編調用C子程序〔續2〕 AREAFUNCTION,CODE,READONLY;ARM匯編子程序 IMPORTcompare_ip EXPORTfunctionfunction STMFD r13!,{r0-r3,r14} ;保存存放器到棧區 MOV r3,#0x97 ;存入IP地址2的4個數,0x97=151 MOV r2,#0 ;存入0 MOV r1,#0 ;存入0 MOV r0,#0xac ;存入0xac=172 STMIA r13,{r0-r3} ;R0-R4覆蓋存入棧區的R0-R4位置 MOV r3,#0x98 ;存入IP地址1的4個數,0x98=152 MOV r2,#1 ;存入1 MOV r1,#0xa8 ;存入0xa8=168 MOV r0,#0xc0 ;存入0xc0=192 BL compare_ip;0x0 ;調用C語言函數進行IP值比較 ADD r13,r13,#0x10 ;棧指針上移4個字〔元素〕 LDR pc,[r13],#4 ;將保存的r14值加載到PC,而后r13加4 END ;本段匯編代碼的操作圖解參看下一頁2008年10月23日50例2ARM匯編調用C子程序〔續3〕ARM匯編語言子程序Function的棧區操作圖解2008年10月23日51例3ARM匯編程序調用C++子程序//這是C++調用ARM匯編的范例程序//文件名:try_C++_call_S//main函數位于這個.CPP文件extern"C"voidasmfunc(void);intmain(void){
asmfunc();}2008年10月23日52例3ARM匯編調用C++子程序〔續〕;這個ARM匯編語言程序被main函數調用;該函數又調用ARM匯編函數cppfunc; AREAmypro,CODE,READONLY IMPORTcppfunc EXPORTasmfuncasmfunc STMFDsp!,{lr}
BLcppfunc LDMFDsp!,{pc} END2008年10月23日53例3ARM匯編調用C++子程序〔續2〕#include<iostream>#include<cmath>usingnamespacestd;constdoublePI=3.1415926;classpoint{public: point(){x=0;y=0;}; point(doublea,doubleb){x=a;y=b;}; point(point&a){x=a.x;y=a.y;}; ~point(){};2008年10月23日54例3ARM匯編調用C++子程序〔續3〕doubleGetX(){returnx;};doubleGetY(){returny;};point&Move(constpoint&a){this->x+=a.x;this->y+=a.y;return*this;};doubleGetArea(point&a){returnabs((this->x-a.x))*abs((a.y-this->y));};point&Rotate(constintdegree){ doubletempX=this->x,tempY=this->y,length,a; a=atan(tempY/tempX); length=sqrt(tempX*tempX+tempY*tempY);2008年10月23日55例3ARM匯編調用C++子程序〔續4〕
this->x=length*cos(a+degree*PI/180); this->y=length*sin(a+degree*PI/180); return*this; };private: doublex,y;};2008年10月23日56例3ARM匯編調用C++子程序〔續5〕extern"C"intcppfunc(){ pointa(1.5,1.9); pointb(2.0,0.0); pointc(1.0,1.0); a.Move(b); c.Rotate(90); cout<<"ais("<<a.GetX()<<","<<a.GetY()<<")"<<endl; cout<<"bis("<<b.GetX()<<","<<b.GetY()<<")"<<endl; cout<<"cis("<<c.GetX()<<","<<c.GetY()<<")"<<endl; cout<<"aandb'sretangleareais"<<a.GetArea(b)<<endl; cout<<"bandc'sretangleareais"<<b.GetArea(c)<<endl; cout<<"aandc'sretangleareais"<<a.GetArea(c)<<endl;}2008年10月23日57例3ARM匯編程序調用C++子程序的半主機方式運行結果輸出截圖2008年10月23日58例4C語言程序調用C++子程序/*main.c源代碼清單*/#include<stdio.h>structS{charca[12];};externvoidcppfunc(structS*p);
/*DeclarationoftheC++functiontobecalledfromC*/voidf(structS*s){/*f是C語言函數*/ char*tmp="Hello"; char*source=s->ca; while(*source++=*tmp++); //copy"hello"tos->ca
cppfunc(s);/*調用C++函數cppfunc(),初始化's'*/}2008年10月23日59例4C語言程序調用C++子程序〔續1〕intmain(){ structSs; f(&s);/*調用C語言的函數f()*/ printf("%s\n",s.ca); return0;}2008年10月23日60例4C語言程序調用C++子程序〔續2〕//CPP.CPP函數清單classS{//hasnobaseclassesorvirtualfunctionspublic: charca[12]; S(){ca[0]='\0';}};extern"C"voidcppfunc(S*p){//DefinitionoftheC++functiontobecalledfromC.//ThefunctioniswritteninC++,onlythelinkageisC char*tmp="world!"; char*source=p->ca; while(*source!='\0') //掃描過原先在c程序中的賦值 source++; *source++=''; //將結束符改為空格 while(*source++=*tmp++);//copy"world"top->ca}2008年10月23日61ARM匯編〔子〕程序的相互調用根本要點:如果一個ARM匯編語言程序文件含有調用外部匯編語言程序文件中子程序〔函數〕的指令,那么需要用IMPORT指示符來指明將要調用的子程序名稱。如果本匯編語言程序文件中的某個子程序〔函數〕,需要被外部的ARM匯編語言程序文件中的語句調用,那么需要用EXPORT指示符來指明將要被調用的子程序〔函數〕名稱。被執行的匯編子程序在運行前,要注意將存放器組壓入棧區,返回時要注意將棧區保存的工作現場恢復到處理器的存放器組。2008年10月23日62例5ARM匯編子程序嵌套調用舉例-1這里給出的ARM匯編程序嵌套調用范例程序做如下計算:求自然數1到n的階乘的總和,半主機方式輸出運算結果如以下圖所示。第3行顯示的是1~9的階乘,第2行顯示的是1!+2!+3!+4!+5!+6!+7!+8!+9!之總和。2008年10月23日63例5ARM匯編子程序嵌套調用舉例-2/*Thisprogramissemihostingoutputmode*//*Firstthemainfunctioncallassemblysummingsubprogram*//*Thenthesummingsubprogramcallassemblyfactorialsubprogram*/#include<stdio.h>externintasmFac(intn);structfactorial_sum{intcal_fn;intsum_fn;intfn[9];};externstructfactorial_sum*summing(structfactorial_sum*arg1);2008年10月23日64例5ARM匯編子程序嵌套調用舉例-3intmain(void){ intj; structfactorial_sumfac={9,0,{1,1,1,1,1,1,1,1,1} };//設置參數 structfactorial_sum*result; //申請變量作為返回值 printf("ExampleofamultiAssemblyprogramcalling!\n"); result=summing(&fac); //調用求和函數R0存放的是FAC變量的首地址 printf("Thetotalsumis%d\n",result->sum_fn); //輸出結果 for(j=0;j<9;j++){ printf("%d\t",(result->fn)[j]); } }2008年10月23日65例5ARM匯編子程序嵌套調用舉例-4;thedetailsofparameterstransfercomesfromATPCS;iftherearemorethan4args,stackwillbeusedEXPORTsummingIMPORTasmFac ;說明用到了其他文件中的子匯編程序AREASUMMING,CODE,READONLYsumming STMFD SP!,{R4-R5} ldr r1,[r0] ;r1=cal_fn mov r2,#1 ;將r2設置為當前需要計算的階乘數, ;它從1變化到cal_fn add r3,r0,#8 ;將r3指向fn數組 mov r5,#0 ;r5為總和,初始值置為0loop cmp r1,r2 ;將cal_fn與當前所需計算的階乘值比較 blt back ;如果小于,那么返回2008年10月23日66例5ARM匯編子程序嵌套調用舉例-5 STMFD SP!,{R0-R3,lr} ;保存ro~r3,lr ;因為調用了外部文件的匯編子程序 mov r0,r2 ;將r0設置為當前所需計算的階乘值 bl asmFac ;調用階乘函數 mov r4,r0 ;將返回值(階乘)存在r4中 ldmfd SP!,{R0-R3,lr} ;恢復先前保存的存放器值 str r4,[r3] ;將計算所得的階乘值存入數組中 add r3,r3,#4 ;將r3指向數組的下一個 add r5,r5,r4 ;將階乘值參加總和 add r2,r2,#1 ;計算下一個階乘 bloop ;循環back str r5,[r0,#4] ;將計算所得的總和存入結構體中 ldnfd SP!,{R4-R5} ;恢復存放器值 mov pc,lr ;summing子程序返回 END ;匯編代碼結束2008年10月23日67例5ARM匯編子程序嵌套調用舉例-6;thedetailsofparameterstransfercomesfromATPCS;iftherearemorethan4args,stackwillbeused;這個ARM匯編函數也可以被C函數調用,符合ATPCS標準;intasmFac(intn)EXPORTasmFacAREAASMFILE,CODE,READONLYasmFac mov r1,r0 ;r1=nloop subs r1, r1,#1 ;將r1減1 mulgt r0, r1,r0 ;如果大于0,那么乘上r1(相當與n*(n-1)) bgt loop ;如果大于0,繼續 movpc,lr ;asmFac子程序返回 END ;匯編代碼結束2008年10月23日68ARM9五級流水線互鎖現象舉例互鎖使得指令的執行周期增加,下面舉例說明:LDR r1,[r2,#8]ADD r0,r0,r1MOV r2,#02008年10月23日695.8.95級流水線的互鎖問題ARM9指令流水線有5級。五個流水線階段分別是:取指、譯碼、ALU、LS1、LS2。流水線的增加增加了系統的吞吐量,但也引起了流水線互鎖〔pipelineinterlock〕,即一條指令需要前一條指令的執行結果,而這時結果還沒有出來,那么處理器就會等待。2008年10月23日70ARM9五級流水線互鎖現象的圖解流水線取值譯碼ALULS1LS2周期1LDR周期2ADDLDR周期3MOVADDLDR…周期4…MOVADDLDR…周期5MOVADD--周期6MOV-2008年10月23日71ARM9五級流水線互鎖現象的解決如果將指令順序該為:LDR r1,[r2,#8]MOV r2,#0ADD r0,r0,r1這樣的指令順序執行由于沒有產生流水線互鎖,執行上述指令只需要3個周期,即一個時鐘周期完成一條指令。在保持結果正確無誤的前提下,比修改之前減少了一個時鐘周期。2008年10月23日725.8.10ARM匯編語言程序中的宏定義和宏指令指示符MACRO和MENDMACRO指示符標識宏定義的開始,MEND標識宏定義的結束。用MACRO及MEND定義一段代碼,稱為宏定義體,這樣在程
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 安全試題分類標準及答案
- 安全生產模擬試題及答案
- 安全考核試題及答案
- 2025年工業領域CCS技術應用案例深度解讀報告
- 《編制說明-公安交通集成指揮平臺數據共享技術規范》
- 中國動畫課件下載網
- 淤血肝超聲診斷
- 肝硬化患者的飲食護理
- 春節學生安全教育
- 紅色教育基地分享
- 氧、氬、二氧化碳氣體充裝企業風險點分級管控資料
- 醫學專題杏林中人乳腺穴位敷貼
- 公路水運工程施工安全標準化指南(42頁)
- 人教版 2021-2022學年 五年級下冊數學期末測試試卷(一)含答案
- 錫槽缺陷手冊(上
- (完整版)全國校園籃球特色學校申報材料
- 西門子SAMA圖DEH邏輯講解
- 檢測交通視頻中運動目標的程序設計
- 施工現場安全、文明施工檢查評分表
- 管道支架重量計算表常用圖文精
- 國家開放大學《數據結構(本)》單元測試參考答案
評論
0/150
提交評論