STARTUP.A51文件分析

$NOMOD51  ;Ax51宏汇编器控制命令,禁止预定义的8051。使编译器不使能预定义的;8051符号,避免产生重复定义的错误。
;------------------------------------------------------------------------------
;  This file is part of the C51 Compiler package
;  Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc.
;------------------------------------------------------------------------------
;  STARTUP.A51:  This code is executed after processor reset.
;
;  To translate this file use A51 with the following invocation:
;
;     A51 STARTUP.A51
;
;  To link the modified STARTUP.OBJ file to your application use the following
;  BL51 invocation:
;
;     BL51 <your object file list>, STARTUP.OBJ <controls>
;     BL51是Keil使用的链接器(Linker),这是命令行的使用格式,一般不用,使用IDE环境,
;用project管理,有相应的按钮可以实现该功能.
;------------------------------------------------------------------------------
;
;  User-defined Power-On Initialization of Memory ---  初始化RAM单元
;
;  With the following EQU statements the initialization of memory---用下面的EQU声明初;始化ram单元
;  at processor reset can be defined:
;
; the absolute start-address of IDATA memory is always 0
IDATALEN EQU 80H ; the length ofIDATA memory in bytes.--根据你选用的芯片可以适
;当的修改这些值。IDATALEN 只是一个标号,EQU只是做宏一样的替换,类似于C语;言中的#define uint (unsigned int) ,以上的代码使得程序以后在碰到IDATALEN时替换;成80H


XDATASTART      EQU     0H      ; the absolute start-address of XDATA memory--以下;两项根据目标系统的外设配置和连接自己修改  
XDATALEN        EQU     0H      ; the length of XDATA memory in bytes.


PDATASTART      EQU     0H      ; the absolute start-address of PDATA memory
PDATALEN        EQU     0H      ; the length of PDATA memory in bytes.
;
;  Notes:  The IDATA space overlaps physically the DATA and BIT areas of the
;          8051 CPU. At minimum the memory space occupied from the C51 
;          run-time routines must be set to zero.
;------------------------------------------------------------------------------
;
;  Reentrant Stack Initilization   --注意:再入堆栈的方向区别于芯片自带的堆栈的生长方;式,自顶向下生长的!而SP是是自底向上的!
        
;   --且再入堆栈是由编译器自己管理的,一般不必去关心,只是在有再入函数的时候,根据;函数的存储器模式使用相应的RAM空间做为再入堆栈。 
;  The following EQU statements define the stack pointer for reentrant
;  functions and initialized it:
;Keil C默认情况不是用堆栈来传递参数的,所以造成函数不可重入,Keil要求用户显示声;明函数是否具有可重入属性,以便为C函数调用初始化栈。
;  Stack Space for reentrant functions in the SMALL model.
IBPSTACK        EQU     0       ; set to 1 if small reentrant is used.
IBPSTACKTOP     EQU     0FFH+1  ; set top of stack to highest location+1.
;
;  Stack Space for reentrant functions in the LARGE model.      
XBPSTACK        EQU     0       ; set to 1 if large reentrant is used.
XBPSTACKTOP     EQU     0FFFFH+1; set top of stack to highest location+1.
;
;  Stack Space for reentrant functions in the COMPACT model.    
PBPSTACK        EQU     0       ; set to 1 if compact reentrant is used.
PBPSTACKTOP     EQU     0FFFFH+1; set top of stack to highest location+1.
;不同内存模式下的堆栈。Keil 编译器中有三种模式设置:
;Small:所有的变量都放在内部RAM区
;Compact:所有变量在默认情况下都会放在外部RAM的低256字节中(可由R0寻址)
;Large:所有变量都放在外部RAM中(DPTR寻址)
;这是由51处理器繁多的寻址模式导致的,不同的寻址模式有不同的效率
;
;------------------------------------------------------------------------------
;
;  Page Definition for Using the Compact Model with 64 KByte xdata RAM
;
;  The following EQU statements define the xdata page used for pdata
;  variables. The EQU PPAGE must conform with the PPAGE control used
;  in the linker invocation.
;
PPAGEENABLE     EQU     0       ; set to 1 if pdata object are used.
;
PPAGE           EQU     0       ; define PPAGE number.
;
PPAGE_SFR       DATA    0A0H    ; SFR that supplies uppermost address byte

