;/*****************************************************************************
; * @file: startup_MKL02Z4.s
; * @purpose: CMSIS Cortex-M0plus Core Device Startup File for the
; * MKL02Z4
; * @version: 1.0
; * @date: 2012-10-4
; *
; * Copyright: 1997 - 2013 Freescale Semiconductor, Inc. All Rights Reserved.
;*
; *------- <<< Use Configuration Wizard in Context Menu >>> ------------------
; *
; *****************************************************************************/
; Stack Configuration
; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
Stack_Size EQU 0x00000100
;EQU定义符号指示Stack大小
AREA STACK, NOINIT, READWRITE, ALIGN=3
;AREA 通知汇编器汇编一段新的代码或数据节(section)
;STACK 为AREA所定义的新的节的节名称(sectionname)
;NOINIT 指示这段数据节不初始化或初始化为0,以SPACE等指示的空间初始化为0,但不能初始化为其它
; 备注:即这段不能指定初始化值,如果不加NOINIT的话,MAP文件SPACE的数据类型为Data,为RW Data
; 如果加NOINIT的话,MAP文件SPACE的数据类型为Zero,为ZI Data
;READWRITE 指示该节类型为RW
;ALIGN=3 指示该节对齐到8字节boundary,即为双字地址
; 备注:在MAP文件中,可以发现是通过添加PAD类型的数据进行节的对齐
; PAD取何值可以指定
Stack_Mem SPACE Stack_Size
;Stack_Mem 为一个标签(label),标签值为在当前节中的地址
;SPACE 指示(directive)一块内存(memory),这块内存所在节的特性由上面的AREA指定
__initial_sp
;__initial_sp 为上面SPACE块的顶端地址+1,即说明堆栈的初始值为顶端地址,堆栈是向下生长的满栈
; 备注:因为CM的入栈操作是,*(--R13)=R0类似的一种方式,R13指向最后的数据
; Heap Configuration
; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
Heap_Size EQU 0x00000100
;定义符号指示Heap大小
AREA HEAP, NOINIT, READWRITE, ALIGN=3
;定义一个新的节,节名称为HEAP,其它与STACK相同
;EXPORT __heap_base
__heap_base
;定义一个标签,指示HEAP的基地址,这个标签只用在使用MICROLIB时被EXPORT,即只有这时有效
;使用MICROLIB时,这个标签被EXPORT,类似于C语言中的extern,但只有当HEAP被使用的时候
; 才出现在MAP文件中,如在main()中可以这样来访问__heap_base
; void main(void)
; {
; extern int __heap_base;
; static int HEAPBASE; //定义静态变量,在内存中有固定的存储空间
; ......
; HEAPBASE = __heap_base; //读取HEAP的即地址,只在MICROLIB时有效
; ......
; }
;如果要在不使用MICROLIB时,读取__heap_base, 那只需要在__heap_base前添加EXPORT __heap_base
Heap_Mem SPACE Heap_Size
;EXPORT Heap_Mem
;定义HEAP的内存段,标签为Heap_Mem,将Heap_Mem EXPORT之后,可以这样访问:
; extern int Heap_Mem;
; static int* pHEAPMEM;
; pHEAPMEM = (int*)Heap_Mem;
__heap_limit
;定义一个标签,HEAP的地址范围为__heap_base ~ (__heap_limit - 1)
;这里结合MAP文件外插上几句
;1. 当:STACK 所在节属性为 AREA STACK, NOINIT, READWRITE, ALIGN=3
; HEAP 所在节属性为 AREA HEAP, NOINIT, READWRITE, ALIGN=3
; 时,MAP文件的执行时期RAM镜像为
; Execution Region RW_IRAM2 (Base: 0x20000000, Size: 0x00000268, Max: 0x00000c00, ABSOLUTE)
;
; Base Addr Size Type Attr Idx E Section Name Object
;
; 0x20000000 0x00000004 Data RW 4 .data system_mkl02z4.o
; 0x20000004 0x00000004 Data RW 61 .data blinky.o
; 0x20000008 0x00000060 Zero RW 139 .bss c_p.l(libspace.o)
; 0x20000068 0x00000100 Zero RW 48 HEAP startup_mkl02z4.o
; 0x20000168 0x00000100 Zero RW 47 STACK startup_mkl02z4.o
;
; 可见,在程序运行时,数据在内存中存放的顺序为有初始化的Data类型,和0初始化的Zero类型
; 此时,HEAP向上增长,STACK向下生长,二者的方向是相向的
; 全局变量,如果没有指定初始值,如static int gTestData; 是存放在.dada节,而不是.bss
;
;2. 当:STACK 所在节属性为 AREA STACK, READWRITE, ALIGN=3
; HEAP 所在节属性为 AREA HEAP, NOINIT, READWRITE, ALIGN=3
; 时,MAP文件的执行时期RAM镜像为
; Execution Region RW_IRAM2 (Base: 0x20000000, Size: 0x00000268, Max: 0x00000c00, ABSOLUTE)
;
; Base Addr Size Type Attr Idx E Section Name Object
;
; 0x20000000 0x00000004 Data RW 4 .data system_mkl02z4.o
; 0x20000004 0x00000004 Data RW 61 .data blinky.o
; 0x20000008 0x00000100 Data RW 47 STACK startup_mkl02z4.o
; 0x20000108 0x00000060 Zero RW 139 .bss c_p.l(libspace.o)
; 0x20000168 0x00000100 Zero RW 48 HEAP startup_mkl02z4.o
;
; 此时HEAP向上增长,STACK向下生长,二者的方向是相背的
; 同时可以看出,不用NOINIT修饰时,STACK的数据类型为Data,是一种RW Type,否则是一种ZI Type
;
;部分细节看参见Linker User Guide: Type 2 image, one load region and non-contiguous execution regions
PRESERVE8
;通知链接器(linker)当前文件是以堆栈8字节对齐,使用PRESERVE8的话,说明我们现在的文件堆栈是以8字节对齐的
;这样的话,这里的函数可以调用由REQUIRE8指示的文件的函数,而不引起错误,如LDRD and STRD指令,因为
;LDRD and STRD instructions (double-word transfers) only work correctly if the address they access
;is 8-byte aligned.
THUMB
;通知编译器采用THUMB指令集
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
;指示当前节为RESET,节的属性为DATA(Contains data, not instructions),RO
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
;全局变量__Vectors,__Vectors_End,和__Vectors_Size
;分散加载文件SCT为
; LR_IROM1 0x00000000 0x00008000 { ; load region size_region
; ER_IROM1 0x00000000 0x00008000 { ; load address = execution address
; *.o (RESET, +First) ; +First指示执行时RESET节置于最开始
; *(InRoot$Sections) ; InRoot$Sections指代所有必须放在根区域的节
; ; 如__main.o, __scatter*.o,
; ; __dc*.o, and * Region$Table
; .ANY (+RO) ; Read only的数据执行时在这里
; }
; RW_IRAM1 0x1FFFFC00 0x00000400 { ; RW data
; .ANY (+RW +ZI)
; }
; RW_IRAM2 0x20000000 0x00000C00 {
; .ANY (+RW +ZI)
; }
; }
;我们可以这样更改分散加载文件为
; LR_IROM1 0x00000000 0x00008000 { ; load region size_region
; ER_IROM1 0x00000000 0x00008000 { ; load address = execution address
; *.o (RESET, +First)
; *(InRoot$Sections)
; .ANY (+RO)
; }
; RW_IRAM1 0x1FFFFC00 0x00000400 { ; RW data
; .ANY (+ZI)
; }
; RW_IRAM2 0x20000000 0x00000C00 {
; .ANY (+RW)
; *.o (.bss)
; }
; }
;这样,执行时候的内存镜像变成这样子了,我们利用起来了两块RAM区的特点
; Execution Region RW_IRAM1 (Base: 0x1ffffc00, Size: 0x00000200, Max: 0x00000400, ABSOLUTE)
;
; Base Addr Size Type Attr Idx E Section Name Object
;
; 0x1ffffc00 0x00000100 Zero RW 48 HEAP startup_mkl02z4.o
; 0x1ffffd00 0x00000100 Zero RW 47 STACK startup_mkl02z4.o
;
;
; Execution Region RW_IRAM2 (Base: 0x20000000, Size: 0x00000068, Max: 0x00000c00, ABSOLUTE)
;
; Base Addr Size Type Attr Idx E Section Name Object
;
; 0x20000000 0x00000004 Data RW 4 .data system_mkl02z4.o
; 0x20000004 0x00000004 Data RW 61 .data blinky.o
; 0x20000008 0x00000060 Zero RW 139 .bss c_p.l(libspace.o)
__Vectors DCD __initial_sp ; Top of Stack
; DCD 申请4字节的空间,存放数据
; 由于分散加载文件SCT中的*.o (RESET, +First)属性
; RESET节被放在了LR_IROM1的开始位置,即__initial_sp存放在0地址
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD Reserved16_IRQHandler ; Reserved interrupt 16
DCD Reserved17_IRQHandler ; Reserved interrupt 17
DCD Reserved18_IRQHandler ; Reserved interrupt 18
DCD Reserved19_IRQHandler ; Reserved interrupt 19
DCD Reserved20_IRQHandler ; Reserved interrupt 20
DCD FTFA_IRQHandler ; FTFA command complete/read collision interrupt
DCD LVD_LVW_IRQHandler ; Low Voltage Detect, Low Voltage Warning
DCD Reserved23_IRQHandler ; Reserved interrupt 23
DCD I2C0_IRQHandler ; I2C0 interrupt
DCD I2C1_IRQHandler ; I2C1 interrupt
DCD SPI0_IRQHandler ; SPI0 interrupt
DCD Reserved27_IRQHandler ; Reserved interrupt 27
DCD UART0_IRQHandler ; UART0 status/error interrupt
DCD Reserved29_IRQHandler ; Reserved interrupt 29
DCD Reserved30_IRQHandler ; Reserved interrupt 30
DCD ADC0_IRQHandler ; ADC0 interrupt
DCD CMP0_IRQHandler ; CMP0 interrupt
DCD TPM0_IRQHandler ; TPM0 fault, overflow and channels interrupt
DCD TPM1_IRQHandler ; TPM1 fault, overflow and channels interrupt
DCD Reserved35_IRQHandler ; Reserved interrupt 35
DCD Reserved36_IRQHandler ; Reserved interrupt 36
DCD Reserved37_IRQHandler ; Reserved interrupt 37
DCD Reserved38_IRQHandler ; Reserved interrupt 38
DCD Reserved39_IRQHandler ; Reserved interrupt 39
DCD Reserved40_IRQHandler ; Reserved interrupt 40
DCD Reserved41_IRQHandler ; Reserved interrupt 41
DCD Reserved42_IRQHandler ; Reserved interrupt 42
DCD MCG_IRQHandler ; MCG interrupt
DCD LPTimer_IRQHandler ; LPTimer interrupt
DCD Reserved45_IRQHandler ; Reserved interrupt 45
DCD PORTA_IRQHandler ; Port A interrupt
DCD PORTB_IRQHandler ; Port B interrupt
__Vectors_End
;这里__Vectors_End的值为0x000000c0 (在MAP文件里查看)
__Vectors_Size EQU __Vectors_End - __Vectors ;计算中断向量表的大小
; 以下为Freescale特有的配置方式(我的理解,在ST中不是采用的这种配置方法)
; Flash配置区域在Flash的0x0000_0400开始的空间,一共16字节
; 关于Flash配置区域在帖子 http://www.amobbs.com/thread-5588189-1-1.html 中有描述
; 以下定义的变量值,在下面有采用,这边略过Flash配置字的含义,详见Reference Mannual
;
;
; Flash Configuration
; 16-byte flash configuration field that stores default protection settings (loaded on reset)
; and security information that allows the MCU to restrict acces to the FTFL module.
; Backdoor Comparison Key
; Backdoor Key 0 <0x0-0xFF:2>
; Backdoor Key 1 <0x0-0xFF:2>
; Backdoor Key 2 <0x0-0xFF:2>
; Backdoor Key 3 <0x0-0xFF:2>
; Backdoor Key 4 <0x0-0xFF:2>
; Backdoor Key 5 <0x0-0xFF:2>
; Backdoor Key 6 <0x0-0xFF:2>
; Backdoor Key 7 <0x0-0xFF:2>
BackDoorK0 EQU 0xFF
BackDoorK1 EQU 0xFF
BackDoorK2 EQU 0xFF
BackDoorK3 EQU 0xFF
BackDoorK4 EQU 0xFF
BackDoorK5 EQU 0xFF
BackDoorK6 EQU 0xFF
BackDoorK7 EQU 0xFF
;
; Program flash protection bytes (FPROT)
; Each program flash region can be protected from program and erase operation by setting the associated PROT bit.
; Each bit protects a 1/32 region of the program flash memory.
; FPROT0
; Program flash protection bytes
; 1/32 - 8/32 region
; FPROT0.0
; FPROT0.1
; FPROT0.2
; FPROT0.3
; FPROT0.4
; FPROT0.5
; FPROT0.6
; FPROT0.7
nFPROT0 EQU 0x00
FPROT0 EQU nFPROT0:EOR:0xFF
;
; FPROT1
; Program Flash Region Protect Register 1
; 9/32 - 16/32 region
; FPROT1.0
; FPROT1.1
; FPROT1.2
; FPROT1.3
; FPROT1.4
; FPROT1.5
; FPROT1.6
; FPROT1.7
nFPROT1 EQU 0x00
FPROT1 EQU nFPROT1:EOR:0xFF
;
; FPROT2
; Program Flash Region Protect Register 2
; 17/32 - 24/32 region
; FPROT2.0
; FPROT2.1
; FPROT2.2
; FPROT2.3
; FPROT2.4
; FPROT2.5
; FPROT2.6
; FPROT2.7
nFPROT2 EQU 0x00
FPROT2 EQU nFPROT2:EOR:0xFF
;
; FPROT3
; Program Flash Region Protect Register 3
; 25/32 - 32/32 region
; FPROT3.0
; FPROT3.1
; FPROT3.2
; FPROT3.3
; FPROT3.4
; FPROT3.5
; FPROT3.6
; FPROT3.7
nFPROT3 EQU 0x00
FPROT3 EQU nFPROT3:EOR:0xFF
;
;
;
; Flash nonvolatile option byte (FOPT)
; Allows the user to customize the operation of the MCU at boot time.
; LPBOOT0
; <0=> Core and system clock divider (OUTDIV1) is 0x7 (divide by 8) or 0x3 (divide by 4)
; <1=> Core and system clock divider (OUTDIV1) is 0x1 (divide by 2) or 0x0 (divide by 1)
; LPBOOT1
; <0=> Core and system clock divider (OUTDIV1) is 0x7 (divide by 8) or 0x1 (divide by 2)
; <1=> Core and system clock divider (OUTDIV1) is 0x3 (divide by 4) or 0x0 (divide by 1)
; NMI_DIS
; <0=> NMI interrupts are always blocked
; <1=> NMI pin/interrupts reset default to enabled
; RESET_PIN_CFG
; <0=> RESET pin is disabled following a POR and cannot be enabled as RESET function
; <1=> RESET pin is dedicated
; FAST_INIT
; <0=> Slower initialization
; <1=> Fast Initialization
FOPT EQU 0xFF
;
; Flash security byte (FSEC)
; WARNING: If SEC field is configured as "MCU security status is secure" and MEEN field is configured as "Mass erase is disabled",
; MCU's security status cannot be set back to unsecure state since Mass erase via the debugger is blocked !!!
; SEC
; <2=> MCU security status is unsecure
; <3=> MCU security status is secure
; Flash Security
; This bits define the security state of the MCU.
; FSLACC
; <2=> Freescale factory access denied
; <3=> Freescale factory access granted
; Freescale Failure Analysis Access Code
; This bits define the security state of the MCU.
; MEEN
; <2=> Mass erase is disabled
; <3=> Mass erase is enabled
; Mass Erase Enable Bits
; Enables and disables mass erase capability of the FTFL module
; KEYEN
; <2=> Backdoor key access enabled
; <3=> Backdoor key access disabled
; Backdoor key Security Enable
; These bits enable and disable backdoor key access to the FTFL module.
FSEC EQU 0xFE
;
;
; 在这里,定义了一个新的节,名称是.ARM,位于地址0x400,在MAP文件里是这样的
; ......
; 0x000003cc 0x00000030 Data RO 263 Region$Table anon$obj.o
; 0x000003fc 0x00000004 PAD
; 0x00000400 0x00000010 Code RO 50 .ARM.__at_0x400 startup_mkl02z4.o
; 0x00000410 0x00000174 Code RO 59 .text blinky.o
; 0x00000584 0x0000015a Code RO 93 .text c_p.l(aeabi_sdiv.o)
; ......
; 可见PAD补充字节空间,.ARM.__at_0x400放在了0x0400地址,而这些地址存放的数据,是CODE,RO类型
; 下面的DCB填充了这16个字节
IF :LNOT::DEF:RAM_TARGET
; :DEF:A 语句,如果A定义,返回真,否则返回假
; :LNOT:A 语句,是对A的逻辑取反
; 结合上面的 IF,所以以下代码尽在RAM_TARGET没定义的时候会产生
; 如果在RAM中调试的话,应该定义RAM_TARGET,那样的话也就不需要FLASH配置字了
;
AREA |.ARM.__at_0x400|, CODE, READONLY
; 定义一个节,存放配置数据,单片机复位后,FLASH控制器加载这些配置
;
DCB BackDoorK0, BackDoorK1, BackDoorK2, BackDoorK3
DCB BackDoorK4, BackDoorK5, BackDoorK6, BackDoorK7
DCB FPROT0, FPROT1, FPROT2, FPROT3
DCB FSEC, FOPT, 0xFF, 0xFF
ENDIF
; 下面是程序端的开始
AREA |.text|, CODE, READONLY
; AREA定义.text节存放代码,因为.text不是有效的变量名,所以加||限定
; Reset Handler
Reset_Handler PROC
; 同FUNCTION,标记一个函数的开始
EXPORT Reset_Handler [WEAK]
; 弱引用,通知链接器,其它文件中的同名函数的优先级高于这个函数,即只有当其它文件中无
; Reset_Handler函数时,Reset_Handler()才指向这里
IMPORT SystemInit
; 告诉链接器到其它文件中查找SystemInit函数
IMPORT __main
; 告诉链接器到其它文件中查找__main函数
LDR R0, =SystemInit
; 执行SystemInit();
BLX R0
LDR R0, =__main
; 执行__main(); __main()调用main(),因而正常情况下不返回
BX R0
ENDP
; 标记函数的结束
; Dummy Exception Handlers (infinite loops which can be modified)
; 异常函数,弱引用,需要在其它文件中自定义相同名称的函数,以进行异常的处理
;
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B . ; B . 表示跳转到当前地址
ENDP
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
PendSV_Handler PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
Default_Handler PROC
EXPORT Reserved16_IRQHandler [WEAK]
EXPORT Reserved17_IRQHandler [WEAK]
EXPORT Reserved18_IRQHandler [WEAK]
EXPORT Reserved19_IRQHandler [WEAK]
EXPORT Reserved20_IRQHandler [WEAK]
EXPORT FTFA_IRQHandler [WEAK]
EXPORT LVD_LVW_IRQHandler [WEAK]
EXPORT Reserved23_IRQHandler [WEAK]
EXPORT I2C0_IRQHandler [WEAK]
EXPORT I2C1_IRQHandler [WEAK]
EXPORT SPI0_IRQHandler [WEAK]
EXPORT Reserved27_IRQHandler [WEAK]
EXPORT UART0_IRQHandler [WEAK]
EXPORT Reserved29_IRQHandler [WEAK]
EXPORT Reserved30_IRQHandler [WEAK]
EXPORT ADC0_IRQHandler [WEAK]
EXPORT CMP0_IRQHandler [WEAK]
EXPORT TPM0_IRQHandler [WEAK]
EXPORT TPM1_IRQHandler [WEAK]
EXPORT Reserved35_IRQHandler [WEAK]
EXPORT Reserved36_IRQHandler [WEAK]
EXPORT Reserved37_IRQHandler [WEAK]
EXPORT Reserved38_IRQHandler [WEAK]
EXPORT Reserved39_IRQHandler [WEAK]
EXPORT Reserved40_IRQHandler [WEAK]
EXPORT Reserved41_IRQHandler [WEAK]
EXPORT Reserved42_IRQHandler [WEAK]
EXPORT MCG_IRQHandler [WEAK]
EXPORT LPTimer_IRQHandler [WEAK]
EXPORT Reserved45_IRQHandler [WEAK]
EXPORT PORTA_IRQHandler [WEAK]
EXPORT PORTB_IRQHandler [WEAK]
EXPORT DefaultISR [WEAK]
Reserved16_IRQHandler
Reserved17_IRQHandler
Reserved18_IRQHandler
Reserved19_IRQHandler
Reserved20_IRQHandler
FTFA_IRQHandler
LVD_LVW_IRQHandler
Reserved23_IRQHandler
I2C0_IRQHandler
I2C1_IRQHandler
SPI0_IRQHandler
Reserved27_IRQHandler
UART0_IRQHandler
Reserved29_IRQHandler
Reserved30_IRQHandler
ADC0_IRQHandler
CMP0_IRQHandler
TPM0_IRQHandler
TPM1_IRQHandler
Reserved35_IRQHandler
Reserved36_IRQHandler
Reserved37_IRQHandler
Reserved38_IRQHandler
Reserved39_IRQHandler
Reserved40_IRQHandler
Reserved41_IRQHandler
Reserved42_IRQHandler
MCG_IRQHandler
LPTimer_IRQHandler
Reserved45_IRQHandler
PORTA_IRQHandler
PORTB_IRQHandler
DefaultISR
;上面这些函数的地址都是一样的,即标号的值都相同,但都是弱引用
B .
ENDP
ALIGN
; ALIGN不指定参数时,将当前地址对起到4字节,填0或NOP,或其它给定值
; User Initial Stack & Heap
IF :DEF:__MICROLIB
; 如果定义使用MICROLIB,则将下面的标号声明为全局变量,供MICROLIB使用
;
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
; 指定存储器模式为双区模式
; 单区模型:(r0, r1)是单个堆栈和堆区,r1大于r0,忽略r2和r3
; 堆和栈共用一块内存区域
; 双区模型:(r0, r2)是初始堆,(r3, r1)是初始栈
; 堆和栈分别指定了单独的内存区域
;
EXPORT __user_initial_stackheap
; 声明一个全局标号 __user_initial_stackheap作为函数使用
__user_initial_stackheap
; C标准库调用__user_initial_stackheap()函数,获得堆栈信息
; 这里没有使用PROC标记
;
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ALIGN
ENDIF
END
;/*****************************************************************************
; * @file: startup_MKL02Z4.s
; * @purpose: CMSIS Cortex-M0plus Core Device Startup File for the
; * MKL02Z4
; * @version: 1.0
; * @date: 2012-10-4
; *
; * Copyright: 1997 - 2013 Freescale Semiconductor, Inc. All Rights Reserved.
;*
; *------- <<< Use Configuration Wizard in Context Menu >>> ------------------
; *
; *****************************************************************************/
;
;
;
Stack_Size EQU 0x00000100
;EQU定义符号指示Stack大小
AREA STACK, NOINIT, READWRITE, ALIGN=3
;AREA 通知汇编器汇编一段新的代码或数据节(section)
;STACK 为AREA所定义的新的节的节名称(sectionname)
;NOINIT 指示这段数据节不初始化或初始化为0,以SPACE等指示的空间初始化为0,但不能初始化为其它
; 备注:即这段不能指定初始化值,如果不加NOINIT的话,MAP文件SPACE的数据类型为Data,为RW Data
; 如果加NOINIT的话,MAP文件SPACE的数据类型为Zero,为ZI Data
;READWRITE 指示该节类型为RW
;ALIGN=3 指示该节对齐到8字节boundary,即为双字地址
; 备注:在MAP文件中,可以发现是通过添加PAD类型的数据进行节的对齐
; PAD取何值可以指定
Stack_Mem SPACE Stack_Size
;Stack_Mem 为一个标签(label),标签值为在当前节中的地址
;SPACE 指示(directive)一块内存(memory),这块内存所在节的特性由上面的AREA指定
__initial_sp
;__initial_sp 为上面SPACE块的顶端地址+1,即说明堆栈的初始值为顶端地址,堆栈是向下生长的满栈
; 备注:因为CM的入栈操作是,*(--R13)=R0类似的一种方式,R13指向最后的数据
;
;
;
Heap_Size EQU 0x00000100
;定义符号指示Heap大小
AREA HEAP, NOINIT, READWRITE, ALIGN=3
;定义一个新的节,节名称为HEAP,其它与STACK相同
;EXPORT __heap_base
__heap_base
;定义一个标签,指示HEAP的基地址,这个标签只用在使用MICROLIB时被EXPORT,即只有这时有效
;使用MICROLIB时,这个标签被EXPORT,类似于C语言中的extern,但只有当HEAP被使用的时候
; 才出现在MAP文件中,如在main()中可以这样来访问__heap_base
; void main(void)
; {
; extern int __heap_base;
; static int HEAPBASE; //定义静态变量,在内存中有固定的存储空间
; ......
; HEAPBASE = __heap_base; //读取HEAP的即地址,只在MICROLIB时有效
; ......
; }
;如果要在不使用MICROLIB时,读取__heap_base, 那只需要在__heap_base前添加EXPORT __heap_base
Heap_Mem SPACE Heap_Size
;EXPORT Heap_Mem
;定义HEAP的内存段,标签为Heap_Mem,将Heap_Mem EXPORT之后,可以这样访问:
; extern int Heap_Mem;
; static int* pHEAPMEM;
; pHEAPMEM = (int*)Heap_Mem;
__heap_limit
;定义一个标签,HEAP的地址范围为__heap_base ~ (__heap_limit - 1)
;这里结合MAP文件外插上几句
;1. 当:STACK 所在节属性为 AREA STACK, NOINIT, READWRITE, ALIGN=3
; HEAP 所在节属性为 AREA HEAP, NOINIT, READWRITE, ALIGN=3
; 时,MAP文件的执行时期RAM镜像为
; Execution Region RW_IRAM2 (Base: 0x20000000, Size: 0x00000268, Max: 0x00000c00, ABSOLUTE)
;
; Base Addr Size Type Attr Idx E Section Name Object
;
; 0x20000000 0x00000004 Data RW 4 .data system_mkl02z4.o
; 0x20000004 0x00000004 Data RW 61 .data blinky.o
; 0x20000008 0x00000060 Zero RW 139 .bss c_p.l(libspace.o)
; 0x20000068 0x00000100 Zero RW 48 HEAP startup_mkl02z4.o
; 0x20000168 0x00000100 Zero RW 47 STACK startup_mkl02z4.o
;
; 可见,在程序运行时,数据在内存中存放的顺序为有初始化的Data类型,和0初始化的Zero类型
; 此时,HEAP向上增长,STACK向下生长,二者的方向是相向的
; 全局变量,如果没有指定初始值,如static int gTestData; 是存放在.dada节,而不是.bss
;
;2. 当:STACK 所在节属性为 AREA STACK, READWRITE, ALIGN=3
; HEAP 所在节属性为 AREA HEAP, NOINIT, READWRITE, ALIGN=3
; 时,MAP文件的执行时期RAM镜像为
; Execution Region RW_IRAM2 (Base: 0x20000000, Size: 0x00000268, Max: 0x00000c00, ABSOLUTE)
;
; Base Addr Size Type Attr Idx E Section Name Object
;
; 0x20000000 0x00000004 Data RW 4 .data system_mkl02z4.o
; 0x20000004 0x00000004 Data RW 61 .data blinky.o
; 0x20000008 0x00000100 Data RW 47 STACK startup_mkl02z4.o
; 0x20000108 0x00000060 Zero RW 139 .bss c_p.l(libspace.o)
; 0x20000168 0x00000100 Zero RW 48 HEAP startup_mkl02z4.o
;
; 此时HEAP向上增长,STACK向下生长,二者的方向是相背的
; 同时可以看出,不用NOINIT修饰时,STACK的数据类型为Data,是一种RW Type,否则是一种ZI Type
;
;部分细节看参见Linker User Guide: Type 2 image, one load region and non-contiguous execution regions
PRESERVE8
;通知链接器(linker)当前文件是以堆栈8字节对齐,使用PRESERVE8的话,说明我们现在的文件堆栈是以8字节对齐的
;这样的话,这里的函数可以调用由REQUIRE8指示的文件的函数,而不引起错误,如LDRD and STRD指令,因为
;LDRD and STRD instructions (double-word transfers) only work correctly if the address they access
;is 8-byte aligned.
THUMB
;通知编译器采用THUMB指令集
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
;指示当前节为RESET,节的属性为DATA(Contains data, not instructions),RO
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
;全局变量__Vectors,__Vectors_End,和__Vectors_Size
;分散加载文件SCT为
; LR_IROM1 0x00000000 0x00008000 { ; load region size_region
; ER_IROM1 0x00000000 0x00008000 { ; load address = execution address
; *.o (RESET, +First) ; +First指示执行时RESET节置于最开始
; *(InRoot$Sections) ; InRoot$Sections指代所有必须放在根区域的节
; ; 如__main.o, __scatter*.o,
; ; __dc*.o, and * Region$Table
; .ANY (+RO) ; Read only的数据执行时在这里
; }
; RW_IRAM1 0x1FFFFC00 0x00000400 { ; RW data
; .ANY (+RW +ZI)
; }
; RW_IRAM2 0x20000000 0x00000C00 {
; .ANY (+RW +ZI)
; }
; }
;我们可以这样更改分散加载文件为
; LR_IROM1 0x00000000 0x00008000 { ; load region size_region
; ER_IROM1 0x00000000 0x00008000 { ; load address = execution address
; *.o (RESET, +First)
; *(InRoot$Sections)
; .ANY (+RO)
; }
; RW_IRAM1 0x1FFFFC00 0x00000400 { ; RW data
; .ANY (+ZI)
; }
; RW_IRAM2 0x20000000 0x00000C00 {
; .ANY (+RW)
; *.o (.bss)
; }
; }
;这样,执行时候的内存镜像变成这样子了,我们利用起来了两块RAM区的特点
; Execution Region RW_IRAM1 (Base: 0x1ffffc00, Size: 0x00000200, Max: 0x00000400, ABSOLUTE)
;
; Base Addr Size Type Attr Idx E Section Name Object
;
; 0x1ffffc00 0x00000100 Zero RW 48 HEAP startup_mkl02z4.o
; 0x1ffffd00 0x00000100 Zero RW 47 STACK startup_mkl02z4.o
;
;
; Execution Region RW_IRAM2 (Base: 0x20000000, Size: 0x00000068, Max: 0x00000c00, ABSOLUTE)
;
; Base Addr Size Type Attr Idx E Section Name Object
;
; 0x20000000 0x00000004 Data RW 4 .data system_mkl02z4.o
; 0x20000004 0x00000004 Data RW 61 .data blinky.o
; 0x20000008 0x00000060 Zero RW 139 .bss c_p.l(libspace.o)
__Vectors DCD __initial_sp ; Top of Stack
; DCD 申请4字节的空间,存放数据
; 由于分散加载文件SCT中的*.o (RESET, +First)属性
; RESET节被放在了LR_IROM1的开始位置,即__initial_sp存放在0地址
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD Reserved16_IRQHandler ; Reserved interrupt 16
DCD Reserved17_IRQHandler ; Reserved interrupt 17
DCD Reserved18_IRQHandler ; Reserved interrupt 18
DCD Reserved19_IRQHandler ; Reserved interrupt 19
DCD Reserved20_IRQHandler ; Reserved interrupt 20
DCD FTFA_IRQHandler ; FTFA command complete/read collision interrupt
DCD LVD_LVW_IRQHandler ; Low Voltage Detect, Low Voltage Warning
DCD Reserved23_IRQHandler ; Reserved interrupt 23
DCD I2C0_IRQHandler ; I2C0 interrupt
DCD I2C1_IRQHandler ; I2C1 interrupt
DCD SPI0_IRQHandler ; SPI0 interrupt
DCD Reserved27_IRQHandler ; Reserved interrupt 27
DCD UART0_IRQHandler ; UART0 status/error interrupt
DCD Reserved29_IRQHandler ; Reserved interrupt 29
DCD Reserved30_IRQHandler ; Reserved interrupt 30
DCD ADC0_IRQHandler ; ADC0 interrupt
DCD CMP0_IRQHandler ; CMP0 interrupt
DCD TPM0_IRQHandler ; TPM0 fault, overflow and channels interrupt
DCD TPM1_IRQHandler ; TPM1 fault, overflow and channels interrupt
DCD Reserved35_IRQHandler ; Reserved interrupt 35
DCD Reserved36_IRQHandler ; Reserved interrupt 36
DCD Reserved37_IRQHandler ; Reserved interrupt 37
DCD Reserved38_IRQHandler ; Reserved interrupt 38
DCD Reserved39_IRQHandler ; Reserved interrupt 39
DCD Reserved40_IRQHandler ; Reserved interrupt 40
DCD Reserved41_IRQHandler ; Reserved interrupt 41
DCD Reserved42_IRQHandler ; Reserved interrupt 42
DCD MCG_IRQHandler ; MCG interrupt
DCD LPTimer_IRQHandler ; LPTimer interrupt
DCD Reserved45_IRQHandler ; Reserved interrupt 45
DCD PORTA_IRQHandler ; Port A interrupt
DCD PORTB_IRQHandler ; Port B interrupt
__Vectors_End
;这里__Vectors_End的值为0x000000c0 (在MAP文件里查看)
__Vectors_Size EQU __Vectors_End - __Vectors ;计算中断向量表的大小
; 以下为Freescale特有的配置方式(我的理解,在ST中不是采用的这种配置方法)
; Flash配置区域在Flash的0x0000_0400开始的空间,一共16字节
; 关于Flash配置区域在帖子 http://www.amobbs.com/thread-5588189-1-1.html 中有描述
; 以下定义的变量值,在下面有采用,这边略过Flash配置字的含义,详见Reference Mannual
;
;
;
; 16-byte flash configuration field that stores default protection settings (loaded on reset)
; and security information that allows the MCU to restrict acces to the FTFL module.
;
;
;
;
;
;
;
;
;
BackDoorK0 EQU 0xFF
BackDoorK1 EQU 0xFF
BackDoorK2 EQU 0xFF
BackDoorK3 EQU 0xFF
BackDoorK4 EQU 0xFF
BackDoorK5 EQU 0xFF
BackDoorK6 EQU 0xFF
BackDoorK7 EQU 0xFF
;
;
; Each program flash region can be protected from program and erase operation by setting the associated PROT bit.
; Each bit protects a 1/32 region of the program flash memory.
;
; Program flash protection bytes
; 1/32 - 8/32 region
;
;
;
;
;
;
;
;
nFPROT0 EQU 0x00
FPROT0 EQU nFPROT0:EOR:0xFF
;
;
; Program Flash Region Protect Register 1
; 9/32 - 16/32 region
;
;
;
;
;
;
;
;
nFPROT1 EQU 0x00
FPROT1 EQU nFPROT1:EOR:0xFF
;
;
; Program Flash Region Protect Register 2
; 17/32 - 24/32 region
;
;
;
;
;
;
;
;
nFPROT2 EQU 0x00
FPROT2 EQU nFPROT2:EOR:0xFF
;
;
; Program Flash Region Protect Register 3
; 25/32 - 32/32 region
;
;
;
;
;
;
;
;
nFPROT3 EQU 0x00
FPROT3 EQU nFPROT3:EOR:0xFF
;
;
;
;
; Allows the user to customize the operation of the MCU at boot time.
;
; <0=> Core and system clock divider (OUTDIV1) is 0x7 (divide by 8) or 0x3 (divide by 4)
; <1=> Core and system clock divider (OUTDIV1) is 0x1 (divide by 2) or 0x0 (divide by 1)
;
; <0=> Core and system clock divider (OUTDIV1) is 0x7 (divide by 8) or 0x1 (divide by 2)
; <1=> Core and system clock divider (OUTDIV1) is 0x3 (divide by 4) or 0x0 (divide by 1)
;
; <0=> NMI interrupts are always blocked
; <1=> NMI pin/interrupts reset default to enabled
;
; <0=> RESET pin is disabled following a POR and cannot be enabled as RESET function
; <1=> RESET pin is dedicated
;
; <0=> Slower initialization
; <1=> Fast Initialization
FOPT EQU 0xFF
;
;
; WARNING: If SEC field is configured as "MCU security status is secure" and MEEN field is configured as "Mass erase is disabled",
; MCU's security status cannot be set back to unsecure state since Mass erase via the debugger is blocked !!!
;
; <2=> MCU security status is unsecure
; <3=> MCU security status is secure
; Flash Security
; This bits define the security state of the MCU.
;
; <2=> Freescale factory access denied
; <3=> Freescale factory access granted
; Freescale Failure Analysis Access Code
; This bits define the security state of the MCU.
;
; <2=> Mass erase is disabled
; <3=> Mass erase is enabled
; Mass Erase Enable Bits
; Enables and disables mass erase capability of the FTFL module
;
; <2=> Backdoor key access enabled
; <3=> Backdoor key access disabled
; Backdoor key Security Enable
; These bits enable and disable backdoor key access to the FTFL module.
FSEC EQU 0xFE
;
;
; 在这里,定义了一个新的节,名称是.ARM,位于地址0x400,在MAP文件里是这样的
; ......
; 0x000003cc 0x00000030 Data RO 263 Region$Table anon$obj.o
; 0x000003fc 0x00000004 PAD
; 0x00000400 0x00000010 Code RO 50 .ARM.__at_0x400 startup_mkl02z4.o
; 0x00000410 0x00000174 Code RO 59 .text blinky.o
; 0x00000584 0x0000015a Code RO 93 .text c_p.l(aeabi_sdiv.o)
; ......
; 可见PAD补充字节空间,.ARM.__at_0x400放在了0x0400地址,而这些地址存放的数据,是CODE,RO类型
; 下面的DCB填充了这16个字节
IF :LNOT::DEF:RAM_TARGET
; :DEF:A 语句,如果A定义,返回真,否则返回假
; :LNOT:A 语句,是对A的逻辑取反
; 结合上面的 IF,所以以下代码尽在RAM_TARGET没定义的时候会产生
; 如果在RAM中调试的话,应该定义RAM_TARGET,那样的话也就不需要FLASH配置字了
;
AREA |.ARM.__at_0x400|, CODE, READONLY
; 定义一个节,存放配置数据,单片机复位后,FLASH控制器加载这些配置
;
DCB BackDoorK0, BackDoorK1, BackDoorK2, BackDoorK3
DCB BackDoorK4, BackDoorK5, BackDoorK6, BackDoorK7
DCB FPROT0, FPROT1, FPROT2, FPROT3
DCB FSEC, FOPT, 0xFF, 0xFF
ENDIF
; 下面是程序端的开始
AREA |.text|, CODE, READONLY
; AREA定义.text节存放代码,因为.text不是有效的变量名,所以加||限定
; Reset Handler
Reset_Handler PROC
; 同FUNCTION,标记一个函数的开始
EXPORT Reset_Handler [WEAK]
; 弱引用,通知链接器,其它文件中的同名函数的优先级高于这个函数,即只有当其它文件中无
; Reset_Handler函数时,Reset_Handler()才指向这里
IMPORT SystemInit
; 告诉链接器到其它文件中查找SystemInit函数
IMPORT __main
; 告诉链接器到其它文件中查找__main函数
LDR R0, =SystemInit
; 执行SystemInit();
BLX R0
LDR R0, =__main
; 执行__main(); __main()调用main(),因而正常情况下不返回
BX R0
ENDP
; 标记函数的结束
; Dummy Exception Handlers (infinite loops which can be modified)
; 异常函数,弱引用,需要在其它文件中自定义相同名称的函数,以进行异常的处理
;
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B . ; B . 表示跳转到当前地址
ENDP
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
PendSV_Handler PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
Default_Handler PROC
EXPORT Reserved16_IRQHandler [WEAK]
EXPORT Reserved17_IRQHandler [WEAK]
EXPORT Reserved18_IRQHandler [WEAK]
EXPORT Reserved19_IRQHandler [WEAK]
EXPORT Reserved20_IRQHandler [WEAK]
EXPORT FTFA_IRQHandler [WEAK]
EXPORT LVD_LVW_IRQHandler [WEAK]
EXPORT Reserved23_IRQHandler [WEAK]
EXPORT I2C0_IRQHandler [WEAK]
EXPORT I2C1_IRQHandler [WEAK]
EXPORT SPI0_IRQHandler [WEAK]
EXPORT Reserved27_IRQHandler [WEAK]
EXPORT UART0_IRQHandler [WEAK]
EXPORT Reserved29_IRQHandler [WEAK]
EXPORT Reserved30_IRQHandler [WEAK]
EXPORT ADC0_IRQHandler [WEAK]
EXPORT CMP0_IRQHandler [WEAK]
EXPORT TPM0_IRQHandler [WEAK]
EXPORT TPM1_IRQHandler [WEAK]
EXPORT Reserved35_IRQHandler [WEAK]
EXPORT Reserved36_IRQHandler [WEAK]
EXPORT Reserved37_IRQHandler [WEAK]
EXPORT Reserved38_IRQHandler [WEAK]
EXPORT Reserved39_IRQHandler [WEAK]
EXPORT Reserved40_IRQHandler [WEAK]
EXPORT Reserved41_IRQHandler [WEAK]
EXPORT Reserved42_IRQHandler [WEAK]
EXPORT MCG_IRQHandler [WEAK]
EXPORT LPTimer_IRQHandler [WEAK]
EXPORT Reserved45_IRQHandler [WEAK]
EXPORT PORTA_IRQHandler [WEAK]
EXPORT PORTB_IRQHandler [WEAK]
EXPORT DefaultISR [WEAK]
Reserved16_IRQHandler
Reserved17_IRQHandler
Reserved18_IRQHandler
Reserved19_IRQHandler
Reserved20_IRQHandler
FTFA_IRQHandler
LVD_LVW_IRQHandler
Reserved23_IRQHandler
I2C0_IRQHandler
I2C1_IRQHandler
SPI0_IRQHandler
Reserved27_IRQHandler
UART0_IRQHandler
Reserved29_IRQHandler
Reserved30_IRQHandler
ADC0_IRQHandler
CMP0_IRQHandler
TPM0_IRQHandler
TPM1_IRQHandler
Reserved35_IRQHandler
Reserved36_IRQHandler
Reserved37_IRQHandler
Reserved38_IRQHandler
Reserved39_IRQHandler
Reserved40_IRQHandler
Reserved41_IRQHandler
Reserved42_IRQHandler
MCG_IRQHandler
LPTimer_IRQHandler
Reserved45_IRQHandler
PORTA_IRQHandler
PORTB_IRQHandler
DefaultISR
;上面这些函数的地址都是一样的,即标号的值都相同,但都是弱引用
B .
ENDP
ALIGN
; ALIGN不指定参数时,将当前地址对起到4字节,填0或NOP,或其它给定值
; User Initial Stack & Heap
IF :DEF:__MICROLIB
; 如果定义使用MICROLIB,则将下面的标号声明为全局变量,供MICROLIB使用
;
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
; 指定存储器模式为双区模式
; 单区模型:(r0, r1)是单个堆栈和堆区,r1大于r0,忽略r2和r3
; 堆和栈共用一块内存区域
; 双区模型:(r0, r2)是初始堆,(r3, r1)是初始栈
; 堆和栈分别指定了单独的内存区域
;
EXPORT __user_initial_stackheap
; 声明一个全局标号 __user_initial_stackheap作为函数使用
__user_initial_stackheap
; C标准库调用__user_initial_stackheap()函数,获得堆栈信息
; 这里没有使用PROC标记
;
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ALIGN
ENDIF
END