summaryrefslogtreecommitdiff
path: root/interrupt/fault.cpp
blob: 8a577bfe067ae63b42b13b01c08e7591fe91b118 (plain)
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
#include "interrupt.h"
#include <os/thread.h>
#include <os/time.h>

inline void __attribute__((naked)) switch_context() {
	asm volatile ("cpsid i");
	
	// Save unsaved registers.
	asm volatile ("push {r4, r5, r6, r7, r8, r9, r10, r11, lr}" ::: "memory");
	
	// Store stack pointer for old thread.
	asm volatile ("str sp, [%0]" :: "r" (&Thread::active_thread->sp));
	
	// Update running thread.
	if(!Thread::reschedule()) {
		// No threads are ready - set SLEEPONEXIT.
		SCB.SCR = 1 << 1;
	} else {
		// Clear SLEEPONEXIT.
		SCB.SCR = 0 << 1;
	}
	
	// Fetch stack pointer for new thread.
	asm volatile ("ldr sp, [%0]" :: "r" (&Thread::active_thread->sp));
	
	asm volatile ("cpsie i");
	
	// Load registers and return.
	asm volatile ("pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}" ::: "memory");
}

template<>
void interrupt<Interrupt::SVCall>() {
	switch_context();
}

template<>
void interrupt<Interrupt::SysTick>() {
	Time::tick();
}

template<> void interrupt<Interrupt::NMI>()         { while(1); }
template<> void interrupt<Interrupt::HardFault>()   { while(1); }
template<> void interrupt<Interrupt::MemManage>()   { while(1); }
template<> void interrupt<Interrupt::BusFault>()    { while(1); }
template<> void interrupt<Interrupt::UsageFault>()  { while(1); }
template<> void interrupt<Interrupt::PendSV>()      { while(1); }