【启动代码】:启动代码的最前面通常是异常向量表(Exception Vector Table)。异常向量表是一组存储在特定地址的指令,用于定义处理器在遇到不同类型的异常时应该跳转到哪个处理程序。在许多嵌入式系统中,这些异常包括复位异常、中断异常、和其他一些特殊情况。
下面的代码是一个简单的 ARM9 启动代码示例,仅包含基本的初始化过程和一个 main 函数的调用。需要根据特定的硬件和需求进行适当的修改。特别是,确保设置正确的堆栈指针(Stack Pointer)地址和适当的初始化数据拷贝过程。
/* ARM9 Startup Code */
/* Vector Table */
.section .vectors
.word _start /* Reset Vector */
.word _undefined /* Undefined Instruction */
.word _swi /* Software Interrupt (SWI/SVC) */
.word _prefetch_abort /* Prefetch Abort */
.word _data_abort /* Data Abort */
.word _reserved /* Reserved */
.word _irq /* IRQ Interrupt */
.word _fiq /* FIQ Interrupt */
/* Start of the program */
.section .text
.global _start
_start:
/* Initialize stack pointer (SP) - You need to set it to a valid RAM address */
ldr sp, =0x20000000 /* Example: Set SP to 0x20000000 */
/* Copy initialized data from ROM to RAM */
bl copy_initialized_data
/* Call main function */
bl main
/* Infinite loop */
b .
/* Copy initialized data from ROM to RAM */
copy_initialized_data:
ldr r0, =_data_loadaddr /* Address of the data in ROM */
ldr r1, =_data /* Address of the data in RAM */
ldr r2, =_edata /* End address of the data in RAM */
copy_loop:
ldr r3, [r0], #4 /* Load word from ROM */
str r3, [r1], #4 /* Store word to RAM */
cmp r1, r2 /* Compare with end address */
blt copy_loop /* If not finished, repeat */
bx lr /* Return from function */
/* Main function */
main:
/* Your main code goes here */
/* Endless loop */
b .
【异常处理,异常向量表】:异常向量表包含了处理各种异常(例如中断、故障、终止等)的处理程序的地址。通过设置 VBAR,可以告诉处理器在哪里查找这些处理程序的入口地址。
【异常和中断】:
异常(Exception)和中断(Interrupt)是计算机体系结构中两个不同的概念,但它们都与处理器的响应机制有关。以下是它们的主要区别:
-
触发原因:
- 异常: 异常通常是由于程序执行期间的错误或非法操作引起的,例如除以零、访问非法内存区域等。异常通常表示程序出现了问题,需要采取相应的处理措施。
- 中断: 中断是由外部事件引起的,可以是来自硬件设备(硬中断)或其他处理器(软中断)的信号。中断允许处理器在执行程序的同时响应外部事件,提高系统的并发性。
-
响应时机:
- 异常: 异常通常在程序执行期间即时发生,导致处理器立即转移到异常处理程序。
- 中断: 中断可以在任何时刻发生,而不受当前程序的控制。当中断发生时,处理器会中断当前执行的程序,跳转到相应的中断服务程序。
-
处理方式:
- 异常: 异常通常需要程序员采取措施来处理,以修复问题或执行适当的错误处理。
- 中断: 中断服务程序通常由系统或应用程序提供,用于处理特定的中断事件。中断服务程序执行完成后,处理器返回到原先执行的程序。
-
临界性:
- 异常: 异常通常是临界的,表示程序执行中出现了无法继续执行的错误。
- 中断: 中断可以是临界的,也可以是非临界的,具体取决于中断的类型和系统的设计。
总体而言,异常和中断都是处理器对外部事件的响应机制,但它们的触发原因、时机和处理方式有所不同。异常更关注于程序执行过程中的错误,而中断更关注于处理外部事件和提高系统的并发性。在某些体系结构中,异常和中断的处理机制可能有所重叠,因此具体实现可能有所不同。
【.ld
文件】通常是链接脚本(Linker Script)的文件扩展名。链接脚本是由链接器使用的文本文件,用于指导链接器如何组织目标文件(Object Files)并生成最终的可执行文件或固件。.ld
文件定义了程序的存储器布局,包括代码、数据、堆栈等的分配方式。
对于嵌入式系统和裸机编程,.ld
文件尤其重要,因为在这些情况下,程序往往直接运行在硬件上,而不依赖于标准操作系统的加载和管理。
MEMORY
{
/* Define memory regions */
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
SECTIONS
{
/* Specify sections and their memory locations */
.text : {
*(.text)
} > FLASH
.data : {
*(.data)
} > RAM
.bss : {
*(.bss)
} > RAM
}
在这个示例中:
-
MEMORY
部分定义了目标设备上的不同存储器区域,比如 Flash 存储器和 RAM。每个区域都有其起始地址(ORIGIN
)和长度(LENGTH
)。 -
SECTIONS
部分定义了程序中不同段(section)的存放位置。.text
区域包含可执行代码,被放置在 Flash 存储器中。.data
区域包含初始化的数据,被放置在 RAM 中。.bss
区域包含未初始化的数据,也被放置在 RAM 中。
这只是一个简化的示例,实际的链接脚本可能会更加复杂,以满足具体的应用程序需求。链接脚本对于裸机编程和嵌入式系统的开发非常重要,因为它决定了代码和数据的布局,以及程序在内存中的执行方式。