startup_ch32v00x.S启动文件分析(上)

发布时间 2023-08-09 23:00:28作者: 3V4NZ

引言

CH32系列MCU是由南京沁恒(WCH)公司推出的一系列处理器芯片。引自官网:

CH32V、CH32X、CH32L系列MCU采用自研的青稞RISC-V内核,基于蓬勃发展的RISC-V开源指令集架构,针对低功耗和高速响应等应用优化扩展,免费配套IDE等开发工具软件,免除第三方内核技术的授权费和提成费,通过内置和组合USB、PD、低功耗蓝牙、以太网等专业接口外设,构建了既有全球未来生态又能自主可控、且极具长期竞争力的MCU产品线。

产品页 - 青稞RISC-V通用系列

本文通过对 CH32V003 芯片所使用的启动文件 startup_ch32v00x.S 进行分析,梳理RISC-V芯片的启动过程。

文件内容预览

点击跳转查看

逐句分析

Part1 - Init

从代码第一行看起。

.section .init, "ax", @progbits

  • .section 标明本句为对段的定义。
  • .init是该段的名字。
  • "ax"标识段的权限,a代表运行时载入内存,x代表可执行。
  • @progbits标识了段的类型,表示“Section contains either initialized data and instructions or instructions only."。

.section完整语法文档

.globl _start

定义_start位置全局可见,用于作程序的起始地址。

.align 2

定义下一条指令/数据对齐方式。可确保下一条指令的地址为“2的x次方”的倍数。此处,2的2次方为4,因此下一条指令的地址将顺推至4的倍数。

注意与.balign伪指令的区分,其用于将下一条指令地址顺推至x的倍数。即.align 2等效于.balign 4。

_start:

程序起始位置。

.option norvc;

rvc、norvc是RISC-V架构特有的选项:

  • “.option rvc”伪操作表示接下来的汇编程序可以被汇编生成16位宽的压缩指令。
  • “.option norvc”伪操作表示接下来的汇编程序不可以被汇编生成16位宽的压缩指令

j handle_reset

跳转至 handle_reset 处。

Part2 - Reset

从代码106行开始看起。

.section .text.handle_reset, "ax", @progbits

对段的定义,不再赘述。

handle_reset:

由上一部分跳转至此,随后顺序执行。

.option push

  • “.option push”伪操作暂时将当前的选项设置保存起来,从而允许之后使用.option伪操作指定新的选项;而“.option pop”伪操作将最近保存的选项设置恢复出来重新生效。
  • 通过“.option push”和“.option pop”的组合,便可以在汇编程序中在不影响全局选项设置的情况下,为其中嵌入的某一段代码特别地设置不同的选项。

.option norelax

la gp, __global_pointer$

将ld文件中的标签__global_pointer所处的地址值赋给gp寄存器

.option pop

恢复option。

启动部分

把启动部分一起,通过注释进行解释。该部分用到的各类预设地址,均来自于ld链接脚本文件Link.ld。

1:
	la sp, _eusrstack               /* 将ld文件中的标签_eusrstack所处的地址值赋给sp寄存器 */
2:
	/* Load data section from flash to RAM */
	la a0, _data_lma                /* Flash中的data段地址 */
	la a1, _data_vma                /* 物理RAM地址 */
	la a2, _edata                   /* data段尾地址 */
	bgeu a1, a2, 2f                 /* a1 greater/equal a2时,跳转到下一个2标签 */
1:
	lw t0, (a0)
	sw t0, (a1)
	addi a0, a0, 4
	addi a1, a1, 4
	bltu a1, a2, 1b                 /* a1 less than a2时,跳转到上一个1标签 */
2:
    /* clear bss section */
    la a0, _sbss                    /* bss起始地址 */
    la a1, _ebss                    /* bss结尾地址 */
    bgeu a0, a1, 2f                 /* a0 greater/equal a1时,跳转到下一个2标签 */
1:
    sw zero, (a0)
    addi a0, a0, 4
    bltu a0, a1, 1b                 /* a0 less than a1时,跳转到上一个1标签 */
2:
    li t0, 0x80                     /* 立即数0x80 */
    csrw mstatus, t0                /* 写入mstatus寄存器 */
  
    li t0, 0x3                      /* 立即数0x3 */
    csrw 0x804, t0                  /* 写入intsyscr寄存器 */
  
    la t0, _start                   /* _start地址 */
    ori t0, t0, 3                   /* t0 = t0 | 3 */
    csrw mtvec, t0                  /* 写入mtvec寄存器 */
  
    jal   SystemInit                /* 跳转至SystemInit,随后函数返回 */
    la t0, main                     /* main函数地址 */
    csrw mepc, t0                   /* 写入mepc寄存器 */
    mret                            /* 退出机器模式,进入用户模式。 */

Part3 - INT vectors

剩余部分,为中断向量的设置,与MCU所提供的具体功能相关,不再赘述。

源代码

	.section  .init, "ax", @progbits
	.globl  _start
	.align  2
