前言
前面搭建了RISC-V的开发环境,这一篇来讲讲SDK代码框架,这有利于后面程序开发。
过程
查找链接脚本
对于嵌入式项目,要了解代码框架,最先要从链接脚本入手,从这里可以找到启动代码,程序入口等信息,然后层层递进抽丝剥茧才能了解全貌。
右键点击工程->Properties
看到链接脚本如下
D:\BOARD\SF1-FPSoC\SF1S60CG121I_SF102\SF1S60CG121I_SF102\TN810_SF102\src\mcu_ahb_to_fpga\sdk_project\bmp_image_display\anlogic_sdk\SoC\anlogic\Board\sf1_eval\Source\GCC\gcc_anlogic_work3.ld
我们就打开这个文件看看
看到该目录下还有其他不同的ld文件,应用于不同工作模式的工程,原理都是一样的,看一个就行。
ld文件格式可以网上搜索文档查阅,这里不再赘述,主要讲和本工程相关的内容。
先看前面定义了存储
MEMORY
{
flash (rxai!w) : ORIGIN = 0x000E0000, LENGTH = 4M
ilm (rxai!w) : ORIGIN = 0x08000000, LENGTH = 8K
ram (wxa!ri) : ORIGIN = 0x20000000, LENGTH = 8K
}
从这里可以看到存储的布局。
我们然后来找程序的入口
.init :
{
*(.vtable)
KEEP (*(SORT_NONE(.init)))
} >flash AT>flash
这里最新将.vtable放在了flash处,所以这里指导就是程序的入口
搜索.vtable
菜单栏Serch->Search
看到该段正是启动代码
固定中断向量
开始定义的是固定的终端向量表
/*** Vector Table Code Section ***/
/*
* Put the interrupt vectors in this section according to the run mode:
* FlashXIP: .vtable
* ILM: .vtable
* Flash: .vtable_ilm
*/
#if defined(DOWNLOAD_MODE) && (DOWNLOAD_MODE == DOWNLOAD_MODE_FLASH)
.section .vtable_ilm
#else
.section .vtable
#endif
.weak eclic_msip_handler
.weak eclic_mtip_handler
.weak uart0_handler
.weak i2c_handler
.weak QSPI0_handler
.weak QSPI_handler
.weak gpio0_handler
.weak gpio1_handler
.weak gpio2_handler
.weak gpio3_handler
.weak gpio4_handler
.weak gpio5_handler
.weak gpio6_handler
.weak gpio7_handler
.weak fpga0_handler
.weak fpga1_handler
.weak fpga2_handler
.weak fpga3_handler
.weak fpga4_handler
.weak fpga5_handler
.weak fpga6_handler
.weak fpga7_handler
.weak fpga8_handler
.weak fpga9_handler
.weak fpga10_handler
.weak fpga11_handler
.weak fpga12_handler
.weak fpga13_handler
.weak fpga14_handler
.weak fpga15_handler
用户中断向量
然后后面才是用户中断向量入口
.globl vector_base
vector_base:
#if defined(DOWNLOAD_MODE) && (DOWNLOAD_MODE != DOWNLOAD_MODE_FLASH)
// j _start /* 0: Reserved, Jump to _start when reset for ILM/FlashXIP mode.*/
la ra,_start // fix according to suggestion of S.W
ret
.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 Flash download mode */
DECLARE_INT_HANDLER default_intexc_handler /* 1: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 2: Reserved */
#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 default_intexc_handler /* 16: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 17: Reserved */
DECLARE_INT_HANDLER default_intexc_handler /* 18: Reserved */
DECLARE_INT_HANDLER uart0_handler /* 19: Interrupt 19 */
DECLARE_INT_HANDLER i2c_handler /* 21: Interrupt 21 */
DECLARE_INT_HANDLER QSPI0_handler /* 22: Interrupt 22 */
DECLARE_INT_HANDLER QSPI_handler /* 29: Interrupt 29 */
DECLARE_INT_HANDLER gpio0_handler /* 30: Interrupt 30 */
DECLARE_INT_HANDLER gpio1_handler /* 31: Interrupt 31 */
DECLARE_INT_HANDLER gpio2_handler /* 32: Interrupt 32 */
DECLARE_INT_HANDLER gpio3_handler /* 33: Interrupt 33 */
DECLARE_INT_HANDLER gpio4_handler /* 34: Interrupt 34 */
DECLARE_INT_HANDLER gpio5_handler /* 35: Interrupt 35 */
DECLARE_INT_HANDLER gpio6_handler /* 36: Interrupt 36 */
DECLARE_INT_HANDLER gpio7_handler /* 37: Interrupt 37 */
DECLARE_INT_HANDLER fpga0_handler /* 38: Interrupt 38 */
DECLARE_INT_HANDLER fpga1_handler /* 39: Interrupt 39 */
DECLARE_INT_HANDLER fpga2_handler /*40: Interrupt 40 */
DECLARE_INT_HANDLER fpga3_handler /* 41: Interrupt 41 */
DECLARE_INT_HANDLER fpga4_handler /* 42: Interrupt 42 */
DECLARE_INT_HANDLER fpga5_handler /* 43: Interrupt 43 */
DECLARE_INT_HANDLER fpga6_handler /* 44: Interrupt 44 */
DECLARE_INT_HANDLER fpga7_handler /* 45: Interrupt 45 */
DECLARE_INT_HANDLER fpga8_handler /* 43: Interrupt 43 */
DECLARE_INT_HANDLER fpga9_handler /* 44: Interrupt 44 */
DECLARE_INT_HANDLER fpga10_handler /* 45: Interrupt 45 */
DECLARE_INT_HANDLER fpga11_handler /* 44: Interrupt 44 */
DECLARE_INT_HANDLER fpga12_handler /* 45: Interrupt 45 */
DECLARE_INT_HANDLER fpga13_handler /* 44: Interrupt 44 */
DECLARE_INT_HANDLER fpga14_handler /* 45: Interrupt 45 */
DECLARE_INT_HANDLER fpga15_handler /* 45: Interrupt 45 */
搜索vector_base
可以看到后面正是设置该地址为用户中断向量基地址
/*
* Intialize ECLIC vector interrupt
* base address mtvt to vector_base
*/
la t0, vector_base
csrw CSR_MTVT, t0
启动代码
.globl vector_base
vector_base:
#if defined(DOWNLOAD_MODE) && (DOWNLOAD_MODE != DOWNLOAD_MODE_FLASH)
// j _start /* 0: Reserved, Jump to _start when reset for ILM/FlashXIP mode.*/
la ra,_start // fix according to suggestion of S.W
ret
如果是DOWNLOAD_MODE模式跳转到_start
.section .init
.globl _start
.type _start,@FUNCTION
.option norvc
/**
* Reset Handler called on controller reset
*/
_start:
和链接脚本对应,放在了.init段
.init :
{
*(.vtable)
KEEP (*(SORT_NONE(.init)))
} >flash AT>flash
后面就是中断 栈指针等初始化,不再赘述,可以参照RISC-V的文章理解指令。
后面重点关注下,code data段的加载bss段的初始化,_data等变量都是在链接脚本中定义的地址,
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
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:
然后是调用SystemInit初始化systick定时器
call SystemInit
最后进入main
#ifdef RTOS_RTTHREAD
// Call entry function when using RT-Thread
call entry
#else
call main
#endif
代码框架
anlogic_sdk下是芯片相关代码,主要关注启动代码,中断处理代码,链接脚本
application下是用户代码
总结
以上介绍了代码框架,主要是启动流程,方便对SDK有一个整体上的理解。