- Debugged context switching

- Semaphore, mutex support
This commit is contained in:
2013-07-14 15:59:16 +02:00
parent 2456d68b00
commit 3b5c555117
12 changed files with 326 additions and 67 deletions

View File

@@ -5,7 +5,7 @@ OBJCOPY=arm-none-eabi-objcopy
OBJDUMP=arm-none-eabi-objdump OBJDUMP=arm-none-eabi-objdump
#CFLAGS=-ffreestanding -march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=gnu99 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -Og -flto #CFLAGS=-ffreestanding -march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=gnu99 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -Og -flto
CXXFLAGS=-ffreestanding -march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=c++11 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -fno-rtti -fstrict-enums -Wabi -Og -flto -D__DYNAMIC_REENT__ CXXFLAGS=-ffreestanding -march=armv7-a -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon --std=c++11 -ggdb -Wall -Wextra -pedantic -Wno-unused-parameter -fno-rtti -fstrict-enums -Wabi -Og -flto
LDFLAGS=-static LDFLAGS=-static
C_SRCS= C_SRCS=
CXX_SRCS=cortexa8.cc drv_omap35x_gpt.cc drv_omap35x_i2c.cc drv_tps65950.cc main.cc mm.cc newlib_syscall.cc omap35x.cc omap35x_intc.cc omap35x_prcm.cc phys_mm.cc scheduler.cc syscall.cc uart.cc CXX_SRCS=cortexa8.cc drv_omap35x_gpt.cc drv_omap35x_i2c.cc drv_tps65950.cc main.cc mm.cc newlib_syscall.cc omap35x.cc omap35x_intc.cc omap35x_prcm.cc phys_mm.cc scheduler.cc syscall.cc uart.cc

View File