;     (most 8051 variants use P2 as uppermost address byte)

; 很多的外部页面寻址以P2;口为高位地址的数值,有使用外部页面RAM的情况;     对PPAGEENABLE 设置为1 ,根据硬件连接修改PPAGE的值。

;------------------------------------------------------------------------------
; Standard SFR Symbols ---标准的SFR符号
ACC   DATA   0E0H;关键字DATA A51伪指令定义单片机内部数据存储器字节地址的符号
B       DATA    0F0H
SP      DATA    81H
DPL     DATA    82H
DPH     DATA    83H
                                  NAME          ?C_STARTUP   ;定义当前程序模块的目标模块名


?C_C51STARTUP     SEGMENT   CODE       ;定义一个可再定位的段符号名和段所在的;存储空间,汇编器产生的这个段符号名在BL51/L51连接定位时用
?STACK                     SEGMENT   IDATA      ;定义一个IDATA段,段名?STACK ,符合;C51编译器的命名规则   (SEGMENT  用于定义一个段)
                                  RSEG           ?STACK    ;声明当前段是IDATA段,段中保留空间;RSEG伪指令用于选择一个事先用SEGMENT伪指令声明的普通段
                                  DS                1 ; DS是预留空间定义指令
                                  EXTRN  CODE (?C_START)  ;声明本模块引用的外部全局符号,;用于和C相连接在.src文件中可以看到这个符号 
                                  PUBLIC        ?C_STARTUP     ;声明可被其他模块使用的全局符;号,由.src文件中可以看出这个符号的作用。
                                  CSEG           AT         0      ;结束当前的IDATA段,产生一个位于;CODE中新段,起始地址是0000H。代码段的起始点
?C_STARTUP:           LJMP           STARTUP1       ;C编译器编译源程序后,芯片复位之;后的复位代码第一个就是执行这条语句。
                                  RSEG           ?C_C51STARTUP  ;选择段名为?C_C51STARTUP;的CODE段为当前段,存储程序代码。
STARTUP1:
IF IDATALEN <> 0                      ;条件汇编指令,有IDATA区的话,清IDATA区。
                                  MOV                   R0,#IDATALEN – 1  ;区域为0——IDATALEN-1
                                  CLR             A
IDATALOOP:      MOV                   @R0,A
                                  DJNZ                  R0,IDATALOOP
ENDIF   ;(一)如果上;面idatalen=80H,那么是对0~7FH清零;如果你的程序是改写成:;IDATALEN    EQU    0100H    ;;就是对0~FFH清零。
;             (二)二、如何按你意愿加载这段程序
;一般考虑到这个往往是你的设计中要区分上电复位和程序复位。有时候当程序复位时
;你不希望一些内存单元被清零了,那么你不对startup.a51作点修改,就不行了。
;默认是自动加载这段startup.a51的。
;所以你要这样做:
;把lib目录下的原始startup.a51文件拷到你的项目所在目录下,再把你项目目录下的
;这个startup.a51加入到你的项目中

;比如改成:
;IDATALEN    EQU    00H    ; the length of IDATA memory in bytes.
;然后编译链接。这样你的程序中就不会包含对idata清零的内码了。


;为什么?上面提到的IF语句的作用呀!当定义IDATALEN=0时,清零代码被跳过!
 
 
IF XDATALEN <> 0          ;如果有外部数据区,则把外部数据区中从XDATASTART到
;XDATASTART+ XDATALEN的区域清零
                                  MOV                   DPTR,#XDATASTART
                                  MOV                   R7,#LOW (XDATALEN)
    IF (LOW (XDATALEN)) <> 0
                                  MOV                   R6,#(HIGH (XDATALEN)) +1;如果低地址是零,一个;高地址就代表256字节
