MC9S12XE 启动过程

0、注意

本文与CodeWarrior5.1 IDE与CPU12密切相关,对二者进行深入了解有助于理解MC9S12XE的具体启动细节,所以需要参考CodeWarrior5.1 IDE的参考手册:HC(S)08/RS08 and S12(X) Build Tools Utilities Manual和S12(X)Build Tools Reference Manual以及CPU12 的参考手册CPU12/CPU12X Reference Manual。二者均可在NXP官网下载。
1)HC(S)08/RS08 and S12(X) Build Tools Utilities Manual和S12(X)Build Tools Reference Manual主要介绍了CodeWarrior 5.1的个主要工具,具体如下:
在这里插入图片描述在这里插入图片描述
2)CPU12/CPU12X Reference Manual主要介绍CPU12和CPU12X的CPU结构、寻址方式和汇编指令集,具体内容如下:
在这里插入图片描述

1.CodeWarrior 5.1智能链接器

C程序经过编译后生成obj文件,然后链接器将其链接成最终可执行程序。在CodeWarrior 5.1中链接器生成.abs文件,然后烧录器再将.abs文件转换成.abs.s19文件。具体链接过程为:链接器将导入的obj文件中程序用到的初始化数据、启动数据结构、需要拷贝的数据、堆栈、固定页代码、非固定页代码、数据等代码或数据类型根据prm文件中设置的对应代码或数据类型指定的内存资源进行整合、归类并进行地址分配。例如在prm文件中,PLACEMENT…END如下定义:

      _PRESTART,              /* Used in HIWARE format: jump to _Startup at the code start */
      _PRESTART,                /* startup data structures */
      ROM_VAR,                /* constant variables */
      STRINGS,                /* string literals */
      VIRTUAL_TABLE_SEGMENT,  /* C++ virtual table segment */
    //.ostext,                /* eventually OSEK code  */
      NON_BANKED,             /* runtime routines which must not be banked */
      COPY                    /* copy down information: how to initialize variables */
                              /* in case you want to use ROM_4000 here as well, make sure
                                 that all files (incl. library files) are compiled with the
                                 option: -OnB=b */
                        INTO  ROM_C000;

.map文件如下:

  • 该部分定义的是对应类型代码和数据对应的地址和所在的内存资源块,如.init、.startData、.copy、text由于prm文件中PLACEMENT定义将_PRESTART、START、COPY、NON_BNAKED置于ROM_C000,所以链接器将其分配到ROM_C0000,地址范围为0xC000-0xC052。
    在这里插入图片描述
  • 该段定义的对应类型的代码和数据包含的具体函数和数据。Delay_Ms、Test_Func1、Test_Func2、main、init函数属于.text,所以包含在ROM_C000内。变量Test_Var1_Init、Test_Var2_Init是定义的全局变量属于.data,所以放在RAM内,Test_Var1_No_Init是定义的全局const变量,所以属于.rodata.也就是只读数据,放电ROM_C000.
    在这里插入图片描述
  • .copy文件,对于初始化的全局变量来说,在启动过程中需要将ROM内的变量拷贝到RAM内对全局变量的进行初始化,所以链接器内含有.copy模块用于启动时将负责的变量从ROM拷贝到RAM内,Test_Var1_Init和Test_Var2_Init是需要初始化的全局变量,所以在.copy内。
    在这里插入图片描述
  • _startupData是链接器生成的用于对所使用RAM进行清零并将ROM内的数据拷贝到RAM内进行数据初始化等的结构体数据,链接器生成的_startupData位于.map文件。本工程生成的如下:
    在这里插入图片描述

_startupData结构体在start12.h内定义,定义如下:


typedef struct _Range {
  unsigned char * __far beg; int size;      /* [beg..beg+size] */
} _Range;

