1 /* Author: Domen Puncer <domen@cba.si>. License: WTFPL, see file LICENSE */
7 #include <arch/sched.h>
8 #include <arch/cm3_regs.h>
16 /* cortex-m3 pushes following on stack when entering exception: xPSR, PC, LR, r12, r3, r2, r1, r0
17 * what's remaining/needs to be saved is: PSP, r4-r11
19 void arch_task_new(struct task
*task
, void (*func
)(u32 arg
), u32 arg
)
21 /* saved by exception */
22 task
->stack
[task
->stack_len
-1] = 1<<24 /* xPSR, thumb bit */;
23 task
->stack
[task
->stack_len
-2] = (u32
)func
;
24 task
->stack
[task
->stack_len
-3] = 0x01010101*14 /* LR - this could be something nice, so tasks can actually exit */;
25 task
->stack
[task
->stack_len
-4] = 0x01010101*12 /* r12 */;
26 task
->stack
[task
->stack_len
-5] = 0x01010101*3 /* r3 */;
27 task
->stack
[task
->stack_len
-6] = 0x01010101*2 /* r2 */;
28 task
->stack
[task
->stack_len
-7] = 0x01010101*1 /* r1 */;
29 task
->stack
[task
->stack_len
-8] = arg
/* r0 */;
32 task
->stack
[task
->stack_len
-9] = 0x01010101*11 /* r11 */;
33 task
->stack
[task
->stack_len
-10] = 0x01010101*10 /* r10 */;
34 task
->stack
[task
->stack_len
-11] = 0x01010101*9 /* r9 */;
35 task
->stack
[task
->stack_len
-12] = 0x01010101*8 /* r8 */;
36 task
->stack
[task
->stack_len
-13] = 0x01010101*7 /* r7 */;
37 task
->stack
[task
->stack_len
-14] = 0x01010101*6 /* r6 */;
38 task
->stack
[task
->stack_len
-15] = 0x01010101*5 /* r5 */;
39 task
->stack
[task
->stack_len
-16] = 0x01010101*4 /* r4 */;
41 task
->context
.psp
= (u32
)&task
->stack
[task
->stack_len
-16];
44 void __naked
arch_task_first(struct task
*task
)
48 /* restore created context */
51 "pop {r0-r3,r12,lr}\n\t"
53 "add sp, sp, #8\n\t" /* pc and xPSR space, just ignore it */
55 "ldr pc, [sp, #-8]\n\t" /* and jump to the task entry, sp here is top of stack, so -8 is entry -2 = func */
56 : : "r" (task
->context
.psp
)
60 /* task to switch to */
61 static struct task
*new_task
;
63 /* cortex-m3 trm 5.11 Setting up multiple stacks
64 * does the task switching from current to new_task */
65 void __naked
pendsv_handler()
68 "ldr r0, =current\n\t"
72 "stmdb r3!, {r4-r11}\n\t" /* save regs to process stack */
73 "str r3, [r1, %0]\n\t" /* current->context.psp = PSP */
75 "ldr r2, =new_task\n\t"
78 "ldr r3, [r2, %0]\n\t" /* PSP = new_task->context.psp */
79 "ldmia r3!, {r4-r11}\n\t" /* restore regs from process stack */
83 "str r2, [r0]\n\t" /* current = new_task */
86 : : "i" (offsetof(struct task
, context
))
90 void arch_task_switch(struct task
*newt
)
93 /* request PendSV exception */
94 ICSR
= ICSR_PENDSVSET
;
97 void arch_sched_start_timer()
99 DEMCR
|= DEMCR_TRCENA
;
103 /* core clock, enable interrupt, enable systick */
106 SYSTICK
->CTRL
|= 1<<2 | 1<<1 | 1<<0;
108 /* set SysTick pending to get scheduled asap */
109 ICSR
= ICSR_PENDSTSET
;
112 void arch_wait_for_interrupt()
114 asm volatile ("wfi");
117 static int systick_whole
;
118 static int systick_remainder
;
120 /* writing anything to SYSTICK->VALUE clears it (and doesn't cause the interrupt), but the reloads it with RELOAD on next timer tick */
121 void arch_sched_next_interrupt(int offset
)
123 systick_whole
= offset
>> 24;
124 systick_remainder
= offset
& 0xffffff;
125 if (systick_remainder
== 0)
126 systick_remainder
= 1;
129 SYSTICK
->RELOAD
= 0xffffff;
132 SYSTICK
->RELOAD
= systick_remainder
;
133 SYSTICK
->VALUE
= 0; /* clear */
137 void systick_handler()
140 /* last part? then load the remainder */
141 if (--systick_whole
== 0) {
142 SYSTICK
->RELOAD
= systick_remainder
;