ELSE
                           MOV           R6,#HIGH (XDATALEN)
ENDIF
                           CLR             A
XDATALOOP:            MOVX          @DPTR,A
                           INC              DPTR
                           DJNZ                  R7,XDATALOOP
                           DJNZ                  R6,XDATALOOP
ENDIF
IF PPAGEENABLE <> 0                   ;清外部页RAM区域
                                  MOV                   PPAGE_SFR,#PPAGE;给P2口赋相应的值,根据用;户自己的目标系统。
ENDIF
IF PDATALEN <> 0                     ;清外部页RAM区域
                                  MOV                   R0,#LOW (PDATASTART)
                                  MOV                   R7,#LOW (PDATALEN)
                                  CLR             A
PDATALOOP:            MOVX          @R0,A
                                  INC              R0
                                  DJNZ                  R7,PDATALOOP
ENDIF
IF IBPSTACK <> 0        ;使用再入堆栈的情况,用户自己在程序中定义函数的存储模式。 ; C51定义了三个全局变量,?C_IBP,?C_XBP,?C_PBP来存储再入堆栈的栈顶地址
EXTRN DATA (?C_IBP)     ; 声明本模块使用的外部全局符号,符号的段类型限制了符号;的使用范围,而符号本身则代表的是一个RAM单元的地址址
                                  MOV                   ?C_IBP,#LOW IBPSTACKTOP
ENDIF                                  
IF XBPSTACK <> 0                      ;函数是Large存储模式的时候,存储再入堆栈的区域。
EXTRN DATA (?C_XBP)                   ;
                                  MOV                   ?C_XBP,#HIGH XBPSTACKTOP
                                  MOV                   ?C_XBP+1,#LOW XBPSTACKTOP
ENDIF
IF PBPSTACK <> 0       ;函数是Compact模式的时候,存储再入堆栈栈顶地址的存储单元;和栈的利用空间
EXTRN DATA (?C_PBP)         
                                  MOV                   ?C_PBP,#LOW PBPSTACKTOP
ENDIF
                                  MOV                   SP,#?STACK-1  ;定义的硬件栈的常数。区别再入堆;栈和硬件栈。定义的段符号代表该段的首地址 
; This code is required if you use L51_BANK.A51 with Banking Mode 4
#if  0
EXTRN CODE (?B_SWITCH0)
                                  CALL    ?B_SWITCH0  ; init bank mechanism to code bank 0
#endif
                                  LJMP           ?C_START       ;把执行的权力交给C主函数。也就是;说指定函数的入口点。改句话结束以后将跳入C的main函数开始执行。

                                  END




—————————————————————————————————M51————————————————————————————————————

通过*.m51文件我们可以清楚的看到单片机存储器的使用情况,以及可以看到每个变量包括局部变量的位置。
之前碰到一个问题,同样的程序,在small模式下编译后运行没问题,但在large模式下可以编译,但是运行出错。最后查看m51文件,发现了问题,在一个对时序要求很严格的地方声明几个局部变量,这几个局部变量有的被分配到data中,有的分配到xdata,在xdata中的变量访问时间要大于data中,导致整个代码时间管控出现混乱,最后将分配到xdata的变量用data修饰后,,编译成功通过。

下面是对m51文件的解析,参考一下:
BL51 BANKED LINKER/LOCATER V6.11, INVOKED BY:
C:\KEIL\C51\BIN\BL51.EXE 1910base.obj, 1910.obj TO Keil_1910 RAMSIZE (256) STACK (?STACK (0080H))

MEMORY MODEL: SMALL WITH FLOATING POINT ARITHMETIC

INPUT MODULES INCLUDED:
  1910base.obj (PROC1910)
  1910.obj (1910)
  C:\KEIL\C51\LIB\C51FPS.LIB (?C?FPADD)
  ………………………………  ;省略类同部分
  C:\KEIL\C51\LIB\C51S.LIB (?C?LSTPDATA)