_start:
	.option   norvc;
    j       handle_reset
    .word   0
    .word   NMI_Handler                  /* NMI Handler */
    .word   HardFault_Handler            /* Hard Fault Handler */
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   SysTick_Handler             /* SysTick Handler */
    .word   0
    .word   SW_Handler                  /* SW Handler */
    .word   0
    /* External Interrupts */
    .word   WWDG_IRQHandler         	/* Window Watchdog */
    .word   PVD_IRQHandler          	/* PVD through EXTI Line detect */
    .word   FLASH_IRQHandler        	/* Flash */
    .word   RCC_IRQHandler          	/* RCC */
    .word   EXTI7_0_IRQHandler       	/* EXTI Line 7..0 */
    .word   AWU_IRQHandler              /* AWU */
    .word   DMA1_Channel1_IRQHandler   	/* DMA1 Channel 1 */
    .word   DMA1_Channel2_IRQHandler   	/* DMA1 Channel 2 */
    .word   DMA1_Channel3_IRQHandler   	/* DMA1 Channel 3 */
    .word   DMA1_Channel4_IRQHandler   	/* DMA1 Channel 4 */
    .word   DMA1_Channel5_IRQHandler   	/* DMA1 Channel 5 */
    .word   DMA1_Channel6_IRQHandler   	/* DMA1 Channel 6 */
    .word   DMA1_Channel7_IRQHandler   	/* DMA1 Channel 7 */
    .word   ADC1_IRQHandler          	/* ADC1 */
    .word   I2C1_EV_IRQHandler         	/* I2C1 Event */
    .word   I2C1_ER_IRQHandler         	/* I2C1 Error */
    .word   USART1_IRQHandler          	/* USART1 */
    .word   SPI1_IRQHandler            	/* SPI1 */
    .word   TIM1_BRK_IRQHandler        	/* TIM1 Break */
    .word   TIM1_UP_IRQHandler         	/* TIM1 Update */
    .word   TIM1_TRG_COM_IRQHandler    	/* TIM1 Trigger and Commutation */
    .word   TIM1_CC_IRQHandler         	/* TIM1 Capture Compare */
    .word   TIM2_IRQHandler            	/* TIM2 */

	.option rvc;
	.section  .text.vector_handler, "ax", @progbits
	.weak   NMI_Handler
	.weak   HardFault_Handler
	.weak   SysTick_Handler
	.weak   SW_Handler
	.weak   WWDG_IRQHandler
	.weak   PVD_IRQHandler
	.weak   FLASH_IRQHandler
	.weak   RCC_IRQHandler
	.weak   EXTI7_0_IRQHandler
	.weak   AWU_IRQHandler
	.weak   DMA1_Channel1_IRQHandler
	.weak   DMA1_Channel2_IRQHandler
	.weak   DMA1_Channel3_IRQHandler
	.weak   DMA1_Channel4_IRQHandler
	.weak   DMA1_Channel5_IRQHandler
	.weak   DMA1_Channel6_IRQHandler
	.weak   DMA1_Channel7_IRQHandler
	.weak   ADC1_IRQHandler
	.weak   I2C1_EV_IRQHandler
	.weak   I2C1_ER_IRQHandler
	.weak   USART1_IRQHandler
	.weak   SPI1_IRQHandler
	.weak   TIM1_BRK_IRQHandler
	.weak   TIM1_UP_IRQHandler
	.weak   TIM1_TRG_COM_IRQHandler
	.weak   TIM1_CC_IRQHandler
	.weak   TIM2_IRQHandler

NMI_Handler:              1: j 1b
HardFault_Handler:        1: j 1b
SysTick_Handler:          1: j 1b
SW_Handler:               1: j 1b
WWDG_IRQHandler:          1: j 1b
PVD_IRQHandler:           1: j 1b
FLASH_IRQHandler:         1: j 1b
RCC_IRQHandler:           1: j 1b
EXTI7_0_IRQHandler:       1: j 1b
AWU_IRQHandler:           1: j 1b
DMA1_Channel1_IRQHandler: 1: j 1b
DMA1_Channel2_IRQHandler: 1: j 1b
DMA1_Channel3_IRQHandler: 1: j 1b
DMA1_Channel4_IRQHandler: 1: j 1b
DMA1_Channel5_IRQHandler: 1: j 1b
DMA1_Channel6_IRQHandler: 1: j 1b
DMA1_Channel7_IRQHandler: 1: j 1b
ADC1_IRQHandler:          1: j 1b
I2C1_EV_IRQHandler:       1: j 1b
I2C1_ER_IRQHandler:       1: j 1b
USART1_IRQHandler:        1: j 1b
SPI1_IRQHandler:          1: j 1b
TIM1_BRK_IRQHandler:      1: j 1b
TIM1_UP_IRQHandler:       1: j 1b
TIM1_TRG_COM_IRQHandler:  1: j 1b
TIM1_CC_IRQHandler:       1: j 1b
TIM2_IRQHandler:          1: j 1b


	.section  .text.handle_reset, "ax", @progbits
	.weak     handle_reset
	.align    1
handle_reset:
.option push
.option norelax
	la gp, __global_pointer$
.option pop
1:
	la sp, _eusrstack
2:
	/* Load data section from flash to RAM */
	la a0, _data_lma
	la a1, _data_vma
	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, _sbss
    la a1, _ebss
    bgeu a0, a1, 2f
1:
    sw zero, (a0)
    addi a0, a0, 4
    bltu a0, a1, 1b
2:
    li t0, 0x80
    csrw mstatus, t0
  
    li t0, 0x3
    csrw 0x804, t0
  
    la t0, _start
    ori t0, t0, 3
    csrw mtvec, t0
  
    jal   SystemInit
    la t0, main
    csrw mepc, t0
    mret

点击返回