-
Notifications
You must be signed in to change notification settings - Fork 0
/
os.c
109 lines (94 loc) · 3.27 KB
/
os.c
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
107
108
109
#include <stdint.h>
#include "os.h"
OSThread * volatile OS_curr = 0; /* pointer to the current thread */
OSThread * volatile OS_next = 0; /* pointer to the next thread to run */
void OS_init(void) {
/* set the PendSV interrupt priority to the lowest level 0xFF */
*(uint32_t volatile *)0xE000ED20 |= (0xFFU << 16);
}
void OS_sched(void) {
extern OSThread bluld;
extern OSThread rdld;
if(OS_curr == &bluld) {
OS_next = &rdld;
} else {
OS_next = &bluld;
}
/* OS_next = ... */
OSThread const *next = OS_next; /* volatile to temporary */
if (next != OS_curr) {
*(uint32_t volatile *)0xE000ED04 = (1U << 28);
}
}
void OSThread_start(
OSThread *me,
OSThreadHandler threadHandler,
void *stkSto, uint32_t stkSize)
{
/* round down the stack top to the 8-byte boundary
* NOTE: ARM Cortex-M stack grows down from hi -> low memory
*/
uint32_t *sp = (uint32_t *)((((uint32_t)stkSto + stkSize) / 8) * 8);
uint32_t *stk_limit;
*(--sp) = (1U << 24); /* xPSR */
*(--sp) = (uint32_t)threadHandler; /* PC */
*(--sp) = 0x0000000EU; /* LR */
*(--sp) = 0x0000000CU; /* R12 */
*(--sp) = 0x00000003U; /* R3 */
*(--sp) = 0x00000002U; /* R2 */
*(--sp) = 0x00000001U; /* R1 */
*(--sp) = 0x00000000U; /* R0 */
/* additionally, fake registers R4-R11 */
*(--sp) = 0x0000000BU; /* R11 */
*(--sp) = 0x0000000AU; /* R10 */
*(--sp) = 0x00000009U; /* R9 */
*(--sp) = 0x00000008U; /* R8 */
*(--sp) = 0x00000007U; /* R7 */
*(--sp) = 0x00000006U; /* R6 */
*(--sp) = 0x00000005U; /* R5 */
*(--sp) = 0x00000004U; /* R4 */
/* save the top of the stack in the thread's attibute */
me->sp = sp;
/* round up the bottom of the stack to the 8-byte boundary */
stk_limit = (uint32_t *)(((((uint32_t)stkSto - 1U) / 8) + 1U) * 8);
/* pre-fill the unused part of the stack with 0xDEADBEEF */
for (sp = sp - 1U; sp >= stk_limit; --sp) {
*sp = 0xDEADBEEFU;
}
}
/* inline assembly syntax for Compiler 6 (ARMCLANG) */
__attribute__ ((naked))
void PendSV_Handler(void) {
__asm volatile (
/* __disable_irq(); */
" CPSID I \n"
/* if (OS_curr != (OSThread *)0) { */
" LDR r1,=OS_curr \n"
" LDR r1,[r1,#0x00] \n"
" CMP r1,#0 \n"
" BEQ PendSV_restore \n"
" PUSH {r4-r11} \n"
/* OS_curr->sp = sp; */
" LDR r1,=OS_curr \n"
" LDR r1,[r1,#0x00] \n"
" MOV r0,sp \n"
" STR r0,[r1,#0x00] \n"
/* } */
"PendSV_restore: \n"
/* sp = OS_next->sp; */
" LDR r1,=OS_next \n"
" LDR r1,[r1,#0x00] \n"
" LDR r0,[r1,#0x00] \n"
" MOV sp,r0 \n"
/* OS_curr = OS_next; */
" LDR r1,=OS_next \n"
" LDR r1,[r1,#0x00] \n"
" LDR r2,=OS_curr \n"
" STR r1,[r2,#0x00] \n"
" POP {r4-r11} \n"
/* __enable_irq(); */
" CPSIE I \n"
/* return to the next thread */
" BX lr \n"
);
}