LINK MAP OF MODULE:  Keil_1910 (PROC1910)

;           存储器数据分配情况
;           类型    起始地址    长度       类型           段名
            TYPE    BASE      LENGTH    RELOCATION   SEGMENT NAME
            -----------------------------------------------------

            * * * * * * *   D A T A   M E M O R Y   * * * * * * *  
; 内部数据内存区分配情况,REG代表是常规寄存器,
            REG     0000H     0008H     ABSOLUTE     "REG BANK 0"  
; 寄存器类型,从0000H开始,0008H个字节,绝对定位,寄存器BANK0 
            REG     0008H     0008H     ABSOLUTE     "REG BANK 1"  
; 寄存器类型,从0000H开始,0008H个字节,绝对定位,寄存器BANK1 
            DATA    0010H     0006H     UNIT         ?DT?1910


BL51 BANKED LINKER/LOCATER V6.11                                                      12/30/2009  16:15:01  PAGE 2


            DATA    0016H     0005H     UNIT         ?DT?_WRITESLITPARAMETER?1910    
;DATA代表是DATA型数据,可访问地址范围0-128,或者在 128 .. 255 范围内的一个特殊功能寄存器(SFR),以直接寻址方式操作
            DATA    001BH     0004H     UNIT         ?DT?_READSLITPARAMETER?1910
                    001FH     0001H                  *** GAP ***                     
;代表空余,未用
            DATA    0020H     0001H     BIT_ADDR     ?BA?1910
            BIT     0021H.0   0001H.4   UNIT         ?BI?1910                        
;BIT代表可以位操作的数据,是在内部数据存储空间中 20H .. 2FH 区域中一个位的地址,或者 8051 位可寻址 SFR 的一个位地址。
            BIT     0022H.4   0000H.4   UNIT         _BIT_GROUP_
            DATA    0023H     002DH     UNIT         _DATA_GROUP_
            IDATA   0050H     001FH     UNIT         _IDATA_GROUP_                   
;IDATA是可访问地址范围 0 to 255 内的数据,以间接寻址方式操作,速度略慢于DATA型数据
            IDATA   006FH     0006H     UNIT         ?ID?1910
                    0075H     000BH                  *** GAP ***
            IDATA   0080H     0001H     UNIT         ?STACK                          
;堆栈区,8051压栈的方式是向上增长,可绝对定位

            * * * * * * *  X D A T A   M E M O R Y  * * * * * * *                    
;外部数据内存分配情况,XDATA表示数据存放在外部数据存储器上
            XDATA   0000H     0065H     UNIT         ?XD?1910                        
;XDATA是存放在外部数据存储器上的数据,可访问地址范围0-65535,速度最慢
            XDATA   0065H     000CH     UNIT         _XDATA_GROUP_

            * * * * * * *   C O D E   M E M O R Y   * * * * * * *                    
;程序存储器分配情况,CODE代表是的程序指令
            CODE    0000H     0003H     ABSOLUTE     
            CODE    0003H     0005H     UNIT         ?PR?RESETWATCHDOGTIMER?1910
                    0008H     0003H                  *** GAP ***
            CODE    000BH     0003H     ABSOLUTE    
            ………………………… ;省略类同部分 
            CODE    000EH     0011H     UNIT         ?PR?_XWRITEPOINTER?1910
            CODE    5846H     0039H     UNIT         ?PR?_READPORT?1910
            CODE    587FH     0031H     UNIT         ?PR?_X5045_WRITE?1910
            CODE    58B0H     0030H     UNIT         ?PR?X5045_READ?1910
            CODE    58E0H     002CH     UNIT         ?PR?INITSYSTEM?1910
            CODE    590CH     002CH     UNIT         ?PR?_XOUTBYTE?1910
            CODE    5938H     0028H     UNIT         ?PR?XINBYTE?1910
            CODE    5960H     0025H     UNIT         ?PR?_XREADCHAR?1910
            CODE    5985H     0020H     UNIT         ?PR?READSERIALADDRESS?1910
            CODE    59A5H     0020H     UNIT         ?CO?1910
            CODE    59C5H     0017H     UNIT         ?PR?SETWRITESTATE?1910
            CODE    59DCH     000CH     UNIT         ?PR?GETWIPSTATE?1910
            CODE    59E8H     000CH     UNIT         ?PR?_ABS?ABS



