created a throughly commented startup file.
It's based on the OG factory startup code data.
This commit is contained in:
parent
1ab0edaf24
commit
6be8210eae
1 changed files with 245 additions and 0 deletions
245
src/startup_ch32v003.S
Normal file
245
src/startup_ch32v003.S
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
#; Filename: startup_ch32v003.S
|
||||
#; Author: Jake G
|
||||
#; Date: 2026-01-05
|
||||
#; Version: 0.1.0
|
||||
#; Description: Vectortable and startup code.
|
||||
#; Mostly it's just built from the QingKeV2 reference manual combined with the
|
||||
#; comments and definitions I've found online and from the RISC-V ISA for the
|
||||
#; ISA: RV32I with Ec extension, missing the multiplacation hardware from the
|
||||
#; CH32V002/4/5/6/7 series.
|
||||
|
||||
#; First some info about the terms:
|
||||
#; handler: Actual code that "handles" events that causes the intterput.
|
||||
#; Vector table entry: address that points to the code/handler.
|
||||
#; Example: For SPI1_IRQHandler the order would go:
|
||||
#; vector_table --> SPI1_IRQHandler --> code or orverride.
|
||||
|
||||
|
||||
#; Create the init section,
|
||||
#; .init, places it at the reset address.
|
||||
#; a --> allocate(goes into memory)
|
||||
#; x --> executable.
|
||||
#; @progbits --> contains actual code/data not bss
|
||||
.section .init, "ax", @progbits
|
||||
.globl _start /* Export entry point, aka where cpu begins after reset.*/
|
||||
.align 2 /* We pad until we align on 2byte boundry. */
|
||||
_start: /* The start label */
|
||||
.option norvc; /* Disables generation of compressed instructions*/
|
||||
j handle_reset /* Starts from QingKeV2 Table 3-1 Exeception & interrupt vector table.*/
|
||||
.word 0 /* All of these jump to zero/reset vector if hit, they are reserved / unused. */
|
||||
.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 */
|
||||
/* Re-enable the usage of compressed instructions. */
|
||||
/* The following aren't posision-sensative so compressed is okay.*/
|
||||
.option rvc
|
||||
/* Section where we start code stuff (text), allocated and executable. */
|
||||
/* The seperate section allows us to relocate it wherever we need. */
|
||||
.section .text.vector_handler, "ax", @progbits
|
||||
/*Weak symbol declaractions, can be overriden without modifying startupcode. */
|
||||
.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
|
||||
|
||||
|
||||
/* Define te default handler's*/
|
||||
/* These handlers preform infinite loops if entered without an override.*/
|
||||
/* ASM Instructions: `1` Local label, `j` jump, `1b` nearest label 1 backwards. */
|
||||
/* From what I can see it's a single line way to impliment a inf loop.*/
|
||||
/* These using the compressed instructions only take 2Bytes per line. */
|
||||
|
||||
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
|
||||
|
||||
|
||||
/* Another section that holds the text section, aka code for handle_reset*/
|
||||
/* Same as previous sections, marked for allocation and execution. */
|
||||
.section .text.handle_reset, "ax", @progbits
|
||||
/* We weakly define the handle_reset label */
|
||||
.weak handle_reset
|
||||
/* Align 1 because of RVC(compressed instructions).*/
|
||||
.align 1
|
||||
|
||||
handle_reset:
|
||||
/* Global Pointer(GP) register init.*/
|
||||
.option push /* What does this mean? */
|
||||
.option norelax /* Prevents optimizing the la(load address) instruction. */
|
||||
la gp, __global_pointer$ /* __global_pointer$ is liker defined */
|
||||
.option pop /* What does this mean? */
|
||||
|
||||
/* We need to do the stack setup because the MCU has no MMU or stack checking */
|
||||
/* GNUC stuff needs some more inspection.*/
|
||||
1:
|
||||
la sp, _eusrstack /*Sets stack pointer to the top of user stack.*/
|
||||
/* MAX: Addition needed here */
|
||||
#if __GNUC__ > 10
|
||||
.option arch, +zicsr /*Enables CSR(control and status registers) needed for newer GCC toolchains. */
|
||||
#endif
|
||||
|
||||
2:
|
||||
/* Load data section from flash to RAM */
|
||||
/* LMA (Load Memory Address) is a term used in embedded systems to */
|
||||
/* indicate the address in memory where a program or data is loaded */
|
||||
/* VMA: Virtual Memory Address. */
|
||||
|
||||
la a0, _data_lma /* SRC: Load arg/address a0 with (flash/LMA) */
|
||||
la a1, _data_vma /* DST: load return/address a1 with (RAM/VMA) */
|
||||
la a2, _edata /* End of data */
|
||||
bgeu a1, a2, 2f /* If `.data` is empty then skip. */
|
||||
|
||||
/* The copy loop: local label*/
|
||||
1:
|
||||
lw t0, (a0) /*Load word into temp 0 reg, from a0 `()` from pointed loc? */
|
||||
sw t0, (a1) /*Stores word from tmp0 into a1 reg pointed addr */
|
||||
addi a0, a0, 4 /*Add immediate, */
|
||||
addi a1, a1, 4 /*Add immediate, */
|
||||
bltu a1, a2, 1b /*Unsigned comparision, with jump/loop back.*/
|
||||
|
||||
/* Clear the .bss: local label */
|
||||
/* The .bss section is all for the zero initialized globals. */
|
||||
2:
|
||||
/* clear bss section */
|
||||
la a0, _sbss /* Load address reg a0 with linker defined _sbss */
|
||||
la a1, _ebss /* Load address reg a1 with linker defined _ebss */
|
||||
bgeu a0, a1, 2f /* Compare and jump 2 forward */
|
||||
|
||||
/* */
|
||||
1:
|
||||
sw zero, (a0) /* Store Word into a0, aka zero out a0 */
|
||||
addi a0, a0, 4 /* Add immediate*/
|
||||
bltu a0, a1, 1b /* Compare and loop this local label */
|
||||
|
||||
/* This is jumped to if X */
|
||||
/* */
|
||||
2:
|
||||
/* Sets the MIE, machine interrupt enable bit, enables interrupts globally */
|
||||
/* Needed for the QingKeV2 otherwise all the interrupts are masked forever. */
|
||||
li t0, 0x80 /* Load immediate to temp 0, with 0x80 */
|
||||
csrw mstatus, t0 /* Control and status register write: t0 to mstatus. */
|
||||
|
||||
|
||||
/* Sets/configures the QingKeV2 interrupt controller */
|
||||
/* Enables: vectored interrupts, nested interrupts. */
|
||||
li t0, 0x3 /* Load immediate to temp 0 with `0x3` */
|
||||
csrw 0x804, t0 /* Control and status register write: t0. */
|
||||
|
||||
/* Load address into tmp 0 with address of _start code. */
|
||||
la t0, _start
|
||||
ori t0, t0, 3 /* OR immediate, */
|
||||
csrw mtvec, t0 /* Control status register write: _start to vector base table*/
|
||||
|
||||
/* mtvec: 00 --> direct mode, 11 --> vectored mode. */
|
||||
/* Logical OR with 3(0b11) means we selected vector mode. */
|
||||
|
||||
/* Saves some space if we don't use it.*/
|
||||
/* Optional C++ runtime support:*/
|
||||
/* Run Constructors __libc_fini_array */
|
||||
/* Destructors registered at `atexit` */
|
||||
|
||||
#if defined(__PIO_CPP_SUPPORT__)
|
||||
/* register fini (destructor array) call at exit if wanted (bloats up RAM+Flash) */
|
||||
#if defined(__PIO_CPP_CALL_FINI__)
|
||||
la a0,__libc_fini_array
|
||||
call atexit
|
||||
#endif
|
||||
/* call into C++ constructors now */
|
||||
call __libc_init_array
|
||||
#endif
|
||||
|
||||
/* SystemInit: does stuff like clock setup, PLL cnofig, Periph reset. */
|
||||
|
||||
/* This mcu and microprocessor only has "M-Mode" or machine mode */
|
||||
/* The other modes, U(user) and S(???) aren't availble. */
|
||||
/* MEPC: Machine Exception Program Counter.*/
|
||||
/* Jump's and links(ra --> return address) to SystemInit */
|
||||
jal SystemInit
|
||||
la t0, main /* Load address of main into tmp 0 */
|
||||
csrw mepc, t0 /* Control status register write t0 to the */
|
||||
mret
|
||||
|
||||
|
||||
|
||||
Loading…
Add table
Reference in a new issue