typedef struct _Copy {
    int size; unsigned char * __far dest;
} _Copy;
extern struct _tagStartup {
#ifndef __NO_FLAGS_OFFSET
     unsigned char   flags;
#endif
#ifndef __NO_MAIN_OFFSET
     _PFunc          main;            /* top level procedure of user program */
#endif
#ifndef __NO_STACKOFFSET_OFFSET
     Word            stackOffset;     /* 16bit, initial value of the stack pointer */
#endif
     unsigned int    nofZeroOuts;     /* number of zero out ranges */
     _Range *PTR16   pZeroOut;        /* vector of ranges with nofZeroOuts elements */
#if defined(__BANKED_COPY_DOWN)
     _Copy *__pptr    toCopyDownBeg;   /* rom-address where copydown-data begins */
#else
     _Copy *PTR16    toCopyDownBeg;   /* rom-address where copydown-data begins */
#endif
#if 0 /* switch on to implement ROM libraries */
     unsigned int    nofLibInits;     /* number of library startup descriptors */
     _LibInit *PTR16 libInits;        /* vector of pointers to library startup descriptors */
#endif
#ifdef __cplusplus
     unsigned int    nofInitBodies;   /* number of init functions for C++ constructors */
     _Cpp *PTR16     initBodies;      /* vector of function pointers to init functions for C++ constructors */
     unsigned int    nofFiniBodies;   /* number of fini functions for C++ destructors */
     _Cpp *PTR16     finiBodies;      /* vector of function pointers to fini functions for C++ destructors */
#endif
} _startupData;

_startupData结构体内变量的意义如下,如若没有使用,则不会生成对应类型的数据:

在这里插入图片描述其中主要用到的是nofZeroOuts、pZeroOut和toCopyDownBeg,正如表中解释所说nofZeroOuts是要清零的RAM块的块数,pZeroOut为_Range结构体变量,内含有要清零的RAM块的起始地址和清零数目,toCopyDownBeg为_Copy结构变量,内含有需初始化的全局变量的RAM起始地址和需初始化内存的数目。

2.CPU12架构

CPU12含有A、B两个8位累加器(或者A、B组成一个16位累加器D),X、Y两个索引寄存器,堆栈指针SP、程序指针PC和状态码寄存器,如下所示:
在这里插入图片描述
其中状态寄存器中的各位与51单片机类型,具体含义如下:
在这里插入图片描述

3.启动程序解释

MC9S12的启动文件由汇编实现,主要使用第2节中的A、B、D、X、Y寄存器是实现,一般启动过程如下:
0)根据宏定义判断是否开启看门狗、是否进行内存分页使能判断、是否进行内存控制等;
1)初始化堆栈指针,代码如下:

INIT_SP_FROM_STARTUP_DESC();

该代码的具体意思为#define INIT_SP_FROM_STARTUP_DESC() __asm LDS #__SEG_END_SSTACK;,也即是将堆栈栈尾的地址载入堆栈指针SP。
2)将需要清零的全局变量清零,也就是链接器中生成的RAM中应该清零的内存块清零。该段根据链接器生成的_startupData中nofZeroOuts和pZeroOut将对应RAM块清零,代码如下:

ZeroOut:
#if defined(__HIWARE_OBJECT_FILE_FORMAT__) && defined(__LARGE__)
             LDX   _startupData.pZeroOut:1   ; in the large memory model in the HIWARE format, pZeroOut is a 24 bit pointer
#else
             LDX   _startupData.pZeroOut    ; *pZeroOut
#endif
             LDY   _startupData.nofZeroOuts ; nofZeroOuts
             BEQ   CopyDown                 ; if nothing to zero out

NextZeroOut: PSHY                           ; save nofZeroOuts
#if defined(FAR_DATA)
             LDAB  1,X+                     ; load page of destination address
             LDY   2,X+                     ; load offset of destination address
#if defined(__HCS12X__)
             STAB  __GPAGE_ADR__
#else /* defined(__HCS12X__) */
             __PIC_JSR(_SET_PAGE)           ; sets the page in the correct page register
#endif /* defined(__HCS12X__) */
#else   /* FAR_DATA */
             LDY   2,X+                     ; start address and advance *pZeroOut (X = X+4)
#endif  /* FAR_DATA */

