STARTUP.A51详解

STARTUP.A51 这个文件有什么用,有必要添加到工程吗?
  如果不添加"startup.a51"文件,编译器就会自动加入一段初始化内存以及堆栈等的代码,这时的内存初始化部分你就无法去控制了,当然这在大部分情况下没什么关系。但是如果你想你的程序在复位后,内存里面的信息依然还保存着(所说的热复位),那么你就需要添加该启动文件,并且去里面修改内存初始化部分,不要初始化你需要保留的部分内存。

  启动文件. 清理RAM.设置堆栈等.即执行完start.a51后跳转到.c文件的main函数。这些初始化完毕后,还会设置SP指针。对非变量区域,如堆栈区,将不会有赋值或清零动作。

  有人喜欢改startup.a51,为了满足自己一些想当然的爱好,这是不必要的,有可能错误的。比如掉电保护的时候想保存一些变量,但改startup.a51来实现是很笨的方法,实际只要利用非变量区域的特性,定义一个指针变量指向堆栈低部:0xff处就可实现。为什么还要去改? 可以这么说:任何时候都可以不需要改startup.a51,如果你明白它的特性。 

Startup code:启动代码。

在Keil中,启动代码在复位目标系统后立即被执行。启动代码主要实现以下功能:

(1)       清除内部数据存储器

(2)       清除外部数据存储器

(3)       清除外部页存储器

(4)       初始化small模式下的可重入栈和指针

(5)       初始化large模式下的可重入栈和指针

(6)       初始化compact模式下的可重入栈和指针

(7)       初始化8051硬件栈指针

(8)       传递初始化全局变量的控制命令或者在没有初始化全局变量时给main函数传递命令。

在每一个启动文件中,提供了可供用户自己修改有来控制程序执行的汇编常量。见表1

Name

Description

IDATALEN

Specifies the number of bytes of idata to clear to 0. The default is 80h because most 8051 derivatives contain at least 128 bytes of internal data memory. Use a value of 100h for the 8052 and other derivatives that have 256 bytes of internal data memory.

XDATASTART

Specifies the initial xdata address to clear to 0.

XDATALEN

Indicates the number of bytes of xdata to clear to 0. The default is 0.

PDATASTART

Specifies the initial pdata address to clear to 0.

PDATALEN

Specifies the number of bytes of pdata to clear to 0. The default is 0.

IBPSTACK

Specifies whether or not the small model reentrant stack pointer (?C_IBP) should be initialized. A value of 1 causes this pointer to be initialized. A value of 0 prevents initialization of this pointer. The default is 0.

IBPSTACKTOP

Specifies the top of the small model reentrant stack. The default is 0xFF in idata memory.
The Cx51 Compiler does not check to see if the stack area available satisfies the requirements of the application. It is your responsibility to perform such a test.

XBPSTACK

Specifies whether or not the large model reentrant stack pointer (?C_XBP) should be initialized. A value of 1 causes this pointer to be initialized. A value of 0 prevents initialization of this pointer. The default is 0.

XBPSTACKTOP

Specifies the top of the large model reentrant stack. The default is 0xFFFF in xdata memory.
The Cx51 Compiler does not check to see if the stack area available satisfies the requirements of the application. It is your responsibility to perform such a test.

PBPSTACK

Specifies whether the compact model reentrant stack pointer (?C_PBP) should be initialized. A value of 1 causes this pointer to be initialized. A value of 0 prevents initialization of this pointer. The default is 0.

PBPSTACKTOP

Specifies the top of the compact model reentrant stack. The default is 0xFF in pdata memory.
The Cx51 Compiler does not check to see if the stack area available satisfies the requirements of the application. It is your responsibility to perform such a test.

PPAGEENABLE

Enables (a value of 1) or disables (a value of 0) Port 2 initialization for pdata memory access. The default is 0. pdata addressing uses Port 2 for the upper address (or page) byte.

PPAGE

