OpenCores
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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.