/*****************************************************************************
* SEGGER Microcontroller GmbH & Co. KG *
* Solutions for real time microcontroller applications *
*****************************************************************************
* *
* (c) 2017 SEGGER Microcontroller GmbH & Co. KG *
* *
* Internet: www.segger.com Support: support@segger.com *
* *
*****************************************************************************/
/*****************************************************************************
* Preprocessor Definitions *
* ------------------------ *
* NO_FPU_ENABLE *
* *
* If defined, FPU will not be enabled. *
* *
* NO_STACK_INIT *
* *
* If defined, the stack pointer will not be initialised. *
* *
* NO_SYSTEM_INIT *
* *
* If defined, the SystemInit() function will not be called. By default *
* SystemInit() is called after reset to enable the clocks and memories to *
* be initialised prior to any C startup initialisation. *
* *
* NO_VTOR_CONFIG *
* *
* If defined, the vector table offset register will not be configured. *
* *
* MEMORY_INIT *
* *
* If defined, the MemoryInit() function will be called. By default *
* MemoryInit() is called after SystemInit() to enable an external memory *
* controller. *
* *
* STACK_INIT_VAL *
* *
* If defined, specifies the initial stack pointer value. If undefined, *
* the stack pointer will be initialised to point to the end of the *
* RAM segment. *
* *
* VECTORS_IN_RAM *
* *
* If defined, the exception vectors will be copied from Flash to RAM. *
* *
*****************************************************************************/
.syntax unified
.syntax unified是ARM汇编器的一种语法规则,它指定了ARM和Thumb指令使用同一种语法规则进行汇编。
这种语法规则相对于.syntax divided来说更加简洁易懂,同时也更加符合现代汇编语言的风格。
在使用.syntax unified语法规则时,ARM和Thumb指令的语法是一致的,因此可以更加方便地进行代码编写和维护。
.global Reset_Handler
.global Reset_Handler是一个汇编指令,它用于定义一个全局的Reset_Handler函数。
在引用的代码中,Reset_Handler函数是用来初始化程序的,包括初始化线程栈指针、关中断和异常等。
这个函数是由编译器自动生成的,但是我们也可以自己写一个Reset_Handler函数来完成相同的初始化工作。
#ifdef INITIALIZE_USER_SECTIONS
.global InitializeUserMemorySections
在Python中,global是一个关键字,用于在函数内部声明一个变量为全局变量。如果在函数内部需要对函数外的变量
进行操作或修改,就需要使用global关键字来声明该变量为全局变量。这样,在函数内部对该变量进行修改后,函数外
部的该变量也会被修改。需要注意的是,全局变量只能在函数外部定义,而不能在函数内部定义。同时,全局变量在函数
内部可以被读取,但是不能被修改,除非使用global关键字声明该变量为全局变量。
#endif
.extern _vectors
根据提供的引用内容,我们可以看到在某个c文件中进行了如下调用:extern uint32_t __Vectors;
这里的extern关键字表示该变量在其他文件中定义,这里只是声明。而__Vectors则是一个变量名,它的类型是
uint32_t,即32位无符号整数。因此,.extern _vectors应该是一个类似的声明,表示_vectors变量在其他文件中
定义,这里只是声明。具体_vectors变量的类型和作用需要查看其他文件的定义。
.section .init, "ax"
这段代码是汇编语言中的一段指令,它的作用是将代码放在.init节中,这是Linux内核中的一个特殊节,用于存放一些
初始化代码。具体来说,这段代码中的232.*willberemovedbypaging_init()是一个函数调用,它的作用是初始化分
页机制,而255.*Thenmapfirst1MBoframincaseitcontainsourbootparams.则是将内存中的前1MB映射到虚拟地址
空间中,以便内核能够访问这些参数。这些参数通常包括内存大小、启动设备等信息,它们是内核启动时非常重要的一部分。
.thumb_func
.equ VTOR_REG, 0xE000ED08
.equ VTOR_REG, 0xE000ED08是一条汇编指令,用于定义一个符号常量VTOR_REG,并将其赋值为0xE000ED08。
在ARM Cortex-M0+/M3/M4内核中,VTOR寄存器的地址就是0xE000ED08,这个寄存器用于设置异常和中断向量表的默认
地址。因此,我们可以使用.equ指令来定义VTOR_REG常量,方便在程序中使用。
.equ FPU_CPACR_REG, 0xE000ED88
#ifndef STACK_INIT_VAL
#define STACK_INIT_VAL __RAM_segment_end__
#define STACK_INIT_VAL __RAM_segment_end__是一个宏定义,它的作用是将栈的初始值设置为RAM段的末尾地址。
在嵌入式系统中,栈是用来存储函数调用时的局部变量和返回地址等信息的一块内存区域。通过将栈的初始值设置为RAM段的
末尾地址,可以确保栈不会与其他变量或数据重叠,从而保证程序的正常运行。
#endif
Reset_Handler:
Reset_Handler是一个处理器的复位中断处理函数,它是在处理器复位时自动调用的。在引用中,Reset_Handler被定义
为一个汇编过程,它的主要作用是设置初始SP(堆栈指针)和PC(程序计数器),并初始化向量表。在初始化向量表后,
Reset_Handler会调用SystemInit函数,将系统时钟配置为72M。最后,Reset_Handler会跳转到标号_main,进入C
程序文件。在引用中,Reset_Handler被定义为一个弱符号,这意味着它可以被用户定义的Reset_Handler所覆盖。
#ifndef NO_STACK_INIT
/* Initialise main stack */
ldr r0, =STACK_INIT_VAL
ldr r1, =0x7
bics r0, r1
mov sp, r0
#endif
这段代码是用来初始化主栈的。首先,它会加载一个叫做 STACK_INIT_VAL 的常量到寄存器 r0 中。然后,它会将常量
0x7 加载到寄存器 r1 中,并对它进行位清操作。接着,它将 r0 和 r1 的值进行按位与操作,并将结果存储回 r0 中。
最后,它将 r0 中的值赋给栈指针寄存器 sp,从而完成了主栈的初始化。
#ifndef NO_SYSTEM_INIT
/* Initialise system */
ldr r0, =SystemInit
blx r0
#endif
根据提供的引用内容,这段代码片段是一个嵌入式系统的main函数,其中包含了一些头文件和任务创建函数。而你提供的代码
片段则是一个条件编译指令,用于在编译时判断是否需要初始化系统。如果定义了NO_SYSTEM_INIT宏,则不会执行
SystemInit函数,否则会执行该函数进行系统初始化。
#ifdef MEMORY_INIT
ldr r0, =MemoryInit
blx r0
#endif
#ifdef VECTORS_IN_RAM
/* Copy exception vectors into RAM */
ldr r0, =__vectors_start__
ldr r1, =__vectors_end__
ldr r2, =__vectors_ram_start__
1:
cmp r0, r1
beq 2f
ldr r3, [r0]
str r3, [r2]
adds r0, r0, #4
adds r2, r2, #4
b 1b
2:
#endif
#ifdef VECTORS_IN_RAM是一个条件编译指令,用于判断是否将异常向量表放在RAM中。如果定义了VECTORS_IN_RAM,
则需要将异常向量表从Flash中复制到RAM中。具体实现方法是使用ldr指令将__vectors_start__和__vectors_end__
的地址加载到r0和r1寄存器中,将__vectors_ram_start__的地址加载到r2寄存器中。然后使用循环将Flash中的异常向
量表逐个读取到r3寄存器中,再使用str指令将其存储到RAM中。最后使用条件分支指令b将程序跳转到1b标签处,继续循环读
取和存储异常向量表,直到读取完毕。如果没有定义VECTORS_IN_RAM,则不需要进行这个操作。
#ifndef NO_VTOR_CONFIG
/* Configure vector table offset register */
ldr r0, =VTOR_REG
#ifdef VECTORS_IN_RAM
ldr r1, =_vectors_ram
#else
ldr r1, =_vectors
#endif
str r1, [r0]
#endif
这段代码是用来配置向量表偏移寄存器的。向量表是一个存储中断处理程序地址的表格,当中断发生时,处理器会根据中断号
从向量表中读取对应的中断处理程序的地址并跳转到该地址执行。在这段代码中,首先判断是否定义了NO_VTOR_CONFIG宏,
如果没有定义,则执行向量表偏移寄存器的配置。具体来说,将VTOR_REG寄存器的地址加载到r0寄存器中,然后根据是否将
向量表放在RAM中,将向量表的地址加载到r1寄存器中。最后,将r1寄存器中的向量表地址存储到VTOR_REG寄存器中,
完成向量表偏移寄存器的配置。
#if (defined(__ARM_ARCH_FPV4_SP_D16__) || defined(__ARM_ARCH_FPV5_D16__)) && !defined(NO_FPU_ENABLE)
/* Enable FPU */
ldr r0, =FPU_CPACR_REG
ldr r1, [r0]
orr r1, r1, #(0xF << 20)
str r1, [r0]
dsb
isb
#endif
/* Jump to program start */
b _start
#ifdef INITIALIZE_USER_SECTIONS
.thumb_func
InitializeUserMemorySections:
ldr r0, =__start_nrf_sections
ldr r1, =__start_nrf_sections_run
ldr r2, =__end_nrf_sections_run
cmp r0, r1
beq 2f
subs r2, r2, r1
beq 2f
1:
ldrb r3, [r0]
adds r0, r0, #1
strb r3, [r1]
adds r1, r1, #1
subs r2, r2, #1
bne 1b
2:
bx lr
#endif