色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 深入剖析keil c51 --- 從匯編到c51

          深入剖析keil c51 --- 從匯編到c51

          作者: 時間:2016-11-09 來源:網(wǎng)絡(luò) 收藏
          C插入匯編語句
          #pragma asm
          ljmp 0
          #pragma endasm

          如果就這樣直接編譯的話,會出現(xiàn)以下錯誤:
          error C272: asm/endasm requires src-control to be active

          解決方法:在 Files Toolbar 中選中當前C51文件,點右鍵查看文件選項,將 Generate Assembler SRC File 與 Assemble SRC File 的勾選由灰色變?yōu)楹谏词惯@兩項有效!



          第一節(jié)main()函數(shù)和啟動代碼
          匯編是從org 0000h開始啟動,那么keil c51是如何啟動main()函數(shù)的?keil c51有一個啟動程序startup.a51,它總是和c程序一起編譯和鏈接。下面看看它和main()函數(shù)是如何編譯的;
          //主函數(shù)如下;
          void main(void)
          {
          while (1)這是個無條件空循環(huán)。
          {
          }
          }
          把上面的main()函數(shù)編譯后的匯編程序和反匯編代碼整理后對照如下;
          ?C_C51STARTUPSEGMENTCODE
          ?PR?main?TESTMAINSEGMENT CODE

          ?STACKSEGMENTIDATA

          RSEG?STACK
          DS1

          CSEGAT0
          ?C_STARTUP:LJMPSTARTUP1
          C:0x0000020003LJMPSTARTUP1(C:0003)

          RSEG?C_C51STARTUP
          STARTUP1:;該段程序把內(nèi)存清零
          ;MOVR0,#IDATALEN -1
          C:0x0003787FMOVR0,#0x7F
          ;CLRA
          C:0x0005E4CLRA
          ;MOV@R0,A
          IDATALOOP:
          C:0x0006F6MOV@R0,A
          ;DJNZR0,IDATALOOP
          C:0x0007D8FDDJNZR0,IDATALOOP(C:0006)
          ;MOVSP,#?STACK-1;設(shè)制CPU的堆棧起始地址
          C:0x0009758107MOVSP(0x81),#0x07
          ;LJMP?C_START
          C:0x000C02000FLJMPmain(C:000F)

          RSEG?PR?main?TESTMAIN
          main:
          ;void main(void)
          C:0x000F80FESJMPmain(C:000F);main()函數(shù)

          現(xiàn)在分析上面的匯編程序就會明白c51程序是如何啟動的。
          該程序有三個代碼段;
          第一個代碼段?C_STARTUP在0x0000地址,是CPU第一條指令的入口,它只有一條長跳轉(zhuǎn)指令,直接跳到第二個代碼段.
          第二個代碼段?C_C51STARTUP是可重定位的段,該程序把內(nèi)存清零,然后再設(shè)置CPU的堆棧,最后跳轉(zhuǎn)到main()函數(shù).
          第三個代碼段就是main()函數(shù),在keil c51編譯器里main()的段地址名就是?C_START。

          還有一個IDATA數(shù)據(jù)段?STACK就是堆棧,?STACK用于設(shè)制CPU的堆棧起始地址,這是由keil編譯器自動完成的
          /*******************************************************************/
          keil c51函數(shù)的返回值是存儲在r0-r7中的。
          多字節(jié)變量在存儲器里都是低地址存高位,高地址存低位。
          main()函數(shù)的局部變量都是放在存儲器里的,不象別的函數(shù)先選寄存器r0-r7存放,如果不夠用再存入存儲器里。

          看下面的示例;
          c51程序;
          unsigned int SumXY(unsigned int X,Y);
          void main(void)
          {unsigned int a,b,c;
          a=0x5500;
          b=0xaa;
          while (1)
          {
          c=SumXY(a,b);
          }
          }

          unsigned int SumXY(unsigned int X,Y)
          {unsigned int Z;
          Z=X+Y;
          return Z;
          }

          編譯后的反匯編代碼列表;
          C:0x0000020027LJMPSTARTUP1(C:0027)

          4: void main(void)
          5: {unsigned int a,b,c;
          6:a=0x5500;
          C:0x0003750855MOV0x08,#0x55;ram地址0x08和0x09存放變量a=0x5500。
          C:0x0006750900MOV0x09,#0x00
          7:b=0xaa;
          C:0x0009750A00MOV0x0A,#0x00;ram地址0x0A和0x0B存放變量b=0x00AA。
          C:0x000C750BAAMOV0x0B,#0xAA


          8:while (1)
          9:{
          10:c=SumXY(a,b);
          C:0x000FAD0BMOVR5,0x0B;寄存器R4和R5傳遞變量a的值。
          C:0x0011AC0AMOVR4,0x0A
          C:0x0013AF09MOVR7,0x09;寄存器R6和R7傳遞變量b的值。
          C:0x0015AE08MOVR6,0x08
          C:0x0017120020LCALLSumXY(C:0020);調(diào)用函數(shù)SumXY(a,b)求c=a+b
          C:0x001A8E0CMOV0x0C,R6;函數(shù)SumXY(a,b)返回的整型值存在R6和R7里,
          C:0x001C8F0DMOV0x0D,R7;把返回值存入變量c,ram地址0x0C和0x0D存放變量c
          11:}
          12: }
          13:
          C:0x001E80EFSJMPC:000F


          14: unsigned int SumXY(unsigned int X,Y)
          15: {unsigned int Z;
          16:Z=X+Y;
          C:0x0020EFMOVA,R7;參數(shù)變量X放在寄存器R6和R7里
          C:0x00212DADDA,R5;參數(shù)變量Y放在寄存器R4和R5里
          C:0x0022FFMOVR7,A
          C:0x0023EEMOVA,R6
          C:0x00243CADDCA,R4;計算Z=X+Y;
          C:0x0025FEMOVR6,A;局部變量Z也放在寄存器R6和R7里
          17:return Z;;由寄存器R6和R7里返回函數(shù)的值
          C:0x002622RET


          151:MOVSP,#?STACK-1
          152: ; This code is required if you use L51_BANK.A51 with Banking Mode 4
          153: ; EXTRN CODE (?B_SWITCH0)
          154: ;CALL?B_SWITCH0; init bank mechanism to code bank 0
          C:0x002775810DMOVSP(0x81),#0x0D
          155:LJMP?C_START
          C:0x002A020003LJMPmain(C:0003)

          函數(shù)的入口地址,如何調(diào)用匯編函數(shù),c和匯編的混合編程
          /*******************************************************************/
          c函數(shù)的函數(shù)名是一個指向函數(shù)的指針常量,它的值就是函數(shù)的入口地址。
          從匯編程序上看,函數(shù)名也是該匯編函數(shù)代碼段的入口地址標號。
          調(diào)用匯編函數(shù)就是調(diào)用匯編函數(shù)的入口地址標號,但是要注意c函數(shù)名和匯編函數(shù)標號之間的轉(zhuǎn)換規(guī)則。
          1.不帶參數(shù)的匯編函數(shù)標號和c函數(shù)名相同.
          2.帶參數(shù)的匯編函數(shù)標號在c函數(shù)名前加字符_,例如;如果c函數(shù)名是SumXY,匯編函數(shù)標號是_SumXY
          3.再入函數(shù)的匯編函數(shù)標號在c函數(shù)名前加_?,例如;如果c函數(shù)名是DoTask,匯編函數(shù)標號是_?DoTask


          程序示例,該例有兩個文件,一個文件是exam1.c,一個文件是funcasm.c
          主程序文件: exam1.c
          extern unsigned int SumXY(unsigned int X,Y);//聲明外部匯編語言函數(shù),和聲明c函數(shù)方法相同。
          extern void Delay(unsigned char T);

          void main(void)
          {unsigned int a,b,c;
          a=0x5500;
          b=0x00aa;
          while (1)
          {
          Delay(100);
          c=SumXY(a,b);
          }
          }

          混合編程文件: funcasm.c

          //c和匯編的混合編程演示.
          //注意要把匯編語言函數(shù)放在文件前面。

          //求Z=X+Y的匯編語言函數(shù),Z,X,Y是整型數(shù)。
          #pragma ASM
          PUBLIC_SumXY
          ?PR?_SumXY?FUNCASMSEGMENT CODE
          RSEG?PR?_SumXY?FUNCASM
          _SumXY:;求Z=X+Y
          MOVA,R7;參數(shù)X放在寄存器R6和R7里
          ADDA,R5;參數(shù)Y放在寄存器R4和R5里
          MOVR7,A
          MOVA,R6
          ADDCA,R4;撲鉠=X+Y;
          MOVR6,A;局部變量Z也放在寄存器R6和R7里
          RET
          #pragma ENDASM


          //c語言函數(shù),延時函數(shù)。
          void Delay(unsigned char T)
          {unsigned char i;
          for (i=0;i{
          for (i=0;i}
          }

          /**********************************************************************/
          上面程序編譯后的反匯編代碼列表;
          C_STARTUP:
          C:0x0000020041LJMPSTARTUP1(C:0041)

          main:
          //給變量a和b賦值a=0x5500;b=0x00aa;
          C:0x0003750855MOV0x08,#0x55
          C:0x0006750900MOV0x09,#0x00
          C:0x0009750A00MOV0x0A,#0x00
          C:0x000C750BAAMOV0x0B,#0xAA

          //調(diào)用延時函數(shù)Delay(100);
          C:0x000F7F64MOVR7,#0x64
          C:0x0011120025LCALLDELAY(C:0025)

          //求c=SumXY(a,b);
          C:0x0014AD0BMOVR5,0x0B
          C:0x0016AC0AMOVR4,0x0A
          C:0x0018AF09MOVR7,0x09
          C:0x001AAE08MOVR6,0x08
          C:0x001C12003ALCALLSUMXY(C:003A);調(diào)用匯編語言函數(shù)SumXY(unsigned int X,Y)
          C:0x001F8E0CMOV0x0C,R6
          C:0x00218F0DMOV0x0D,R7
          C:0x002380EASJMPC:000F


          //c語言延時函數(shù)的反匯編代碼
          //void Delay(unsigned char T)
          DELAY:
          C:0x0025E4CLRA
          C:0x0026FEMOVR6,A
          C0001:
          C:0x0027EEMOVA,R6
          C:0x0028C3CLRC
          C:0x00299FSUBBA,R7
          C:0x002A500DJNCC0007(C:0039)
          C:0x002CE4CLRA
          C:0x002DFEMOVR6,A
          C0004:
          C:0x002EEEMOVA,R6
          C:0x002FC3CLRC
          C:0x00309FSUBBA,R7
          C:0x00315003JNCC0003(C:0036)
          C:0x00330EINCR6
          C:0x003480F8SJMPC0004(C:002E)
          C0003:
          C:0x00360EINCR6
          C:0x003780EESJMPC0001(C:0027)
          C0007:
          C:0x003922RET


          //匯編語言函數(shù)SumXY(unsigned int X,Y)的反匯編代碼,求Z=X+Y
          SUMXY:
          C:0x003AEFMOVA,R7
          C:0x003B2DADDA,R5
          C:0x003CFFMOVR7,A
          C:0x003DEEMOVA,R6
          C:0x003E3CADDCA,R4
          C:0x003FFEMOVR6,A
          C:0x004022RET

          //程序啟動代碼;
          STARTUP1:
          C:0x004175810DMOVSP(0x81),#0x0D
          C:0x0044020003LJMPmain(C:0003)


          參數(shù)傳遞規(guī)則例子:
          fun1(int a)//a是第一個參數(shù),在R6,R7中傳遞.
          fun2(int b ,int c , int *d)//b在R6,R7中傳遞;C在R4,R5中傳遞;d在R1,R2,R3中傳遞.
          fun3(long e ,long f)//e在R4-R7中傳遞;f不能在寄存器中傳遞,只能在參數(shù)傳遞段中傳遞.
          fun3(float g ,char h)//g在R4-R7中傳遞;h不能在寄存器中傳遞,只能在參數(shù)傳遞段中傳遞


          關(guān)鍵詞: keilc51匯

          評論


          技術(shù)專區(qū)

          關(guān)閉