Specifies the value to write to Port 2 of the 8051 for pdata memory access. This value represents the xdata memory page to use for pdata. This is the upper 8 bits of the absolute address range to use for pdata. For example, if the pdata area begins at address 1000h (page 10h) in xdata memory, PPAGEENABLE should be set to 1, and PPAGEshould be set to 10h. You must specify the starting pdata address to use to the BL51 Linker using the PDATA directive. For example:

BL51 input modules PDATA (1050H)

Neither the BL51 Linker nor the Cx51 Compiler checks to see if the PDATA directive and the PPAGE startup constant are correctly specified. You must ensure that these parameters contain suitable values.

上面这些只是标号,如果愿意,自己可以换成其他的名字。这样写意义更直观。

$NOMOD51  ; Ax51宏汇编器控制命令,禁止预定义的8051。使编译器不使能预定义的8051符号,避免产生重复定义的错误。
;------------------------------------------------------------------------------
;  This file is part of the C51 Compiler package
;  Copyright (c) 1988-2001 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 of IDATA 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
; --- 使用COMPACT存储器模式时64K字节XDATA存储器空间的分页定义
;
;  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.
;---  以下用EQU指令定义PDATA类型变量在XDATA存储器空间的页地址
;---  使用EQU指令定义PFAGE时必须与L51连接定位器PDATA指令的控制参数一致
;
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 required in XBANKING.A51  ;--- 标准的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:
;---  单片机上电IDATA内存清零。如果不需要上电清零IDATA,
;---  可以注销IF到IFEDN之间的话句或者修改IDTALEN的长度
IF IDATALEN <> 0            ;如果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时,清零代码被跳过!


;---  单片机上电XDATA内存清零。如果不需要上电清零XDATA,
;---  可以注销IF到IFEDN之间的话句或者修改XDATALEN的长度
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    P2,#PPAGE           ;给P2口赋相应的值,根据用户自己的目标系统。
ENDIF

;---  单片机上电XDATA内存清零。如果不需要上电清零XDATA,
;---  可以注销IF到IFEDN之间的话句或者修改XDATALEN的长度
IF PDATALEN <> 0                ;清外部页RAM区域
        MOV    R0,#PDATASTART
        MOV    R7,#LOW (PDATALEN)
        CLR    A
PDATALOOP:     
     MOVX   @R0,A
        INC    R0
        DJNZ   R7,PDATALOOP
ENDIF

;--- 设置使用SMALL存储器模式时再入函数的堆栈空间
IF IBPSTACK <> 0               ; 使用再入堆栈的情况,用户自己在程序中定义函数的存储模式。
                        ; C51定义了三个全局变量,?C_IBP,?C_XBP,?C_PBP来存储再入堆栈的栈顶地址
EXTRN DATA (?C_IBP)             ; 声明本模块使用的外部全局符号,符号的段类型限制了符号的使用范围,
                      ; 而符号本身则代表的是一个RAM单元的地址址
        MOV    ?C_IBP,#LOW IBPSTACKTOP
ENDIF

;--- 设置使用LARGE存储器模式时再入函数的堆栈空间
IF XBPSTACK <> 0              ;函数是Large存储模式的时候,存储再入堆栈的区域。
EXTRN DATA (?C_XBP)

        MOV    ?C_XBP,#HIGH XBPSTACKTOP
        MOV    ?C_XBP+1,#LOW XBPSTACKTOP
ENDIF

;--- 设置使用COMPACT存储器模式时再入函数的堆栈空间
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
EXTRN CODE (?B_SWITCH0)
        CALL   ?B_SWITCH0              ; init bank mechanism to code bank 0                        
                       ; 程序从第一组bank 0 块开始执行,跳转到用户程序MAIN函数
        LJMP   ?C_START         ; 把执行的权力交给C主函数。也就是说指定函数的入口点。改句话结束以后将跳入C的main函数开始执行。

        END


posted @ 2014-12-30 14:50  SuperThinker  阅读(57)  评论(0编辑  收藏  举报  来源