-
Notifications
You must be signed in to change notification settings - Fork 4
/
startup.S
106 lines (92 loc) · 3.13 KB
/
startup.S
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#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:
// Weird things seem to happen if you fall off the end of flash
la a0, _bootloader_limit
lw a0, (a0)
// Note that flash *doesn't* erase to 0xffffffff but instead this value
// (yes, this is technically mentioned in the reference manual)
la a1, 0xe339e339
beq a0, a1, _enter_bootloader
// 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, _bootloader_limit // 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)
// If the delay expires, boot the application after all
_enter_application_code:
sh zero, (a3)
// 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)
j _bootloader_limit
_enter_bootloader:
// Set up global pointer
.option push
.option norelax
la gp, __global_pointer$
.option pop
li t0, 0x1f
csrw 0xbc0, t0
// Invoke main
// XXX the mepc thing does something really weird
j main