欢迎关注“安全有理”微信公众号。
概述
以nuclei-sdk-0.5.0版本进行说明,编译SoC和开发板分别选择默认的evalsoc
和nuclei_fpga_eval
,启动的汇编代码参见startup_evalsoc.S。
复位
/* If BOOT_HARTID is not defined, default value is 0 */
#ifndef BOOT_HARTID
.equ BOOT_HARTID, 0
#endif
.macro DECLARE_INT_HANDLER INT_HDL_NAME
#if defined(__riscv_xlen) && (__riscv_xlen == 32)
.word \INT_HDL_NAME
#else
.dword \INT_HDL_NAME
#endif
.endm
.section .text.vtable
.weak eclic_msip_handler
.weak eclic_mtip_handler
.weak eclic_uart0_int_handler
.weak eclic_inter_core_int_handler
.globl vector_base
.type vector_base, @object
.option push
.option norelax
vector_base:
#ifndef VECTOR_TABLE_REMAPPED
j _start /* 0: Reserved, Jump to _start when reset for vector table not remapped cases.*/
.align LOG_REGBYTES /* Need to align 4 byte for RV32, 8 Byte for RV64 */
#else
DECLARE_INT_HANDLER default_intexc_handler /* 0: Reserved, default handler for vector table remapped cases */
#endif
DECLARE_INT_HANDLER default_intexc_handler /* 1: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 2: Reserved */
DECLARE_INT_HANDLER eclic_msip_handler /* 3: Machine software interrupt */
DECLARE_INT_HANDLER default_intexc_handler /* 4: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 5: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 6: Reserved */
DECLARE_INT_HANDLER eclic_mtip_handler /* 7: Machine timer interrupt */
DECLARE_INT_HANDLER default_intexc_handler /* 8: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 9: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 10: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 11: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 12: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 13: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 14: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 15: Reserved */
DECLARE_INT_HANDLER eclic_inter_core_int_handler /* 16: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 17: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 18: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 19: Interrupt 19 */
DECLARE_INT_HANDLER default_intexc_handler /* 20: Interrupt 20 */
DECLARE_INT_HANDLER default_intexc_handler /* 21: Interrupt 21 */
DECLARE_INT_HANDLER default_intexc_handler /* 22: Interrupt 22 */
DECLARE_INT_HANDLER default_intexc_handler /* 23: Interrupt 23 */
DECLARE_INT_HANDLER default_intexc_handler /* 24: Interrupt 24 */
DECLARE_INT_HANDLER default_intexc_handler /* 25: Interrupt 25 */
DECLARE_INT_HANDLER default_intexc_handler /* 26: Interrupt 26 */
DECLARE_INT_HANDLER default_intexc_handler /* 27: Interrupt 27 */
DECLARE_INT_HANDLER default_intexc_handler /* 28: Interrupt 28 */
DECLARE_INT_HANDLER default_intexc_handler /* 29: Interrupt 29 */
DECLARE_INT_HANDLER default_intexc_handler /* 30: Interrupt 30 */
DECLARE_INT_HANDLER default_intexc_handler /* 31: Interrupt 31 */
DECLARE_INT_HANDLER default_intexc_handler /* 32: Interrupt 32 */
DECLARE_INT_HANDLER default_intexc_handler /* 33: Interrupt 33 */
DECLARE_INT_HANDLER default_intexc_handler /* 34: Interrupt 34 */
DECLARE_INT_HANDLER default_intexc_handler /* 35: Interrupt 35 */
DECLARE_INT_HANDLER default_intexc_handler /* 36: Interrupt 36 */
DECLARE_INT_HANDLER default_intexc_handler /* 37: Interrupt 37 */
DECLARE_INT_HANDLER default_intexc_handler /* 38: Interrupt 38 */
DECLARE_INT_HANDLER default_intexc_handler /* 39: Interrupt 39 */
DECLARE_INT_HANDLER default_intexc_handler /* 40: Interrupt 40 */
DECLARE_INT_HANDLER default_intexc_handler /* 41: Interrupt 41 */
DECLARE_INT_HANDLER default_intexc_handler /* 42: Interrupt 42 */
DECLARE_INT_HANDLER default_intexc_handler /* 43: Interrupt 43 */
DECLARE_INT_HANDLER default_intexc_handler /* 44: Interrupt 44 */
DECLARE_INT_HANDLER default_intexc_handler /* 45: Interrupt 45 */
DECLARE_INT_HANDLER default_intexc_handler /* 46: Interrupt 46 */
DECLARE_INT_HANDLER default_intexc_handler /* 47: Interrupt 47 */
DECLARE_INT_HANDLER default_intexc_handler /* 48: Interrupt 48 */
DECLARE_INT_HANDLER default_intexc_handler /* 49: Interrupt 49 */
DECLARE_INT_HANDLER default_intexc_handler /* 50: Interrupt 50 */
DECLARE_INT_HANDLER eclic_uart0_int_handler /* 51: Interrupt 51 */
DECLARE_INT_HANDLER default_intexc_handler /* 52: Interrupt 52 */
DECLARE_INT_HANDLER default_intexc_handler /* 53: Interrupt 53 */
DECLARE_INT_HANDLER default_intexc_handler /* 54: Interrupt 54 */
DECLARE_INT_HANDLER default_intexc_handler /* 55: Interrupt 55 */
DECLARE_INT_HANDLER default_intexc_handler /* 56: Interrupt 56 */
DECLARE_INT_HANDLER default_intexc_handler /* 57: Interrupt 57 */
DECLARE_INT_HANDLER default_intexc_handler /* 58: Interrupt 58 */
DECLARE_INT_HANDLER default_intexc_handler /* 59: Interrupt 59 */
DECLARE_INT_HANDLER default_intexc_handler /* 60: Interrupt 60 */
DECLARE_INT_HANDLER default_intexc_handler /* 61: Interrupt 61 */
DECLARE_INT_HANDLER default_intexc_handler /* 62: Interrupt 62 */
DECLARE_INT_HANDLER default_intexc_handler /* 63: Interrupt 63 */
.option pop
.equ BOOT_HARTID, 0
:.equ
伪操作定义常数,这里定义启动线程ID默认值为0.macro DECLARE_INT_HANDLER INT_HDL_NAME
:.macro
和.endm
伪操作定义宏,这里声明了中断处理程序,如果是RV32就分配一个字的空间,如果是RV64就分配一个双字的空间.section .text.vtable
:接下来代码汇编到.text.vtable
段.weak ...
:设置了4个中断向量的属性为弱,即后续的相同定义(强属性)可以将其覆盖.globl vector_base
:.globl
伪操作定义一个全局的符号,这里定义向量基地址.type vector_base, @object
:.type
伪操作定义符号的类型,这里声明向量基地址为一个对象.option ...
:.option
伪操作用于设定某些架构特定的选项,push和pop用于临时保存或者恢复.option
伪操作指定的选项,这里.option norelax
用于告诉编译器不进行松弛处理优化,即.option push
和.option pop
之间的代码都不进行这种优化vector_base:
:定义中断向量表,如果定义VECTOR_TABLE_REMAPPED
,开启重映射,即向量表的LMA和VMA不同,定义默认的向量表为default_intexc_handler
,如果向量表没有重映射,就直接跳转到_start
.align LOG_REGBYTES
:.align
伪操作将PC进行对齐,这里RV32表示向量表需要4字节对齐,RV64需要8字节对齐DECLARE_INT_HANDLER ...
:声明中断号0~63的中断处理程序,这里只定义了4个中断处理程序eclic_msip_handler
、eclic_mtip_handler
、eclic_uart0_int_handler
和eclic_inter_core_int_handler
,其他中断均未定义
启动第一阶段
第一阶段主要是关闭中断,初始化gp全局寄存器和tp线程寄存器,配置中断、NVM和异常向量表基地址等。
.section .text.init
.globl _start
.type _start, @function
/**
* Reset Handler called on controller reset
*/
_start:
/* ===== Startup Stage 1 ===== */
/* Disable Global Interrupt */
csrc CSR_MSTATUS, MSTATUS_MIE
/* If SMP_CPU_CNT is not defined,
* assume that only 1 core is allowed to run,
* the core hartid is defined via BOOT_HARTID.
* other harts if run to here, just do wfi in __amp_wait
*/
#ifndef SMP_CPU_CNT
/* take bit 0-7 for hart id in a local cluster */
csrr a0, CSR_MHARTID
andi a0, a0, 0xFF
/* BOOT_HARTID is configurable in Makefile via BOOT_HARTID variable */
li a1, BOOT_HARTID
bne a0, a1, __amp_wait
#endif
/* Initialize GP and TP and jump table base when zcmt enabled */
.option push
.option norelax
la gp, __global_pointer$
la tp, __tls_base
#if defined(__riscv_zcmt)
la t0, __jvt_base$
csrw CSR_JVT, t0
#endif
.option pop
#if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
/* Set correct sp for each cpu
* each stack size is __STACK_SIZE
* defined in linker script */
lui t0, %hi(__STACK_SIZE)
addi t0, t0, %lo(__STACK_SIZE)
la sp, _sp
csrr a0, CSR_MHARTID
andi a0, a0, 0xFF
li a1, 0
1:
beq a0, a1, 2f
sub sp, sp, t0
addi a1, a1, 1
j 1b
2:
#else
/* Set correct sp for current cpu */
la sp, _sp
#endif
/*
* Set the the NMI base mnvec to share
* with mtvec by setting CSR_MMISC_CTL
* bit 9 NMI_CAUSE_FFF to 1
*/
li t0, MMISC_CTL_NMI_CAUSE_FFF
csrs CSR_MMISC_CTL, t0
/*
* Enable Zc feature when compiled zcmp & zcmt
*/
#if defined(__riscv_zcmp) || defined(__riscv_zcmt)
li t0, MMISC_CTL_ZC
csrs CSR_MMISC_CTL, t0
#endif
/*
* Intialize ECLIC vector interrupt
* base address mtvt to vector_base
*/
la t0, vector_base
csrw CSR_MTVT, t0
/*
* Set ECLIC non-vector entry to be controlled
* by mtvt2 CSR register.
* Intialize ECLIC non-vector interrupt
* base address mtvt2 to irq_entry.
*/
la t0, irq_entry
csrw CSR_MTVT2, t0
csrs CSR_MTVT2, 0x1
/*
* Set Exception Entry MTVEC to early_exc_entry
* Due to settings above, Exception and NMI
* will share common entry.
* This early_exc_entry is only used during early
* boot stage before main
*/
la t0, early_exc_entry
csrw CSR_MTVEC, t0
/* Set the interrupt processing mode to ECLIC mode */
li t0, 0x3f
csrc CSR_MTVEC, t0
csrs CSR_MTVEC, 0x3
_start
:定义复位中断处理函数,即系统复位就从此开始执行csrc CSR_MSTATUS, MSTATUS_MIE
:清零mstatus寄存器中的MIE位,即关闭M模式下所有中断csrr a0, CSR_MHARTID
:读取CSR寄存器的硬件线程ID,然后获取低8位andi a0, a0, 0xFF
li a1, BOOT_HARTID
:读取Makefile配置的启动线程IDbne a0, a1, __amp_wait
:如果配置的BOOT_HARTID
与CSR_MHARTID
不相等,即当前运行的核不是配置启动的核,就直接进入wfila gp, __global_pointer$
:初始化gp全局寄存器,gp用于链接器松弛优化la tp, __tls_base
:初始化tp线程寄存器,tp用于在操作系统中保存指向进程控制块——task_struct数据结构的指针la t0, __jvt_base$
和csrw CSR_JVT, t0
:使能zcmt扩展lui t0, %hi(__STACK_SIZE)
和addi t0, t0, %lo(__STACK_SIZE)
:将__STACK_SIZE
的值加载到t0
寄存器中,%hi
和%lo
宏用于提取一个32位地址的高16位和低16位la sp, _sp
:初始化sp栈针寄存器,指向栈的地址csrr a0, CSR_MHARTID
和andi a0, a0, 0xFF
:读取CSR寄存器的硬件线程IDli a1, 0
:加载立即数到a1寄存器beq a0, a1, 2f
、sub sp, sp, t0
、addi a1, a1, 1
和j 1b
:循环为每个CPU核心调整栈指针,最终都会被设置为初始栈指针减去相应数量的__STACK_SIZE
la sp, _sp
:如果未定义SMP_CPU_CNT
,即一个cluster只有一个cpu,就直接跳转至此,初始化sp栈针寄存器,指向栈的地址li t0, MMISC_CTL_NMI_CAUSE_FFF
和csrs CSR_MMISC_CTL, t0
:配置NMI与异常有相同的入口地址li t0, MMISC_CTL_ZC
和csrs CSR_MMISC_CTL, t0
:使能Zc特性la t0, vector_base
和csrw CSR_MTVT, t0
:初始化ECLIC中断向量表的基地址为vector_base
la t0, irq_entry
、csrw CSR_MTVT2, t0
和csrs CSR_MTVT2, 0x1
:初始化非向量中断处理模式的中断入口地址为irq_entry
,并将非向量中断的入口地址与异常的入口地址分开la t0, early_exc_entry
和csrw CSR_MTVEC, t0
:设置异常入口基地址为early_exc_entry
li t0, 0x3f
、csrc CSR_MTVEC, t0
和csrs CSR_MTVEC, 0x3
:设置中断处理模式为ECLIC模式
启动第二阶段
第二阶段主要是使能FPU和Vector单元,开启控制计数器。
/* Enable FPU and Vector Unit if f/d/v exist in march */
#if defined(__riscv_flen) && __riscv_flen > 0
/* Enable FPU, and set state to initial */
li t0, MSTATUS_FS
csrc mstatus, t0
li t0, MSTATUS_FS_INITIAL
csrs mstatus, t0
#endif
#if defined(__riscv_vector)
/* Enable Vector, and set state to initial */
li t0, MSTATUS_VS
csrc mstatus, t0
li t0, MSTATUS_VS_INITIAL
csrs mstatus, t0
#endif
/* Enable mcycle and minstret counter */
csrci CSR_MCOUNTINHIBIT, 0x5
#if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
csrr a0, CSR_MHARTID
li a1, BOOT_HARTID
bne a0, a1, __skip_init
#endif
li t0, MSTATUS_FS
、csrc mstatus, t0
、li t0, MSTATUS_FS_INITIAL
和csrs mstatus, t0
:使能浮点运算单元,设置状态为初始化li t0, MSTATUS_VS
、csrc mstatus, t0
、li t0, MSTATUS_VS_INITIAL
和csrs mstatus, t0
:使能可伸缩矢量扩展,设置状态为初始化csrci CSR_MCOUNTINHIBIT, 0x5
:使能mcycle和minstret的计数csrr a0, CSR_MHARTID
、li a1, BOOT_HARTID
和bne a0, a1, __skip_init
:如果配置的BOOT_HARTID
与CSR_MHARTID
不相等,即当前运行的核不是配置启动的核,就跳过第三阶段相关的初始化动作
启动第三阶段
第三阶段主要是完成数据段和代码段搬运,BSS清零等工作。
__init_common:
/* ===== Startup Stage 3 ===== */
/*
* Load text section from CODE ROM to CODE RAM
* when text LMA is different with VMA
*/
la a0, _text_lma
la a1, _text
/* If text LMA and VMA are equal
* then no need to copy text section */
beq a0, a1, 2f
la a2, _etext
bgeu a1, a2, 2f
1:
/* Load code section if necessary */
lw t0, (a0)
sw t0, (a1)
addi a0, a0, 4
addi a1, a1, 4
bltu a1, a2, 1b
2:
/* Load data section */
la a0, _data_lma
la a1, _data
/* If data vma=lma, no need to copy */
beq a0, a1, 2f
la a2, _edata
bgeu a1, a2, 2f
1:
lw t0, (a0)
sw t0, (a1)
addi a0, a0, 4
addi a1, a1, 4
bltu a1, a2, 1b
2:
/* Clear bss section */
la a0, __bss_start
la a1, _end
bgeu a0, a1, 2f
1:
sw zero, (a0)
addi a0, a0, 4
bltu a0, a1, 1b
2:
la a0, _text_lma
和la a1, _text
:分别加载代码段载入地址和运行地址到a0和a1寄存器中beq a0, a1, 2f
、la a2, _etext
和bgeu a1, a2, 2f
:如果加载地址和运行地址相等,不需要执行代码段拷贝动作,即跳转到标签2处lw t0, (a0)
、sw t0, (a1)
、addi a0, a0, 4
、addi a1, a1, 4
和bltu a1, a2, 1b
:从加载地址处搬运代码段到运行地址处la a0, _data_lma
、la a1, _data
、beq a0, a1, 2f
、la a2, _edata
和bgeu a1, a2, 2f
:同理如果加载地址和运行地址相等,不需要执行数据段拷贝动作,即跳转到标签2处lw t0, (a0)
、sw t0, (a1)
、addi a0, a0, 4
、addi a1, a1, 4
和bltu a1, a2, 1b
:从加载地址处搬运数据段到运行地址处la a0, __bss_start
、la a1, _end
和bgeu a0, a1, 2f
:加载bss段起始地址和结束地址到a0和a1中sw zero, (a0)
、addi a0, a0, 4
和bltu a0, a1, 1b
:清零bss段
跳转主函数
.globl _start_premain
.type _start_premain, @function
_start_premain:
/*
* Call vendor defined SystemInit to
* initialize the micro-controller system
* SystemInit will just be called by boot cpu
*/
call SystemInit
/*
* Call C/C++ constructor start up code,
* __libc_fini is defined in linker script,
* so register_fini function will be called
* and will run atexit (__libc_fini_array)
* to do previous call atexit function
*/
call __libc_init_array
__skip_init:
/* Sync all harts at this function */
call __sync_harts
/* do pre-init steps before main */
/* _premain_init will be called by each cpu
* please make sure the implementation of __premain_int
* considered this
*/
call _premain_init
/*
* When all initialization steps done
* set exception entry to correct exception
* entry and jump to main.
* And set the interrupt processing mode to
* ECLIC mode
*/
la t0, exc_entry
csrw CSR_MTVEC, t0
li t0, 0x3f
csrc CSR_MTVEC, t0
csrs CSR_MTVEC, 0x3
/* BPU cold bringup need time, so enable BPU before enter to main */
li t0, MMISC_CTL_BPU
csrs CSR_MMISC_CTL, t0
/* ===== Call SMP Main Function ===== */
/* argc = argv = 0 */
li a0, 0
li a1, 0
#if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1)
/* The weak implementation of smp_main is in this file */
call smp_main
#else
#ifdef RTOS_RTTHREAD
// Call entry function when using RT-Thread
call entry
#else
call main
#endif
#endif
-
call SystemInit
:调用厂商定义的系统初始化函数,目前是配置系统时钟void SystemInit(void) { /* ToDo: add code to initialize the system * Warn: do not use global variables because this function is called before * reaching pre-main. RW section maybe overwritten afterwards. */ SystemCoreClock = SYSTEM_CLOCK; }
-
call __libc_init_array
:调用C/C++构建启动代码 -
call __sync_harts
:同步所有的harts,即有的hart可能在等待启动hart完成数据段、bss段以及C运行环境的初始化,因此只针对一个cluster的cpu数大于1的情形void __sync_harts(void) { // Only do synchronize when SMP_CPU_CNT is defined and number > 0 #if defined(SMP_CPU_CNT) && (SMP_CPU_CNT > 1) unsigned long hartid = __get_hart_id(); unsigned long tmr_hartid = __get_hart_index(); unsigned long clint_base, irgb_base, smp_base; unsigned long mcfg_info; mcfg_info = __RV_CSR_READ(CSR_MCFG_INFO); if (mcfg_info & MCFG_INFO_IREGION_EXIST) { // IRegion Info present // clint base = system timer base + 0x1000 irgb_base = (__RV_CSR_READ(CSR_MIRGB_INFO) >> 10) << 10; clint_base = irgb_base + IREGION_TIMER_OFS + 0x1000; smp_base = irgb_base + IREGION_SMP_OFS; } else { clint_base = FALLBACK_DEFAULT_SYSTIMER_BASE + 0x1000; smp_base = (__RV_CSR_READ(CSR_MSMPCFG_INFO) >> 4) << 4; } // Enable SMP and L2, disable cluster local memory SMP_CTRLREG(smp_base, 0xc) = 0xFFFFFFFF; SMP_CTRLREG(smp_base, 0x10) = 0x1; SMP_CTRLREG(smp_base, 0xd8) = 0x0; __SMP_RWMB(); // pre-condition: interrupt must be disabled, this is done before calling this function // BOOT_HARTID is defined <Device.h> if (hartid == BOOT_HARTID) { // boot hart // clear msip pending for (int i = 0; i < SMP_CPU_CNT; i ++) { CLINT_MSIP(clint_base, i) = 0; } __SMP_RWMB(); } else { // Set machine software interrupt pending to 1 CLINT_MSIP(clint_base, tmr_hartid) = 1; __SMP_RWMB(); // wait for pending bit cleared by boot hart while (CLINT_MSIP(clint_base, tmr_hartid) == 1); } #endif }
-
call _premain_init
:在跳转到main函数之前,执行一些初始化步骤,void _premain_init(void) { // TODO to make it possible for configurable boot hartid unsigned long hartid = __get_hart_id(); // BOOT_HARTID is defined <Device.h> if (hartid == BOOT_HARTID) { // only done in boot hart // IREGION INFO MUST BE SET BEFORE ANY PREMAIN INIT STEPS _get_iregion_info((IRegion_Info_Type *)(&SystemIRegionInfo)); } /* TODO: Add your own initialization code here, called before main */ // This code located in RUNMODE_CONTROL ifdef endif block just for internal usage // No need to use in your code #ifdef RUNMODE_CONTROL #if defined(RUNMODE_ILM_EN) && RUNMODE_ILM_EN == 0 // Only disable ilm when it is present if (__RV_CSR_READ(CSR_MCFG_INFO) & MCFG_INFO_ILM) { __RV_CSR_CLEAR(CSR_MILM_CTL, MILM_CTL_ILM_EN); } #endif #if defined(RUNMODE_DLM_EN) && RUNMODE_DLM_EN == 0 // Only disable dlm when it is present if (__RV_CSR_READ(CSR_MCFG_INFO) & MCFG_INFO_DLM) { __RV_CSR_CLEAR(CSR_MDLM_CTL, MDLM_CTL_DLM_EN); } #endif #endif /* __ICACHE_PRESENT and __DCACHE_PRESENT are defined in demosoc.h */ // For our internal cpu testing, they want to set demosoc __ICACHE_PRESENT/__DCACHE_PRESENT to be 1 // __CCM_PRESENT is still default to 0 in demosoc.h, since it is used in core_feature_eclic.h to register interrupt, if set to 1, it might cause exception // but in the cpu, icache or dcache might not exist due to cpu configuration, so here // we need to check whether icache/dcache really exist, if yes, then turn on it #if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1) if (ICachePresent()) { // Check whether icache real present or not EnableICache(); } #endif #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1) if (DCachePresent()) { // Check whether dcache real present or not EnableDCache(); } #endif /* Do fence and fence.i to make sure previous ilm/dlm/icache/dcache control done */ __RWMB(); __FENCE_I(); if (hartid == BOOT_HARTID) { // only required for boot hartid // TODO implement get_cpu_freq function to get real cpu clock freq in HZ or directly give the real cpu HZ SystemCoreClock = get_cpu_freq(); uart_init(SOC_DEBUG_UART, 115200); /* Display banner after UART initialized */ SystemBannerPrint(); /* Initialize exception default handlers */ Exception_Init(); /* ECLIC initialization, mainly MTH and NLBIT */ ECLIC_Init(); Trap_Init(); // TODO: internal usage for Nuclei #ifdef RUNMODE_CONTROL printf("Current RUNMODE=%s, ilm:%d, dlm %d, icache %d, dcache %d, ccm %d\n", \ RUNMODE_STRING, RUNMODE_ILM_EN, RUNMODE_DLM_EN, \ RUNMODE_IC_EN, RUNMODE_DC_EN, RUNMODE_CCM_EN); printf("CSR: MILM_CTL 0x%x, MDLM_CTL 0x%x, MCACHE_CTL 0x%x\n", \ __RV_CSR_READ(CSR_MILM_CTL), __RV_CSR_READ(CSR_MDLM_CTL), \ __RV_CSR_READ(CSR_MCACHE_CTL)); #endif } }
_get_iregion_info
:获取CPU内部寄存器信息,如eclic基地址,系统定时器基地址,smp基地址等EnableICache
和EnableDCache
:使能ICACHE和DCACHE__RWMB
和__FENCE_I
:展开为fence iorw, iorw
和fence.i
,fence所有的内存和I/O,类似于arm的isb
命令get_cpu_freq
:获取cpu时钟频率uart_init(SOC_DEBUG_UART, 115200)
:串口初始化SystemBannerPrint
:打印编译时间,下载模式,CPU频率以及HartID等信息Exception_Init
:配置默认的异常处理函数ECLIC_Init
:初始化eclic配置Trap_Init
:初始化监控模式下的trap(中断和异常)入口地址
-
la t0, exc_entry
、csrw CSR_MTVEC, t0
、li t0, 0x3f
、csrc CSR_MTVEC, t0
和csrs CSR_MTVEC, 0x3
:配置异常程序的入口地址,并设置处理器位ECLIC中断模式,exc_entry
在intexc_evalsoc.S
有一个弱函数实现,先保存上下文,保存CSR寄存器,然后调用core_exception_handler
进行异常处理,最后恢复上下文和CSR寄存器,进行异常返回:.weak exc_entry exc_entry: /* Save the caller saving registers (context) */ SAVE_CONTEXT /* Save the necessary CSR registers */ SAVE_CSR_CONTEXT /* * Set the exception handler function arguments * argument 1: mcause value * argument 2: current stack point(SP) value */ csrr a0, mcause mv a1, sp /* * TODO: Call the exception handler function * By default, the function template is provided in * system_Device.c, you can adjust it as you want */ call core_exception_handler /* Restore the necessary CSR registers */ RESTORE_CSR_CONTEXT /* Restore the caller saving registers (context) */ RESTORE_CONTEXT /* Return to regular code */ mret
-
li t0, MMISC_CTL_BPU
和csrs CSR_MMISC_CTL, t0
:开启控制分支预测器 -
li a0, 0
和li a1, 0
:加载0到a0和a1寄存器,即main函数的argc和argv均置为0 -
call smp_main
:如果是多CPU系统,就跳转到smp_main
-
call entry
:如果使用RT-Thread相同,就跳转到entry
函数 -
call main
:如果是裸机就跳转到main
函数,进入主函数继续执行