OVERLAY MAP OF MODULE:   Keil_1910 (PROC1910)

;以下是各函数中的数据分配情况
;段名                                       位操作数据起址地址      DATA数据             IDATA数据           XDATA数据
SEGMENT                                       BIT_GROUP          DATA_GROUP          IDATA_GROUP         XDATA_GROUP
  +--> CALLED SEGMENT                      START    LENGTH     START    LENGTH     START    LENGTH     START    LENGTH
----------------------------------------------------------------------------------------------------------------------
?C_C51STARTUP                              -----    -----      -----    -----      -----    -----      -----    -----
  +--> ?PR?MAIN?1910
  +--> ?C_INITSEG
  
; main()函数中数据使用情况(下面是调用的函数列表)
?PR?MAIN?1910                              -----    -----      0023H    0001H      -----    -----      -----    -----
  +--> ?PR?INITSYS?1910
  +--> ?PR?SENDBACKACCUMULATEERROR?1910
  +--> ?PR?INSTRECEIVEOK?1910
  +--> ?PR?EXECUTEINSTRUCTION?1910
  +--> ?PR?RESETWATCHDOGTIMER?1910
…………………………………;省略类同部分


;以下是变量、常量和寄存器等的存储位置分配

SYMBOL TABLE OF MODULE:  Keil_1910 (PROC1910)

;地址            类型          名称
  VALUE           TYPE          NAME
  ----------------------------------
  -------         MODULE        PROC1910
  C:55B0H         SEGMENT       ASMFUNCTIONS              
;C:55B0H--C代表是在Code区,即存在程序存储器(ROM)上,55B0H是地址
  C:55C1H         PUBLIC        DETERMINEBAUDRATE
  ……………………………………;省略类同部分  
  D:00A8H         SYMBOL        IE                        
;D代表DATA型数据,存在RAM上0-127之间,或者在 128 .. 255 范围内的一个特殊功能寄存器(SFR),
  ……………………………………;类同部分省略
  N:0000H         SYMBOL        PROC1910
  ……………………………………;
  B:0088H.4       SYMBOL        TR0                       
;B代表可以位寻址的数据或寄存器
  B:0088H.6       SYMBOL        TR1
  ……………………………………;
  C:0000H         SYMBOL        _ICE_DUMMY_   
  X:0000H         PUBLIC        LampMotorCurrentPhase     
;X代表存放在外部存储器XRAM区的数据
  C:4E55H         PUBLIC        SendBack
  …………………………………;
  C:0026H         PUBLIC        ExecuteInstruction        
;C代表村放在CODE驱动的数据或指令
  D:00B0H         PUBLIC        P3
  C:4ADEH         PUBLIC        _ReadAD
  C:568AH         PUBLIC        InstReceiveOK
  ……………………………………;
  I:0071H         PUBLIC        ScanEndWaveLength         
;I 代表可以IDATA型数据
  …………………………………
  C:41E9H         PUBLIC        _CheckLampEnergy
  X:0049H         PUBLIC        FilterMotorCurrentPhase
  ……………………………………;省略

;以下是编译结果
*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
    SEGMENT: ?PR?_WRITESLITPARAMETER?1910

*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
    SEGMENT: ?PR?ASSIGNSLITPARAMETER?1910

Program Size: data=117.0 xdata=113 code=23021
LINK/LOCATE RUN COMPLETE.  2 WARNING(S),  0 ERROR(S)




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值