F:\study\bl602\study_bl_iot_sdk\bl_iot_sdk\components\platform\soc\bl602\bl602\evb\src\boot\gcc\start.S
源码如下:
//See LICENSE for license details.
/*This is defined in sifive/platform.h, but that can't be included from
* assembly. */
/*
mstatus (Machine Status) 它保存全局中断使能,以及许多其他状态
Bit3: MIE 中断总开关,1开,0关
Bit14~bit13:FS 表示浮点单元的状态,0b00 All off; 0b01initial; 0b10 Clean; 0b11 Dirty
*/
#defineCLINT_CTRL_ADDR 0x02000000
#defineMSTATUS_FS 0x00006000 //mstaus register FS bit position
#defineMSTATUS_MIE 0x00000008 //mstatus register MIE bit position
/* risc-v汇编语法: .section name [,subsection]
* .section 伪操作 将下面代码汇编到名为name的段当中
* 这是是将下面代码汇编到.init段(section)中
*/
.section .init
/* risc-v汇编语法: .global symbol
* .global伪操作定义bl602_start 是全局的
* 我的另一篇帖子"bl602链接文件分析"中可以知道bl602_start就是程序的入口地址
*/
.globl bl602_start
/* risc-v汇编语法: .type name,type description
* .type伪操作符号类型,将bl602_start定义为函数
*/
.type bl602_start,@function
/* cpu 从这里开始执行 */
bl602_start:
/* 以.cfi_开头的汇编指示符CFI即Call Frame Information ,是DWARF2.0定义的函数栈信息,是一种调试信息
* .cfi_开头汇编指示符用来告诉汇编编译器生成相应的DWARF调试信息,详情参考
* https://sourceware.org/binutils/docs-2.31/as/CFI-directives.html
* .cfi_startproc 出现在程序开始,程序结束时使用 .cfi_endproc
* .cfi_undefined ra 是取消ra寄存器之前的值,不能再恢复了
* ra:return address register 用于保存函数调用返回地址
*/
.cfi_startproc
.cfi_undefined ra
/*.option{rvc,norvc,push,pop}
* .option 伪操作用于设定某些架构特定的选项
* .option push 临时保存当前的选项设置
* .option pop 将最近操作设置恢复出来重新生效
* .option push .option pop 成对使用可以在汇编程序中不影响全局选项的情况下,为其中嵌入的某一段
* 代码特别的设置不同选项
* . option relax 允许链接器松弛(链接时多次扫描,尽可能将跳转的两条指定替换为一条)
* .option norelax 不允许链接器松弛
* 此处.option push 就是将所有.option设置入栈选保存起来,等执行完特殊代码后
* 再执行.option pop 恢复
*/
.optionpush
.optionnorelax
/*disable IRQ*/
/* li a0,immediately
*li伪指令可以将任意的32位数据或者地址加载到指定的寄存器
* 这里是 将MSTATUS_MIE 加载到临时寄存器t0
*
*csrc 是特权指令(属于CSR操作指令,CSR指令操作CSR寄存器,CSR寄存器有8个比较重要的)
*
* csrc mstatus,t0 是将mstatus寄存器的t0中对应位置零,这样就是mstatus.mie= 0 关闭总中断*/
li t0, MSTATUS_MIE
csrc mstatus, t0
/*
*la是一条加载伪指令
*gp 全局指针寄存器
* 将ld文件中标签 __global_pointer的值赋值给gp
*我的理解是读取ld文件中__global_pointer$的值,这里是内存地址,给到gp全局指针寄存器
*这样可以使用 relax 优化全局变量访问跳转指令,__global_pointer$值这里是一个内存地址,可以
*优化范围是基于此地址 +-2K范围。这里是优化 .sdata
*
* PROVIDE(__global_pointer$ = . + 0x7F0 );
* KEEP(*libfreertos_riscv.a:*(.sdata.*))
* 可以看出这里是优化 libfreertos_riscv.a
*/
la gp, __global_pointer$
/* 恢复到当前选项配置
*总结一下:在.option push和.optionpop 之间做了两件事情
*1.关中断
*2.将ld文件中__global_pointer$ 赋值给gp寄存器,优化libfreertos_risc-v.a
*/
.optionpop
/*将 ld文件中_sp_main 值赋值给sp寄存器
* sp:栈指针 寄存器 Stack poninter
*
*. = . +__stack_size;
* PROVIDE(_sp_main = . );
* __freertos_irq_stack_top= .;
* 这里的_sp_main 就是 __freertos_irq_stack_top指定freertos 中断 栈地址
* 关于freertos 在risc-v上的移植可以查阅:
* https://www.freertos.org/Using-FreeRTOS-on-RISC-V.html
*/
la sp, _sp_main
#ifndefRUN_IN_RAM
/* Load boot2 partition address */
/* 这里定义的立即数在ld文件中有定义 是boot2的分区表地址
*__boot2_pt_addr_src 地址在BOOT2_PT_ADDR = 0x42049C00 分区表flash存储地址
* __boot2_pt_addr_start 分区表内存起始地址
* __boot2_pt_addr_end分区表内存结束地址
*/
la a0, __boot2_pt_addr_src
la a1, __boot2_pt_addr_start
la a2, __boot2_pt_addr_end
/* bgeu a1,a2,2f 2f表示本地标签,执行2:后的程序,翻译成C伪代码:
*if(a1 >=a2)
* jump 2:
*/
bgeu a1, a2, 2f
/* __boot2_pt_addr_start值< __boot2_pt_addr_end 值 拷贝flash分区表到内存 */
1:
/* 从a0寄存器读值赋值给t0 */
lw t0, (a0)
/* 把t0寄存器值存入寄存器a1,保留最右侧的32bit */
sw t0, (a1)
/* a0 = a0+4 */
addi a0, a0, 4
/* a1 = a1+4 */
addi a1, a1, 4
/* [a1]小于[a2] 的话跳转到1:*/
bltu a1, a2, 1b
/*翻译成C伪代码
While(__boot2_pt_addr_start < __boot2_pt_addr_end)
*__boot2_pt_addr_start++ = *__boot2_pt_addr_src++
*/
/* __boot2_pt_addr_start值 >= __boot2_pt_addr_end 值 */
2:
/* Load boot2 flashCfg address */
/* 跳转到 hal_boot2_get_flash_addr 处执行代码 */
jal hal_boot2_get_flash_addr
la a1, __boot2_flashCfg_start
la a2, __boot2_flashCfg_end
/* 也是判断跳转 */
bgeu a1, a2, 2f
/* 拷贝flash参数表到内存 */
1:
lw t0, (a0)
sw t0, (a1)
addi a0, a0, 4
addi a1, a1, 4
bltu a1, a2, 1b
2:
#endif
/* Load data section */
/*
*_data_load 加载程序地址LMA
*_data_run 运行程序地址 VMA
* _data_run_end
* 拷贝 LMA程序 到 VMA 地址段
*/
la a0, _data_load
la a1, _data_run
la a2, _data_run_end
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 */
/* .bss section 清零 */
la a0, __bss_start
la a1, __bss_end
bgeu a0, a1, 3f
1:
sw zero, (a0)
addi a0, a0, 4
bltu a0, a1, 1b
/* Clear bss section */
/* wifi .bss section 清零 */
la a0, __wifi_bss_start
la a1, __wifi_bss_end
bgeu a0, a1, 3f
1:
sw zero, (a0)
addi a0, a0, 4
bltu a0, a1, 1b
3:
/* Call global constructors */
#if0
la a0, __libc_fini_array
call atexit
call __libc_init_array
#endif
#ifndef__riscv_float_abi_soft
/* Enable FPU */
li t0, MSTATUS_FS
csrs mstatus, t0 //将mstatus 寄存器MSTATUS_FS 位置1 开FPU
csrr t1, mstatus//读取mstatus值到t0寄存器
and t1, t1, t0 //[t1] = [t1] &[ t0]
beqz t1, 1f //如果[t1] == 0 jump 1:
fssr x0 //x0也是zero寄存器,初始化浮点数寄存器为0
1:
#endif
#ifdefined(ENABLE_SMP)
smp_resume(t0, t1)
csrr a0, mhartid
bnez a0, 2f
#endif
auipc ra, 0
addi sp, sp, -16
#if__riscv_xlen == 32
sw ra, 8(sp)
#else
sd ra, 8(sp)
#endif
#ifdefBL602_MATTER_SUPPORT
call setup_heap
#endif
//call global obj constructors
//初始化__preinit_array_,__init_array_区域函数
la s1, __preinit_array_start
la s2, __preinit_array_end
li s3, 4 //[s3] = 4
1:
bgeu s1, s2, 2f
lw a3, (s1) //s1 赋值给a3
jalr a3
add s1, s1, s3
j 1b
2:
la s1, __init_array_start
la s2, __init_array_end
li s3, 4
1:
bgeu s1, s2, 2f
lw a3, (s1)
jalr a3
add s1, s1, s3
j 1b
2:
/* argc = argv = 0 */
li a0, 0
li a1, 0
/* 跳转到 bfl_main 函数 */
call bfl_main
#if 0
tail exit
#endif
1:
j 1b
#ifdefined(ENABLE_SMP)
2:
la t0, trap_entry
csrw mtvec, t0
csrr a0, mhartid
la t1, _sp_main
slli t0, a0, 10
sub sp, t1, t0
auipc ra, 0
addi sp, sp, -16
#if__riscv_xlen == 32
sw ra, 8(sp)
#else
sd ra, 8(sp)
#endif
call secondary_main
tail exit
1:
j 1b
#endif
.cfi_endproc