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 surethat all files (incl. library files) are compiled with theoption: -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_OFFSETunsigned char   flags;
#endif
#ifndef __NO_MAIN_OFFSET_PFunc          main;            /* top level procedure of user program */
#endif
#ifndef __NO_STACKOFFSET_OFFSETWord            stackOffset;     /* 16bit, initial value of the stack pointer */
#endifunsigned 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 __cplusplusunsigned 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
#elseLDX   _startupData.pZeroOut    ; *pZeroOut
#endifLDY   _startupData.nofZeroOuts ; nofZeroOutsBEQ   CopyDown                 ; if nothing to zero outNextZeroOut: PSHY                           ; save nofZeroOuts
#if defined(FAR_DATA)LDAB  1,X+                     ; load page of destination addressLDY   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)PSHXLDX   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
#elseLDD #0LSRXBEQ   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 byteGSTAA 1,Y+                                          ; handle last byte
LastClr:
#endifPULXLEAX  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 countLSRD                           ; /2 and save bit 0 in the carryBEQ   LoopClrW1                ; do we copy more than 1 byte?PSHXLDX   #0
LoopClrW:    STX   2,Y+                     ; Word-Clear__FEED_COP_IN_HLI()            ; feed the COP if necessary /*lint !e505 !e522 asm code */DBNE  D, LoopClrWPULX
LoopClrW1:BCC   LastClr                  ; handle last byteCLR   1,Y+
LastClr:
#endif /* __OPTIMIZE_FOR_SIZE__/__OPTIMIZE_FOR_TIME__ */PULY                           ; restore nofZeroOutsDEY                            ; dec nofZeroOutsBNE  NextZeroOut

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

opyDown:
#if defined(__BANKED_COPY_DOWN)LDAA  _startupData.toCopyDownBeg:0 ; get PAGE address of .copy sectionSTAA    __PPAGE_ADR__          ; set PPAGE addressLDX   _startupData.toCopyDownBeg:1 ; load address of copy down desc.
#elif defined(__ELF_OBJECT_FILE_FORMAT__)LDX   _startupData.toCopyDownBeg ; load address of copy down desc.
#elseLDX   _startupData.toCopyDownBeg:2 ; load address of copy down desc.
#endif
NextBlock:LDD   2,X+                     ; size of init-data -> DBEQ   funcInits                ; end of copy down desc.
#ifdef FAR_DATAPSHD                           ; save counterLDAB  1,X+                     ; load destination pageLDY   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:        PSHALDAA  1,X+GSTAA  1,Y+                    ; move a byte from ROM to the data areaPULA__FEED_COP_IN_HLI()            ; feed the COP if necessary /*lint !e505 !e522 asm code */DBNE  D,Copy                   ; copy-byte loop
#elseLSRD                           ; /2 and save bit 0 in the carryBEQ    Copy1                   ; do we copy more than 1 byte?Copy:        PSHDLDD   2,X+GSTD  2,Y+                     ; move a word from ROM to the data areaPULD__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 carryBEQ   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 doneLDX   _startupData.initBodies  ; load address of first module to initialize
nextInit:LEAX   3,X                     ; increment to next initPSHX                           ; save address of next function to initializePSHY                           ; save cpp counterCALL  [-3,X]                   ; use double indirect call to load the page register alsoPULY                           ; restore cpp counterPULX                           ; restore actual addressDEY                            ; decrement cpp counterBNE    nextInit
#else  /* defined( __BANKED__) || defined(__LARGE__) */LDD   _startupData.nofInitBodies; load number of cpp.BEQ   done                     ; if cppcount == 0, goto doneLDX   _startupData.initBodies  ; load address of first module to initialize
nextInit:LDY   2,X+                     ; load address of first module to initializePSHDPSHX                           ; save actual addressJSR   0,Y                      ; call initialization functionPULX                           ; restore actual addressPULD                           ; restore cpp counterDBNE 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 functionBEQ   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 initializeCALL  [-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 initializeBEQ   done                     ; stop when address of function == 0PSHX                           ; save actual addressJSR   0,Y                      ; call initialization function
#endif /* defined( __BANKED__) || defined(__LARGE__) */PULX                           ; restore actual addressBRA   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 doneLDX   _startupData.finiBodies  ; load address of first module to finalize
nextInit2:LEAX   3,X                     ; increment to next initPSHX                           ; save address of next function to finalizePSHY                           ; save cpp counterCALL  [-3,X]                   ; use double indirect call to load the page register alsoPULY                           ; restore cpp counterPULX                           ; restore actual addressDEY                            ; decrement cpp counterBNE    nextInit2
#else  /* defined( __BANKED__) || defined(__LARGE__) */LDD   _startupData.nofFiniBodies; load number of cpp.BEQ   done                     ; if cppcount == 0, goto doneLDX   _startupData.finiBodies  ; load address of first module to finalize
nextInit2:LDY   2,X+                     ; load address of first module to finalizePSHDPSHX                           ; save actual addressJSR   0,Y                      ; call finalize functionPULX                           ; restore actual addressPULD                           ; restore cpp counterDBNE D, nextInit2
#endif /* defined(__BANKED__) || defined(__LARGE__) */

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

MC9S12XE 启动过程相关推荐

  1. Android系统的启动过程

    Android系统的启动过程可以简单地总结为以下几个流程: 加载BootLoader -> 初始化内核 -> 启动init进程 -> init进程fork出Zygote(孵化器)进程 ...

  2. Android系统默认Home应用程序(Launcher)的启动过程源代码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应 ...

  3. Linux0.11内核引导启动过程概述

    Linux0.11仅支持x86架构.它的内核引导启动程序在文件夹boot内,共有三个汇编代码文件.按照启动流程依次是: (1)bootsect.s.boot是启动引导的意思,sect即sector,是 ...

  4. linux启动sql server数据库,SQL Server数据库启动过程详解及启动不起来的问题分析及解决方法...

    第五步.启动系统数据库model model系统数据库同样也是SQL Server启动过程中用到的一个非常关键的数据库,如果这个库损坏,SQL Server启动也会失败,关于model数据不能启动的原 ...

  5. Linux必知必会的目录与启动过程

    第1章 /etc/目录 1.1 /etc/sysconfig/network-scripts/ifcfg-eth0 linux第一块网卡的配置文件 [root@znix ~]# cat /etc/sy ...

  6. Spring Boot启动过程(二)

    书接上篇 该说refreshContext(context)了,首先是判断context是否是AbstractApplicationContext派生类的实例,之后调用了强转为AbstractAppl ...

  7. Linux X Window System运行原理和启动过程

    本文主要说明X Window System的基本运行原理,其启动过程,及常见的跨网络运行X Window System. 一) 基本运行原理 X Window System采用C/S结构,但和我们常见 ...

  8. Spring 容器的启动过程

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 本文来源:http://r6f.cn/b47K 一. 前言 ...

  9. golang源码分析-启动过程概述

    golang源码分析-启动过程概述 golang语言作为根据CSP模型实现的一种强类型的语言,本文主要就是通过简单的实例来分析一下golang语言的启动流程,为深入了解与学习做铺垫. golang代码 ...

  10. tiny4412学习之u-boot启动过程

    这个文档简要分析了tiny4412自带的u-boot的启动过程,这个u-boot启用了mmu,并且命令的接收和执行方式跟以前的不同. 文档下载地址: http://pan.baidu.com/s/1s ...

