Files
wch-uf2-example/startup.S
T
2024-04-12 23:53:30 +01:00

127 lines
3.2 KiB
ArmAsm

#define R16_BKP_DATAR10 0x40006C28
#define BOOT_MAGIC_APP_IMMEDIATELY 0x4170
#define BOOT_MAGIC_BOOTLOADER 0x624c
#define R32_PWR_CTLR 0x40007000
#define RCC_BASE 0x40021000
#define R32_RCC_APB1PCENR 0x4002101C
#define R32_RCC_RSTSCKR 0x40021024
#define SYSTICK_BASE 0xE000F000
#define STK_CTLR 0xE000F000
#define STK_SR 0xE000F004
#define STK_CMPLR 0xE000F010
#define WAIT_TIME (500 /* ms */ * 1000 /* assume 8 MHz system clock, div8 */)
.section .vector,"ax",@progbits
.align 1
.global _start
_start:
// Use Adafruit(?)-inspired boot entry, namely "double-reset in short succession to enter bootloader"
// 1. If the reset wasn't triggered by the nRST pin, go to application
// 2. On nRST, if not first reset, go to bootloader
// 3. On nRST, if *is* first reset, set magic and wait
// 4a. If wait times out, go to application
// 4b. If wait doesn't time out but a reset happens again, detect "not first" reset and go to bootloader
la a0, RCC_BASE
lw a1, (R32_RCC_RSTSCKR-RCC_BASE)(a0)
slli a1, a1, (31 - 26)
bgez a1, _enter_application_code // if PINRSTF == 0
// Enable BKP and PWR clock
lw a1, (R32_RCC_APB1PCENR-RCC_BASE)(a0)
la a2, (1 << 27) | (1 << 28)
or a1, a1, a2
sw a1, (R32_RCC_APB1PCENR-RCC_BASE)(a0)
// Enable BKP write
la a0, R32_PWR_CTLR
lw a1, (a0)
ori a1, a1, (1 << 8)
sw a1, (a0)
// Check for magic values
la a3, R16_BKP_DATAR10
lhu a1, (a3)
la a2, BOOT_MAGIC_APP_IMMEDIATELY
beq a1, a2, _enter_application_code
la a2, BOOT_MAGIC_BOOTLOADER
beq a1, a2, _enter_bootloader
// Here we're on the first reset
sh a2, (a3)
la a0, SYSTICK_BASE
la a1, WAIT_TIME
sw a1, (STK_CMPLR-SYSTICK_BASE)(a0)
la a1, 0b111000
sw a1, (STK_CTLR-SYSTICK_BASE)(a0)
// Seems to spuriously fire immediately if start bit is set concurrently
la a1, 0b111001
sw a1, (STK_CTLR-SYSTICK_BASE)(a0)
1:
lw a1, (STK_SR-SYSTICK_BASE)(a0)
slli a1, a1, (31 - 0)
bgez a1, 1b
// Delay done, clear systick and magic
sw zero, (STK_CTLR-SYSTICK_BASE)(a0)
sw zero, (STK_SR-SYSTICK_BASE)(a0)
sh zero, (a3)
// If the delay expires, boot the application after all
_enter_application_code:
// Clear all of these enables that we had set
la a0, R32_PWR_CTLR
lw a1, (a0)
xori a1, a1, (1 << 8)
sw a1, (a0)
la a0, R32_RCC_APB1PCENR
lw a1, (a0)
la a2, (1 << 27) | (1 << 28)
xor a1, a1, a2
sw a1, (a0)
_wipwipwip:
j _wipwipwip
j _bootloader_limit
_enter_bootloader:
// Set up global pointer
.option push
.option norelax
la gp, __global_pointer$
.option pop
la sp, 0
// 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, 0x1f
csrw 0xbc0, t0
// Invoke main
la t0, main
csrw mepc, t0
mret