#if defined(__HCS12X__) && defined(FAR_DATA)
             PSHX
             LDX   0,X                      ; byte count
#if defined(__OPTIMIZE_FOR_SIZE__)
             CLRA
NextWord:    GSTAA 1,Y+                     ; clear memory byte
             __FEED_COP_IN_HLI()            ; feed the COP if necessary /*lint !e505 !e522 asm code */
             DBNE  X, NextWord              ; dec byte count
#else
             LDD #0
             LSRX
             BEQ   LoopClrW1                ; do we copy more than 1 byte?
NextWord:    GSTD 2,Y+                      ; clear memory word
             __FEED_COP_IN_HLI()            ; feed the COP if necessary /*lint !e505 !e522 asm code */
             DBNE  X, NextWord              ; dec word count
LoopClrW1:
             BCC   LastClr                  ; handle last byte
             GSTAA 1,Y+											; handle last byte
LastClr:
#endif
             PULX
             LEAX  2,X
#elif defined(__OPTIMIZE_FOR_SIZE__)               /* -os, default */
             LDD   2,X+                     ; byte count
NextWord:    CLR   1,Y+                     ; clear memory byte
             __FEED_COP_IN_HLI()            ; feed the COP if necessary /*lint !e505 !e522 asm code */
             DBNE  D, NextWord              ; dec byte count
#else /* __OPTIMIZE_FOR_TIME__ */
             LDD   2,X+                     ; byte count
             LSRD                           ; /2 and save bit 0 in the carry
             BEQ   LoopClrW1                ; do we copy more than 1 byte?
             PSHX
             LDX   #0
LoopClrW:    STX   2,Y+                     ; Word-Clear
             __FEED_COP_IN_HLI()            ; feed the COP if necessary /*lint !e505 !e522 asm code */
             DBNE  D, LoopClrW
             PULX
LoopClrW1:
             BCC   LastClr                  ; handle last byte
             CLR   1,Y+
LastClr:
#endif /* __OPTIMIZE_FOR_SIZE__/__OPTIMIZE_FOR_TIME__ */
             PULY                           ; restore nofZeroOuts
             DEY                            ; dec nofZeroOuts
             BNE  NextZeroOut

3)将需要初始化的全局变量初始化,也就是链接器中生成的RAM中应该赋值的内存块从对应的ROM中拷贝赋值。该段根据链接器生成的_startupData中ntoCopyDownBeg将数据从ROM中拷贝到RAM中对全局变量进行初始化,代码如下:

opyDown:
#if defined(__BANKED_COPY_DOWN)
             LDAA  _startupData.toCopyDownBeg:0 ; get PAGE address of .copy section
             STAA	 __PPAGE_ADR__          ; set PPAGE address
             LDX   _startupData.toCopyDownBeg:1 ; load address of copy down desc.
#elif defined(__ELF_OBJECT_FILE_FORMAT__)
             LDX   _startupData.toCopyDownBeg ; load address of copy down desc.
#else
             LDX   _startupData.toCopyDownBeg:2 ; load address of copy down desc.
#endif
NextBlock:
             LDD   2,X+                     ; size of init-data -> D
             BEQ   funcInits                ; end of copy down desc.
#ifdef FAR_DATA
             PSHD                           ; save counter
             LDAB  1,X+                     ; load destination page
             LDY   2,X+                     ; destination address
#if defined(__HCS12X__)
             STAB  __GPAGE_ADR__
#else  /* __HCS12X__ */
             __PIC_JSR(_SET_PAGE)           ; sets the destinations page register
#endif /* __HCS12X__ */
             PULD                           ; restore counter
#else  /* FAR_DATA */
             LDY   2,X+                     ; load destination address
#endif /* FAR_DATA */

#if defined(__HCS12X__) && defined(FAR_DATA)
#if defined(__OPTIMIZE_FOR_SIZE__)               /* -os, default */
Copy:        PSHA
             LDAA  1,X+
             GSTAA  1,Y+                    ; move a byte from ROM to the data area
             PULA
             __FEED_COP_IN_HLI()            ; feed the COP if necessary /*lint !e505 !e522 asm code */
             DBNE  D,Copy                   ; copy-byte loop
