OpenCores
URL https://opencores.org/ocsvn/plasma/plasma/trunk

Subversion Repositories plasma

[/] [plasma/] [trunk/] [kernel/] [rtos.c] - Diff between revs 400 and 402

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 400 Rev 402
Line 10... Line 10...
 *    Plasma Real Time Operating System
 *    Plasma Real Time Operating System
 *    Fully pre-emptive RTOS with support for:
 *    Fully pre-emptive RTOS with support for:
 *       Heaps, Threads, Semaphores, Mutexes, Message Queues, and Timers.
 *       Heaps, Threads, Semaphores, Mutexes, Message Queues, and Timers.
 *    This file tries to be hardware independent except for calls to:
 *    This file tries to be hardware independent except for calls to:
 *       MemoryRead() and MemoryWrite() for interrupts.
 *       MemoryRead() and MemoryWrite() for interrupts.
 *    Partial support for multiple CPUs using symmetric multiprocessing.
 *    Support for multiple CPUs using symmetric multiprocessing.
 *--------------------------------------------------------------------*/
 *--------------------------------------------------------------------*/
#include "plasma.h"
#include "plasma.h"
#include "rtos.h"
#include "rtos.h"
 
 
#define HEAP_MAGIC 0x1234abcd
#define HEAP_MAGIC 0x1234abcd
Line 132... Line 132...
static int ThreadSwapEnabled;
static int ThreadSwapEnabled;
static uint32 ThreadTime;         //Number of ~10ms ticks since reboot
static uint32 ThreadTime;         //Number of ~10ms ticks since reboot
static void *NeedToFree;          //Closed but not yet freed thread
static void *NeedToFree;          //Closed but not yet freed thread
static OS_Semaphore_t SemaphoreReserved[SEM_RESERVED_COUNT];
static OS_Semaphore_t SemaphoreReserved[SEM_RESERVED_COUNT];
static OS_Semaphore_t *SemaphoreSleep;
static OS_Semaphore_t *SemaphoreSleep;
static OS_Semaphore_t *SemaphoreRelease;
static OS_Semaphore_t *SemaphoreRelease; //Protects NeedToFree
static OS_Semaphore_t *SemaphoreLock;
static OS_Semaphore_t *SemaphoreLock;
static OS_Semaphore_t *SemaphoreTimer;
static OS_Semaphore_t *SemaphoreTimer;
static OS_Timer_t *TimerHead;     //Linked list of timers sorted by timeout
static OS_Timer_t *TimerHead;     //Linked list of timers sorted by timeout
static OS_FuncPtr_t Isr[32];
static OS_FuncPtr_t Isr[32];      //Interrupt service routines
 
#if defined(WIN32) && OS_CPU_COUNT > 1
 
static unsigned int Registration[OS_CPU_COUNT];
 
