diff options
Diffstat (limited to 'os')
-rw-r--r-- | os/mutex.h | 42 | ||||
-rw-r--r-- | os/pool.cpp | 5 | ||||
-rw-r--r-- | os/pool.h | 146 | ||||
-rw-r--r-- | os/thread.cpp | 4 | ||||
-rw-r--r-- | os/thread.h | 63 | ||||
-rw-r--r-- | os/time.cpp | 3 | ||||
-rw-r--r-- | os/time.h | 32 |
7 files changed, 295 insertions, 0 deletions
diff --git a/os/mutex.h b/os/mutex.h new file mode 100644 index 0000000..d12331d --- /dev/null +++ b/os/mutex.h @@ -0,0 +1,42 @@ +#ifndef MUTEX_H +#define MUTEX_H + +class Mutex { + private: + uint8_t locked; + public: + Mutex() : locked(0) {} + Mutex(uint8_t l) : locked(l) {} + + bool trylock() { + uint8_t val; + + // Check if mutex is locked. + asm volatile ("ldrexb %0, [%1]" : "=r" (val) : "r" (&locked)); + if(val) { + return false; + } + + // Try taking the lock. + asm volatile ("strexb %0, %1, [%2]" : "=r" (val) : "r" (1), "r" (&locked)); + if(val) { + return false; + } + + asm volatile("dmb"); + return true; + } + + void lock() { + while(!trylock()) { + Thread::yield(); + } + } + + void unlock() { + asm volatile("dmb"); + locked = 0; + } +}; + +#endif diff --git a/os/pool.cpp b/os/pool.cpp new file mode 100644 index 0000000..f059b05 --- /dev/null +++ b/os/pool.cpp @@ -0,0 +1,5 @@ +#include "pool.h" + +void* operator new(unsigned int, char* buf) { + return (void*)buf; +} diff --git a/os/pool.h b/os/pool.h new file mode 100644 index 0000000..1cb0a71 --- /dev/null +++ b/os/pool.h @@ -0,0 +1,146 @@ +#ifndef POOL_H +#define POOL_H + +#include "stdint.h" + +template<class T> +class BasePool { + public: + struct Element { + unsigned int use_count; + BasePool* pool; + + char data[sizeof(T)]; + }; + + virtual void free(Element* e) = 0; +}; + +template<class T> +class P { + private: + typedef typename BasePool<T>::Element Element; + + Element* e; + + void inc() { + e->use_count++; + } + + void dec() { + e->use_count--; + if(!e->use_count) { + T* p = (T*)e->data; + p->~T(); + e->pool->free(e); + } + } + + public: + P() : e(0) {} + + explicit P(Element* ep) : e(ep) { + inc(); + } + + P(const P& p) : e(p.e) { + inc(); + } + + ~P() { + if(e) { + dec(); + } + } + + void operator=(const P& p) { + if(e) { + dec(); + } + + e = p.e; + + if(e) { + inc(); + } + } + + void reset() { + if(e) { + dec(); + } + + e = 0; + } + + T* operator->() { + return (T*)e->data; + } + + T* operator*() { + return (T*)e->data; + } + + operator bool() { + return bool(e); + } +}; + +template<class T, unsigned int size> +class Pool : public BasePool<T> { + private: + typedef typename BasePool<T>::Element Element; + + union Node { + Element e; + Node* next; + }; + + Node elements[size]; + + Node* next_free; + + void free(Element* e) { + Node* n = (Node*)e; + + n->next = next_free; + next_free = n; + } + + Element* alloc() { + if(!next_free) { + return 0; + } + + Element* e = &next_free->e; + next_free = next_free->next; + + e->use_count = 0; + e->pool = this; + + return e; + } + + public: + Pool() : next_free(0) { + for(unsigned int i = 0; i < size; i++) { + free(&elements[i].e); + } + } + + P<T> create() { + Element* e = alloc(); + + if(!e) { + return P<T>(); + } + + new (e->data) T; + + return P<T>(e); + } +}; + +void* operator new(unsigned int, char* buf); + +#endif diff --git a/os/thread.cpp b/os/thread.cpp new file mode 100644 index 0000000..426fffd --- /dev/null +++ b/os/thread.cpp @@ -0,0 +1,4 @@ +#include "thread.h" + +Thread Thread::main_thread __attribute__ ((init_priority (1000))); +Thread* Thread::active_thread = &Thread::main_thread; diff --git a/os/thread.h b/os/thread.h new file mode 100644 index 0000000..2213d6f --- /dev/null +++ b/os/thread.h @@ -0,0 +1,63 @@ +#ifndef THREAD_H +#define THREAD_H + +#include <stdint.h> + +class Thread { + friend void switch_context(); + + private: + struct int_frame_t { + // Software saved. + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t lr_ex; + + // Hardware saved. + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t psr; + }; + + int_frame_t* sp; + + Thread* next; + + static Thread* active_thread; + static Thread main_thread; + + Thread() : next(this) {} + + public: + Thread(void* stack, uint32_t stack_size, void (*func)()) { + sp = (int_frame_t*)((uint8_t*)stack + stack_size - sizeof(int_frame_t)); + + sp->lr_ex = 0xfffffff9; + + // frame->lr = thread exit handler + sp->pc = (uint32_t)func; + sp->psr = 0x01000000; + } + + void start() { + next = active_thread->next; + active_thread->next = this; + } + + static inline void yield() { + asm volatile("svc 0"); + } +}; + +#endif diff --git a/os/time.cpp b/os/time.cpp new file mode 100644 index 0000000..6c96027 --- /dev/null +++ b/os/time.cpp @@ -0,0 +1,3 @@ +#include "time.h" + +volatile uint32_t Time::systime; diff --git a/os/time.h b/os/time.h new file mode 100644 index 0000000..3533967 --- /dev/null +++ b/os/time.h @@ -0,0 +1,32 @@ +#ifndef TIME_H +#define TIME_H + +#include "thread.h" + +struct STK_t { + volatile uint32_t CTRL; + volatile uint32_t LOAD; + volatile uint32_t VAL; + volatile uint32_t CALIB; +}; + +static STK_t& STK = *(STK_t*)0xe000e010; + +class Time { + private: + static volatile uint32_t systime; + + public: + inline static void tick() { + systime++; + } + + inline static void sleep(uint32_t ms) { + ms += systime; + while(systime < ms) { + Thread::yield(); + } + } +}; + +#endif |