最新文章

  1. H3C 基于IP的限速
  2. 改变css名称,样式命名规则?css
  3. [zz]linux之sed用法
  4. codeM美团编程大赛初赛B轮E题
  5. windows 10下让jar文件双击可以运行的解决方法
  6. 备战数学建模34-BP神经网络预测2
  7. Word把普通表格改为三线表格的方法
  8. 程序员的金融笔记:经济学原理-微观经济学-曼昆-第7版
  9. 12项目管理--项目采购管理
  10. C#如何输入对号字符串
  11. play Framework 配置
  12. DOS命令格式化制作U盘
  13. 【积水成渊-逐步定制自己的Emacs神器】1:Emacs入门
  14. 网络钓鱼攻击类型,载体及其技术途径
  15. 网站移动适配之Meta标注、移动跳转实用篇 转载
  16. 菜鸟了解点“调查取证套路”刀在你我手
  17. 华为OLT接入网ONT_MA5671配置笔记
  18. 如何方便的在Office(powerpoint、word)中输入数学公式?
  19. miui8.5 android版本,小米MIUI8.5稳定版
  20. 测试工程师技术之外软技能提升指南

热门文章

  1. windows下编程可执行程序加载.dll动态库失败
  2. 用qpython3写一个发送短信的程序
  3. Python学习教程公开课:好玩的Python
  4. EL表达式和JSTL笔记
  5. 安卓开发学习之锁屏的实现
  6. delphi调试需要管理员权限程序报错“Unable to create process:请求的操作需要提升”
  7. Unity Editor 画地面贴图工具
  8. C++模拟斗地主发牌
  9. 如何获取公众号二维码
  10. R.Koo 改良后的分页类(主要是显示属性)