#else
             LSRD                           ; /2 and save bit 0 in the carry
             BEQ    Copy1                   ; do we copy more than 1 byte?

Copy:        PSHD
             LDD   2,X+
             GSTD  2,Y+                     ; move a word from ROM to the data area
             PULD
             __FEED_COP_IN_HLI()            ; feed the COP if necessary /*lint !e505 !e522 asm code */
             DBNE  D,Copy                   ; copy-word loop
Copy1:
             BCC   NextBlock                ; handle last byte?
             LDAA  1,X+
             GSTAA  1,Y+                    ; move a byte from ROM to the data area
#endif
#elif defined(__OPTIMIZE_FOR_SIZE__)               /* -os, default */
Copy:        MOVB  1,X+,1,Y+                ; move a byte from ROM to the data area
             __FEED_COP_IN_HLI()            ; feed the COP if necessary /*lint !e505 !e522 asm code */
             DBNE  D,Copy                   ; copy-byte loop
#else /* __OPTIMIZE_FOR_TIME__ */
             LSRD                           ; /2 and save bit 0 in the carry
             BEQ   Copy1                    ; do we copy more than 1 byte?
Copy:        MOVW  2,X+,2,Y+                ; move a word from ROM to the data area
             __FEED_COP_IN_HLI()            ; feed the COP if necessary /*lint !e505 !e522 asm code */
             DBNE  D,Copy                   ; copy-word loop
Copy1:
             BCC   NextBlock                ; handle last byte?
             MOVB  1,X+,1,Y+                ; copy the last byte
#endif /* __OPTIMIZE_FOR_SIZE__/__OPTIMIZE_FOR_TIME__ */
             BRA   NextBlock

4)如果采用了C++类型的函数,则还需要进行函数初始化,代码如下:

funcInits:                                  ; call of global construtors is only in c++ necessary
#if defined(__cplusplus)
#if defined(__ELF_OBJECT_FILE_FORMAT__)
#if defined( __BANKED__) || defined(__LARGE__)
             LDY   _startupData.nofInitBodies; load number of cpp.
             BEQ   done                     ; if cppcount == 0, goto done
             LDX   _startupData.initBodies  ; load address of first module to initialize
nextInit:
             LEAX   3,X                     ; increment to next init
             PSHX                           ; save address of next function to initialize
             PSHY                           ; save cpp counter
             CALL  [-3,X]                   ; use double indirect call to load the page register also
             PULY                           ; restore cpp counter
             PULX                           ; restore actual address
             DEY                            ; decrement cpp counter
             BNE    nextInit
#else  /* defined( __BANKED__) || defined(__LARGE__) */

             LDD   _startupData.nofInitBodies; load number of cpp.
             BEQ   done                     ; if cppcount == 0, goto done
             LDX   _startupData.initBodies  ; load address of first module to initialize
nextInit:
             LDY   2,X+                     ; load address of first module to initialize
             PSHD
             PSHX                           ; save actual address
             JSR   0,Y                      ; call initialization function
             PULX                           ; restore actual address
             PULD                           ; restore cpp counter
             DBNE D, nextInit
#endif /* defined( __BANKED__) || defined(__LARGE__) */
#else /* __ELF_OBJECT_FILE_FORMAT__  */
             LDX   _startupData.mInits      ; load address of first module to initialize
#if defined( __BANKED__) || defined(__LARGE__)
nextInit:    LDY   3,X+                     ; load address of initialization function
             BEQ   done                     ; stop when address  == 0
                                            ; in common environments the offset of a function is never 0, so this test could be avoided
#ifdef __InitFunctionsMayHaveOffset0__
             BRCLR -1,X, done, 0xff         ; stop when address  == 0
#endif  /* __InitFunctionsMayHaveOffset0__ */
             PSHX                           ; save address of next function to initialize
             CALL  [-3,X]                   ; use double indirect call to load the page register also
