#; 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(Supervisor) 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