#endif
 
 
/***************** Heap *******************/
/***************** Heap *******************/
/******************************************/
/******************************************/
OS_Heap_t *OS_HeapCreate(const char *name, void *memory, uint32 size)
OS_Heap_t *OS_HeapCreate(const char *name, void *memory, uint32 size)
{
{
Line 418... Line 420...
      if(threadCurrent)
      if(threadCurrent)
      {
      {
         assert(threadCurrent->magic[0] == THREAD_MAGIC); //check stack overflow
         assert(threadCurrent->magic[0] == THREAD_MAGIC); //check stack overflow
         if(threadCurrent->state == THREAD_RUNNING)
         if(threadCurrent->state == THREAD_RUNNING)
            OS_ThreadPriorityInsert(&ThreadHead, threadCurrent);
            OS_ThreadPriorityInsert(&ThreadHead, threadCurrent);
 
         //printf("Pause(%d,%s) ", OS_CpuIndex(), threadCurrent->name);
         rc = setjmp(threadCurrent->env);  //ANSI C call to save registers
         rc = setjmp(threadCurrent->env);  //ANSI C call to save registers
         if(rc)
         if(rc)
 
         {
 
            //threadCurrent = ThreadCurrent[OS_CpuIndex()];
 
            //printf("Resume(%d,%s) ", OS_CpuIndex(), threadCurrent->name);
            return;  //Returned from longjmp()
            return;  //Returned from longjmp()
      }
      }
 
      }
 
 
      //Remove the new running thread from the ThreadHead linked list
      //Remove the new running thread from the ThreadHead linked list
      threadNext = ThreadCurrent[OS_CpuIndex()]; //removed warning
      threadNext = ThreadCurrent[OS_CpuIndex()]; //removed warning
      assert(threadNext->state == THREAD_READY);
      assert(threadNext->state == THREAD_READY);
      OS_ThreadPriorityRemove(&ThreadHead, threadNext);
      OS_ThreadPriorityRemove(&ThreadHead, threadNext);
      threadNext->state = THREAD_RUNNING;
      threadNext->state = THREAD_RUNNING;
      threadNext->cpuIndex = OS_CpuIndex();
      threadNext->cpuIndex = OS_CpuIndex();
 
#if defined(WIN32) && OS_CPU_COUNT > 1
 
      //Set the Windows thread that the Plasma thread is running on
 
      ((jmp_buf2*)threadNext->env)->extra[0] = Registration[threadNext->cpuIndex];
 
#endif
      longjmp(threadNext->env, 1);         //ANSI C call to restore registers
      longjmp(threadNext->env, 1);         //ANSI C call to restore registers
   }
   }
}
}
 
 
 
 
Line 474... Line 485...
{
{
   OS_Thread_t *thread;
   OS_Thread_t *thread;
   uint8 *stack;
   uint8 *stack;
   jmp_buf2 *env;
   jmp_buf2 *env;
   uint32 state;
   uint32 state;
 
#ifdef WIN32
 
   int stackFrameSize;
 
#endif
 
 
   OS_SemaphorePend(SemaphoreRelease, OS_WAIT_FOREVER);
   OS_SemaphorePend(SemaphoreRelease, OS_WAIT_FOREVER);
   if(NeedToFree)
   if(NeedToFree)
      OS_HeapFree(NeedToFree);
      OS_HeapFree(NeedToFree);
   NeedToFree = NULL;
   NeedToFree = NULL;
Line 519... Line 533...
   thread->prevTimeout = NULL;
   thread->prevTimeout = NULL;
   thread->magic[0] = THREAD_MAGIC;
   thread->magic[0] = THREAD_MAGIC;
 
 
   OS_ThreadRegsInit(thread->env);
   OS_ThreadRegsInit(thread->env);
   env = (jmp_buf2*)thread->env;
   env = (jmp_buf2*)thread->env;
   env->sp = (uint32)stack + stackSize - 24; //minimum stack frame size
 
   env->pc = (uint32)OS_ThreadInit;
   env->pc = (uint32)OS_ThreadInit;
 
#ifndef WIN32
 
   env->sp = (uint32)stack + stackSize - 24; //minimum stack frame size
 
#else
 
   stackFrameSize = env->Ebp - env->sp;
 
   env->Ebp = (uint32)stack + stackSize - 24;//stack frame base pointer
 
   env->sp =  env->Ebp - stackFrameSize;
 
#endif
 
 
   //Add thread to linked list of ready to run threads
   //Add thread to linked list of ready to run threads
   state = OS_CriticalBegin();
   state = OS_CriticalBegin();
   OS_ThreadPriorityInsert(&ThreadHead, thread);
   OS_ThreadPriorityInsert(&ThreadHead, thread);
   OS_ThreadReschedule(0);                   //run highest priority thread
   OS_ThreadReschedule(0);                   //run highest priority thread
Line 635... Line 655...
 
 
 
 
/******************************************/
/******************************************/
//Must be called with interrupts disabled every ~10 msecs
//Must be called with interrupts disabled every ~10 msecs
//Will wake up threads that have timed out waiting on a semaphore
//Will wake up threads that have timed out waiting on a semaphore
void OS_ThreadTick(void *Arg)
static void OS_ThreadTick(void *Arg)
{
{
   OS_Thread_t *thread;
   OS_Thread_t *thread;
   OS_Semaphore_t *semaphore;
   OS_Semaphore_t *semaphore;
   int diff;
   int diff;
   (void)Arg;
   (void)Arg;
Line 1178... Line 1198...
 
 
/******************************************/
/******************************************/
//Plasma hardware dependent
//Plasma hardware dependent
uint32 OS_InterruptStatus(void)
uint32 OS_InterruptStatus(void)
{
{
   return MemoryRead(IRQ_STATUS);
   return MemoryRead(IRQ_STATUS) & MemoryRead(IRQ_MASK);
}
}
 
 
 
 
/******************************************/
/******************************************/
//Plasma hardware dependent
//Plasma hardware dependent
Line 1212... Line 1232...
 
 
/**************** Init ********************/
/**************** Init ********************/
/******************************************/
/******************************************/
//If there aren't any other ready to run threads then spin here
//If there aren't any other ready to run threads then spin here
static volatile uint32 IdleCount;
static volatile uint32 IdleCount;
 
static int SimulateIsr;
static void OS_IdleThread(void *arg)
static void OS_IdleThread(void *arg)
{
{
   (void)arg;
   (void)arg;
 
 
   //Don't block in the idle thread!
   //Don't block in the idle thread!
   for(;;)
   for(;;)
   {
   {
      ++IdleCount;
      ++IdleCount;
   }
 
}
 
 
 
 
 
/******************************************/
 
#ifndef DISABLE_IRQ_SIM
#ifndef DISABLE_IRQ_SIM
//Simulate the hardware interrupts
      MemoryRead(IRQ_MASK + 4);  //will call Sleep
static void OS_IdleSimulateIsr(void *arg)
      if(SimulateIsr && (int)arg == OS_CPU_COUNT-1)
{
{
   uint32 count=0, value;
         unsigned int value = IRQ_COUNTER18;   //tick interrupt
   (void)arg;
 
 
 
   for(;;)
   for(;;)
   {
   {
      MemoryRead(IRQ_MASK + 4);       //calls Sleep(10)
            value |= OS_InterruptStatus();
#if WIN32
            if(value == 0)
      while(OS_InterruptMaskSet(0) & IRQ_UART_WRITE_AVAILABLE)
               break;
         OS_InterruptServiceRoutine(IRQ_UART_WRITE_AVAILABLE, 0);
 
#endif
 
      value = OS_InterruptMaskSet(0) & 0xf;
 
      if(value)
 
         OS_InterruptServiceRoutine(value, 0);
         OS_InterruptServiceRoutine(value, 0);
      ++count;
            value = 0;
 
         }
 
      }
 
#endif
 
#if OS_CPU_COUNT > 1
 
      if((int)arg < OS_CPU_COUNT - 1)
 
      {
 
         unsigned int state;
 
#ifndef WIN32
 
         for(IdleCount = 0; IdleCount < 100000; ++IdleCount) ;
 
#endif
 
         state = OS_SpinLock();
 
         OS_ThreadReschedule(1);
 
         OS_SpinUnlock(state);
 
      }
 
#endif
   }
   }
}
}
#endif //DISABLE_IRQ_SIM
 
 
 
 
 
/******************************************/
/******************************************/
//Plasma hardware dependent
//Plasma hardware dependent
//ISR called every ~10 msecs when bit 18 of the counter register toggles
//ISR called every ~10 msecs when bit 18 of the counter register toggles
static void OS_ThreadTickToggle(void *arg)
static void OS_InterruptTick(void *arg)
{
{
   uint32 status, mask, state;
   uint32 state, mask;
 
 
   //Toggle looking for IRQ_COUNTER18 or IRQ_COUNTER18_NOT
   //Toggle looking for IRQ_COUNTER18 or IRQ_COUNTER18_NOT
   state = OS_SpinLock();
   state = OS_SpinLock();
   status = MemoryRead(IRQ_STATUS) & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT);
   mask = MemoryRead(IRQ_MASK);
   mask = MemoryRead(IRQ_MASK) | IRQ_COUNTER18 | IRQ_COUNTER18_NOT;
   mask ^= IRQ_COUNTER18 | IRQ_COUNTER18_NOT;
   mask &= ~status;
 
   MemoryWrite(IRQ_MASK, mask);
   MemoryWrite(IRQ_MASK, mask);
   OS_ThreadTick(arg);
   OS_ThreadTick(arg);
   OS_SpinUnlock(state);
   OS_SpinUnlock(state);
}
}
 
 
Line 1271... Line 1294...
/******************************************/
/******************************************/
//Initialize the OS by setting up the system heap and the tick interrupt
//Initialize the OS by setting up the system heap and the tick interrupt
void OS_Init(uint32 *heapStorage, uint32 bytes)
void OS_Init(uint32 *heapStorage, uint32 bytes)
{
{
   int i;
   int i;
 
 
   if((int)OS_Init > 0x10000000)        //Running from DDR?
   if((int)OS_Init > 0x10000000)        //Running from DDR?
      OS_AsmInterruptInit();            //Patch interrupt vector
      OS_AsmInterruptInit();            //Patch interrupt vector
   OS_InterruptMaskClear(0xffffffff);   //Disable interrupts
   OS_InterruptMaskClear(0xffffffff);   //Disable interrupts
   HeapArray[0] = OS_HeapCreate("Default", heapStorage, bytes);
   HeapArray[0] = OS_HeapCreate("Default", heapStorage, bytes);
   HeapArray[1] = HeapArray[0];
   HeapArray[1] = HeapArray[0];
   SemaphoreSleep = OS_SemaphoreCreate("Sleep", 0);
   SemaphoreSleep = OS_SemaphoreCreate("Sleep", 0);
   SemaphoreRelease = OS_SemaphoreCreate("Release", 1);
   SemaphoreRelease = OS_SemaphoreCreate("Release", 1);
   SemaphoreLock = OS_SemaphoreCreate("Lock", 1);
   SemaphoreLock = OS_SemaphoreCreate("Lock", 1);
   for(i = 0; i < OS_CPU_COUNT; ++i)
   if((MemoryRead(IRQ_STATUS) & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT)) == 0)
      OS_ThreadCreate("Idle", OS_IdleThread, NULL, 0, 256);
 
#ifndef DISABLE_IRQ_SIM
 
   if((OS_InterruptStatus() & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT)) == 0)
 
   {
   {
      //Detected that running in simulator so create SimIsr thread
      //Detected running in simulator
      UartPrintfCritical("SimIsr\n");
      UartPrintfCritical("SimIsr\n");
      OS_ThreadCreate("SimIsr", OS_IdleSimulateIsr, NULL, 1, 0);
      SimulateIsr = 1;
   }
   }
#endif //DISABLE_IRQ_SIM
   for(i = 0; i < OS_CPU_COUNT; ++i)
 
      OS_ThreadCreate("Idle", OS_IdleThread, (void*)i, i, 256);
   //Plasma hardware dependent (register for OS tick interrupt every ~10 msecs)
   //Plasma hardware dependent (register for OS tick interrupt every ~10 msecs)
   OS_InterruptRegister(IRQ_COUNTER18 | IRQ_COUNTER18_NOT, OS_ThreadTickToggle);
   OS_InterruptRegister(IRQ_COUNTER18 | IRQ_COUNTER18_NOT, OS_InterruptTick);
   OS_InterruptMaskSet(IRQ_COUNTER18 | IRQ_COUNTER18_NOT);
   OS_InterruptMaskSet(IRQ_COUNTER18);
}
}
 
 
 
 
/******************************************/
/******************************************/
//Start thread swapping
//Start thread swapping
void OS_Start(void)
void OS_Start(void)
{
{
 
#if defined(WIN32) && OS_CPU_COUNT > 1
 
   jmp_buf env;
 
   OS_ThreadRegsInit(env);
 
   Registration[OS_CpuIndex()] = ((jmp_buf2*)env)->extra[0];
 
#endif
   ThreadSwapEnabled = 1;
   ThreadSwapEnabled = 1;
   (void)OS_SpinLock();
   (void)OS_SpinLock();
   OS_ThreadReschedule(1);
   OS_ThreadReschedule(1);
}
}
 
 
Line 1312... Line 1339...
void OS_Assert(void)
void OS_Assert(void)
{
{
}
}
 
 
 
 
#if OS_CPU_COUNT > 1
 
static uint8 SpinLockArray[OS_CPU_COUNT];
 
/******************************************/
 
uint32 OS_CpuIndex(void)
 
{
 
   return 0; //0 to OS_CPU_COUNT-1
 
}
 
 
 
 
 
/******************************************/
 
//Symmetric Multiprocessing Spin Lock Mutex
 
uint32 OS_SpinLock(void)
 
{
 
   uint32 state, cpuIndex, i, j, ok, delay;
 
 
 
   cpuIndex = OS_CpuIndex();
 
   delay = cpuIndex + 8;
 
   state = OS_AsmInterruptEnable(0);
 
   //Spin until only this CPU has the spin lock
 
   do
 
   {
 
      ok = 1;
 
      if(++SpinLockArray[cpuIndex] == 1)
 
      {
 
         for(i = 0; i < OS_CPU_COUNT; ++i)
 
         {
 
            if(i != cpuIndex && SpinLockArray[i])
 
               ok = 0;   //Another CPU has the spin lock
 
         }
 
         if(ok == 0)
 
         {
 
            SpinLockArray[cpuIndex] = 0;
 
            for(j = 0; j < delay; ++j)  //wait a bit
 
               ++i;
 
            if(delay < 128)
 
               delay <<= 1;
 
         }
 
      }
 
   } while(ok == 0);
 
   return state;
 
}
 
 
 
 
 
/******************************************/
 
void OS_SpinUnlock(uint32 state)
 
{
 
   uint32 cpuIndex;
 
   cpuIndex = OS_CpuIndex();
 
   if(--SpinLockArray[cpuIndex] == 0)
 
      OS_AsmInterruptEnable(state);
 
 
 
   assert(SpinLockArray[cpuIndex] < 10);
 
}
 
#endif  //OS_CPU_COUNT > 1
 
 
 
 
 
/************** WIN32/Linux Support *************/
 
#ifdef WIN32
 
#ifdef LINUX
 
#define putch putchar
 
#undef _LIBC
 
#undef kbhit
 
#undef getch
 
#define UartPrintf UartPrintf2
 
#define UartScanf UartScanf2
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <termios.h>
 
#include <unistd.h>
 
//Support RTOS inside Linux
 
void Sleep(unsigned int value)
 
{
 
   usleep(value * 1000);
 
}
 
 
 
int kbhit(void)
 
{
 
   struct termios oldt, newt;
 
   struct timeval tv;
 
   fd_set read_fd;
 
 
 
   tcgetattr(STDIN_FILENO, &oldt);
 
   newt = oldt;
 
   newt.c_lflag &= ~(ICANON | ECHO);
 
   tcsetattr(STDIN_FILENO, TCSANOW, &newt);
 
   tv.tv_sec=0;
 
   tv.tv_usec=0;
 
   FD_ZERO(&read_fd);
 
   FD_SET(0,&read_fd);
 
   if(select(1, &read_fd, NULL, NULL, &tv) == -1)
 
      return 0;
 
   if(FD_ISSET(0,&read_fd))
 
      return 1;
 
   return 0;
 
}
 
 
 
int getch(void)
 
{
 
   struct termios oldt, newt;
 
   int ch;
 
 
 
   tcgetattr(STDIN_FILENO, &oldt);
 
   newt = oldt;
 
   newt.c_lflag &= ~(ICANON | ECHO);
 
   tcsetattr(STDIN_FILENO, TCSANOW, &newt);
 
   ch = getchar();
 
   return ch;
 
}
 
#else
 
//Support RTOS inside Windows
 
#undef kbhit
 
#undef getch
 
#undef putch
 
extern int kbhit(void);
 
extern int getch(void);
 
extern int putch(int);
 
extern void __stdcall Sleep(unsigned long value);
 
#endif
 
 
 
static uint32 Memory[8];
 
 
 
//Simulates device register memory reads
 
uint32 MemoryRead(uint32 address)
 
{
 
   Memory[2] |= IRQ_UART_WRITE_AVAILABLE;    //IRQ_STATUS
 
   switch(address)
 
   {
 
   case UART_READ:
 
      if(kbhit())
 
         Memory[0] = getch();                //UART_READ
 
      Memory[2] &= ~IRQ_UART_READ_AVAILABLE; //clear bit
 
      return Memory[0];
 
   case IRQ_MASK:
 
      return Memory[1];                      //IRQ_MASK
 
   case IRQ_MASK + 4:
 
      Sleep(10);
 
      return 0;
 
   case IRQ_STATUS:
 
      if(kbhit())
 
         Memory[2] |= IRQ_UART_READ_AVAILABLE;
 
      return Memory[2];
 
   }
 
   return 0;
 
}
 
 
 
//Simulates device register memory writes
 
void MemoryWrite(uint32 address, uint32 value)
 
{
 
   switch(address)
 
   {
 
   case UART_WRITE:
 
      putch(value);
 
      break;
 
   case IRQ_MASK:
 
      Memory[1] = value;
 
      break;
 
   case IRQ_STATUS:
 
      Memory[2] = value;
 
      break;
 
   }
 
}
 
 
 
uint32 OS_AsmInterruptEnable(uint32 enableInterrupt)
 
{
 
   return enableInterrupt;
 
}
 
 
 
void OS_AsmInterruptInit(void)
 
{
 
}
 
#endif  //WIN32
 
 
 
 
 
/**************** Example *****************/
/**************** Example *****************/
#ifndef NO_MAIN
#ifndef NO_MAIN
#ifdef WIN32
#ifdef WIN32
static uint8 HeapSpace[1024*512];  //For simulation on a PC
static uint8 HeapSpace[1024*512];  //For simulation on a PC
#endif
#endif
Line 1506... Line 1360...
   OS_Init((uint32*)programEnd,
   OS_Init((uint32*)programEnd,
           RAM_EXTERNAL_BASE + RAM_EXTERNAL_SIZE - programEnd);
           RAM_EXTERNAL_BASE + RAM_EXTERNAL_SIZE - programEnd);
#endif
#endif
   UartInit();
   UartInit();
   OS_ThreadCreate("Main", MainThread, NULL, 100, 4000);
   OS_ThreadCreate("Main", MainThread, NULL, 100, 4000);
 
#if defined(WIN32) && OS_CPU_COUNT > 1
 
   OS_InitSimulation();
 
#endif
   OS_Start();
   OS_Start();
   return 0;
   return 0;
}
}
#endif  //NO_MAIN
#endif  //NO_MAIN
 
 

powered by: WebSVN 2.1.0

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