#else  /* defined( __BANKED__) || defined(__LARGE__) */
nextInit:
             LDY   2,X+                     ; load address of first module to initialize
             BEQ   done                     ; stop when address of function == 0
             PSHX                           ; save actual address
             JSR   0,Y                      ; call initialization function
#endif /* defined( __BANKED__) || defined(__LARGE__) */
             PULX                           ; restore actual address
             BRA   nextInit
#endif  /* __ELF_OBJECT_FILE_FORMAT__  */
done:
#endif /* __cplusplus */
   }
}
#endif /* __ONLY_INIT_SP */

#if defined( __ELF_OBJECT_FILE_FORMAT__) && defined(__cplusplus ) && 0 /* the call to main does not support to return anymore */

#if !defined(FAR_DATA) && (defined( __BANKED__) || defined(__LARGE__))
static void __far Fini(void)
#else
static void Fini(void)
#endif
{
/* purpose:     1) call global destructors in C++ */
   asm {
#if defined( __BANKED__) || defined(__LARGE__)

             LDY   _startupData.nofFiniBodies; load number of cpp.
             BEQ   done                     ; if cppcount == 0, goto done
             LDX   _startupData.finiBodies  ; load address of first module to finalize
nextInit2:
             LEAX   3,X                     ; increment to next init
             PSHX                           ; save address of next function to finalize
             PSHY                           ; save cpp counter
             CALL  [-3,X]                   ; use double indirect call to load the page register also
             PULY                           ; restore cpp counter
             PULX                           ; restore actual address
             DEY                            ; decrement cpp counter
             BNE    nextInit2
#else  /* defined( __BANKED__) || defined(__LARGE__) */

             LDD   _startupData.nofFiniBodies; load number of cpp.
             BEQ   done                     ; if cppcount == 0, goto done
             LDX   _startupData.finiBodies  ; load address of first module to finalize
nextInit2:
             LDY   2,X+                     ; load address of first module to finalize
             PSHD
             PSHX                           ; save actual address
             JSR   0,Y                      ; call finalize function
             PULX                           ; restore actual address
             PULD                           ; restore cpp counter
             DBNE D, nextInit2
#endif /* defined(__BANKED__) || defined(__LARGE__) */

5)判断是否开启看门狗,并调用main函数,单片机开始运行。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MC9S12 Simulink库是一款专门为MC9S12微控制器设计的Simulink支持包。MC9S12是一种高性能、高集成度的16位微控制器,Simulink是一种功能强大的图形化建模和仿真工具。MC9S12 Simulink库的目的是为MC9S12微控制器提供一个易于使用的开发环境,使工程师能够通过图形化建模的方式进行系统设计、仿真和代码生成。 MC9S12 Simulink库提供了与MC9S12微控制器密切相关的模块和函数库,旨在帮助工程师快速、高效地开发嵌入式系统。这个库包括了MC9S12微控制器的所有外设模块,如GPIO、定时器、ADC、CAN、SPI等,以及与这些外设模块交互的函数库。工程师可以通过简单拖放的方式在Simulink中搭建整个系统的模型,并进行仿真和调试。此外,MC9S12 Simulink库还提供了代码生成功能,可以将Simulink模型自动生成可在MC9S12微控制器上运行的底层代码,这极大地简化了系统开发过程。 MC9S12 Simulink库的优点在于它将系统设计与底层编程相结合,使得工程师不需要深入了解底层硬件细节就能进行系统级开发。通过使用Simulink进行建模和仿真,工程师可以快速验证和优化系统设计,减少开发时间和成本。而且,由于MC9S12 Simulink库已经经过验证和优化,生成的代码具有较高的质量和可靠性,不容易出错。 综上所述,MC9S12 Simulink库为MC9S12微控制器提供了一个高效、便捷的开发环境,使工程师能够更加轻松地进行系统设计、仿真和代码生成。这个库的应用范围广泛,适用于各种嵌入式系统的开发,大大简化了开发过程,提高了开发效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值