URL
https://opencores.org/ocsvn/altor32/altor32/trunk
Subversion Repositories altor32
Compare Revisions
- This comparison shows the changes necessary to convert path
/altor32/trunk
- from Rev 20 to Rev 21
- ↔ Reverse comparison
Rev 20 → Rev 21
/sw/rtos/kernel/critical.h
0,0 → 1,15
#ifndef __CRITICAL_H__ |
#define __CRITICAL_H__ |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
|
// Force interrupts to be disabled (recursive ok) |
int critical_start(void); |
|
// Restore interrupt enable state (recursive ok) |
void critical_end(int cr); |
|
#endif |
|
/sw/rtos/kernel/mailbox.h
0,0 → 1,45
#ifndef __MAILBOX_H__ |
#define __MAILBOX_H__ |
|
#include "list.h" |
#include "semaphore.h" |
|
//----------------------------------------------------------------- |
// Defines |
//----------------------------------------------------------------- |
#ifdef DEFAULT_MAILBOX_SIZE |
#define MAILBOX_MAX_ITEMS DEFAULT_MAILBOX_SIZE |
#else |
#define MAILBOX_MAX_ITEMS 32 |
#endif |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
struct mailbox |
{ |
void* entries[MAILBOX_MAX_ITEMS]; |
int head; |
int tail; |
int count; |
|
struct semaphore sema; |
}; |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
|
// Initialise mailbox |
void mailbox_init(struct mailbox *pMbox); |
|
// Post message to mailbox (copy pointer 'val') |
int mailbox_post(struct mailbox *pMbox, void *val); |
|
// Wait for mailbox message |
void mailbox_pend(struct mailbox *pMbox, void **val); |
|
// Wait for mailbox message (with timeout) |
int mailbox_pend_timed(struct mailbox *pMbox, void **val, int timeoutMs); |
|
#endif |
/sw/rtos/kernel/mutex.c
0,0 → 1,133
//----------------------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRISC |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 Alternative Lightweight OpenRISC project. |
// |
// AltOR32 is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free Software |
// Foundation; either version 2 of the License, or (at your option) any later |
// version. |
// |
// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
// details. |
// |
// You should have received a copy of the GNU General Public License |
// along with AltOR32; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
#include "rtos.h" |
#include "mutex.h" |
#include "thread.h" |
#include "os_assert.h" |
|
#ifdef INCLUDE_MUTEX |
//----------------------------------------------------------------- |
// mutex_init: Initialise mutex |
//----------------------------------------------------------------- |
void mutex_init(struct mutex *pMtx) |
{ |
OS_ASSERT(pMtx != NULL); |
|
// No default owner |
pMtx->owner = NULL; |
|
// Pending thread list |
list_init(&pMtx->pend_list); |
} |
//----------------------------------------------------------------- |
// mutex_acquire: Acquire mutex (non-recursive) |
//----------------------------------------------------------------- |
void mutex_acquire(struct mutex *pMtx) |
{ |
struct thread* this_thread; |
int cr; |
|
OS_ASSERT(pMtx != NULL); |
|
cr = critical_start(); |
|
// Get current (this) thread |
this_thread = thread_current(); |
|
OS_ASSERT(pMtx->owner != this_thread); |
|
// Is the mutex not already locked |
if (pMtx->owner == NULL) |
{ |
// Acquire mutex for this thread |
pMtx->owner = this_thread; |
} |
// The mutex is already 'owned', add |
// thread to pending list |
else |
{ |
struct link_node *listnode; |
|
// Get list node |
listnode = &this_thread->blocking_node; |
|
// Add node to end of pending list |
list_insert_last(&pMtx->pend_list, listnode); |
|
// Block the thread from running |
thread_block(this_thread); |
} |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// mutex_release: Release mutex (non-recursive) |
//----------------------------------------------------------------- |
void mutex_release(struct mutex *pMtx) |
{ |
struct thread* this_thread; |
int cr; |
|
OS_ASSERT(pMtx != NULL); |
|
cr = critical_start(); |
|
// Get current (this) thread |
this_thread = thread_current(); |
|
// We cannot release a lock that we dont own! |
OS_ASSERT(this_thread == pMtx->owner); |
|
// If there are threads pending on this mutex |
if (!list_is_empty(&pMtx->pend_list)) |
{ |
// Unblock the first pending thread |
struct link_node *node = list_first(&pMtx->pend_list); |
|
// Get the thread item |
struct thread* thread = list_entry(node, struct thread, blocking_node); |
|
// Remove node from linked list |
list_remove(&pMtx->pend_list, node); |
|
// Transfer mutex ownership |
pMtx->owner = thread; |
|
// Unblock the first waiting thread |
thread_unblock(thread); |
} |
// Else no-one wants it, no owner |
else |
pMtx->owner = NULL; |
|
critical_end(cr); |
} |
#endif |
/sw/rtos/kernel/mutex.h
0,0 → 1,29
#ifndef __MUTEX_H__ |
#define __MUTEX_H__ |
|
#include "list.h" |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
struct mutex |
{ |
void * owner; |
struct link_list pend_list; |
}; |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
|
// Initialise mutex |
void mutex_init(struct mutex *pMtx); |
|
// Acquire mutex (non-recursive) |
void mutex_acquire(struct mutex *pMtx); |
|
// Release mutex (non-recursive) |
void mutex_release(struct mutex *pMtx); |
|
#endif |
|
/sw/rtos/kernel/os_assert.h
0,0 → 1,27
#ifndef __OS_ASSERT_H__ |
#define __OS_ASSERT_H__ |
|
// To disable RTOS assertions then define OS_RELEASE_MODE |
|
//----------------------------------------------------------------- |
// DEBUG |
//----------------------------------------------------------------- |
#ifndef OS_RELEASE_MODE |
|
extern void _thread_assert(const char *reason, const char *file, int line); |
|
#define OS_ASSERT(exp) do { if (!(exp)) _thread_assert(#exp, __FILE__, __LINE__); } while (0) |
#define OS_PANIC(reason) _thread_assert(reason, __FILE__, __LINE__) |
|
//----------------------------------------------------------------- |
// RELEASE |
//----------------------------------------------------------------- |
#else |
|
#define OS_ASSERT(exp) ((void)0) |
#define OS_PANIC(reason) while (1) |
|
#endif |
|
#endif |
|
/sw/rtos/kernel/thread.c
0,0 → 1,912
//----------------------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRISC |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 Alternative Lightweight OpenRISC project. |
// |
// AltOR32 is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free Software |
// Foundation; either version 2 of the License, or (at your option) any later |
// version. |
// |
// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
// details. |
// |
// You should have received a copy of the GNU General Public License |
// along with AltOR32; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
#include "rtos.h" |
#include "thread.h" |
#include "os_assert.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#ifdef PLATFORM_IDLE_TASK_STACK |
#define IDLE_TASK_STACK PLATFORM_IDLE_TASK_STACK |
#else |
#define IDLE_TASK_STACK 256 |
#endif |
|
//----------------------------------------------------------------- |
// Locals: |
//----------------------------------------------------------------- |
static struct link_list _thread_runable; |
static struct link_list _thread_blocked; |
static struct link_list _thread_sleeping; |
static struct link_list _thread_dead; |
static struct thread* _currentThread = NULL; |
static struct thread _idle_task; |
static struct thread* _thread_list_all = NULL; |
static int _initd = 0; |
static volatile long _tick_count = 0; |
static volatile long _thread_picks = 0; |
static unsigned long _idle_task_stack[IDLE_TASK_STACK]; |
|
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
static void thread_idle_task(void* arg); |
static struct thread* thread_pick(void); |
static void thread_func(void *pThd); |
|
static void thread_switch(void); |
static void thread_insert_priority(struct link_list *pList, struct thread *pInsertNode); |
|
//----------------------------------------------------------------- |
// thread_kernel_init: Initialise the RTOS kernel |
//----------------------------------------------------------------- |
int thread_kernel_init(void) |
{ |
// NOTE: Interrupts should be disabled prior |
// to calling this function! |
|
// Initialise thread lists |
list_init(&_thread_runable); |
list_init(&_thread_sleeping); |
list_init(&_thread_blocked); |
list_init(&_thread_dead); |
|
_thread_list_all = NULL; |
|
// Create an idle task |
thread_init(&_idle_task, "IDLE_TASK", THREAD_IDLE_PRIO, thread_idle_task, (void*)NULL, (void*)_idle_task_stack, IDLE_TASK_STACK); |
|
_tick_count = 0; |
_initd = 1; |
return 1; |
} |
//----------------------------------------------------------------- |
// thread_kernel_run: Start the RTOS kernel |
//----------------------------------------------------------------- |
void thread_kernel_run(void) |
{ |
if (!_initd) |
{ |
OS_PANIC("Halt:Not Initialized\n"); |
while(1); |
} |
|
// Start with idle task so we then pick the best thread to |
// run rather than the first in the list |
_currentThread = &_idle_task; |
|
// Switch context to the highest priority thread |
cpu_thread_start(); |
} |
//----------------------------------------------------------------- |
// thread_init_ex: Create thread with specified start state |
//----------------------------------------------------------------- |
int thread_init_ex(struct thread *pThread, char *name, int pri, void (*f)(void *), void *arg, unsigned long *stack, unsigned int stack_size, tThreadState initial_state) |
{ |
int cr; |
int l = 0; |
|
OS_ASSERT(pThread != NULL); |
|
// Thread name |
if (!name) |
name = "NO_NAME"; |
|
while (l < THREAD_NAME_LEN && name[l]) |
{ |
pThread->name[l] = name[l]; |
l++; |
} |
|
pThread->name[THREAD_NAME_LEN-1] = 0; |
|
// Setup priority |
pThread->priority = pri; |
|
// Thread function |
pThread->thread_func = f; |
pThread->thread_arg = arg; |
|
pThread->state = initial_state; |
pThread->wait_delta = 0; |
pThread->run_count = 0; |
|
#ifdef RTOS_MEASURE_THREAD_TIME |
pThread->run_time = 0; |
pThread->run_start = 0; |
#endif |
|
// Task control block |
cpu_thread_init_tcb(&pThread->tcb, thread_func, pThread, stack, stack_size); |
|
// Begin critical section |
cr = critical_start(); |
|
// Runable: Insert this thread at the end of run list |
if (initial_state == THREAD_RUNABLE) |
thread_insert_priority(&_thread_runable, pThread); |
else if (initial_state == THREAD_BLOCKED) |
list_insert_last(&_thread_blocked, &pThread->node); |
else |
{ |
OS_ASSERT(initial_state != THREAD_SLEEPING); |
} |
|
// Add to simple all threads list |
pThread->next_all = _thread_list_all; |
_thread_list_all = pThread; |
|
// Set the checkword |
pThread->checkword = THREAD_CHECK_WORD; |
|
critical_end(cr); |
|
return 1; |
} |
//----------------------------------------------------------------- |
// thread_init: Create thread (immediately run-able) |
//----------------------------------------------------------------- |
int thread_init(struct thread *pThread, char *name, int pri, void (*f)(void *), void *arg, unsigned long *stack, unsigned int stack_size) |
{ |
return thread_init_ex(pThread, name, pri, f, arg, stack, stack_size, THREAD_RUNABLE); |
} |
//----------------------------------------------------------------- |
// thread_kill: Kill thread and remove from all thread lists. |
// Once complete, thread data/stack will not be accessed again by |
// RTOS. |
// You cannot kill a thread from itself, use thread_suicide instead. |
// Returns: 1 = ok, 0 = failed |
//----------------------------------------------------------------- |
int thread_kill(struct thread *pThread) |
{ |
int ok = 0; |
struct thread *pCurr = NULL; |
struct thread *pLast = NULL; |
int cr = critical_start(); |
|
// Thread cannot kill itself using thread_kill |
if (pThread != _currentThread) |
{ |
// Is the thread currently runable? |
if (pThread->state == THREAD_RUNABLE) |
{ |
// Remove from the run list |
list_remove(&_thread_runable, &pThread->node); |
} |
// or is it blocked |
else if (pThread->state == THREAD_BLOCKED) |
{ |
// Remove from the blocked list |
list_remove(&_thread_blocked, &pThread->node); |
} |
// or is it blocked |
else if (pThread->state == THREAD_SLEEPING) |
{ |
// Remove from the blocked list |
list_remove(&_thread_sleeping, &pThread->node); |
} |
// or is already dead |
else if (pThread->state == THREAD_DEAD) |
{ |
// Remove from the dead list |
list_remove(&_thread_dead, &pThread->node); |
} |
else |
OS_PANIC("Unknown thread state!"); |
|
// Remove from simple 'all threads' list |
pCurr = _thread_list_all; |
while (pCurr != NULL) |
{ |
if (pCurr == pThread) |
{ |
if (pLast != NULL) |
pLast->next_all = pCurr->next_all; |
else |
_thread_list_all = pCurr->next_all; |
break; |
} |
pLast = pCurr; |
} |
|
ok = 1; |
} |
|
critical_end(cr); |
|
return ok; |
} |
//----------------------------------------------------------------- |
// thread_suicide: Allows a thread to self terminate. |
//----------------------------------------------------------------- |
void thread_suicide(struct thread *pThread) |
{ |
int cr = critical_start(); |
|
OS_ASSERT(pThread == _currentThread); |
OS_ASSERT(pThread->state == THREAD_RUNABLE); |
|
// Remove from the run list |
list_remove(&_thread_runable, &pThread->node); |
|
// Mark thread as dead and add to dead thread list |
pThread->state = THREAD_DEAD; |
list_insert_last(&_thread_dead, &pThread->node); |
|
// Mark thread as NULL so it is not re-added to the run |
// list by thread_pick()! |
_currentThread = NULL; |
|
// Switch context to the new highest priority thread |
thread_switch(); |
|
// We should never reach here |
OS_PANIC("Should not be here"); |
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// thread_sleep_thread: Put a specific thread on to the sleep queue |
//----------------------------------------------------------------- |
void thread_sleep_thread(struct thread *pSleepThread, int timeoutMs) |
{ |
int cr = critical_start(); |
long total = 0; |
long prevtotal = 0; |
struct link_node *node; |
|
OS_ASSERT(pSleepThread); |
|
// Is the thread currently runable? |
if (pSleepThread->state == THREAD_RUNABLE) |
{ |
// Remove from the run list |
list_remove(&_thread_runable, &pSleepThread->node); |
} |
// or is it blocked |
else if (pSleepThread->state == THREAD_BLOCKED) |
{ |
// Remove from the blocked list |
list_remove(&_thread_blocked, &pSleepThread->node); |
} |
else |
OS_PANIC("Thread already sleeping!"); |
|
// Mark thread as sleeping |
pSleepThread->state = THREAD_SLEEPING; |
|
// NOTE: Add 1 to the sleep time to get at least the time slept for. |
timeoutMs = timeoutMs + 1; |
|
// Get the first sleeping thread |
node = list_first(&_thread_sleeping); |
|
// Current sleep list is empty? |
if (node == NULL) |
{ |
// delta is total timeout |
pSleepThread->wait_delta = timeoutMs; |
|
// Add to the start of the sleep list |
list_insert_first(&_thread_sleeping, &pSleepThread->node); |
} |
// Timer list has items |
else |
{ |
// Iterate through current list and add at correct location |
for ( ; node ; node = list_next(&_thread_sleeping, node)) |
{ |
// Get the thread item |
struct thread * pThread = list_entry(node, struct thread, node); |
|
// Increment cumulative total |
total += pThread->wait_delta; |
|
// New timeout less than total (or end of list reached) |
if (timeoutMs <= total) |
{ |
// delta time from previous to this node |
pSleepThread->wait_delta = timeoutMs - prevtotal; |
|
// Insert into list before this sleeping thread |
list_insert_before(&_thread_sleeping, &pThread->node, &pSleepThread->node); |
|
// Adjust next nodes delta time |
pThread->wait_delta -= pSleepThread->wait_delta; |
break; |
} |
|
prevtotal = total; |
|
// End of list reached, still not added |
if (list_next(&_thread_sleeping, node) == NULL) |
{ |
// delta time from previous to this node |
pSleepThread->wait_delta = timeoutMs - prevtotal; |
|
// Insert into list after last node (end of list) |
list_insert_last(&_thread_sleeping, &pSleepThread->node); |
break; |
} |
} |
} |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// thread_sleep_cancel: Stop a thread from sleeping |
//----------------------------------------------------------------- |
void thread_sleep_cancel(struct thread *pThread) |
{ |
int cr = critical_start(); |
|
OS_ASSERT(pThread); |
|
// If the item has not already expired (and is in the sleeping list) |
if (pThread->state == THREAD_SLEEPING) |
{ |
// Is there another thread after this in the delta list? |
struct link_node *node = list_next(&_thread_sleeping, &pThread->node); |
if (node) |
{ |
struct thread *pNextThread = list_entry(node, struct thread, node); |
|
// Add current item's remaining time to next |
pNextThread->wait_delta += pThread->wait_delta; |
} |
|
// Remove from the sleeping list |
list_remove(&_thread_sleeping, &pThread->node); |
|
// Clear the sleep timer |
pThread->wait_delta = 0; |
|
// Until this thread is put back in the run list or |
// is re-added to the sleep list then mark as blocked. |
pThread->state = THREAD_BLOCKED; |
list_insert_last(&_thread_blocked, &pThread->node); |
} |
// Else thread timeout has expired and is now runable (or blocked) |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// thread_sleep: Sleep thread for x milliseconds |
//----------------------------------------------------------------- |
void thread_sleep(int timeoutMs) |
{ |
int cr = critical_start(); |
|
// Put the current thread to sleep |
if (timeoutMs > 0) |
thread_sleep_thread(_currentThread, timeoutMs); |
else |
thread_load_context(0); |
// TODO: thread_sleep(0) will not work with co-operative scheduler |
|
// Switch context to the next highest priority thread |
thread_switch(); |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// thread_switch: Switch context to the highest priority thread |
//----------------------------------------------------------------- |
static void thread_switch(void) |
{ |
// Get the current run count |
long oldRuncount = _currentThread->run_count; |
|
// Cause context switch |
cpu_context_switch(); |
|
// In-order to get back to this point, we must have been |
// picked by thread_pick() and the run-count incremented. |
OS_ASSERT(oldRuncount != (_currentThread->run_count)); |
|
// This thread must be in the run list otherwise something has gone wrong! |
OS_ASSERT(_currentThread->state == THREAD_RUNABLE); |
} |
//----------------------------------------------------------------- |
// thread_load_context: Find highest priority run-able thread to run |
//----------------------------------------------------------------- |
CRITICALFUNC void thread_load_context(int preempt) |
{ |
struct thread * pThread; |
|
// If non pre-emptive scheduler, don't change threads for pre-emption. |
// (Don't change context until the current thread is non-runnable) |
#ifdef RTOS_COOPERATIVE_SCHEDULING |
if (preempt && _currentThread->state == THREAD_RUNABLE) |
return; |
#endif |
|
#ifdef RTOS_MEASURE_THREAD_TIME |
// How long was this thread scheduled for? |
if (_currentThread->run_start != 0) |
_currentThread->run_time += cpu_timediff(cpu_timenow(), _currentThread->run_start); |
#endif |
|
// Now pick the highest thread that can be run and restore it's context. |
pThread = thread_pick(); |
|
#ifdef RTOS_MEASURE_THREAD_TIME |
// Take a snapshot of the system clock when thread selected |
pThread->run_start = cpu_timenow(); |
|
// Time=0 has a special meaning! |
if (pThread->run_start == 0) |
pThread->run_start = 1; |
#endif |
|
// Load new thread's context |
_currentThread = pThread; |
|
// Load the new TCB reference |
_currentTCB = &_currentThread->tcb; |
|
// Try and detect stack overflow |
OS_ASSERT(_currentTCB->StackAlloc[0] == STACK_CHK_BYTE); |
} |
//----------------------------------------------------------------- |
// thread_current: Get the current thread that is active! |
//----------------------------------------------------------------- |
struct thread* thread_current() |
{ |
return _currentThread; |
} |
//----------------------------------------------------------------- |
// thread_pick: Pick the highest priority runable thread |
// NOTE: Must be called within critical protection region |
//----------------------------------------------------------------- |
static CRITICALFUNC struct thread* thread_pick(void) |
{ |
struct thread *pThread; |
struct link_node *node; |
|
// If we have a current running task and if the current thread |
// is still run-able, put it in the correct position in the list. |
if (_currentThread && _currentThread->state == THREAD_RUNABLE) |
{ |
// Remove it from the run list |
list_remove(&_thread_runable, &_currentThread->node); |
// and re-insert at appropriate position in run list |
// based on thread priority. |
// This will be after all the other threads at the same |
// priority level, hence allowing round robin execution |
// of other threads with the same priority level. |
thread_insert_priority(&_thread_runable, _currentThread); |
} |
|
// Get the first runable thread |
node = list_first(&_thread_runable); |
OS_ASSERT(node != NULL); |
|
pThread = list_entry(node, struct thread, node); |
|
// We should have found a task to run as long as there is at least one |
// task on the run list (there should be as this is why we have the idle |
// task!). |
OS_ASSERT(pThread != NULL); |
OS_ASSERT(pThread->checkword == THREAD_CHECK_WORD); |
OS_ASSERT(pThread->state == THREAD_RUNABLE); |
|
pThread->run_count++; |
|
// Total thread context switches / timer ticks have occurred |
_thread_picks++; |
|
return pThread; |
} |
//----------------------------------------------------------------- |
// thread_tick: Kernel tick handler |
// NOTE: Must be called within critical protection region (or INT) |
//----------------------------------------------------------------- |
CRITICALFUNC void thread_tick(void) |
{ |
struct thread *pThread = NULL; |
struct link_node *node; |
|
// Get the first sleeping thread |
node = list_first(&_thread_sleeping); |
pThread = list_entry(node, struct thread, node); |
|
// Decrement a tick from the first item in the list |
if (pThread && pThread->wait_delta) |
pThread->wait_delta--; |
|
// Iterate through list of sleeping threads |
while (pThread != NULL) |
{ |
OS_ASSERT(pThread->checkword == THREAD_CHECK_WORD); |
OS_ASSERT(pThread->state == THREAD_SLEEPING); |
|
// Has this item timed out? |
if (pThread->wait_delta == 0) |
{ |
// Remove from the sleep list |
list_remove(&_thread_sleeping, &pThread->node); |
|
// Add to the run list and mark runable |
pThread->state = THREAD_RUNABLE; |
thread_insert_priority(&_thread_runable, pThread); |
|
// Get next node (new first node) |
node = list_first(&_thread_sleeping); |
pThread = list_entry(node, struct thread, node); |
} |
// Non-zero timeout remaining, end of timed out items |
else |
break; |
} |
|
// Thats all, thread_load_context() will do the pick |
// of the highest priority runable task... |
|
_tick_count++; |
} |
//----------------------------------------------------------------- |
// thread_tick_count: Get the tick count for the RTOS |
//----------------------------------------------------------------- |
long thread_tick_count(void) |
{ |
return _tick_count; |
} |
//----------------------------------------------------------------- |
// thread_func: Wrapper for thread entry point |
//----------------------------------------------------------------- |
static void thread_func(void *pThd) |
{ |
struct thread *pThread = (struct thread *)pThd; |
|
OS_ASSERT(pThread); |
OS_ASSERT(pThread->checkword == THREAD_CHECK_WORD); |
|
// Execute thread function |
pThread->thread_func(pThread->thread_arg); |
|
// Now thread has exited, call thread_suicide! |
thread_suicide(pThread); |
|
// We should never reach here! |
OS_PANIC("Should not be here"); |
} |
//----------------------------------------------------------------- |
// thread_block: Block specified thread from executing |
// WARNING: Call within critical section! |
//----------------------------------------------------------------- |
void thread_block(struct thread *pThread) |
{ |
OS_ASSERT(pThread->checkword == THREAD_CHECK_WORD); |
OS_ASSERT(pThread->state == THREAD_RUNABLE); |
|
// Mark thread as blocked |
pThread->state = THREAD_BLOCKED; |
|
// Remove from the run list |
list_remove(&_thread_runable, &pThread->node); |
|
// Add to the blocked list |
list_insert_last(&_thread_blocked, &pThread->node); |
|
// Switch context to the new highest priority thread |
thread_switch(); |
} |
//----------------------------------------------------------------- |
// _thread_unblock: Unblock specified thread. Internal function. |
// Manipulates the ready/blocked/sleeping lists only. |
// WARNING: Call within critical section! |
//----------------------------------------------------------------- |
static void _thread_unblock(struct thread *pThread) |
{ |
// WARNING: There is no gaurantee that unblock is not called |
// on a thread that is already runable. |
// This is due to a timed semaphore timing out, being made |
// runable again but that thread not being scheduled prior |
// to the post operation which will unblock it... |
|
// Is thread sleeping (i.e doing a timed pend using thread_sleep)? |
if (pThread->state == THREAD_SLEEPING) |
{ |
// Is there another thread after this in the delta sleeping list? |
struct link_node *node = list_next(&_thread_sleeping, &pThread->node); |
if (node) |
{ |
struct thread *pNextThread = list_entry(node, struct thread, node); |
|
// Add current item's remaining time to next |
pNextThread->wait_delta += pThread->wait_delta; |
} |
|
// Remove from the sleeping list |
list_remove(&_thread_sleeping, &pThread->node); |
|
// Clear the sleep timer |
pThread->wait_delta = 0; |
} |
// Is the thread in the blocked list |
else if (pThread->state == THREAD_BLOCKED) |
{ |
// Remove from the blocked list |
list_remove(&_thread_blocked, &pThread->node); |
} |
// Already in the run list, exit! |
else if (pThread->state == THREAD_RUNABLE) |
return ; |
|
// Mark thread as run-able |
pThread->state = THREAD_RUNABLE; |
|
// Add to the run list |
thread_insert_priority(&_thread_runable, pThread); |
} |
//----------------------------------------------------------------- |
// thread_unblock: Unblock specified thread / enable execution |
// WARNING: Call within critical section! |
//----------------------------------------------------------------- |
void thread_unblock(struct thread *pThread) |
{ |
OS_ASSERT(pThread->checkword == THREAD_CHECK_WORD); |
|
// Make sure thread is now in the run list |
_thread_unblock(pThread); |
|
// If un-blocked thread is higher priority than this thread |
// then switch context to the new highest priority thread |
if (pThread->priority > _currentThread->priority) |
thread_switch(); |
} |
//----------------------------------------------------------------- |
// thread_unblock_irq: Unblock thread from IRQ |
//----------------------------------------------------------------- |
void thread_unblock_irq(struct thread *pThread) |
{ |
// Critical section should not be required, but for sanity |
int cr = critical_start(); |
|
OS_ASSERT(pThread->checkword == THREAD_CHECK_WORD); |
|
// Make sure thread is now in the run list |
_thread_unblock(pThread); |
|
// Schedule a context switch to occur after IRQ completes |
cpu_context_switch_irq(); |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// thread_insert_priority: Insert thread into list in priority order |
//----------------------------------------------------------------- |
static CRITICALFUNC void thread_insert_priority(struct link_list *pList, struct thread *pInsertNode) |
{ |
struct link_node *node; |
|
OS_ASSERT(pList != NULL); |
OS_ASSERT(pInsertNode != NULL); |
|
// No items in the queue, insert at the head |
if (list_is_empty(pList)) |
list_insert_first(pList, &pInsertNode->node); |
else |
{ |
// Iterate through list and add in order of priority |
// NOTE: Duplicates will be added to end of list of duplicate |
// threads priorities. |
list_for_each(pList, node) |
{ |
// Get the thread item |
struct thread* thread = list_entry(node, struct thread, node); |
|
// Is threads priority lower than this thread? |
if (pInsertNode->priority > thread->priority) |
{ |
// Insert before this node |
list_insert_before(pList, node, &pInsertNode->node); |
break; |
} |
|
// End of the list reached and node not inserted yet |
if (list_next(pList, node) == NULL) |
{ |
// Insert after current last node |
list_insert_after(pList, node, &pInsertNode->node); |
break; |
} |
} |
} |
} |
//----------------------------------------------------------------- |
// thread_idle_task: Idle task function |
//----------------------------------------------------------------- |
static void thread_idle_task(void* arg) |
{ |
while (1) |
rtos_services.idle(); |
} |
//----------------------------------------------------------------- |
// thread_print_thread: Print thread details to OS_PRINTF |
//----------------------------------------------------------------- |
static void thread_print_thread(int idx, struct thread *pThread, long sleepTime) |
{ |
char stateChar; |
|
OS_PRINTF("%d:\t", idx+1); |
OS_PRINTF("|%10.10s|\t", pThread->name); |
OS_PRINTF("%d\t", pThread->priority); |
|
if (pThread == _currentThread) |
stateChar = '*'; |
else |
{ |
switch (pThread->state) |
{ |
case THREAD_RUNABLE: |
stateChar = 'R'; |
break; |
case THREAD_SLEEPING: |
stateChar = 'S'; |
break; |
case THREAD_BLOCKED: |
stateChar = 'B'; |
break; |
case THREAD_DEAD: |
stateChar = 'X'; |
break; |
default: |
stateChar = 'U'; |
break; |
} |
} |
|
OS_PRINTF("%c\t", stateChar); |
OS_PRINTF("%ld\t", sleepTime); |
OS_PRINTF("%ld\t", pThread->run_count); |
OS_PRINTF("%ld\r\n", cpu_thread_stack_free(&pThread->tcb)); |
} |
//----------------------------------------------------------------- |
// thread_dump_list: Dump thread list to OS_PRINTF |
//----------------------------------------------------------------- |
void thread_dump_list(void) |
{ |
struct thread *pThread; |
struct link_node *node; |
long sleepTimeTotal = 0; |
int idx = 0; |
|
int cr = critical_start(); |
|
OS_PRINTF("Thread Dump:\r\n"); |
OS_PRINTF("Num Name Pri State Sleep Runs Free Stack\r\n"); |
|
// Print all runable threads |
pThread = _thread_list_all; |
while (pThread != NULL) |
{ |
if (pThread->state == THREAD_RUNABLE) |
thread_print_thread(idx++, pThread, 0); |
pThread = pThread->next_all; |
} |
|
// Print sleeping threads |
node = list_first(&_thread_sleeping); |
while (node != NULL) |
{ |
pThread = list_entry(node, struct thread, node); |
|
sleepTimeTotal += pThread->wait_delta; |
thread_print_thread(idx++, pThread, sleepTimeTotal); |
|
node = list_next(&_thread_sleeping, node); |
} |
|
// Print blocked threads |
pThread = _thread_list_all; |
while (pThread != NULL) |
{ |
if (pThread->state == THREAD_BLOCKED) |
thread_print_thread(idx++, pThread, 0); |
pThread = pThread->next_all; |
} |
|
// Print dead threads |
pThread = _thread_list_all; |
while (pThread != NULL) |
{ |
if (pThread->state == THREAD_DEAD) |
thread_print_thread(idx++, pThread, 0); |
pThread = pThread->next_all; |
} |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// thread_get_cpu_load: Calculate CPU load percentage. |
// Higher = heavier system task load. |
// Requires RTOS_MEASURE_THREAD_TIME to be defined along with |
// appropriate system clock/time measurement functions. |
//----------------------------------------------------------------- |
#ifdef RTOS_MEASURE_THREAD_TIME |
int thread_get_cpu_load(void) |
{ |
struct thread *pThread; |
unsigned long idle_time = 0; |
unsigned long total_time = 0; |
|
int cr = critical_start(); |
|
// Walk the thread list and calculate sum of total time spent in all threads |
pThread = _thread_list_all; |
while (pThread != NULL) |
{ |
// Idle task |
if (pThread == &_idle_task) |
{ |
OS_ASSERT( idle_time == 0 ); |
idle_time = pThread->run_time; |
total_time += pThread->run_time; |
} |
// Other tasks |
else |
total_time += pThread->run_time; |
|
// Clear time once read |
pThread->run_time = 0; |
|
// Next thread in the list |
pThread = pThread->next_all; |
} |
|
critical_end(cr); |
|
if (total_time) |
return 100 - ((idle_time * 100) / total_time); |
else |
return 0; |
} |
#endif |
//----------------------------------------------------------------- |
// _thread_assert: Assert handler used by OS_ASSERT/OS_PANIC |
//----------------------------------------------------------------- |
void _thread_assert(const char *reason, const char *file, int line) |
{ |
critical_start(); |
|
OS_PRINTF("[%s] Assert failed: %s (%s:%d)\r\n", _currentThread->name, reason, file, line); |
|
// Dump thread list |
thread_dump_list(); |
|
// Dump call stack |
cpu_dump_stack(); |
|
// Perform system specific reboot (or halt) |
rtos_services.reboot(); |
} |
/sw/rtos/kernel/thread.h
0,0 → 1,150
#ifndef __THREAD_H__ |
#define __THREAD_H__ |
|
#include "list.h" |
|
//----------------------------------------------------------------- |
// Defines |
//----------------------------------------------------------------- |
|
// Max name length for a thread |
#define THREAD_NAME_LEN 10 |
|
// Idle task priority (do not change) |
#define THREAD_IDLE_PRIO -1 |
|
// Min thread priority number |
#define THREAD_MIN_PRIO 0 |
|
// Max thread priority number |
#define THREAD_MAX_PRIO 10 |
|
// Min interrupt priority |
#define THREAD_INT_PRIO (THREAD_MAX_PRIO + 1) |
|
// Thread structure checkword |
#define THREAD_CHECK_WORD 0xBABEDEAF |
|
// Thread sleep arg used to yield |
#define THREAD_YIELD 0 |
|
//----------------------------------------------------------------- |
// Enums |
//----------------------------------------------------------------- |
|
// Thread state enumeration |
typedef enum eThreadState |
{ |
THREAD_RUNABLE, |
THREAD_SLEEPING, |
THREAD_BLOCKED, |
THREAD_DEAD |
} tThreadState; |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
struct thread |
{ |
// Thread task control block |
tTaskBlock tcb; |
|
// Thread name (used in debug output) |
char name[THREAD_NAME_LEN]; |
|
// Thread priority |
int priority; |
|
// state (Run-able, blocked or sleeping) |
tThreadState state; |
|
// Sleep time remaining (ticks) (delta) |
long wait_delta; |
|
// Thread run count |
long run_count; |
|
#ifdef RTOS_MEASURE_THREAD_TIME |
// Measure time each thread is active for? |
unsigned long run_time; |
unsigned long run_start; |
#endif |
|
// Thread function |
void (*thread_func)(void *); |
void *thread_arg; |
|
// Run/Sleep/Blocked list node |
struct link_node node; |
|
// next thread in complete name list |
struct thread *next_all; |
|
// Blocking node items |
struct link_node blocking_node; |
void* unblocking_arg; |
|
// Thread check word |
unsigned long checkword; |
}; |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
|
// Initialise the RTOS kernel |
int thread_kernel_init(void); |
|
// Start the RTOS kernel |
void thread_kernel_run(void); |
|
// Create thread (immediately run-able) |
int thread_init(struct thread *pTread, char *name, int pri, void (*f)(void *), void *arg, unsigned long *stack, unsigned int stack_size); |
|
// Create thread with specified start state |
int thread_init_ex(struct thread *pThread, char *name, int pri, void (*f)(void *), void *arg, unsigned long *stack, unsigned int stack_size, tThreadState initial_state); |
|
// Kill thread and remove from all thread lists. |
// Once complete, thread data/stack will not be accessed again by RTOS. |
// You cannot kill a thread from itself, use thread_suicide instead. |
int thread_kill(struct thread *pThread); |
|
// Allows a thread to self terminate |
void thread_suicide(struct thread *pThread); |
|
// Sleep thread for x milliseconds |
void thread_sleep(int timeMs); |
|
// Extended thread sleep API |
void thread_sleep_thread(struct thread *pSleepThread, int timeoutMs); |
void thread_sleep_cancel(struct thread *pThread); |
|
// Get current thread |
struct thread* thread_current(void); |
|
// Kernel tick handler |
void thread_tick(void); |
|
// Get the tick count for the RTOS |
long thread_tick_count(void); |
|
// Block specified thread |
void thread_block(struct thread *pThread); |
|
// Unblock specified thread |
void thread_unblock(struct thread *pThread); |
|
// Unblock thread from running (called from ISR context) |
void thread_unblock_irq(struct thread *pThread); |
|
// Dump thread list to OS_PRINTF |
void thread_dump_list(void); |
|
// Calculate CPU load percentage |
int thread_get_cpu_load(void); |
|
// Find highest priority run-able thread to run |
void thread_load_context( int preempt ); |
|
#endif |
|
/sw/rtos/kernel/interrupts.c
0,0 → 1,263
//----------------------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRISC |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 Alternative Lightweight OpenRISC project. |
// |
// AltOR32 is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free Software |
// Foundation; either version 2 of the License, or (at your option) any later |
// version. |
// |
// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
// details. |
// |
// You should have received a copy of the GNU General Public License |
// along with AltOR32; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
#include "rtos.h" |
#include "interrupts.h" |
#include "thread.h" |
#include "os_assert.h" |
|
#ifdef INCLUDE_INTERRUPTS |
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
static void interrupts_thread(void *pInt); |
|
//----------------------------------------------------------------- |
// Locals: |
//----------------------------------------------------------------- |
static struct interrupt _ints[THREAD_MAX_INTERRUPTS]; |
static void* _int_lookup[CPU_MAX_INTERRUPTS]; |
|
//----------------------------------------------------------------- |
// interrupts_init: Setup interrupt task controller |
//----------------------------------------------------------------- |
void interrupts_init(void) |
{ |
int i; |
|
for (i=0;i<THREAD_MAX_INTERRUPTS; i++) |
{ |
_ints[i].int_enabled = 0; |
_ints[i].int_pending = 0; |
_ints[i].int_function = 0; |
_ints[i].int_func_arg = 0; |
_ints[i].int_number = -1; // Not allocated! |
} |
|
for (i=0;i<CPU_MAX_INTERRUPTS; i++) |
_int_lookup[i] = 0; |
} |
//----------------------------------------------------------------- |
// _interrupt_alloc: Allocate interrupt object |
//----------------------------------------------------------------- |
static struct interrupt * _interrupt_alloc(int intNumber) |
{ |
struct interrupt *pInterrupt = NULL; |
int cr; |
int i; |
|
OS_ASSERT(intNumber >= 0 && intNumber < CPU_MAX_INTERRUPTS); |
|
cr = critical_start(); |
|
for (i=0;i<THREAD_MAX_INTERRUPTS; i++) |
{ |
// If not allocated |
if (_ints[i].int_number == -1) |
{ |
// Allocate |
_ints[i].int_enabled = 0; |
_ints[i].int_function = 0; |
_ints[i].int_func_arg = 0; |
_ints[i].int_number = intNumber; |
|
pInterrupt = &_ints[i]; |
|
// Make sure the interrupt is not already allocated! |
OS_ASSERT(_int_lookup[intNumber] == NULL); |
|
_int_lookup[intNumber] = pInterrupt; |
break; |
} |
} |
|
critical_end(cr); |
|
return pInterrupt; |
} |
//----------------------------------------------------------------- |
// interrupts_establish: Setup interrupt task (linked to intNumber IRQ) |
//----------------------------------------------------------------- |
int interrupts_establish(int intNumber, char *name, int pri, void (*int_task)(void *arg), void *arg, unsigned long *stack, unsigned int stack_size, int enable) |
{ |
// Allocate an interrupt structure |
struct interrupt * pInterrupt = _interrupt_alloc(intNumber); |
int res; |
|
OS_ASSERT(pInterrupt); |
OS_ASSERT(int_task); |
OS_ASSERT(pri >= THREAD_INT_PRIO); |
|
pInterrupt->int_function = int_task; |
pInterrupt->int_func_arg = arg; |
pInterrupt->int_number = intNumber; |
pInterrupt->int_enabled = 0; |
pInterrupt->int_pending = 0; |
|
// Create the interrupt thread in the blocked state |
res = thread_init_ex(&pInterrupt->int_thread, name, pri, interrupts_thread, pInterrupt, stack, stack_size, THREAD_BLOCKED); |
if (res) |
{ |
// Register actual IRQ vector function? |
cpu_int_register(intNumber, interrupts_handler); |
|
// Enable after establishing? |
if (enable) |
{ |
pInterrupt->int_enabled = 1; |
cpu_int_enable(intNumber); |
} |
} |
return res; |
} |
//----------------------------------------------------------------- |
// interrupts_enable: Enable interrupt |
//----------------------------------------------------------------- |
void interrupts_enable(int int_number) |
{ |
struct interrupt *pInterrupt; |
int cr; |
|
OS_ASSERT(int_number < CPU_MAX_INTERRUPTS); |
OS_ASSERT(_int_lookup[int_number]); |
|
cr = critical_start(); |
|
// Lookup interrupt to pointer |
pInterrupt = (struct interrupt *)_int_lookup[int_number]; |
|
// Enabled! |
pInterrupt->int_enabled = 1; |
|
// Enable the hardware interrupt |
cpu_int_enable(pInterrupt->int_number); |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// interrupts_disable: Disable interrupt |
//----------------------------------------------------------------- |
void interrupts_disable(int int_number) |
{ |
struct interrupt *pInterrupt; |
int cr; |
|
OS_ASSERT(int_number < CPU_MAX_INTERRUPTS); |
OS_ASSERT(_int_lookup[int_number]); |
|
// Thread priority must be less than or equal to IRQ task priority! |
OS_ASSERT(thread_current()->priority <= THREAD_INT_PRIO); |
|
// Disable pre-emption & interrupts_handler from being executed. |
cr = critical_start(); |
|
// Lookup interrupt to pointer |
pInterrupt = (struct interrupt *)_int_lookup[int_number]; |
|
// The interrupt top half (actual ISR calling interrupts_handler) may |
// have already occurred, in-which case, block this thread until the |
// bottom half (interrupts_thread) has executed then disable the IRQ |
// from occuring again. |
// This is done so as to not loose a IRQ! |
// Yield whilst IRQ is still pending (IRQ task priority must be higher |
// or equal to disabling thread prio). |
while (pInterrupt->int_pending) |
thread_sleep(THREAD_YIELD); |
|
// Disable the hardware interrupt |
cpu_int_disable(pInterrupt->int_number); |
|
// Disable flag |
pInterrupt->int_enabled = 0; |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// interrupts_handler: Function called on low level interrupt |
//----------------------------------------------------------------- |
void interrupts_handler(int int_number) |
{ |
struct interrupt *pInterrupt; |
|
OS_ASSERT(int_number < CPU_MAX_INTERRUPTS); |
OS_ASSERT(_int_lookup[int_number]); |
|
pInterrupt = (struct interrupt *)_int_lookup[int_number]; |
|
// This interrupt should be enabled & not already pending! |
OS_ASSERT(pInterrupt->int_enabled); |
OS_ASSERT(!pInterrupt->int_pending); |
|
// Mark IRQ handling as pending |
pInterrupt->int_pending = 1; |
|
// Disable the hardware interrupt |
cpu_int_disable(pInterrupt->int_number); |
|
// Acknowledge IRQ event which we have just received |
cpu_int_acknowledge(pInterrupt->int_number); |
|
// Unblock IRQ task and schedule context switch |
thread_unblock_irq(&pInterrupt->int_thread); |
} |
//----------------------------------------------------------------- |
// interrupts_thread: |
//----------------------------------------------------------------- |
static void interrupts_thread(void *pInt) |
{ |
int cr; |
struct interrupt *pInterrupt = (struct interrupt *)pInt; |
|
for ( ; ; ) |
{ |
// ... Wake up after being unblocked by actual ISR ... |
OS_ASSERT(pInterrupt->int_enabled); |
OS_ASSERT(pInterrupt->int_pending); |
|
// Call interrupt thread handler function. |
pInterrupt->int_function(pInterrupt->int_func_arg); |
|
// Disable all interrupts & preemption |
cr = critical_start(); |
|
// Clear pending flag |
pInterrupt->int_pending = 0; |
|
// Re-enable the hardware interrupt source |
cpu_int_enable(pInterrupt->int_number); |
|
// Move IRQ thread to blocked list (and context switch) |
thread_block(&pInterrupt->int_thread); |
|
// Re-enable interrupts / scheduling |
critical_end(cr); |
} |
} |
#endif |
/sw/rtos/kernel/list.h
0,0 → 1,174
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
// FPGA Audio Project |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// If you would like a version with a more permissive license for use in |
// closed source commercial applications please contact me for details. |
//----------------------------------------------------------------------------- |
// |
// This file is part of FPGA Audio Project. |
// |
// FPGA Audio Project is free software; you can redistribute it and/or modify |
// it under the terms of the GNU General Public License as published by |
// the Free Software Foundation; either version 2 of the License, or |
// (at your option) any later version. |
// |
// FPGA Audio Project is distributed in the hope that it will be useful, |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// GNU General Public License for more details. |
// |
// You should have received a copy of the GNU General Public License |
// along with FPGA Audio Project; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
#ifndef __LIST_H__ |
#define __LIST_H__ |
|
#ifndef LIST_ASSERT |
#define LIST_ASSERT(x) |
#endif |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
struct link_list; |
|
struct link_node |
{ |
struct link_node *previous; |
struct link_node *next; |
}; |
|
struct link_list |
{ |
struct link_node *head; |
struct link_node *tail; |
}; |
|
//----------------------------------------------------------------- |
// Macros |
//----------------------------------------------------------------- |
#define list_entry(p, t, m) p ? ((t *)((char *)(p)-(char*)(&((t *)0)->m))) : 0 |
#define list_next(l, p) (p)->next |
#define list_prev(l, p) (p)->previous |
#define list_first(l) (l)->head |
#define list_last(l) (l)->tail |
#define list_for_each(l, p) for ((p) = (l)->head; (p); (p) = (p)->next) |
|
//----------------------------------------------------------------- |
// Inline Functions |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// list_init: Initialise linked list |
//----------------------------------------------------------------- |
static inline void list_init(struct link_list *list) |
{ |
LIST_ASSERT(list); |
|
list->head = list->tail = 0; |
} |
//----------------------------------------------------------------- |
// list_remove: Remove node from list |
//----------------------------------------------------------------- |
static inline void list_remove(struct link_list *list, struct link_node *node) |
{ |
LIST_ASSERT(list); |
LIST_ASSERT(node); |
|
if(!node->previous) |
list->head = node->next; |
else |
node->previous->next = node->next; |
|
if(!node->next) |
list->tail = node->previous; |
else |
node->next->previous = node->previous; |
} |
//----------------------------------------------------------------- |
// list_insert_after: Insert 'new_node' after 'node' |
//----------------------------------------------------------------- |
static inline void list_insert_after(struct link_list *list, struct link_node *node, struct link_node *new_node) |
{ |
LIST_ASSERT(list); |
LIST_ASSERT(node); |
LIST_ASSERT(new_node); |
|
new_node->previous = node; |
new_node->next = node->next; |
if (!node->next) |
list->tail = new_node; |
else |
node->next->previous = new_node; |
node->next = new_node; |
} |
//----------------------------------------------------------------- |
// list_insert_before: Insert 'new_node' before 'node' |
//----------------------------------------------------------------- |
static inline void list_insert_before(struct link_list *list, struct link_node *node, struct link_node *new_node) |
{ |
LIST_ASSERT(list); |
LIST_ASSERT(node); |
LIST_ASSERT(new_node); |
|
new_node->previous = node->previous; |
new_node->next = node; |
if (!node->previous) |
list->head = new_node; |
else |
node->previous->next = new_node; |
node->previous = new_node; |
} |
//----------------------------------------------------------------- |
// list_insert_first: Insert 'node' as first item in the list |
//----------------------------------------------------------------- |
static inline void list_insert_first(struct link_list *list, struct link_node *node) |
{ |
LIST_ASSERT(list); |
LIST_ASSERT(node); |
|
if (!list->head) |
{ |
list->head = node; |
list->tail = node; |
node->previous = 0; |
node->next = 0; |
} |
else |
list_insert_before(list, list->head, node); |
} |
//----------------------------------------------------------------- |
// list_insert_last: Insert 'node' at the end of the list |
//----------------------------------------------------------------- |
static inline void list_insert_last(struct link_list *list, struct link_node *node) |
{ |
LIST_ASSERT(list); |
LIST_ASSERT(node); |
|
if (!list->tail) |
list_insert_first(list, node); |
else |
list_insert_after(list, list->tail, node); |
} |
//----------------------------------------------------------------- |
// list_is_empty: Returns true if the list is empty |
//----------------------------------------------------------------- |
static inline int list_is_empty(struct link_list *list) |
{ |
LIST_ASSERT(list); |
|
return !list->head; |
} |
|
|
#endif |
|
/sw/rtos/kernel/event.c
0,0 → 1,96
//----------------------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRISC |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 Alternative Lightweight OpenRISC project. |
// |
// AltOR32 is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free Software |
// Foundation; either version 2 of the License, or (at your option) any later |
// version. |
// |
// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
// details. |
// |
// You should have received a copy of the GNU General Public License |
// along with AltOR32; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
#include "rtos.h" |
#include "event.h" |
#include "thread.h" |
#include "os_assert.h" |
|
#ifdef INCLUDE_EVENTS |
|
//----------------------------------------------------------------- |
// event_init: Initialise event object |
//----------------------------------------------------------------- |
void event_init(struct event *ev) |
{ |
OS_ASSERT(ev != NULL); |
|
ev->value = 0; |
semaphore_init(&ev->sema, 0); |
} |
//----------------------------------------------------------------- |
// event_get: Wait for an event to be set (returns bitmap) |
//----------------------------------------------------------------- |
unsigned int event_get(struct event *ev) |
{ |
unsigned int value = 0; |
int cr; |
|
OS_ASSERT(ev != NULL); |
|
cr = critical_start(); |
|
// Wait for semaphore |
semaphore_pend(&ev->sema); |
|
// Retrieve value & reset |
value = ev->value; |
ev->value = 0; |
|
critical_end(cr); |
|
return value; |
} |
//----------------------------------------------------------------- |
// event_set: Post event value (or add additional bits if already set) |
//----------------------------------------------------------------- |
void event_set(struct event *ev, unsigned int value) |
{ |
int cr; |
|
OS_ASSERT(ev != NULL); |
OS_ASSERT(value); |
|
cr = critical_start(); |
|
// Already pending event |
if (ev->value != 0) |
ev->value |= value; |
// No pending event |
else |
{ |
ev->value = value; |
semaphore_post(&ev->sema); |
} |
|
critical_end(cr); |
} |
|
#endif |
/sw/rtos/kernel/semaphore.c
0,0 → 1,265
//----------------------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRISC |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 Alternative Lightweight OpenRISC project. |
// |
// AltOR32 is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free Software |
// Foundation; either version 2 of the License, or (at your option) any later |
// version. |
// |
// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
// details. |
// |
// You should have received a copy of the GNU General Public License |
// along with AltOR32; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
#include "rtos.h" |
#include "semaphore.h" |
#include "thread.h" |
#include "os_assert.h" |
|
#ifdef INCLUDE_SEMAPHORE |
//----------------------------------------------------------------- |
// semaphore_init: Initialise semaphore with an initial value |
//----------------------------------------------------------------- |
void semaphore_init(struct semaphore *pSem, int initial_count) |
{ |
OS_ASSERT(pSem != NULL); |
|
// Initial count |
pSem->count = initial_count; |
|
// Pending thread list |
list_init(&pSem->pend_list); |
} |
//----------------------------------------------------------------- |
// semaphore_pend: Decrement semaphore or block if already 0 |
//----------------------------------------------------------------- |
void semaphore_pend(struct semaphore *pSem) |
{ |
int cr; |
|
OS_ASSERT(pSem != NULL); |
|
cr = critical_start(); |
|
// If one immediatly available |
if (pSem->count > 0) |
pSem->count--; |
// None available, add to queue |
else |
{ |
struct link_node *listnode; |
|
// Get current (this) thread |
struct thread* this_thread = thread_current(); |
|
// Setup list node |
listnode = &this_thread->blocking_node; |
|
// Add node to end of pending list |
list_insert_last(&pSem->pend_list, listnode); |
|
// Block the thread from running |
thread_block(this_thread); |
} |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// semaphore_post: Increment semaphore count |
//----------------------------------------------------------------- |
void semaphore_post(struct semaphore *pSem) |
{ |
int cr; |
|
OS_ASSERT(pSem != NULL); |
|
cr = critical_start(); |
|
// Increment semaphore count |
pSem->count++; |
|
// If there are threads pending on this semaphore |
if (!list_is_empty(&pSem->pend_list)) |
{ |
// Unblock the first pending thread |
struct link_node *node = list_first(&pSem->pend_list); |
|
// Get the thread item |
struct thread* thread = list_entry(node, struct thread, blocking_node); |
|
// Remove node from linked list |
list_remove(&pSem->pend_list, node); |
|
// Count down semaphore which has been taken by the |
// pending thread... |
pSem->count--; |
|
// Tell anyone who cares what |
// caused the thread to be unblocked... |
thread->unblocking_arg = node; |
|
// Unblock the waiting thread |
thread_unblock(thread); |
} |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// semaphore_post_irq: Increment semaphore (interrupt context safe) |
//----------------------------------------------------------------- |
void semaphore_post_irq(struct semaphore *pSem) |
{ |
int cr; |
|
OS_ASSERT(pSem != NULL); |
|
cr = critical_start(); |
|
// Increment semaphore count |
pSem->count++; |
|
// If there are threads pending on this semaphore |
if (!list_is_empty(&pSem->pend_list)) |
{ |
// Unblock the first pending thread |
struct link_node *node = list_first(&pSem->pend_list); |
|
// Get the thread item |
struct thread* thread = list_entry(node, struct thread, blocking_node); |
|
// Remove node from linked list |
list_remove(&pSem->pend_list, node); |
|
// Count down semaphore which has been taken by the |
// pending thread... |
pSem->count--; |
|
// Tell anyone who cares what |
// caused the thread to be unblocked... |
thread->unblocking_arg = node; |
|
// Unblock the waiting thread |
thread_unblock_irq(thread); |
} |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// semaphore_try: Attempt to decrement semaphore or return 0 |
//----------------------------------------------------------------- |
int semaphore_try(struct semaphore *pSem) |
{ |
int result; |
int cr; |
|
OS_ASSERT(pSem != NULL); |
|
cr = critical_start(); |
|
// If one immediatly available |
if (pSem->count > 0) |
{ |
pSem->count--; |
result = 1; |
} |
// None available currently |
else |
result = 0; |
|
critical_end(cr); |
|
return result; |
} |
//----------------------------------------------------------------- |
// semaphore_timed_pend: Decrement semaphore (with timeout) |
//----------------------------------------------------------------- |
int semaphore_timed_pend(struct semaphore *pSem, int timeoutMs) |
{ |
int cr; |
int result = 0; |
|
OS_ASSERT(pSem != NULL); |
|
cr = critical_start(); |
|
// If one immediatly available |
if (pSem->count > 0) |
{ |
pSem->count--; |
result = 1; |
} |
// None available, add to queue (if timeout specified) |
else if (timeoutMs > 0) |
{ |
struct link_node *listnode; |
|
// Get current (this) thread |
struct thread* this_thread = thread_current(); |
|
// Setup list node |
listnode = &this_thread->blocking_node; |
|
// Add node to end of pending list |
list_insert_last(&pSem->pend_list, listnode); |
|
// Clear unblocking arg |
this_thread->unblocking_arg = NULL; |
|
// Send the thread to sleep for the timeout period |
thread_sleep(timeoutMs); |
|
// Is the thread awake due to a semaphore_post? |
if (this_thread->unblocking_arg != NULL) |
result = 1; |
// Else we must have timed out |
else |
{ |
struct link_list *pList = &pSem->pend_list; |
struct link_node *node; |
|
// Walk the list |
list_for_each(pList, node) |
{ |
struct thread *node_thread = list_entry(node, struct thread, blocking_node); |
|
// Is this us? |
if (this_thread == node_thread) |
{ |
// Remove node from linked list |
list_remove(pList, node); |
|
// Stop scanning this list! |
break; |
} |
} |
|
// We should not have reached the end of the list |
// without finding our entry. |
OS_ASSERT(node != NULL); |
|
result = 0; |
} |
} |
|
critical_end(cr); |
|
return result; |
} |
#endif |
/sw/rtos/kernel/timer_cb.c
0,0 → 1,271
//----------------------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRISC |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 Alternative Lightweight OpenRISC project. |
// |
// AltOR32 is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free Software |
// Foundation; either version 2 of the License, or (at your option) any later |
// version. |
// |
// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
// details. |
// |
// You should have received a copy of the GNU General Public License |
// along with AltOR32; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
#include "rtos.h" |
#include "timer_cb.h" |
#include "mutex.h" |
#include "os_assert.h" |
|
#ifdef INCLUDE_TIMERCB |
|
//---------------------------------------------------------------------- |
// Locals: |
//---------------------------------------------------------------------- |
static struct link_list timer_list; |
static struct mutex lock; |
|
//---------------------------------------------------------------------- |
// timercb_init: Initialise timer callback service |
//---------------------------------------------------------------------- |
void timercb_init(void) |
{ |
// Initialise timer list & lock |
mutex_init(&lock); |
list_init(&timer_list); |
} |
//---------------------------------------------------------------------- |
// timercb_start: Add item to timer list (with callback to execute on timeout) |
//---------------------------------------------------------------------- |
void timercb_start(struct timer_node* item, tTime timeout, FP_TIMEOUT_FUNC func, void *arg) |
{ |
struct link_node *node; |
struct link_node *newNode; |
tTime total = 0; |
tTime prevtotal = 0; |
struct link_list *list = &timer_list; |
|
OS_ASSERT(item); |
OS_ASSERT(func); |
|
mutex_acquire(&lock); |
|
// Timeout action |
item->func = func; |
item->arg = arg; |
|
// Not expired yet |
item->expired = 0; |
|
// Set up list item data pointer |
newNode = &item->list_node; |
|
// Current list is empty? |
if (list_first(list) == NULL) |
{ |
// delta is total timeout |
item->delta = timeout; |
list_insert_first(list, newNode); |
} |
// Timer list has items |
else |
{ |
// Itterate through current list and add at correct location |
list_for_each(list, node) |
{ |
struct timer_node *tNode = list_entry(node, struct timer_node, list_node); |
OS_ASSERT(tNode); |
|
// Increment cumulative total |
total += tNode->delta; |
|
// New timeout less than total (or end of list reached) |
if (timeout <= total) |
{ |
// delta time from previous to this node |
item->delta = timeout - prevtotal; |
|
// Insert into list before current node |
list_insert_before(list, node, newNode); |
|
// Adjust next nodes delta time |
tNode->delta -= item->delta; |
break; |
} |
|
prevtotal = total; |
|
// End of list reached, still not added |
if (node->next == NULL) |
{ |
// delta time from previous to this node |
item->delta = timeout - prevtotal; |
|
// Insert into list before current node |
list_insert_after(list, node, newNode); |
|
break; |
} |
} |
} |
|
item->magic = TIMER_MAGIC; |
mutex_release(&lock); |
} |
//---------------------------------------------------------------------- |
// timercb_cancel: Cancel pending timeout item (if not already expired) |
//---------------------------------------------------------------------- |
void timercb_cancel(struct timer_node* item) |
{ |
struct link_node *node; |
struct link_node *next; |
struct timer_node *next_item; |
struct link_list *list = &timer_list; |
|
OS_ASSERT(list); |
OS_ASSERT(item); |
|
mutex_acquire(&lock); |
|
// If the item has not already expired |
if (!item->expired) |
{ |
// If the timer has not expired the magic number will be valid |
OS_ASSERT(item->magic == TIMER_MAGIC); |
|
node = &item->list_node; |
next = node->next; |
|
// Not the last item? |
if (next) |
{ |
// Add current item's remaining time to next |
next_item = list_entry(next, struct timer_node, list_node); |
next_item->delta += item->delta; |
} |
|
// Reset state |
item->expired = 1; |
item->magic = ~TIMER_MAGIC; |
|
// Remove from timer list |
list_remove(list, node); |
} |
|
mutex_release(&lock); |
} |
//---------------------------------------------------------------------- |
// timercb_service: Process timer callback items (taking into account |
// time passed since last service call) |
//---------------------------------------------------------------------- |
void timercb_service(tTime timePassed) |
{ |
struct link_node *node; |
struct link_list *list = &timer_list; |
|
OS_ASSERT(list); |
|
mutex_acquire(&lock); |
|
// Iterate through current timer list |
for (node = list_first(list); node ; ) |
{ |
struct timer_node *item = list_entry(node, struct timer_node, list_node); |
OS_ASSERT(item); |
OS_ASSERT(!item->expired); |
OS_ASSERT(item->magic == TIMER_MAGIC); |
|
// Some time has passed but not enough to make first item timeout |
if (timePassed < item->delta) |
{ |
// Decrement first item then exit |
item->delta -= timePassed; |
break; |
} |
else |
{ |
FP_TIMEOUT_FUNC func = item->func; |
void *arg = item->arg; |
|
// Remove delta time from time passed in-case there |
// are more items in the list. |
timePassed -= item->delta; |
|
// Reset node state |
item->expired = 1; |
item->magic = ~TIMER_MAGIC; |
|
// Remove expired node from list before calling callback |
// to allow it to be re-added in the callback. |
list_remove(list, node); |
|
// Release the lock before calling the callback |
mutex_release(&lock); |
|
// NOTE: We should measure time taken by callback and |
// add this to timePassed to improve list timing... |
|
// If action to be performed on timeout, do it! |
if (func) |
func(arg); |
|
// Re-acquire the lock |
mutex_acquire(&lock); |
|
// Get next node (new first node) |
node = list_first(list); |
} |
} |
|
mutex_release(&lock); |
} |
//---------------------------------------------------------------------- |
// timercb_dump: Dump timer callback list to OS_PRINTF |
//---------------------------------------------------------------------- |
#ifdef TIMERCB_TEST |
void timercb_dump(void) |
{ |
struct link_node *node; |
tTime total = 0; |
struct link_list *list = &timer_list; |
|
OS_ASSERT(list); |
|
OS_PRINTF("Timer list:\n"); |
|
mutex_acquire(&lock); |
|
// Iterate through current list and print |
list_for_each(list, node) |
{ |
struct timer_node *item = list_entry(node, struct timer_node, list_node); |
|
OS_ASSERT(item); |
OS_ASSERT(item->magic == TIMER_MAGIC); |
|
// Increment cumulative total |
total += item->delta; |
|
OS_PRINTF("- Timeout at %d (delta %d)\n", total, item->delta); |
} |
|
mutex_release(&lock); |
} |
#endif |
#endif |
/sw/rtos/kernel/interrupts.h
0,0 → 1,49
#ifndef __INTERRUPTS_H__ |
#define __INTERRUPTS_H__ |
|
#include "rtos.h" |
#include "thread.h" |
|
//----------------------------------------------------------------- |
// Defines |
//----------------------------------------------------------------- |
#ifdef DEFAULT_INTERRUPT_THREADS |
#define THREAD_MAX_INTERRUPTS DEFAULT_INTERRUPT_THREADS |
#else |
#define THREAD_MAX_INTERRUPTS 4 |
#endif |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
struct interrupt |
{ |
struct thread int_thread; |
volatile int int_enabled; |
volatile int int_pending; |
void (*int_function)(void *); |
void* int_func_arg; |
int int_number; |
}; |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
|
// Setup interrupt task controller |
void interrupts_init(void); |
|
// Function called on low level interrupt |
void interrupts_handler(int int_number); |
|
// Enable interrupt |
void interrupts_enable(int int_number); |
|
// Disable interrupt |
void interrupts_disable(int int_number); |
|
// Setup interrupt task (linked to intNumber IRQ) |
int interrupts_establish(int intNumber, char *name, int pri, void (*int_task)(void *arg), void *arg, unsigned long *stack, unsigned int stack_size, int enable); |
|
#endif |
|
/sw/rtos/kernel/event.h
0,0 → 1,28
#ifndef __EVENT_H__ |
#define __EVENT_H__ |
|
#include "semaphore.h" |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
struct event |
{ |
unsigned int value; |
struct semaphore sema; |
}; |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
|
// Initialise event object |
void event_init(struct event *ev); |
|
// Wait for an event to be set (returns bitmap) |
void event_set(struct event *ev, unsigned int value); |
|
// Post event value (or add additional bits if already set) |
unsigned int event_get(struct event *ev); |
|
#endif |
/sw/rtos/kernel/rtos.c
0,0 → 1,255
//----------------------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRISC |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 Alternative Lightweight OpenRISC project. |
// |
// AltOR32 is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free Software |
// Foundation; either version 2 of the License, or (at your option) any later |
// version. |
// |
// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
// details. |
// |
// You should have received a copy of the GNU General Public License |
// along with AltOR32; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
#include "rtos.h" |
|
//----------------------------------------------------------------- |
// Globals: |
//----------------------------------------------------------------- |
struct sRtosServices rtos_services; |
|
//----------------------------------------------------------------- |
// Locals: |
//----------------------------------------------------------------- |
static int init_done = 0; |
|
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
static int platform_printf(const char* ctrl1, ...); |
static void platform_idle(void); |
static void platform_reboot(void); |
|
//----------------------------------------------------------------- |
// rtos_init: Initialise RTOS (should be first RTOS function called) |
//----------------------------------------------------------------- |
void rtos_init(void) |
{ |
// Disable interrupts |
critical_start(); |
|
// Initialise interrupt threads services |
#ifdef INCLUDE_INTERRUPTS |
interrupts_init(); |
#endif |
|
// Setup the RTOS |
thread_kernel_init(); |
|
// Initialise platform services |
rtos_services.printf = platform_printf; |
rtos_services.idle = platform_idle; |
rtos_services.reboot = platform_reboot; |
|
init_done = 1; |
} |
//----------------------------------------------------------------- |
// rtos_start: Start RTOS with init task |
//----------------------------------------------------------------- |
#ifdef INCLUDE_RTOS_MALLOC |
void rtos_start(void (*init_func)(void *arg), void *arg, int pri, unsigned int stack_size) |
{ |
OS_ASSERT(init_done); |
|
// Create init thread |
rtos_thread_create("INIT", pri, init_func, arg, stack_size); |
|
// Start kernel |
thread_kernel_run(); |
|
// We should never reach here! |
OS_PANIC("OS EXIT!"); |
} |
#endif |
//----------------------------------------------------------------- |
// platform_reboot: Default reboot function (none - blocks forever) |
//----------------------------------------------------------------- |
static void platform_reboot(void) |
{ |
while (1); |
} |
//----------------------------------------------------------------- |
// platform_idle: Default idle function (no action) |
//----------------------------------------------------------------- |
static void platform_idle(void) |
{ |
// Do nothings |
} |
//----------------------------------------------------------------- |
// platform_printf: Default printf function (no action) |
//----------------------------------------------------------------- |
static int platform_printf(const char* ctrl1, ...) |
{ |
// Do nothing |
return 0; |
} |
|
//----------------------------------------------------------------- |
// Dynamic RTOS item allocation |
//----------------------------------------------------------------- |
#ifdef INCLUDE_RTOS_MALLOC |
|
//----------------------------------------------------------------- |
// rtos_heap_init: RTOS heap init - only required if dynamic RTOS |
// object allocation used |
//----------------------------------------------------------------- |
void rtos_heap_init(unsigned char *heap, unsigned int size) |
{ |
rtos_mem_init(heap, size); |
} |
//----------------------------------------------------------------- |
// rtos_thread_create: Allocate & initialise thread |
//----------------------------------------------------------------- |
struct thread* rtos_thread_create(char *name, int pri, void (*f)(void *), void *arg, unsigned int stack_size) |
{ |
struct thread* thread = (struct thread*)rtos_mem_alloc(sizeof(struct thread)); |
if (thread) |
{ |
unsigned long *stack = rtos_mem_alloc(stack_size * sizeof(unsigned long)); |
if (stack) |
{ |
thread_init(thread, name, pri, f, arg, stack, stack_size); |
return thread; |
} |
else |
rtos_mem_free(thread); |
} |
|
return 0; |
} |
//----------------------------------------------------------------- |
// rtos_mutex_create: Allocate & initialise mutex |
//----------------------------------------------------------------- |
struct mutex* rtos_mutex_create(void) |
{ |
#ifdef INCLUDE_MUTEX |
struct mutex* mtx = (struct mutex*)rtos_mem_alloc(sizeof(struct mutex)); |
if (mtx) |
mutex_init(mtx); |
|
return mtx; |
#else |
return 0; |
#endif |
} |
//----------------------------------------------------------------- |
// rtos_semaphore_create: Allocate & initialise semaphore |
//----------------------------------------------------------------- |
struct semaphore* rtos_semaphore_create(int initial) |
{ |
#ifdef INCLUDE_SEMAPHORE |
struct semaphore* sema = (struct semaphore*)rtos_mem_alloc(sizeof(struct semaphore)); |
if (sema) |
semaphore_init(sema, initial); |
|
return sema; |
#else |
return 0; |
#endif |
} |
//----------------------------------------------------------------- |
// rtos_mailbox_create: Allocate & initialise mailbox |
//----------------------------------------------------------------- |
struct mailbox* rtos_mailbox_create(void) |
{ |
#ifdef INCLUDE_MAILBOX |
struct mailbox* mail = (struct mailbox*)rtos_mem_alloc(sizeof(struct mailbox)); |
if (mail) |
mailbox_init(mail); |
|
return mail; |
#else |
return 0; |
#endif |
} |
//----------------------------------------------------------------- |
// rtos_lock_create: Allocate & initialise lock |
//----------------------------------------------------------------- |
struct lock* rtos_lock_create(void) |
{ |
#ifdef INCLUDE_RECURSIVE_LOCK |
struct lock* lock = (struct lock*)rtos_mem_alloc(sizeof(struct lock)); |
if (lock) |
lock_init(lock); |
|
return lock; |
#else |
return 0; |
#endif |
} |
//----------------------------------------------------------------- |
// rtos_thread_destroy: |
//----------------------------------------------------------------- |
void rtos_thread_destroy(struct thread* thread) |
{ |
// Kill thread |
if (thread && thread_kill(thread)) |
{ |
// Free stack (thread must have been created using rtos_thread_create() |
// otherwise this might not be from the heap) |
rtos_mem_free((void*)thread->tcb.StackAlloc); |
|
// Free thread structure itself |
rtos_mem_free(thread); |
} |
} |
//----------------------------------------------------------------- |
// rtos_mutex_destroy: |
//----------------------------------------------------------------- |
void rtos_mutex_destroy(struct mutex* mtx) |
{ |
if (mtx) |
rtos_mem_free(mtx); |
} |
//----------------------------------------------------------------- |
// rtos_semaphore_destroy: |
//----------------------------------------------------------------- |
void rtos_semaphore_destroy(struct semaphore* sema) |
{ |
if (sema) |
rtos_mem_free(sema); |
} |
//----------------------------------------------------------------- |
// rtos_mailbox_destroy: |
//----------------------------------------------------------------- |
void rtos_mailbox_destroy(struct mailbox* mailbox) |
{ |
if (mailbox) |
rtos_mem_free(mailbox); |
} |
//----------------------------------------------------------------- |
// rtos_lock_destroy: |
//----------------------------------------------------------------- |
void rtos_lock_destroy(struct lock* lock) |
{ |
if (lock) |
rtos_mem_free(lock); |
} |
#endif |
/sw/rtos/kernel/semaphore.h
0,0 → 1,42
#ifndef __SEMAPHORE_H__ |
#define __SEMAPHORE_H__ |
|
#include "list.h" |
|
//----------------------------------------------------------------- |
// Defines |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
struct semaphore |
{ |
int count; |
struct link_list pend_list; |
}; |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
|
// Initialise semaphore with an initial value |
void semaphore_init(struct semaphore *pSem, int initial_count); |
|
// Increment semaphore count |
void semaphore_post(struct semaphore *pSem); |
|
// Increment semaphore (interrupt context safe) |
void semaphore_post_irq(struct semaphore *pSem); |
|
// Decrement semaphore or block if already 0 |
void semaphore_pend(struct semaphore *pSem); |
|
// Attempt to decrement semaphore or return 0 |
int semaphore_try(struct semaphore *pSem); |
|
// Decrement semaphore (with timeout) |
int semaphore_timed_pend(struct semaphore *pSem, int timeoutMs); |
|
#endif |
|
/sw/rtos/kernel/mem_alloc.c
0,0 → 1,366
//----------------------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRISC |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 Alternative Lightweight OpenRISC project. |
// |
// AltOR32 is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free Software |
// Foundation; either version 2 of the License, or (at your option) any later |
// version. |
// |
// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
// details. |
// |
// You should have received a copy of the GNU General Public License |
// along with AltOR32; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
#include "rtos.h" |
#include "mem_alloc.h" |
|
//----------------------------------------------------------------- |
// Based on code from a malloc/free implementation from: |
// http://www.flipcode.com/archives/Simple_Malloc_Free_Functions.shtml |
//----------------------------------------------------------------- |
#ifdef INCLUDE_RTOS_MALLOC |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define MARKER_CHECKWORD 0xfedebace |
|
// Round up to the next 4 byte boundary |
#define ROUNDUP_4BYTES(a) ((((a) + 3) >> 2) << 2) |
#define USED 1 |
|
//----------------------------------------------------------------- |
// Types: |
//----------------------------------------------------------------- |
struct MemBlock |
{ |
unsigned size; |
}; |
|
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
static struct MemBlock* compact_blocks( struct MemBlock *p, unsigned nsize ); |
|
//----------------------------------------------------------------- |
// Locals: |
//----------------------------------------------------------------- |
static struct MemBlock* MemFree = 0; |
static struct MemBlock* MemHeap = 0; |
static int MemAllocInit = 0; |
|
//----------------------------------------------------------------- |
// rtos_mem_init: Initialise RTOS memory allocator. |
// 'heap' is the pointer to memory used for heap, 'len' is in bytes. |
//----------------------------------------------------------------- |
void rtos_mem_init( void *heap, unsigned len ) |
{ |
struct MemBlock *end; |
|
OS_ASSERT(!MemAllocInit); |
|
// Round up to next word boundary |
len = ROUNDUP_4BYTES(len); |
|
// Free pointer is start of heap |
MemFree = MemHeap = (struct MemBlock *) heap; |
|
MemFree->size = MemHeap->size = len - sizeof(struct MemBlock); |
|
// Skip to end point |
end = (struct MemBlock*)(((char *)heap) + len - sizeof(struct MemBlock)); |
|
// Mark last node as NULL |
end->size = 0; |
|
// Memory manager initialised |
MemAllocInit = 1; |
} |
//----------------------------------------------------------------- |
// rtos_mem_alloc: 'malloc' function (thread safe) |
//----------------------------------------------------------------- |
void* rtos_mem_alloc( unsigned size ) |
{ |
unsigned fsize; |
struct MemBlock *p; |
int l; |
#ifdef RTOS_MALLOC_ENDMARKER |
unsigned int *e = 0; |
#endif |
|
OS_ASSERT(MemAllocInit); |
|
if( size == 0 ) |
return 0; |
|
// Round up to next word boundary including extra space for size data |
size = ROUNDUP_4BYTES(size + sizeof(struct MemBlock)); |
|
#ifdef RTOS_MALLOC_ENDMARKER |
// Additional space for end marker check word |
size += 4; |
#endif |
|
l = critical_start(); |
|
// Not enough space? |
if( MemFree == 0 || size > MemFree->size ) |
{ |
// Try running compact_blocks to group together free memory. |
// NOTE: This never returns anything other than NULL if there |
// is not the free space. |
MemFree = compact_blocks( MemHeap, size ); |
|
// No memory free? |
if( MemFree == 0 ) |
{ |
critical_end(l); |
return 0; |
} |
} |
|
p = MemFree; |
|
#ifdef RTOS_MALLOC_ENDMARKER |
// Calculate end marker address (1 word back from size) |
e = (unsigned int*)(((unsigned int)p) + size - 4); |
|
// Set end marker checkword |
*e = MARKER_CHECKWORD; |
#endif |
|
fsize = MemFree->size; |
|
// Free block is larger than requested size & block allocation node |
if( fsize >= size + sizeof(struct MemBlock) ) |
{ |
// Move free pointer onto end of this block |
MemFree = (struct MemBlock *)( (unsigned)p + size ); |
|
// ... now setup free space remaining |
MemFree->size = fsize - size; |
} |
// Free block large enough for data but not for extra for block |
// allocation now. Set the free space to 0. |
else |
{ |
MemFree = 0; |
size = fsize; |
} |
|
// Mark block as used (LSB is not used for size as round-up) |
p->size = size | USED; |
#ifdef RTOS_MALLOC_ENDMARKER |
*e = MARKER_CHECKWORD; |
#endif |
|
critical_end(l); |
|
return (void *)( (unsigned)p + sizeof(struct MemBlock) ); |
} |
//----------------------------------------------------------------- |
// rtos_mem_free: 'free' function (thread safe) |
//----------------------------------------------------------------- |
void rtos_mem_free( void *ptr ) |
{ |
int l = critical_start(); |
|
OS_ASSERT(MemAllocInit); |
|
if( ptr ) |
{ |
// Step back from pointer to find block address |
struct MemBlock *p = (struct MemBlock *)( (unsigned)ptr - sizeof(struct MemBlock) ); |
|
#ifdef RTOS_MALLOC_ENDMARKER |
// Calculate end marker address (1 word back from size) |
unsigned int *e = (unsigned int*)(((unsigned int)p) + (p->size & ~USED) - 4); |
|
// Verify end marker is correct |
OS_ASSERT(*e == MARKER_CHECKWORD); |
|
// Reset end marker |
*e = ~MARKER_CHECKWORD; |
#endif |
|
// Mark block as un-used |
p->size &= ~USED; |
} |
|
critical_end(l); |
} |
//----------------------------------------------------------------- |
// rtos_mem_calloc: 'calloc' function (thread safe) |
//----------------------------------------------------------------- |
void* rtos_mem_calloc( unsigned size ) |
{ |
void *p = rtos_mem_alloc(size); |
if (p) |
{ |
unsigned i; |
unsigned int *ptr = (unsigned int *)p; |
|
// Removed dependency on memset |
for (i=0;i<size;i++) |
*ptr++ = 0; |
} |
return p; |
} |
//----------------------------------------------------------------- |
// compact_blocks: Find a large enough free block on the heap |
// Args: p = heap, nsize = requested block size |
// Returns: Pointer to free block if large enough one found. |
//----------------------------------------------------------------- |
static struct MemBlock* compact_blocks( struct MemBlock *p, unsigned nsize ) |
{ |
unsigned bsize, psize; |
struct MemBlock *best; |
|
best = p; |
bsize = 0; |
|
// While not end of heap |
while( psize = p->size, psize ) |
{ |
// Is block allocated |
if( psize & USED ) |
{ |
// If we have previously found some free blocks |
if( bsize != 0 ) |
{ |
// Set size of block to new total free size |
// NOTE: This has the effect of compacting free space |
// into larger blocks even if this block is not big enough. |
best->size = bsize; |
|
// Is free space big enough for requested ammount |
if( bsize >= nsize ) |
return best; |
} |
|
// Reset free space counter |
bsize = 0; |
|
// Skip to the start of the next block |
best = p = (struct MemBlock *)( (unsigned)p + (psize & ~USED) ); |
} |
// Free block |
else |
{ |
// Add size to running total of contiguous free space |
bsize += psize; |
|
// Find next block pointer |
p = (struct MemBlock *)( (unsigned)p + psize ); |
} |
} |
|
if( bsize != 0 ) |
{ |
// Set size of block to new total free size |
// NOTE: This has the effect of compacting free space |
// into larger blocks even if this block is not big enough. |
best->size = bsize; |
|
// Is free space big enough for requested ammount |
if( bsize >= nsize ) |
return best; |
} |
|
return 0; |
} |
//----------------------------------------------------------------- |
// rtos_mem_size_largest: Find the size of the largest free block |
//----------------------------------------------------------------- |
unsigned rtos_mem_size_largest(void) |
{ |
unsigned psize, largest; |
struct MemBlock *p = MemHeap; |
|
int l = critical_start(); |
|
largest = 0; |
|
// Run the memory compactor first |
compact_blocks( MemHeap, (unsigned)-1); |
|
// While not end of heap |
while( psize = p->size, psize ) |
{ |
// Is block allocated |
if( psize & USED ) |
{ |
// Skip to the start of the next block |
p = (struct MemBlock *)( (unsigned)p + (psize & ~USED) ); |
} |
// Free block |
else |
{ |
if (psize > largest) |
largest = psize; |
|
// Find next block pointer |
p = (struct MemBlock *)( (unsigned)p + psize ); |
} |
} |
|
critical_end(l); |
|
return largest; |
} |
//----------------------------------------------------------------- |
// rtos_mem_size_free: Find the total free space |
//----------------------------------------------------------------- |
unsigned rtos_mem_size_free(void) |
{ |
unsigned psize, total; |
struct MemBlock *p = MemHeap; |
|
int l = critical_start(); |
|
total = 0; |
|
// Run the memory compactor first |
compact_blocks( MemHeap, (unsigned)-1); |
|
// While not end of heap |
while( psize = p->size, psize ) |
{ |
// Is block allocated |
if( psize & USED ) |
{ |
// Skip to the start of the next block |
p = (struct MemBlock *)( (unsigned)p + (psize & ~USED) ); |
} |
// Free block |
else |
{ |
total += psize; |
|
// Find next block pointer |
p = (struct MemBlock *)( (unsigned)p + psize ); |
} |
} |
|
critical_end(l); |
|
return total; |
} |
#endif |
/sw/rtos/kernel/lock.c
0,0 → 1,144
//----------------------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRISC |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 Alternative Lightweight OpenRISC project. |
// |
// AltOR32 is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free Software |
// Foundation; either version 2 of the License, or (at your option) any later |
// version. |
// |
// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
// details. |
// |
// You should have received a copy of the GNU General Public License |
// along with AltOR32; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
#include "rtos.h" |
#include "lock.h" |
#include "thread.h" |
#include "os_assert.h" |
|
#ifdef INCLUDE_RECURSIVE_LOCK |
|
//----------------------------------------------------------------- |
// lock_init: Initialise lock object |
//----------------------------------------------------------------- |
void lock_init(struct lock *pLock) |
{ |
OS_ASSERT(pLock != NULL); |
|
// No default owner |
pLock->owner = NULL; |
|
// No recursive lock count |
pLock->lock_count = 0; |
|
// Pending thread list |
list_init(&pLock->pend_list); |
} |
//----------------------------------------------------------------- |
// lock_acquire: Wait until lock is available (recursive lock) |
//----------------------------------------------------------------- |
void lock_acquire(struct lock *pLock) |
{ |
struct thread* this_thread; |
int cr; |
|
OS_ASSERT(pLock != NULL); |
|
cr = critical_start(); |
|
// Get current (this) thread |
this_thread = thread_current(); |
|
// Is the lock not already locked |
if (pLock->owner == NULL) |
{ |
// Acquire lock for this thread |
pLock->owner = this_thread; |
} |
// Is the lock already locked by this thread |
else if (pLock->owner == this_thread) |
{ |
// Increase recursive lock count |
pLock->lock_count++; |
} |
// The lock is already 'owned', add |
// thread to pending list |
else |
{ |
struct link_node *listnode; |
|
// Get list node |
listnode = &this_thread->blocking_node; |
|
// Add node to end of pending list |
list_insert_last(&pLock->pend_list, listnode); |
|
// Block the thread from running |
thread_block(this_thread); |
} |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// lock_release: Release/decrement lock (recursive lock) |
//----------------------------------------------------------------- |
void lock_release(struct lock *pLock) |
{ |
struct thread* this_thread; |
int cr; |
|
OS_ASSERT(pLock != NULL); |
|
cr = critical_start(); |
|
// Get current (this) thread |
this_thread = thread_current(); |
|
// We cannot release a lock that we dont own! |
OS_ASSERT(this_thread == pLock->owner); |
|
// Reduce recursive lock count |
if (pLock->lock_count > 0) |
pLock->lock_count--; |
// If there are threads pending on this lock |
else if (!list_is_empty(&pLock->pend_list)) |
{ |
// Unblock the first pending thread |
struct link_node *node = list_first(&pLock->pend_list); |
|
// Get the thread item |
struct thread* thread = list_entry(node, struct thread, blocking_node); |
|
// Remove node from linked list |
list_remove(&pLock->pend_list, node); |
|
// Transfer lock ownership |
pLock->owner = thread; |
|
// Unblock the first waiting thread |
thread_unblock(thread); |
} |
// Else no-one wants it, no owner |
else |
pLock->owner = NULL; |
|
critical_end(cr); |
} |
#endif |
/sw/rtos/kernel/timer_cb.h
0,0 → 1,50
#ifndef __TIMER_CB_H__ |
#define __TIMER_CB_H__ |
|
#include "list.h" |
|
//---------------------------------------------------------------------- |
// Defines / Types |
//---------------------------------------------------------------------- |
#define TIMER_MAGIC 0xbeafcafe |
|
typedef unsigned long tTime; |
|
typedef void (*FP_TIMEOUT_FUNC)(void* user); |
|
struct timer_node |
{ |
struct link_node list_node; |
|
tTime delta; |
int expired; |
|
unsigned long magic; |
|
FP_TIMEOUT_FUNC func; |
void* arg; |
}; |
|
//---------------------------------------------------------------------- |
// Prototypes |
//---------------------------------------------------------------------- |
|
// Initialise timer callback service |
void timercb_init(void); |
|
// Add item to timer list (with callback to execute on timeout) |
void timercb_start(struct timer_node* item, tTime timeout, FP_TIMEOUT_FUNC func, void *arg); |
|
// Cancel pending timeout item (if not already expired) |
void timercb_cancel(struct timer_node* item); |
|
// Process timer callback items |
void timercb_service(tTime timePassed); |
|
// Dump timer callback list to OS_PRINTF |
#ifdef TIMERCB_TEST |
void timercb_dump(void); |
#endif |
|
#endif |
|
/sw/rtos/kernel/critical.c
0,0 → 1,47
//----------------------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRISC |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 Alternative Lightweight OpenRISC project. |
// |
// AltOR32 is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free Software |
// Foundation; either version 2 of the License, or (at your option) any later |
// version. |
// |
// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
// details. |
// |
// You should have received a copy of the GNU General Public License |
// along with AltOR32; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
#include "critical.h" |
#include "rtos.h" |
|
//----------------------------------------------------------------- |
// critical_start: Force interrupts to be disabled (recursive ok) |
//----------------------------------------------------------------- |
int critical_start(void) |
{ |
return cpu_critical_start(); |
} |
//----------------------------------------------------------------- |
// critical_end: Restore interrupt enable state (recursive ok) |
//----------------------------------------------------------------- |
void critical_end(int cr) |
{ |
cpu_critical_end(cr); |
} |
/sw/rtos/kernel/mailbox.c
0,0 → 1,159
//----------------------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRISC |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 Alternative Lightweight OpenRISC project. |
// |
// AltOR32 is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free Software |
// Foundation; either version 2 of the License, or (at your option) any later |
// version. |
// |
// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
// details. |
// |
// You should have received a copy of the GNU General Public License |
// along with AltOR32; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
#include "rtos.h" |
#include "mailbox.h" |
#include "thread.h" |
#include "os_assert.h" |
|
#ifdef INCLUDE_MAILBOX |
//----------------------------------------------------------------- |
// mailbox_init: Initialise mailbox |
//----------------------------------------------------------------- |
void mailbox_init(struct mailbox *pMbox) |
{ |
int i; |
|
OS_ASSERT(pMbox != NULL); |
|
for (i=0;i<MAILBOX_MAX_ITEMS;i++) |
pMbox->entries[i] = NULL; |
|
pMbox->head = 0; |
pMbox->tail = 0; |
pMbox->count = 0; |
|
// Initialise mailbox item ready semaphore |
semaphore_init(&pMbox->sema, 0); |
} |
//----------------------------------------------------------------- |
// mailbox_post: Post message to mailbox (copy pointer 'val') |
//----------------------------------------------------------------- |
int mailbox_post(struct mailbox *pMbox, void *val) |
{ |
int cr; |
int res = 0; |
|
OS_ASSERT(pMbox != NULL); |
|
cr = critical_start(); |
|
// Mailbox has free space? |
if (pMbox->count < MAILBOX_MAX_ITEMS) |
{ |
// Add pointer to mailbox |
pMbox->entries[pMbox->tail] = val; |
|
// Wrap? |
if (++pMbox->tail == MAILBOX_MAX_ITEMS) |
pMbox->tail = 0; |
|
// Increment mail count |
pMbox->count++; |
|
// Notify waiting threads that item added |
semaphore_post(&pMbox->sema); |
|
res = 1; |
} |
// Mailbox full! |
else |
res = 0; |
|
critical_end(cr); |
|
return res; |
} |
//----------------------------------------------------------------- |
// mailbox_pend: Wait for mailbox message |
//----------------------------------------------------------------- |
void mailbox_pend(struct mailbox *pMbox, void **val) |
{ |
int cr; |
|
OS_ASSERT(pMbox != NULL); |
|
cr = critical_start(); |
|
// Pend on a new item being added |
semaphore_pend(&pMbox->sema); |
|
OS_ASSERT(pMbox->count > 0); |
|
// Retrieve the mail pointer |
if (val) |
*val = pMbox->entries[pMbox->head]; |
|
// Wrap |
if (++pMbox->head == MAILBOX_MAX_ITEMS) |
pMbox->head = 0; |
|
// Decrement items in queue |
pMbox->count--; |
|
critical_end(cr); |
} |
//----------------------------------------------------------------- |
// mailbox_pend_timed: Wait for mailbox message (with timeout) |
// Returns: 1 = mail retrieved, 0 = timeout |
//----------------------------------------------------------------- |
int mailbox_pend_timed(struct mailbox *pMbox, void **val, int timeoutMs) |
{ |
int cr; |
int result = 0; |
|
OS_ASSERT(pMbox != NULL); |
|
cr = critical_start(); |
|
// Wait for specified timeout period |
if (semaphore_timed_pend(&pMbox->sema, timeoutMs)) |
{ |
OS_ASSERT(pMbox->count > 0); |
|
// Retrieve the mail pointer |
if (val) |
*val = pMbox->entries[pMbox->head]; |
|
// Wrap |
if (++pMbox->head == MAILBOX_MAX_ITEMS) |
pMbox->head = 0; |
|
// Decrement items in queue |
pMbox->count--; |
|
result = 1; |
} |
|
critical_end(cr); |
|
return result; |
} |
#endif |
/sw/rtos/kernel/rtos.h
0,0 → 1,105
#ifndef __RTOS_H__ |
#define __RTOS_H__ |
|
//----------------------------------------------------------------- |
// Build Type |
//----------------------------------------------------------------- |
#if defined ARM_CORTEX_M3 |
#include "arch/cortex_m3/cpu_thread.h" |
#include "arch/cortex_m3/cpu_interrupts.h" |
#elif defined ARM_ARM7TDMI |
#include "arch/arm7tdmi/cpu_thread.h" |
#include "arch/arm7tdmi/cpu_interrupts.h" |
#elif defined AVR_PLATFORM |
#include "arch/avr/cpu_thread.h" |
#include "arch/avr/cpu_interrupts.h" |
#elif defined MPX_PLATFORM |
#include "arch/mpx/cpu_thread.h" |
#include "arch/mpx/cpu_interrupts.h" |
#elif defined ALTOR32_PLATFORM |
#include "arch/altor32/cpu_thread.h" |
#include "arch/altor32/cpu_interrupts.h" |
#elif defined OR32_PLATFORM |
#include "arch/or32/cpu_thread.h" |
#include "arch/or32/cpu_interrupts.h" |
#else |
// ... |
#endif |
|
//----------------------------------------------------------------- |
// Defines |
//----------------------------------------------------------------- |
#ifndef NULL |
#define NULL 0 |
#endif |
|
#ifndef FALSE |
#define FALSE 0 |
#endif |
|
#ifndef TRUE |
#define TRUE 1 |
#endif |
|
//----------------------------------------------------------------- |
// Platform Includes |
//----------------------------------------------------------------- |
#include "critical.h" |
#include "os_assert.h" |
#include "list.h" |
#include "thread.h" |
#include "mutex.h" |
#include "semaphore.h" |
#include "event.h" |
#include "lock.h" |
#include "mailbox.h" |
#include "interrupts.h" |
#include "mem_alloc.h" |
#include "timer_cb.h" |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
struct sRtosServices |
{ |
int (*printf)( const char* ctrl1, ... ); |
void (*idle)( void ); |
void (*reboot)( void ); |
}; |
|
extern struct sRtosServices rtos_services; |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
|
// Initialise RTOS (should be first RTOS function called) |
void rtos_init(void); |
|
// Start RTOS with init task |
void rtos_start(void (*init_func)(void *arg), void *arg, int pri, unsigned int stack_size); |
|
// RTOS heap init - only required if dynamic RTOS object allocation used |
void rtos_heap_init(unsigned char *heap, unsigned int size); |
|
// Allocation of RTOS item |
struct thread* rtos_thread_create(char *name, int pri, void (*f)(void *), void *arg, unsigned int stack_size); |
struct mutex* rtos_mutex_create(void); |
struct semaphore* rtos_semaphore_create(int initial_count); |
struct mailbox* rtos_mailbox_create(void); |
struct lock* rtos_lock_create(void); |
|
// Free RTOS items |
void rtos_thread_destroy(struct thread* thread); |
void rtos_mutex_destroy(struct mutex* mtx); |
void rtos_semaphore_destroy(struct semaphore* sema); |
void rtos_mailbox_destroy(struct mailbox* mailbox); |
void rtos_lock_destroy(struct lock* lock); |
|
//----------------------------------------------------------------- |
// RTOS Macros |
//----------------------------------------------------------------- |
#define OS_PRINTF rtos_services.printf |
|
#endif |
|
/sw/rtos/kernel/mem_alloc.h
0,0 → 1,27
#ifndef __MEM_ALLOC_H__ |
#define __MEM_ALLOC_H__ |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
|
// Initialise RTOS memory allocator |
void rtos_mem_init( void *heap, unsigned len ); |
|
// 'malloc' function (thread safe) |
void* rtos_mem_alloc( unsigned size ); |
|
// 'free' function (thread safe) |
void rtos_mem_free( void *ptr ); |
|
// 'calloc' function (thread safe) |
void* rtos_mem_calloc( unsigned size ); |
|
// Find the size of the largest free block |
unsigned rtos_mem_size_largest(void); |
|
// Find the total free space |
unsigned rtos_mem_size_free(void); |
|
#endif |
|
/sw/rtos/kernel/lock.h
0,0 → 1,30
#ifndef __LOCK_H__ |
#define __LOCK_H__ |
|
#include "list.h" |
|
//----------------------------------------------------------------- |
// Types |
//----------------------------------------------------------------- |
struct lock |
{ |
void * owner; |
struct link_list pend_list; |
int lock_count; |
}; |
|
//----------------------------------------------------------------- |
// Prototypes |
//----------------------------------------------------------------- |
|
// Initialise lock object |
void lock_init(struct lock *pLock); |
|
// Wait until lock is available (recursive lock) |
void lock_acquire(struct lock *pLock); |
|
// Release/decrement lock (recursive lock) |
void lock_release(struct lock *pLock); |
|
#endif |
|
sw/rtos/kernel
Property changes :
Added: bugtraq:number
## -0,0 +1 ##
+true
\ No newline at end of property
Index: sw/rtos/arch/altor32/cpu_thread.c
===================================================================
--- sw/rtos/arch/altor32/cpu_thread.c (nonexistent)
+++ sw/rtos/arch/altor32/cpu_thread.c (revision 21)
@@ -0,0 +1,334 @@
+//-----------------------------------------------------------------------------
+// AltOR32
+// Alternative Lightweight OpenRISC
+// Ultra-Embedded.com
+// Copyright 2011 - 2012
+//
+// Email: admin@ultra-embedded.com
+//
+// License: GPL
+// Please contact the above address if you would like a version of this
+// software with a more permissive license for use in closed source commercial
+// applications.
+//-----------------------------------------------------------------------------
+//
+// This file is part of AltOR32 Alternative Lightweight OpenRISC project.
+//
+// AltOR32 is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; either version 2 of the License, or (at your option) any later
+// version.
+//
+// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License
+// along with AltOR32; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//-----------------------------------------------------------------------------
+#include "kernel/rtos.h"
+#include "kernel/os_assert.h"
+#include "cpu_interrupts.h"
+#include "mem_map.h"
+#include "printf.h"
+#include "irq.h"
+
+//-----------------------------------------------------------------
+// Defines:
+//-----------------------------------------------------------------
+
+// Macro used to stop profiling functions being called
+#define NO_PROFILE __attribute__((__no_instrument_function__))
+
+// SR Register
+#define SPR_SR (17)
+
+// SR_IEE - Interrupt Exception Enable
+#define SPR_SR_IEE 0x00000004
+
+#define STACK_REDZONE_SIZE 128
+
+//-----------------------------------------------------------------
+// Globals:
+//-----------------------------------------------------------------
+volatile tTaskBlock * _currentTCB = NULL;
+volatile unsigned _in_interrupt = 0;
+
+//-----------------------------------------------------------------
+// cpu_thread_init_tcb:
+//-----------------------------------------------------------------
+void cpu_thread_init_tcb( tTaskBlock *tcb, void (*func)(void *), void *funcArg, unsigned long *stack, unsigned int stack_size )
+{
+ unsigned long *stack_pointer;
+ int i;
+
+ OS_ASSERT(stack != NULL);
+
+ // Record end of stack (start of stack array)
+ stack_pointer = stack;
+ tcb->StackSize = stack_size;
+ tcb->StackAlloc = stack_pointer;
+
+ // Set default check byte
+ for (i=0;iStackSize;i++)
+ tcb->StackAlloc[i] = STACK_CHK_BYTE;
+
+ // Set current stack pointer to start (top) of stack
+ stack_pointer += (tcb->StackSize-1);
+
+ // MARKER
+ *stack_pointer = ( unsigned long ) 0xFEADC0ED;
+ stack_pointer--;
+
+ // MARKER 2
+ *stack_pointer = ( unsigned long ) 0xFEADC0ED;
+ stack_pointer--;
+
+ // Make space for redzone...
+ stack_pointer -= STACK_REDZONE_SIZE;
+
+ // Setup registers
+ for (i=31;i>=2;i--)
+ {
+ // R3 = Arg
+ if (i == 3)
+ *stack_pointer = ( unsigned long ) funcArg;
+ else
+ *stack_pointer = ( unsigned long ) i;
+ stack_pointer--;
+ }
+
+ // 4: ESR (start with interrupts enabled)
+ *stack_pointer = ( unsigned long ) SPR_SR_IEE;
+ stack_pointer--;
+
+ // 0: EPC
+ *stack_pointer = ( unsigned long ) func;
+
+ // Critical depth = 0 so not in critical section (ints enabled)
+ tcb->critical_depth = 0;
+
+ /* Record new stack pointer */
+ tcb->StackPointer = stack_pointer;
+}
+//-----------------------------------------------------------------
+// mtspr: Write to SPR
+//-----------------------------------------------------------------
+static inline void mtspr(unsigned long spr, unsigned long value)
+{
+ asm volatile ("l.mtspr\t\t%0,%1,0": : "r" (spr), "r" (value));
+}
+//-----------------------------------------------------------------
+// mfspr: Read from SPR
+//-----------------------------------------------------------------
+static inline unsigned long mfspr(unsigned long spr)
+{
+ unsigned long value;
+ asm volatile ("l.mfspr\t\t%0,%1,0" : "=r" (value) : "r" (spr));
+ return value;
+}
+//-----------------------------------------------------------------
+// cpu_critical_start: Force interrupts to be disabled
+//-----------------------------------------------------------------
+int NO_PROFILE cpu_critical_start(void)
+{
+ // Don't do anything to the interrupt status if already within IRQ
+ if (_in_interrupt || _currentTCB == NULL)
+ return 0;
+
+ // Disable interrupts
+ mtspr(SPR_SR, 0);
+
+ // Increase critical depth
+ _currentTCB->critical_depth++;
+
+ return (int)0;
+}
+//-----------------------------------------------------------------
+// cpu_critical_end: Restore interrupt enable state
+//-----------------------------------------------------------------
+void NO_PROFILE cpu_critical_end(int cr)
+{
+ // Don't do anything to the interrupt status if already within IRQ
+ if (_in_interrupt || _currentTCB == NULL)
+ return ;
+
+ OS_ASSERT(_currentTCB->critical_depth > 0);
+ OS_ASSERT(_currentTCB->critical_depth < 255);
+
+ // Decrement critical depth
+ _currentTCB->critical_depth--;
+
+ // End of critical section?
+ if (_currentTCB->critical_depth == 0)
+ {
+ // Manually re-enable IRQ
+ mtspr(SPR_SR, SPR_SR_IEE);
+ }
+
+ return;
+}
+//-----------------------------------------------------------------
+// cpu_context_switch:
+//-----------------------------------------------------------------
+void cpu_context_switch( void )
+{
+ OS_ASSERT(!_in_interrupt);
+
+ // Cause context switch
+ asm volatile ( "l.nop \n\t" );
+ asm volatile ( "l.sys 0 \n\t" );
+ asm volatile ( "l.nop \n\t" );
+}
+//-----------------------------------------------------------------
+// cpu_context_switch_irq:
+//-----------------------------------------------------------------
+void cpu_context_switch_irq( void )
+{
+ // No need to do anything in this system as all interrupts
+ // cause the kernel to run...
+ OS_ASSERT(_in_interrupt);
+}
+//-----------------------------------------------------------------
+// cpu_load_context:
+//-----------------------------------------------------------------
+static inline void cpu_load_context(int preempt)
+{
+ struct register_set *reg_file;
+
+ // Load new thread context
+ thread_load_context(preempt);
+
+ // Adjust ESR to have correct interrupt enable bit state
+ reg_file = (struct register_set *)_currentTCB->StackPointer;
+
+ if (_currentTCB->critical_depth == 0)
+ reg_file->esr |= SPR_SR_IEE;
+ else
+ reg_file->esr &=~SPR_SR_IEE;
+}
+//-----------------------------------------------------------------
+// cpu_irq:
+//-----------------------------------------------------------------
+CRITICALFUNC void cpu_irq(void)
+{
+ int preempt = 0;
+ unsigned int stat = IRQ_STATUS & IRQ_MASK;
+
+ // Check that this not occuring recursively!
+ OS_ASSERT(!_in_interrupt);
+ _in_interrupt = 1;
+
+ // Has timer event fired?
+ if (stat & (1 << IRQ_SYSTICK))
+ {
+ preempt = 1;
+ thread_tick();
+
+ // Acknowledge interrupt
+ IRQ_STATUS = (1 << IRQ_SYSTICK);
+ stat &= ~(1 << IRQ_SYSTICK);
+ }
+
+ // More pending interrupts?
+ if (stat)
+ irq_handler(stat);
+
+ // Load new thread context
+ cpu_load_context(preempt);
+
+ _in_interrupt = 0;
+}
+//-----------------------------------------------------------------
+// cpu_syscall:
+//-----------------------------------------------------------------
+void cpu_syscall(void)
+{
+ // Load new thread context
+ cpu_load_context(0);
+}
+//-----------------------------------------------------------------
+// cpu_thread_start:
+//-----------------------------------------------------------------
+void cpu_thread_start( void )
+{
+ // Disable all & clear all interrupts
+ IRQ_MASK_CLR = 0xFFFFFFFF;
+ IRQ_STATUS = 0xFFFFFFFF;
+
+ // Force global IRQ enable to disabled prior to starting
+ // systick & restoring initial context
+ mtspr(SPR_SR, 0);
+
+ // Enable Systick IRQ & fault handling
+ cpu_int_enable(IRQ_SYSTICK);
+
+ // Generate syscall interrupt to load first context
+ cpu_context_switch();
+}
+//-----------------------------------------------------------------
+// cpu_dump_stack:
+//-----------------------------------------------------------------
+void cpu_dump_stack(void)
+{
+ struct register_set *reg_file = (struct register_set *)_currentTCB->StackPointer;
+ int i;
+
+ printf("Frame:\n");
+ printf(" Critical Depth 0x%x\n", _currentTCB->critical_depth);
+ printf(" EPC 0x%x\n", reg_file->epc);
+ printf(" ESR 0x%x\n", reg_file->esr);
+ printf(" R0 = 0x0\n");
+ printf(" R1(SP) = 0x%x\n",((unsigned int)_currentTCB->StackPointer) + 132);
+ for (i=0;i<30;i++)
+ {
+ printf(" R%x = 0x%x\n", i+2, reg_file->reg[i]);
+ }
+}
+//-----------------------------------------------------------------
+// cpu_thread_stack_size:
+//-----------------------------------------------------------------
+int cpu_thread_stack_size(tTaskBlock * pCurrent)
+{
+ return (int)pCurrent->StackSize;
+}
+//-----------------------------------------------------------------
+// cpu_thread_stack_free:
+//-----------------------------------------------------------------
+int cpu_thread_stack_free(tTaskBlock * pCurrent)
+{
+ int i;
+ int free = 0;
+
+ for (i=0;iStackSize;i++)
+ {
+ if (pCurrent->StackAlloc[i] != STACK_CHK_BYTE)
+ break;
+ else
+ free++;
+ }
+
+ return free;
+}
+//-----------------------------------------------------------------
+// cpu_fault
+//-----------------------------------------------------------------
+void cpu_fault(void)
+{
+ printf("FAULT:\n");
+ if (_currentTCB)
+ cpu_dump_stack();
+ while (1);
+}
+//-----------------------------------------------------------------
+// cpu_trap
+//-----------------------------------------------------------------
+void cpu_trap(void)
+{
+ printf("TRAP:\n");
+ if (_currentTCB)
+ cpu_dump_stack();
+ while (1);
+}
Index: sw/rtos/arch/altor32/cpu_thread.h
===================================================================
--- sw/rtos/arch/altor32/cpu_thread.h (nonexistent)
+++ sw/rtos/arch/altor32/cpu_thread.h (revision 21)
@@ -0,0 +1,97 @@
+#ifndef __CPU_THREAD_H__
+#define __CPU_THREAD_H__
+
+#ifndef NULL
+ #define NULL 0
+#endif
+
+//-----------------------------------------------------------------
+// Defines
+//-----------------------------------------------------------------
+#define STACK_CHK_BYTE 0xBABEFEAD
+
+// Optional: Define gcc section linkage to relocate critical functions to faster memory
+#ifndef CRITICALFUNC
+ #define CRITICALFUNC
+#endif
+
+//-----------------------------------------------------------------
+// Structures
+//-----------------------------------------------------------------
+
+// Task Control Block
+typedef struct sTaskBlock
+{
+ // Current stack pointer (Must be first item in struct)
+ volatile unsigned long *StackPointer;
+
+ // Stack end pointer
+ volatile unsigned long *StackAlloc;
+
+ // Stack size
+ unsigned int StackSize;
+
+ // Critical section / Interrupt status
+ unsigned int critical_depth;
+} tTaskBlock;
+
+
+// Exception stack frame layout for context save / restore
+struct register_set
+{
+ // EPC (saved PC+4)
+ unsigned int epc;
+
+ // ESR (saved SR)
+ unsigned int esr;
+
+ // Excludes r0, r1
+ unsigned int reg[32-2];
+};
+
+//-----------------------------------------------------------------
+// Globals
+//-----------------------------------------------------------------
+
+// Current Task Control Block
+extern volatile tTaskBlock * _currentTCB;
+
+//-----------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------
+
+// Initialise thread context
+void cpu_thread_init_tcb( tTaskBlock *tcb, void (*func)(void *), void *funcArg, unsigned long *stack, unsigned int stack_size );
+
+// Start first thread switch
+void cpu_thread_start(void);
+
+// Force context switch
+void cpu_context_switch( void );
+
+// Force context switch (from IRQ)
+void cpu_context_switch_irq( void );
+
+// Critical section entry & exit
+int cpu_critical_start(void);
+void cpu_critical_end(int cr);
+
+// Dump thread stack details upon assertion / exception
+void cpu_dump_stack(void);
+
+// Specified thread TCB's free stack entries count
+int cpu_thread_stack_free(tTaskBlock * pCurrent);
+
+// Specified thread TCB's total stack size
+int cpu_thread_stack_size(tTaskBlock * pCurrent);
+
+void cpu_syscall(void);
+
+CRITICALFUNC void cpu_irq(void);
+
+// CPU clocks/time measurement functions (optional, used if RTOS_MEASURE_THREAD_TIME defined)
+unsigned long cpu_timenow(void);
+long cpu_timediff(unsigned long a, unsigned long b);
+
+#endif // __CPU_THREAD_H__
+
Index: sw/rtos/arch/altor32/exception.inc
===================================================================
--- sw/rtos/arch/altor32/exception.inc (nonexistent)
+++ sw/rtos/arch/altor32/exception.inc (revision 21)
@@ -0,0 +1,148 @@
+#-------------------------------------------------------------
+# Context Stack Frame - 128 words
+#-------------------------------------------------------------
+# 0: EPC
+# 4: ESR
+# 8: R2 (FP)
+# 12: R3
+# 16: R4
+# 20: R5
+# 24: R6
+# 28: R7
+# 32: R8
+# 36: R9 (LR)
+# 40: R10
+# 44: R11
+# 48: R12
+# 52: R13
+# 56: R14
+# 60: R15
+# 64: R16
+# 68: R17
+# 72: R18
+# 76: R19
+# 80: R20
+# 84: R21
+# 88: R22
+# 92: R23
+# 96: R24
+# 100: R25
+# 104: R26
+# 108: R27
+# 112: R28
+# 116: R29
+# 120: R30
+# 124: R31
+#-------------------------------------------------------------
+
+#-------------------------------------------------------------
+# asm_save_context:
+#-------------------------------------------------------------
+.macro asm_save_context
+
+ l.nop
+ l.nop
+
+ # Adjust SP (frame size is 128 + allow for 128 uncommitted in-use stack)
+ l.addi r1, r1, -256
+
+ # Save register file to stack
+ l.sw 124(r1), r31
+ l.sw 120(r1), r30
+ l.sw 116(r1), r29
+ l.sw 112(r1), r28
+ l.sw 108(r1), r27
+ l.sw 104(r1), r26
+ l.sw 100(r1), r25
+ l.sw 96(r1), r24
+ l.sw 92(r1), r23
+ l.sw 88(r1), r22
+ l.sw 84(r1), r21
+ l.sw 80(r1), r20
+ l.sw 76(r1), r19
+ l.sw 72(r1), r18
+ l.sw 68(r1), r17
+ l.sw 64(r1), r16
+ l.sw 60(r1), r15
+ l.sw 56(r1), r14
+ l.sw 52(r1), r13
+ l.sw 48(r1), r12
+ l.sw 44(r1), r11
+ l.sw 40(r1), r10
+ l.sw 36(r1), r9
+ l.sw 32(r1), r8
+ l.sw 28(r1), r7
+ l.sw 24(r1), r6
+ l.sw 20(r1), r5
+ l.sw 16(r1), r4
+ l.sw 12(r1), r3
+ l.sw 8(r1), r2
+
+ # R10 = ESR
+ l.mfspr r10, r0, 64
+ l.sw 4(r1), r10
+
+ # R10 = EPC
+ l.mfspr r10, r0, 32
+ l.sw 0(r1), r10
+
+.endm
+
+#-------------------------------------------------------------
+# asm_load_context:
+#-------------------------------------------------------------
+.macro asm_load_context
+
+ # Restore EPC (PC of non-exception code)
+ l.lwz r10, 0(r1)
+
+ # EPC = R10
+ l.mtspr r0,r10,32
+
+ # Restore ESR (SR of non-exception code)
+ l.lwz r10, 4(r1)
+
+ # ESR = R10
+ l.mtspr r0,r10,64
+
+ # Restore register set
+ # r1/r1 already set
+ l.lwz r2, 8(r1)
+ l.lwz r3, 12(r1)
+ l.lwz r4, 16(r1)
+ l.lwz r5, 20(r1)
+ l.lwz r6, 24(r1)
+ l.lwz r7, 28(r1)
+ l.lwz r8, 32(r1)
+ l.lwz r9, 36(r1)
+ l.lwz r10, 40(r1)
+ l.lwz r11, 44(r1)
+ l.lwz r12, 48(r1)
+ l.lwz r13, 52(r1)
+ l.lwz r14, 56(r1)
+ l.lwz r15, 60(r1)
+ l.lwz r16, 64(r1)
+ l.lwz r17, 68(r1)
+ l.lwz r18, 72(r1)
+ l.lwz r19, 76(r1)
+ l.lwz r20, 80(r1)
+ l.lwz r21, 84(r1)
+ l.lwz r22, 88(r1)
+ l.lwz r23, 92(r1)
+ l.lwz r24, 96(r1)
+ l.lwz r25,100(r1)
+ l.lwz r26,104(r1)
+ l.lwz r27,108(r1)
+ l.lwz r28,112(r1)
+ l.lwz r29,116(r1)
+ l.lwz r30,120(r1)
+ l.lwz r31,124(r1)
+
+ # Adjust SP past register set
+ l.addi r1, r1, +256
+
+ # Return from interrupt (to restore PC & SR)
+ l.rfe
+ l.nop
+
+.endm
Index: sw/rtos/arch/altor32/cpu_interrupts.c
===================================================================
--- sw/rtos/arch/altor32/cpu_interrupts.c (nonexistent)
+++ sw/rtos/arch/altor32/cpu_interrupts.c (revision 21)
@@ -0,0 +1,69 @@
+//-----------------------------------------------------------------------------
+// AltOR32
+// Alternative Lightweight OpenRISC
+// Ultra-Embedded.com
+// Copyright 2011 - 2012
+//
+// Email: admin@ultra-embedded.com
+//
+// License: GPL
+// Please contact the above address if you would like a version of this
+// software with a more permissive license for use in closed source commercial
+// applications.
+//-----------------------------------------------------------------------------
+//
+// This file is part of AltOR32 Alternative Lightweight OpenRISC project.
+//
+// AltOR32 is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; either version 2 of the License, or (at your option) any later
+// version.
+//
+// AltOR32 is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License
+// along with AltOR32; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//-----------------------------------------------------------------------------
+#include "kernel/rtos.h"
+#include "cpu_interrupts.h"
+#include "irq.h"
+
+//-----------------------------------------------------------------
+// cpu_int_register:
+//-----------------------------------------------------------------
+void cpu_int_register(int interrupt, void (*func)(int interrupt))
+{
+ irq_register(interrupt, func);
+}
+//-----------------------------------------------------------------
+// cpu_int_enable:
+//-----------------------------------------------------------------
+void cpu_int_enable(int interrupt)
+{
+ irq_enable(interrupt);
+}
+//-----------------------------------------------------------------
+// cpu_int_disable:
+//-----------------------------------------------------------------
+void cpu_int_disable(int interrupt)
+{
+ irq_disable(interrupt);
+}
+//-----------------------------------------------------------------
+// cpu_int_acknowledge:
+//-----------------------------------------------------------------
+void cpu_int_acknowledge(int interrupt)
+{
+ irq_acknowledge(interrupt);
+}
+//-----------------------------------------------------------------
+// cpu_wfi_sleep:
+//-----------------------------------------------------------------
+void cpu_wfi_sleep(void)
+{
+ // Not supported
+}
Index: sw/rtos/arch/altor32/cpu_interrupts.h
===================================================================
--- sw/rtos/arch/altor32/cpu_interrupts.h (nonexistent)
+++ sw/rtos/arch/altor32/cpu_interrupts.h (revision 21)
@@ -0,0 +1,29 @@
+#ifndef __CPU_INTERRUPTS_H__
+#define __CPU_INTERRUPTS_H__
+
+//-----------------------------------------------------------------
+// Defines
+//-----------------------------------------------------------------
+#define CPU_MAX_INTERRUPTS 32
+
+//-----------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------
+
+// Register interrupt handler with interrupt/exception
+void cpu_int_register(int interrupt, void (*func)(int interrupt));
+
+// Enable interrupt/exception
+void cpu_int_enable(int interrupt);
+
+// Disable interrupt/exception
+void cpu_int_disable(int interrupt);
+
+// Acknowledge interrupt source
+void cpu_int_acknowledge(int interrupt);
+
+// Put CPU into sleep mode & wait for interrupts
+void cpu_wfi_sleep(void);
+
+#endif // __CPU_INTERRUPTS_H__
+
Index: sw/rtos/arch/altor32
===================================================================
--- sw/rtos/arch/altor32 (nonexistent)
+++ sw/rtos/arch/altor32 (revision 21)
sw/rtos/arch/altor32
Property changes :
Added: bugtraq:number
## -0,0 +1 ##
+true
\ No newline at end of property
Index: sw/rtos/arch
===================================================================
--- sw/rtos/arch (nonexistent)
+++ sw/rtos/arch (revision 21)
sw/rtos/arch
Property changes :
Added: bugtraq:number
## -0,0 +1 ##
+true
\ No newline at end of property
Index: sw/rtos
===================================================================
--- sw/rtos (nonexistent)
+++ sw/rtos (revision 21)
sw/rtos
Property changes :
Added: bugtraq:number
## -0,0 +1 ##
+true
\ No newline at end of property