先来看一个具体的嵌入式工程的start.S文件:
#include "hpm_csr_regs.h"
.section .start, "ax"
.global _start
.type _start,@function
_start:
/* Initialize global pointer */
.option push
.option norelax
la gp, __global_pointer$
la tp, __thread_pointer$
.option pop
/* reset mstatus to 0*/
csrrw x0, mstatus, x0
#ifdef __riscv_flen
/* Enable FPU */
li t0, CSR_MSTATUS_FS_MASK
csrrs t0, mstatus, t0
/* Initialize FCSR */
fscsr zero
#endif
/* Enable LMM1 clock */
la t0, 0xF4000800
lw t1, 0(t0)
ori t1, t1, 0x80
sw t1, 0(t0)
#ifdef INIT_EXT_RAM_FOR_DATA
la t0, _stack_safe
mv sp, t0
call _init_ext_ram
#endif
/* Initialize stack pointer */
la t0, _stack
mv sp, t0
/*
* Initialize LMA/VMA sections.
* Relocation for any sections that need to be copied from LMA to VMA.
*/
call c_startup
#if defined(__SES_RISCV)
/* Initialize the heap */
la a0, __heap_start__
la a1, __heap_end__
sub a1, a1, a0
la t1, __SEGGER_RTL_init_heap
jalr t1
#endif
/* Do global constructors */
call __libc_init_array
#ifndef NO_CLEANUP_AT_START
/* clean up */
call _clean_up
#endif
#ifdef __nds_execit
/* Initialize EXEC.IT table */
la t0, _ITB_BASE_
csrw uitb, t0
#endif
#if defined(CONFIG_FREERTOS) && CONFIG_FREERTOS
#define HANDLER_TRAP freertos_risc_v_trap_handler
/* Use mscratch to store isr level */
csrw mscratch, 0
#elif defined(CONFIG_UCOS_III) && CONFIG_UCOS_III
#define HANDLER_TRAP ucos_risc_v_trap_handler
/* Use mscratch to store isr level */
csrw mscratch, 0
#elif defined(CONFIG_THREADX) && CONFIG_THREADX
#define HANDLER_TRAP tx_risc_v_trap_handler
#define HANDLER_S_TRAP tx_risc_v_trap_handler
/* Use mscratch to store isr level */
csrw mscratch, 0
#else
#define HANDLER_TRAP irq_handler_trap
#endif
#ifndef USE_NONVECTOR_MODE
/* Initial machine trap-vector Base */
la t0, __vector_table
csrw mtvec, t0
/* Enable vectored external PLIC interrupt */
csrsi CSR_MMISC_CTL, 2
#else
/* Initial machine trap-vector Base */
la t0, HANDLER_TRAP
csrw mtvec, t0
/* Disable vectored external PLIC interrupt */
csrci CSR_MMISC_CTL, 2
#endif
/* System reset handler */
call reset_handler
/* Infinite loop, if returned accidentally */
1: j 1b
.weak exit
exit:
1: j 1b
.section .isr_vector, "ax"
.weak nmi_handler
nmi_handler:
1: j 1b
#include "../vectors.h"
这段代码是一个RISC-V架构下的裸机(bare-metal)启动代码示例,它使用了一些特定于RISC-V的指令和SEGGER Embedded Studio(SES)相关的宏定义。下面是对代码主要部分的详细解释:
-
全局入口点:
_start
标签是程序的入口点。在RISC-V中,链接器通常期望找到这个标签作为程序的起始执行点。
-
全局和线程指针初始化:
- 使用
la
(load address)指令将全局指针(gp
)和线程指针(tp
)分别初始化为__global_pointer$
和__thread_pointer$
的地址。这些符号通常在链接脚本中定义。
- 使用
-
重置
mstatus
寄存器:- 通过
csrrw
(atomic read-set-write CSR)指令将mstatus
寄存器重置为0。mstatus
寄存器包含了机器模式的状态信息。
- 通过
-
启用浮点单元(如果可用):
- 如果定义了
__riscv_flen
,则启用浮点单元(FPU),并初始化浮点控制状态寄存器(FCSR)。
- 如果定义了
-
启用LMM1时钟:
- 通过一系列指令访问某个内存地址(
0xF4000800
),并修改该地址处的值以启用LMM1时钟。
- 通过一系列指令访问某个内存地址(
-
初始化外部RAM(如果需要):
- 如果定义了
INIT_EXT_RAM_FOR_DATA
,则初始化外部RAM作为数据存储区域,并设置堆栈指针。
- 如果定义了
-
堆栈指针初始化:
- 将堆栈指针(
sp
)初始化为_stack
标签对应的地址。
- 将堆栈指针(
-
初始化LMA/VMA段:
- 调用
c_startup
函数来初始化程序的LMA(加载时内存地址)和VMA(虚拟内存地址)段,并进行必要的复制。
- 调用
-
初始化堆(如果使用的是SEGGER RTL):
- 如果定义了
__SES_RISCV
,则初始化堆空间,并调用SEGGER的堆初始化函数。
- 如果定义了
-
执行全局构造函数:
- 调用
__libc_init_array
函数来执行C标准库的全局构造函数。
- 调用
-
清理(如果定义了清理函数):
- 如果定义了
NO_CLEANUP_AT_START
之外的宏,则调用_clean_up
函数进行清理工作。
- 如果定义了
-
初始化EXEC.IT表(如果定义了相关宏):
- 如果定义了
__nds_execit
,则初始化EXEC.IT表,并设置uitb
寄存器。
- 如果定义了
-
设置陷阱处理程序:
- 根据是否定义了FreeRTOS、uCOS-III或ThreadX,设置不同的陷阱处理程序。
-
设置陷阱向量基地址:
- 根据是否使用向量化模式,设置
mtvec
寄存器为陷阱向量表的基地址或陷阱处理程序的地址。
- 根据是否使用向量化模式,设置
-
系统重置处理程序:
- 调用
reset_handler
函数作为系统重置时的处理程序。
- 调用
-
无限循环:
- 如果程序意外返回,则进入一个无限循环,防止程序继续执行未定义的行为。
-
弱定义的退出和中断处理程序:
- 提供了
exit
和nmi_handler
的弱定义,这些函数在默认情况下执行无限循环。exit
函数可以被用户代码覆盖以实现特定的退出行为。
- 提供了
-
中断向量表:
- 包含了中断向量表的定义,并可能包含其他中断处理程序的弱定义。
-
包含外部向量定义:
- 通过
#include "../vectors.h"
包含外部定义的中断向量和其他相关定义。
- 通过
标签:__,初始化,定义,la,t0,嵌入式,start,handler,详细 From: https://blog.csdn.net/m0_59091453/article/details/144982886