startup.S是bl616的启动文件,以汇编格式存在。这就导致对需要看懂此文件的人要level高一些了,再加上汇编竟然是risc-v的,而不是arm的,导致本人还要恶补一下risc-v的汇编指令和risc-v的寄存器。
这里推荐一下比较的介绍risc-v架构的文章,可以加快读者对risc-v架构的理解:
- riscv-v指令:RISC-V 通用寄存器和指令 | Doongz's Site
- risc-v寄存器:RISC-V 扩展寄存器和指令 | Doongz's Site
这里可以看到和arm架构的寄存器以及指令都有所不同了吧,就连我的文案输出格式都不同了。本来打算指令一个篇章然后寄存器一个篇章,但是risc-v的架构本身就有两组寄存器和两组指令集。
先说一下常用的寄存器:
通用寄存器:
就是用来实现运算功能的,一共是32个32位寄存器,比arm敞亮多了,分别叫做是x0-x31。这一组寄存器中比较特殊的是x0,它只允许读,不支持写,且读出的数据永远是0.
-
Stack Pointer Register(SP)
在RISC-V体系结构中,x2寄存器被用作栈指针(sp),并保存栈的基址。此外,栈基址必须对齐到4个字节。如果不这样做,可能会出现加载/存储对齐错误。
-
Global Pointer Register(GP)
RISC-V使用x3 (gp)寄存器将所有全局变量放置在指定的特定区域。x3寄存器将保存全局变量所在位置的基址。
-
Thread Pointer Register(TP)
在多线程应用程序中,每个线程可能有自己的私有变量集,称为“线程特定变量”。这组变量将由寄存器x4 (tp)指向。
因此,每个线程在其x4寄存器中都有一个不同的值。 -
Return Address Register(RA)
x1 (ra)寄存器用于保存子程序的返回地址。在执行子程序调用之前,x1设置为子程序的返回地址,通常为“pc + 4”。标准的软件调用约定使用x1 (ra)寄存器来保存函数调用的返回地址。
-
Argument Register(参数寄存器)
在RISC-V中,8个参数寄存器,即x10x17(对应a0a7)用于在子程序中传递参数。
在子程序调用之前,子程序的参数被复制到参数寄存器。在参数数量超过8的情况下使用栈。 -
Temporary Register(临时寄存器)
临时寄存器用于在指令执行期间保存中间值。在RISC-V中有7个临时寄存器(t0t6)。
扩展寄存器
我喜欢称这组寄存器为控制状态寄存器。主要用来控制cpu的执行流程的。这组寄存器中比较出名的寄存器:
-
mstatus寄存器,用来控制cpu的中断使能标志位的
-
mcause 寄存器,用来记录cpu的中断类型和异常code
-
mtvec 寄存器,用来存储中断向量表的起始地址
厂商寄存器
这一组不是risc-v架构定义的寄存器,但是risc-v架构提出了对这组寄存器定义标准,各个厂商按照这个标准来实现各自的厂商寄存器就好了,这组寄存器中比较重要的:
- mtime寄存器,用来驱动系统tick的定时器,自上电来就以固定的频率产生中断
- mtimecpm寄存器,和mtime一起完成系统的tick时间基准
.extern freertos_risc_v_trap_handler_before_schedule
_start:
.section .text.entry
.align 2
.globl risc_e906_start
.type risc_e906_start, %function
risc_e906_start:
.option push
.option norelax
la gp, __global_pointer$
.option pop
la a0, freertos_risc_v_trap_handler_before_schedule
ori a0, a0, 3
csrw mtvec, a0
la a0, __Vectors
csrw mtvt, a0
.weak _sp_main
la sp, _sp_main
csrw mscratch, sp
/* Load text section */
la a0, _text_load
la a1, _text_run
la a2, _text_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:
/* Load data section */
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 */
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 */
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:
la t0, SystemInit
jalr t0
la t0, board_init
jalr t0
la t0, bfl_main
jalr t0
.size risc_e906_start, . - risc_e906_start