summaryrefslogtreecommitdiff
path: root/os
diff options
context:
space:
mode:
Diffstat (limited to 'os')
-rw-r--r--os/mutex.h42
-rw-r--r--os/pool.cpp5
-rw-r--r--os/pool.h146
-rw-r--r--os/thread.cpp4
-rw-r--r--os/thread.h63
-rw-r--r--os/time.cpp3
-rw-r--r--os/time.h32
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