@@ -8,6 +8,12 @@
extern int _vect_table; extern int _vect_table;
static cortexa8::thread_cb initial_thread_cb;
cortexa8::thread_cb *_current_thread_cb = &initial_thread_cb;
uint32_t cortexa8::read_cpuid(int reg) noexcept { uint32_t cortexa8::read_cpuid(int reg) noexcept {
uint32_t rval; uint32_t rval;
switch(reg) { switch(reg) {
@@ -41,6 +47,7 @@ uint32_t cortexa8::read_cpuid(int reg) noexcept {
void cortexa8::init_mode() { void cortexa8::init_mode() {
__asm__ __volatile__ ("mov r0, r13; mov r1, r14; cps #0x1f; mov r13, r0; mov r14, r1" __asm__ __volatile__ ("mov r0, r13; mov r1, r14; cps #0x1f; mov r13, r0; mov r14, r1"
: : : "r0", "r1"); : : : "r0", "r1");
_impure_ptr = &initial_thread_cb.newlibReent;
} }
void cortexa8::enable_icache() noexcept { void cortexa8::enable_icache() noexcept {
@@ -458,10 +465,6 @@ void _cortexa8_unhandled_fiq() {
// Context switching stuff // Context switching stuff
static cortexa8::thread_cb initial_thread_cb;
cortexa8::thread_cb *_current_thread_cb = &initial_thread_cb;
cortexa8::thread_cb *cortexa8::get_cur_thread() { cortexa8::thread_cb *cortexa8::get_cur_thread() {
return _current_thread_cb; return _current_thread_cb;
} }

View File

@@ -2,6 +2,9 @@
#define _CORTEXA8_HH_ #define _CORTEXA8_HH_
#include <cstdint> #include <cstdint>
#include <cassert>
#include <sys/reent.h>
#define CORTEXA8_CPUID_MAINID 0 #define CORTEXA8_CPUID_MAINID 0
#define CORTEXA8_CPUID_CACHETYPE 1 #define CORTEXA8_CPUID_CACHETYPE 1
@@ -44,11 +47,13 @@ namespace cortexa8 {
struct thread_cb { struct thread_cb {
thread_cb() thread_cb()
: regs{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, cpsr{0} { : regs{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, cpsr{0}, newlibReent _REENT_INIT(newlibReent) {
} }
uint32_t regs[16]; uint32_t regs[16];
uint32_t cpsr; uint32_t cpsr;
struct _reent newlibReent;
}; };
thread_cb *get_cur_thread(); thread_cb *get_cur_thread();
@@ -62,7 +67,7 @@ namespace cortexa8 {
// Wrapper to handle safe disabling/enabling of interrupts // Wrapper to handle safe disabling/enabling of interrupts
class ScopedSetIF { class ScopedSetIF {
public: public:
ScopedSetIF(bool enableInts = false) : savedIF_{cortexa8_get_int()} { ScopedSetIF(bool enableInts = false) : savedIF_{cortexa8_get_int()}, done_{false} {
if(enableInts) if(enableInts)
cortexa8_ena_int(); cortexa8_ena_int();
else else
@@ -70,14 +75,26 @@ namespace cortexa8 {
} }
~ScopedSetIF() { ~ScopedSetIF() {
if(done_)
return;
if(savedIF_) if(savedIF_)
cortexa8_ena_int(); cortexa8_ena_int();
else else
cortexa8_dis_int(); cortexa8_dis_int();
} }
void restore() {
assert(!done_);
if(savedIF_)
cortexa8_ena_int();
else
cortexa8_dis_int();
done_ = true;
}
private: private:
bool savedIF_; bool savedIF_, done_;
}; };
} }

View File

@@ -86,6 +86,13 @@ cortexa8_get_cpsr:
*/ */
.global _cortexa8_int .global _cortexa8_int
_cortexa8_int: _cortexa8_int:
/* If we are not interrupting user or system mode, jump to _cortexa8_inner_int (no context switch) */
mrs r13, spsr
and r13, r13, #0x1f
teq r13, #0x1f
teqne r13, #0x10
bne _cortexa8_inner_int
ldr r13, = _current_thread_cb ldr r13, = _current_thread_cb
ldr r13, [r13] ldr r13, [r13]
stm r13, {r0-r14}^ stm r13, {r0-r14}^
@@ -101,8 +108,25 @@ _cortexa8_int:
ldr r13, [r13] ldr r13, [r13]
ldr r1, [r13, #64] ldr r1, [r13, #64]
msr spsr, r1 msr spsr, r1
ldr lr, [r13, #60]
ldm r13, {r0-r14}^
movs pc,lr
_cortexa8_inner_int:
ldr r13, = __stack_int
push {lr}
add r13, r13, #-60
stm r13, {r0-r14}
mrs r0, spsr
push {r0}
bl _omap35x_intc_handler
pop {r0}
msr spsr, r0
ldm r13, {r0-r15}^ ldm r13, {r0-r15}^
.global _cortexa8_syscall .global _cortexa8_syscall
_cortexa8_syscall: _cortexa8_syscall:
ldr r13, = _current_thread_cb ldr r13, = _current_thread_cb
@@ -122,12 +146,14 @@ _cortexa8_syscall:
andne r0, #0x000000ff andne r0, #0x000000ff
bl syscall_handler bl syscall_handler
ldr r13, = _current_thread_cb ldr r13, = _current_thread_cb
ldr r13, [r13] ldr r13, [r13]
ldr r1, [r13, #64] ldr r1, [r13, #64]
msr spsr, r1 msr spsr, r1
ldm r13, {r0-r15}^ ldr lr, [r13, #60]
ldm r13, {r0-r14}^
movs pc,lr
.global _vect_table .global _vect_table
.align 5 .align 5

View File

@@ -190,7 +190,7 @@ SECTIONS
__stack_int = .; __stack_int = .;
. = . + 0x4000; /* 16KiB syscall stack */ . = . + 0x4000; /* 16KiB syscall stack */
__stack_syscall = .; __stack_syscall = .;
. = . + 0x4000; /* 16KiB kernel startup stack */ . = . + 0x8000; /* 32KiB kernel startup stack */
__stack = .; __stack = .;
__end__ = . ; __end__ = . ;

13
main.cc
View File

@@ -3,6 +3,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <malloc.h> #include <malloc.h>
#include <errno.h>
#include "drv_omap35x_gpt.hh" #include "drv_omap35x_gpt.hh"
#include "drv_omap35x_i2c.hh" #include "drv_omap35x_i2c.hh"
@@ -69,9 +70,7 @@ int main(int argc, char* argv[]) {
global::intc = new OMAP35x_intc{0x48200000}; global::intc = new OMAP35x_intc{0x48200000};
global::prcm->enable_peripherals(); global::prcm->enable_peripherals();
global::console = new UART{0x49020000, 74};
// Enable interrupts // Enable interrupts
cortexa8_ena_int(); cortexa8_ena_int();
@@ -100,12 +99,16 @@ int main(int argc, char* argv[]) {
global::scheduler = new Scheduler{}; global::scheduler = new Scheduler{};
} }
global::console = new UART{0x49020000, 74};
while(1) { while(1) {
char buf[256]; char buf[256];
if(fgets(buf, 256, stdin)) if(fgets(buf, 256, stdin))
printf("%s", buf); printf("%s", buf);
else else {
printf("Error\n"); printf("Error %d\n", errno);
abort();
}
if(strcmp(buf, "exit\n") == 0) if(strcmp(buf, "exit\n") == 0)
break; break;
} }

82
mtprim.hh Normal file
View File

@@ -0,0 +1,82 @@
#ifndef _MTPRIM_HH_
#define _MTPRIM_HH_
#include "scheduler.hh"
#include "cortexa8.hh"
// Multithreading primitives (mutex, conditional)
// Mutex with support for recursive locking
// Uses Scheduler::Semaphore
class Mutex {
public:
Mutex() : owner_(nullptr), ownerCount_(0) {
}
~Mutex() {
assert(ownerCount_ == 0);
}
void lock() {
{
SemScopedAcquire lock_(semInt_);
if(owner_ == &global::scheduler->getCurrentThread()) {
++ownerCount_;
return;
}
}
semMutex_.acquire();
{
SemScopedAcquire lock_(semInt_);
assert(owner_ == nullptr);
owner_ = &global::scheduler->getCurrentThread();
ownerCount_ = 1;
}
}
void release() {
SemScopedAcquire lock_(semInt_);
assert(owner_ == &global::scheduler->getCurrentThread());
--ownerCount_;
if(ownerCount_ > 0) {
return;
}
owner_ = nullptr;
semMutex_.release();
}
private:
Scheduler::Semaphore semMutex_, semInt_;
Scheduler::Thread* owner_;
int ownerCount_;
};
template<class T>
class ScopedLock {
ScopedLock(T& mutex) : mutex_(mutex), done_(false) {
mutex_.lock();
}
~ScopedLock() {
if(!done_)
mutex_.release();
}
void release() {
assert(!done_);
mutex_.release();
done_ = true;
}
void reacquire() {
assert(done_);
mutex_.lock();
done_ = false;
}
private:
T& mutex_;
bool done_;
};
#endif

View File

@@ -1,61 +1,74 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <stdlib.h> #include <stdlib.h>
#include <malloc.h>
#include "cortexa8.hh" #include "cortexa8.hh"
#include "mm.hh" #include "mm.hh"
#include "globals.hh" #include "globals.hh"
#include "scheduler.hh" #include "scheduler.hh"
#include "mtprim.hh"
#include <errno.h> #include <errno.h>
#undef errno #undef errno
extern int errno; extern int errno;
extern cortexa8::thread_cb *_current_thread_cb;
extern "C" { extern "C" {
int _close(int file) __attribute__((used)); int _close_r(void *reent, int file) __attribute__((used));
int _close(int file) { int _close_r(void *reent, int file) {
return -1; return -1;
} }
int _lseek(int file, int ptr, int dir) __attribute__((used)); int _lseek_r(void *reent, int file, int ptr, int dir) __attribute__((used));
int _lseek(int file, int ptr, int dir) { int _lseek_r(void *reent, int file, int ptr, int dir) {
return 0; return 0;
} }
int _fstat(int file, struct stat *st) __attribute__((used)); int _fstat_r(void *reent, int file, struct stat *st) __attribute__((used));
int _fstat(int file, struct stat *st) { int _fstat_r(void *reent, int file, struct stat *st) {
st->st_mode = S_IFCHR; st->st_mode = S_IFCHR;
return 0; return 0;
} }
int _isatty(int file) __attribute__((used)); int _isatty_r(void *reent, int file) __attribute__((used));
int _isatty(int file) { int _isatty_r(void *reent, int file) {
return 1; return 1;
} }
int _read(int file, char *ptr, int len) __attribute__((used)); int _read_r(void *reent, int file, char *ptr, int len) __attribute__((used));
int _read(int file, char *ptr, int len) { int _read_r(void *reent, int file, char *ptr, int len) {
if(file != 0) _reent* reent_ = (_reent*)reent;
return 0;
if(file != 0) {
reent_->_errno = EBADF;
return -1;
}
if(global::console) if(global::console)
return global::console->read(ptr, len); return global::console->read(ptr, len);
else { else {
errno = EIO; reent_->_errno = EIO;
return -1; return -1;
} }
} }
int _write(int file, const char *ptr, int len) __attribute__((used)); int _write_r(void *reent, int file, const char *ptr, int len) __attribute__((used));
int _write(int file, const char *ptr, int len) { int _write_r(void *reent, int file, const char *ptr, int len) {
if(file != 1 && file != 2) // Only stdout supported _reent* reent_ = (_reent*)reent;
return 0;
if(file != 1 && file != 2) {// Only stdout supported
reent_->_errno = EBADF;
return -1;
}
if(global::console) { if(global::console) {
global::console->write(ptr, len); global::console->write(ptr, len);
return len; return len;
} else { } else {
errno = EIO; reent_->_errno = EIO;
return -1; return -1;
} }
} }
@@ -64,8 +77,8 @@ extern "C" {
static uintptr_t heap_end = 0; static uintptr_t heap_end = 0;
static uintptr_t brk; static uintptr_t brk;
caddr_t _sbrk(int incr) __attribute__((used)); caddr_t _sbrk_r(void *reent, int incr) __attribute__((used));
caddr_t _sbrk(int incr) { caddr_t _sbrk_r(void *reent, int incr) {
if(heap_end == 0) { if(heap_end == 0) {
heap_end = mm::get_heap_end(); heap_end = mm::get_heap_end();
brk = (uintptr_t)&__heap_start; brk = (uintptr_t)&__heap_start;
@@ -80,7 +93,7 @@ extern "C" {
++pages; ++pages;
heap_end = mm::grow_heap(pages); heap_end = mm::grow_heap(pages);
} catch (ex::bad_alloc &ex) { } catch (ex::bad_alloc &ex) {
_write(1, "Heap allocation failure\n", 24); //_write(1, "Heap allocation failure\n", 24);
abort(); abort();
} }
} }
@@ -91,19 +104,21 @@ extern "C" {
return prev_brk; return prev_brk;
} }
int _kill(int pid, int sig) __attribute__((used)); int _kill_r(void *reent, int pid, int sig) __attribute__((used));
int _kill(int pid, int sig) { int _kill_r(void *reent, int pid, int sig) {
errno = EINVAL; _reent* reent_ = (_reent*)reent;
reent_->_errno = EINVAL;
return -1; return -1;
} }
int _getpid(void) __attribute__((used)); int _getpid_r(void *reent) __attribute__((used));
int _getpid(void) { int _getpid_r(void *reent) {
return 1; return 1;
} }
int _open(const char *name, int flags, int mode) __attribute__((used)); int _open_r(void *reent, const char *name, int flags, int mode) __attribute__((used));
int _open(const char *name, int flags, int mode) { int _open_r(void *reent, const char *name, int flags, int mode) {
return -1; return -1;
} }
@@ -118,12 +133,25 @@ extern "C" {
__asm__ __volatile__ ("wfi"); __asm__ __volatile__ ("wfi");
} }
/* struct _reent* __getreent() __attribute__((used)); */ // struct _reent* __getreent() __attribute__((used));
/* struct _reent* __getreent() { */ // struct _reent* __getreent() {
/* _write(1,"!", 1); */ // _write_r((void*)&_current_thread_cb->newlibReent, 1,"!", 1);
/* return nullptr; */ // return &_current_thread_cb->newlibReent;
/* } */ // }
static Mutex mutexMalloc{};
void __malloc_lock (struct _reent *reent) {
//_write(1, "L", 1);
if(global::scheduler)
mutexMalloc.lock();
}
void __malloc_unlock (struct _reent *reent) {
//_write(1, "U", 1);
if(global::scheduler)
mutexMalloc.release();
}
} }
#include <cstdio> #include <cstdio>
@@ -131,7 +159,7 @@ extern "C" {
void sbrk_stats() { void sbrk_stats() {
if(heap_end == 0) { if(heap_end == 0) {
_write(1, "Heap not initialized\n", 21); //_write(1, "Heap not initialized\n", 21);
return; return;
} }

View File

@@ -242,6 +242,8 @@ void phys_mm::init() {
} }
uintptr_t phys_mm::alloc(unsigned count) { uintptr_t phys_mm::alloc(unsigned count) {
assert(count > 0);
unsigned i = _find_free(_ln2(count)); unsigned i = _find_free(_ln2(count));
if(i == phys_pages) if(i == phys_pages)
throw bad_alloc{}; throw bad_alloc{};
@@ -252,6 +254,8 @@ uintptr_t phys_mm::alloc(unsigned count) {
} }
void phys_mm::free(uintptr_t base) { void phys_mm::free(uintptr_t base) {
assert(base != 0);
unsigned idx = (base-0x80000000)/4096; unsigned idx = (base-0x80000000)/4096;
_free_at(idx); _free_at(idx);
} }

View File

@@ -1,5 +1,6 @@
#include <memory> #include <memory>
#include <cstdio> #include <cstdio>
#include <sys/reent.h>
#include "cortexa8.hh" #include "cortexa8.hh"
#include "scheduler.hh" #include "scheduler.hh"
@@ -10,8 +11,8 @@ static void idle_task(void *) {
while(true) { while(true) {
++count; ++count;
if(count%100 == 0) { if(count%100 == 0) {
// printf("."); printf(".");
// fflush(stdout); fflush(stdout);
} }
__asm__ __volatile__("wfi"); __asm__ __volatile__("wfi");
} }
@@ -49,6 +50,7 @@ void Scheduler::timeslice() {
runQueue_.pop(); runQueue_.pop();
currentThread_->setState(ThreadState::running); currentThread_->setState(ThreadState::running);
cortexa8::set_cur_thread(currentThread_->get_tcb()); cortexa8::set_cur_thread(currentThread_->get_tcb());
_impure_ptr = &currentThread_->get_tcb()->newlibReent;
} }
void Scheduler::update() { void Scheduler::update() {
@@ -67,14 +69,19 @@ void Scheduler::update() {
currentThread_ = newThread_; currentThread_ = newThread_;
currentThread_->setState(ThreadState::running); currentThread_->setState(ThreadState::running);
cortexa8::set_cur_thread(currentThread_->get_tcb()); cortexa8::set_cur_thread(currentThread_->get_tcb());
_impure_ptr = &currentThread_->get_tcb()->newlibReent;
} }
} }
void Scheduler::yield() { void Scheduler::yield() {
cortexa8::ScopedSetIF disint{}; cortexa8::ScopedSetIF disint{};
if(currentThread_->getState() == ThreadState::running) if(cortexa8::in_handler()) {
currentThread_->setState(ThreadState::yield); if(currentThread_->getState() == ThreadState::running)
currentThread_->setState(ThreadState::yield);
} else {
cortexa8::yield_svc();
}
} }
void Scheduler::exit() { void Scheduler::exit() {

View File

@@ -8,8 +8,10 @@
#include <queue> #include <queue>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <array>
#include "exceptions.hh" #include "exceptions.hh"
#include "globals.hh"
#include "cortexa8.hh" #include "cortexa8.hh"
using thread_entry_t = void(void*); using thread_entry_t = void(void*);
@@ -17,6 +19,7 @@ using thread_entry_t = void(void*);
class Scheduler { class Scheduler {
public: public:
class Process; class Process;
class Semaphore;
enum class ThreadState { enum class ThreadState {
ready, ready,
@@ -78,7 +81,7 @@ public:
: tcb_{new cortexa8::thread_cb}, proc_(proc), stack_{new uint32_t[stacksize/4]}, neverDestruct_{false}, : tcb_{new cortexa8::thread_cb}, proc_(proc), stack_{new uint32_t[stacksize/4]}, neverDestruct_{false},
priority_(0), state_{ThreadState::ready} { priority_(0), state_{ThreadState::ready} {
tcb_->regs[15] = (uint32_t)entry; tcb_->regs[15] = (uint32_t)entry;
tcb_->regs[13] = (uint32_t)stack_.get(); tcb_->regs[13] = (uint32_t)stack_.get()+stacksize;
tcb_->regs[1] = (uint32_t)arg; tcb_->regs[1] = (uint32_t)arg;
tcb_->cpsr = 0x0000015f; tcb_->cpsr = 0x0000015f;
} }
@@ -95,6 +98,7 @@ public:
ThreadState state_; ThreadState state_;
friend class Scheduler; friend class Scheduler;
friend class Semaphore;
}; };
class Process { class Process {
@@ -111,6 +115,65 @@ public:
friend class Scheduler; friend class Scheduler;
}; };
class Semaphore {
public:
Semaphore(int count = 1) : count_(count), waitPos_(0) {
assert(count >= 0);
}
~Semaphore() {
}
void acquire() {
cortexa8::ScopedSetIF disint{};
--count_;
if(count_ < 0) {
// Block
auto curThread = &global::scheduler->getCurrentThread();
waitList_.at(waitPos_++) = curThread;
curThread->setState(ThreadState::waiting);
//disint.restore();
global::scheduler->yield();
}
}
bool tryAcquire() {
cortexa8::ScopedSetIF disint{};
--count_;
if(count_ < 0) {
++count_;
return false;
} else
return true;
}
void release() {
cortexa8::ScopedSetIF disint{};
++count_;
if(count_ <= 0) {
// Wake a thread
auto thread = waitList_.at(--waitPos_);
assert(thread->getState() == ThreadState::waiting);
thread->setState(ThreadState::ready);
global::scheduler->runQueue_.push(thread);
}
}
bool hasWaiters() const {
return (count_ < 0);
}
private:
int count_;
static constexpr int MaxWaiters = 8;
std::array<Thread*, MaxWaiters> waitList_;
int waitPos_;
friend class Scheduler;
};
Scheduler(); Scheduler();
~Scheduler(); ~Scheduler();
@@ -153,4 +216,34 @@ private:
Thread *currentThread_; Thread *currentThread_;
}; };
class SemScopedAcquire {
public:
SemScopedAcquire(Scheduler::Semaphore &sem) : sem_(sem), done_(false) {
sem_.acquire();
}
~SemScopedAcquire() {
if(done_)
return;
sem_.release();
}
void release() {
assert(!done_);
sem_.release();
done_ = true;
}
void reacquire() {
assert(done_);
sem_.acquire();
done_ = false;
}
private:
Scheduler::Semaphore& sem_;
bool done_;
};
#endif #endif

20
uart.cc
View File

@@ -8,11 +8,12 @@
#include "globals.hh" #include "globals.hh"
#include "util.hh" #include "util.hh"
#include "mmio.hh" #include "mmio.hh"
#include "scheduler.hh"
#include "uart.hh" #include "uart.hh"
class UART_impl { class UART_impl {
public: public:
UART_impl(uintptr_t base, int irq) : base_{base}, irq_(irq) { UART_impl(uintptr_t base, int irq) : base_{base}, irq_(irq), semNewData_{0} {
global::intc->register_handler(irq_, std::bind(&UART_impl::recv_handler, this), 1); global::intc->register_handler(irq_, std::bind(&UART_impl::recv_handler, this), 1);
global::intc->enable_int(irq_); global::intc->enable_int(irq_);
@@ -44,8 +45,7 @@ public:
int pos = 0; int pos = 0;
while(true) { while(true) {
bool oldint = cortexa8_get_int(); cortexa8::ScopedSetIF disint{};
cortexa8_dis_int();
// Data available in recvbuffer? // Data available in recvbuffer?
if(((recvbuffer_rdptr_+1)%RECVBUFFERSIZE) != recvbuffer_wrptr_) { if(((recvbuffer_rdptr_+1)%RECVBUFFERSIZE) != recvbuffer_wrptr_) {
@@ -81,18 +81,12 @@ public:
buf[pos++] = rd; buf[pos++] = rd;
} }
if(oldint) //disint.restore();
cortexa8_ena_int();
if(pos > 0) if(pos > 0)
return pos; return pos;
while(!newdata_) { semNewData_.acquire();
if(global::scheduler)
cortexa8::yield_svc();
else
__asm__ __volatile__ ("wfi"); // If we didn't get any data, wait
}
} }
} }
@@ -111,12 +105,14 @@ private:
} }
} }
newdata_ = true; if(semNewData_.hasWaiters())
semNewData_.release();
global::prcm->clear_wake_per(11); global::prcm->clear_wake_per(11);
} }
MMIO_alloc base_; MMIO_alloc base_;
int irq_; int irq_;
Scheduler::Semaphore semNewData_;
uint8_t volatile& r_data() { uint8_t volatile& r_data() {
return _reg8(base_.get_virt(), 0); return _reg8(base_.get_virt(), 0);