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

Subversion Repositories plasma

[/] [plasma/] [trunk/] [kernel/] [rtos.c] - Blame information for rev 233

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 138 rhoads
/*--------------------------------------------------------------------
2
 * TITLE: Plasma Real Time Operating System
3
 * AUTHOR: Steve Rhoads (rhoadss@yahoo.com)
4
 * DATE CREATED: 12/17/05
5
 * FILENAME: rtos.c
6
 * PROJECT: Plasma CPU core
7
 * COPYRIGHT: Software placed into the public domain by the author.
8
 *    Software 'as is' without warranty.  Author liable for nothing.
9
 * DESCRIPTION:
10
 *    Plasma Real Time Operating System
11
 *    Fully pre-emptive RTOS with support for:
12
 *       Heaps, Threads, Semaphores, Mutexes, Message Queues, and Timers.
13
 *    This file tries to be hardware independent except for calls to:
14
 *       MemoryRead() and MemoryWrite() for interrupts.
15 167 rhoads
 *    Partial support for multiple CPUs using symmetric multiprocessing.
16 138 rhoads
 *--------------------------------------------------------------------*/
17
#include "plasma.h"
18
#include "rtos.h"
19
 
20
#define HEAP_MAGIC 0x1234abcd
21
#define THREAD_MAGIC 0x4321abcd
22
#define SEM_RESERVED_COUNT 2
23
#define HEAP_COUNT 8
24
 
25 167 rhoads
 
26 138 rhoads
/*************** Structures ***************/
27
#ifdef WIN32
28 189 rhoads
   #define setjmp _setjmp
29 138 rhoads
   //x86 registers
30
   typedef struct jmp_buf2 {
31
      uint32 Ebp, Ebx, Edi, Esi, sp, pc, extra[10];
32
   } jmp_buf2;
33 189 rhoads
#elif defined(ARM_CPU)
34
   //ARM registers
35
   typedef struct jmp_buf2 {
36
      uint32 r[13], sp, lr, pc, cpsr, extra[5];
37 218 rhoads
   } jmp_buf 2;
38 138 rhoads
#else  
39
   //Plasma registers
40
   typedef struct jmp_buf2 {
41
      uint32 s[9], gp, sp, pc;
42
   } jmp_buf2;
43
#endif
44
 
45
typedef struct HeapNode_s {
46
   struct HeapNode_s *next;
47
   int size;
48
} HeapNode_t;
49
 
50
struct OS_Heap_s {
51
   uint32 magic;
52
   const char *name;
53
   OS_Semaphore_t *semaphore;
54
   HeapNode_t *available;
55
   HeapNode_t base;
56
   struct OS_Heap_s *alternate;
57
};
58
//typedef struct OS_Heap_s OS_Heap_t;
59
 
60 168 rhoads
typedef enum {
61 176 rhoads
   THREAD_PEND    = 0,
62 168 rhoads
   THREAD_READY   = 1,
63
   THREAD_RUNNING = 2
64
} OS_ThreadState_e;
65
 
66 138 rhoads
struct OS_Thread_s {
67 233 rhoads
   const char *name;         //Name of thread
68
   OS_ThreadState_e state;   //Pending, ready, or running
69
   int cpuIndex;             //Which CPU is running the thread
70
   int cpuLock;              //Lock the thread to a specific CPU
71
   jmp_buf env;              //Registers saved during context swap
72
   OS_FuncPtr_t funcPtr;     //First function called
73
   void *arg;                //Argument to first function called
74
   uint32 priority;          //Priority of thread (0=low, 255=high)
75
   uint32 ticksTimeout;      //Tick value when semaphore pend times out
76
   void *info;               //User storage
77
   OS_Semaphore_t *semaphorePending;  //Semaphore thread is blocked on
78
   int returnCode;           //Return value from semaphore pend
79
   uint32 spinLocks;         //Recursion depth of spin locks
80
   uint32 processId;         //Process ID if using MMU
81
   OS_Heap_t *heap;          //Heap used if no heap specified
82
   struct OS_Thread_s *next; //Linked list of threads by priority
83
   struct OS_Thread_s *prev;
84
   struct OS_Thread_s *nextTimeout; //Linked list of threads by timeout
85
   struct OS_Thread_s *prevTimeout;
86
   uint32 magic[1];          //Bottom of stack to detect stack overflow
87 138 rhoads
};
88
//typedef struct OS_Thread_s OS_Thread_t;
89
 
90
struct OS_Semaphore_s {
91
   const char *name;
92
   struct OS_Thread_s *threadHead;
93
   int count;
94
};
95
//typedef struct OS_Semaphore_s OS_Semaphore_t;
96
 
97
struct OS_Mutex_s {
98
   OS_Semaphore_t *semaphore;
99
   OS_Thread_t *thread;
100
   int count;
101
};
102
//typedef struct OS_Mutex_s OS_Mutex_t;
103
 
104
struct OS_MQueue_s {
105
   const char *name;
106
   OS_Semaphore_t *semaphore;
107
   int count, size, used, read, write;
108
};
109
//typedef struct OS_MQueue_s OS_MQueue_t;
110
 
111
struct OS_Timer_s {
112
   const char *name;
113
   struct OS_Timer_s *next, *prev;
114
   uint32 ticksTimeout;
115
   uint32 ticksRestart;
116
   int active;
117 218 rhoads
   OS_TimerFuncPtr_t callback;
118 138 rhoads
   OS_MQueue_t *mqueue;
119
   uint32 info;
120
};
121
//typedef struct OS_Timer_s OS_Timer_t;
122
 
123
 
124
/*************** Globals ******************/
125
static OS_Heap_t *HeapArray[HEAP_COUNT];
126 189 rhoads
static OS_Thread_t *ThreadCurrent[OS_CPU_COUNT];
127
static OS_Thread_t *ThreadHead;   //Linked list of threads sorted by priority
128
static OS_Thread_t *TimeoutHead;  //Linked list of threads sorted by timeout
129 138 rhoads
static int ThreadSwapEnabled;
130
static int ThreadNeedReschedule;
131
static uint32 ThreadTime;
132
static void *NeedToFree;
133
static OS_Semaphore_t SemaphoreReserved[SEM_RESERVED_COUNT];
134 189 rhoads
static OS_Semaphore_t *SemaphoreSleep;
135
static OS_Semaphore_t *SemaphoreLock;
136
static OS_Semaphore_t *SemaphoreTimer;
137 138 rhoads
static OS_Timer_t *TimerHead;     //Linked list of timers sorted by timeout
138
static OS_FuncPtr_t Isr[32];
139
static int InterruptInside;
140 200 rhoads
int InitStack[128];               //Used by boot.asm
141 138 rhoads
 
142
 
143
/***************** Heap *******************/
144
/******************************************/
145 189 rhoads
OS_Heap_t *OS_HeapCreate(const char *name, void *memory, uint32 size)
146 138 rhoads
{
147
   OS_Heap_t *heap;
148
 
149 189 rhoads
   assert(((uint32)memory & 3) == 0);
150
   heap = (OS_Heap_t*)memory;
151 138 rhoads
   heap->magic = HEAP_MAGIC;
152 189 rhoads
   heap->name = name;
153
   heap->semaphore = OS_SemaphoreCreate(name, 1);
154 138 rhoads
   heap->available = (HeapNode_t*)(heap + 1);
155
   heap->available->next = &heap->base;
156 189 rhoads
   heap->available->size = (size - sizeof(OS_Heap_t)) / sizeof(HeapNode_t);
157 138 rhoads
   heap->base.next = heap->available;
158
   heap->base.size = 0;
159
   return heap;
160
}
161
 
162
 
163
/******************************************/
164 189 rhoads
void OS_HeapDestroy(OS_Heap_t *heap)
165 138 rhoads
{
166 189 rhoads
   OS_SemaphoreDelete(heap->semaphore);
167 138 rhoads
}
168
 
169
 
170
/******************************************/
171
//Modified from K&R
172 189 rhoads
void *OS_HeapMalloc(OS_Heap_t *heap, int bytes)
173 138 rhoads
{
174
   HeapNode_t *node, *prevp;
175
   int nunits;
176
 
177 189 rhoads
   if(heap == NULL && OS_ThreadSelf())
178
      heap = OS_ThreadSelf()->heap;
179
   if((uint32)heap < HEAP_COUNT)
180
      heap = HeapArray[(int)heap];
181
   nunits = (bytes + sizeof(HeapNode_t) - 1) / sizeof(HeapNode_t) + 1;
182
   OS_SemaphorePend(heap->semaphore, OS_WAIT_FOREVER);
183
   prevp = heap->available;
184 138 rhoads
   for(node = prevp->next; ; prevp = node, node = node->next)
185
   {
186
      if(node->size >= nunits)       //Big enough?
187
      {
188
         if(node->size == nunits)    //Exactly
189
            prevp->next = node->next;
190
         else
191
         {                           //Allocate tail end
192
            node->size -= nunits;
193
            node += node->size;
194
            node->size = nunits;
195
         }
196 189 rhoads
         heap->available = prevp;
197
         node->next = (HeapNode_t*)heap;
198
         OS_SemaphorePost(heap->semaphore);
199 138 rhoads
         return (void*)(node + 1);
200
      }
201 189 rhoads
      if(node == heap->available)   //Wrapped around free list
202 138 rhoads
      {
203 189 rhoads
         OS_SemaphorePost(heap->semaphore);
204
         if(heap->alternate)
205
            return OS_HeapMalloc(heap->alternate, bytes);
206 138 rhoads
         return NULL;
207
      }
208
   }
209
}
210
 
211
 
212
/******************************************/
213
//Modified from K&R
214 189 rhoads
void OS_HeapFree(void *block)
215 138 rhoads
{
216
   OS_Heap_t *heap;
217
   HeapNode_t *bp, *node;
218
 
219 189 rhoads
   assert(block);
220
   bp = (HeapNode_t*)block - 1;   //point to block header
221 138 rhoads
   heap = (OS_Heap_t*)bp->next;
222
   assert(heap->magic == HEAP_MAGIC);
223
   if(heap->magic != HEAP_MAGIC)
224
      return;
225
   OS_SemaphorePend(heap->semaphore, OS_WAIT_FOREVER);
226
   for(node = heap->available; !(node < bp && bp < node->next); node = node->next)
227
   {
228
      if(node >= node->next && (bp > node || bp < node->next))
229
         break;               //freed block at start or end of area
230
   }
231
 
232
   if(bp + bp->size == node->next)   //join to upper
233
   {
234
      bp->size += node->next->size;
235
      bp->next = node->next->next;
236
   }
237
   else
238
   {
239
      bp->next = node->next;
240
   }
241
 
242
   if(node + node->size == bp)       //join to lower
243
   {
244
      node->size += bp->size;
245
      node->next = bp->next;
246
   }
247
   else
248
      node->next = bp;
249
   heap->available = node;
250
   OS_SemaphorePost(heap->semaphore);
251
}
252
 
253
 
254
/******************************************/
255 189 rhoads
void OS_HeapAlternate(OS_Heap_t *heap, OS_Heap_t *alternate)
256 138 rhoads
{
257 189 rhoads
   heap->alternate = alternate;
258 138 rhoads
}
259
 
260
 
261
/******************************************/
262 189 rhoads
void OS_HeapRegister(void *index, OS_Heap_t *heap)
263 138 rhoads
{
264 189 rhoads
   if((uint32)index < HEAP_COUNT)
265
      HeapArray[(int)index] = heap;
266 138 rhoads
}
267
 
268
 
269
 
270
/***************** Thread *****************/
271
/******************************************/
272
//Linked list of threads sorted by priority
273
//Must be called with interrupts disabled
274
static void OS_ThreadPriorityInsert(OS_Thread_t **head, OS_Thread_t *thread)
275
{
276
   OS_Thread_t *node, *prev;
277
 
278
   prev = NULL;
279
   for(node = *head; node; node = node->next)
280
   {
281
      if(node->priority <= thread->priority)
282
         break;
283
      prev = node;
284
   }
285
 
286
   if(prev == NULL)
287
   {
288
      thread->next = *head;
289
      thread->prev = NULL;
290
      *head = thread;
291
   }
292
   else
293
   {
294
      if(prev->next)
295
         prev->next->prev = thread;
296
      thread->next = prev->next;
297
      thread->prev = prev;
298
      prev->next = thread;
299
   }
300
   assert(ThreadHead);
301 168 rhoads
   if(*head == ThreadHead)
302
      thread->state = THREAD_READY;
303 138 rhoads
}
304
 
305
 
306
/******************************************/
307
//Must be called with interrupts disabled
308
static void OS_ThreadPriorityRemove(OS_Thread_t **head, OS_Thread_t *thread)
309
{
310
   assert(thread->magic[0] == THREAD_MAGIC);  //check stack overflow
311
   if(thread->prev == NULL)
312
      *head = thread->next;
313
   else
314
      thread->prev->next = thread->next;
315
   if(thread->next)
316
      thread->next->prev = thread->prev;
317
   thread->next = NULL;
318
   thread->prev = NULL;
319 176 rhoads
   thread->state = THREAD_PEND;
320 138 rhoads
}
321
 
322
 
323
/******************************************/
324
//Linked list of threads sorted by timeout value
325
//Must be called with interrupts disabled
326
static void OS_ThreadTimeoutInsert(OS_Thread_t *thread)
327
{
328
   OS_Thread_t *node, *prev;
329
   int diff;
330
 
331
   prev = NULL;
332
   for(node = TimeoutHead; node; node = node->nextTimeout)
333
   {
334
      diff = thread->ticksTimeout - node->ticksTimeout;
335
      if(diff <= 0)
336
         break;
337
      prev = node;
338
   }
339
 
340
   if(prev == NULL)
341
   {
342
      thread->nextTimeout = TimeoutHead;
343
      thread->prevTimeout = NULL;
344 151 rhoads
      if(TimeoutHead)
345
         TimeoutHead->prevTimeout = thread;
346 138 rhoads
      TimeoutHead = thread;
347
   }
348
   else
349
   {
350
      if(prev->nextTimeout)
351
         prev->nextTimeout->prevTimeout = thread;
352
      thread->nextTimeout = prev->nextTimeout;
353
      thread->prevTimeout = prev;
354
      prev->nextTimeout = thread;
355
   }
356
}
357
 
358
 
359
/******************************************/
360
//Must be called with interrupts disabled
361
static void OS_ThreadTimeoutRemove(OS_Thread_t *thread)
362
{
363
   if(thread->prevTimeout == NULL && TimeoutHead != thread)
364
      return;         //not in list
365
   if(thread->prevTimeout == NULL)
366
      TimeoutHead = thread->nextTimeout;
367
   else
368
      thread->prevTimeout->nextTimeout = thread->nextTimeout;
369
   if(thread->nextTimeout)
370
      thread->nextTimeout->prevTimeout = thread->prevTimeout;
371
   thread->nextTimeout = NULL;
372
   thread->prevTimeout = NULL;
373
}
374
 
375
 
376 176 rhoads
#if OS_CPU_COUNT <= 1
377 138 rhoads
/******************************************/
378 151 rhoads
//Loads a new thread 
379 138 rhoads
//Must be called with interrupts disabled
380 189 rhoads
static void OS_ThreadReschedule(int roundRobin)
381 138 rhoads
{
382 176 rhoads
   OS_Thread_t *threadNext, *threadCurrent, *threadTry;
383 138 rhoads
   int rc;
384
 
385
   if(ThreadSwapEnabled == 0 || InterruptInside)
386
   {
387 189 rhoads
      ThreadNeedReschedule |= 2 + roundRobin;  //Reschedule later
388 138 rhoads
      return;
389
   }
390
 
391
   //Determine which thread should run
392 176 rhoads
   threadCurrent = ThreadCurrent[0];
393 167 rhoads
   threadNext = threadCurrent;
394 176 rhoads
   if(threadCurrent == NULL || threadCurrent->state == THREAD_PEND)
395
      threadNext = ThreadHead;
396
   else if(threadCurrent->priority < ThreadHead->priority)
397
      threadNext = ThreadHead;
398 189 rhoads
   else if(roundRobin)
399 176 rhoads
   {
400
      //Determine next ready thread with same priority
401
      threadTry = threadCurrent->next;
402
      if(threadTry && threadTry->priority == threadCurrent->priority)
403
         threadNext = threadTry;
404
      else
405
         threadNext = ThreadHead;
406
   }
407
 
408
   if(threadNext != threadCurrent)
409
   {
410
      //Swap threads
411
      ThreadCurrent[0] = threadNext;
412
      assert(threadNext);
413
      if(threadCurrent)
414
      {
415
         assert(threadCurrent->magic[0] == THREAD_MAGIC); //check stack overflow
416
         rc = setjmp(threadCurrent->env);  //ANSI C call to save registers
417
         if(rc)
418
         {
419
            //Returned from longjmp()
420
            return;
421
         }
422
      }
423
 
424
      threadNext = ThreadCurrent[0];       //removed warning
425
      longjmp(threadNext->env, 1);         //ANSI C call to restore registers
426
   }
427
}
428
 
429 189 rhoads
#else //OS_CPU_COUNT > 1
430 176 rhoads
 
431
/******************************************/
432 189 rhoads
//Check if a different CPU needs to swap threads
433
static void OS_ThreadRescheduleCheck(void)
434 176 rhoads
{
435 189 rhoads
   OS_Thread_t *threadBest;
436
   uint32 i, priorityLow, cpuIndex = OS_CpuIndex();
437
   int cpuLow;
438 176 rhoads
 
439 189 rhoads
   //Find the CPU running the lowest priority thread
440 176 rhoads
   cpuLow = 0;
441
   priorityLow = 0xffffffff;
442
   for(i = 0; i < OS_CPU_COUNT; ++i)
443
   {
444
      if(i != cpuIndex && (ThreadCurrent[i] == NULL ||
445
         ThreadCurrent[i]->priority < priorityLow))
446
      {
447
         cpuLow = i;
448
         if(ThreadCurrent[i])
449
            priorityLow = ThreadCurrent[i]->priority;
450
         else
451
            priorityLow = 0;
452
      }
453
   }
454
 
455 189 rhoads
   //Determine highest priority ready thread for other CPUs
456
   for(threadBest = ThreadHead; threadBest && threadBest->priority > priorityLow;
457
      threadBest = threadBest->next)
458
   {
459
      if(threadBest->state == THREAD_READY)
460
      {
461
         if(threadBest->cpuLock == -1)
462
         {
463
            OS_CpuInterrupt(cpuLow, 1);  //Reschedule on the other CPU
464
            break;
465
         }
466
         else if(threadBest->priority > ThreadCurrent[threadBest->cpuLock]->priority)
467
         {
468
            OS_CpuInterrupt(threadBest->cpuLock, 1);  //Reschedule on the other CPU
469
            break;
470
         }
471
      }
472
   }
473
}
474
 
475
 
476
/******************************************/
477
//Loads a new thread in a multiprocessor environment
478
//Must be called with interrupts disabled
479
static void OS_ThreadReschedule(int roundRobin)
480
{
481
   OS_Thread_t *threadNext, *threadCurrent, *threadBest, *threadAlt;
482
   uint32 cpuIndex = OS_CpuIndex();
483
   int rc;
484
 
485
   if(ThreadSwapEnabled == 0 || InterruptInside)
486
   {
487
      ThreadNeedReschedule |= 2 + roundRobin;  //Reschedule later
488
      return;
489
   }
490
 
491
   //Determine highest priority ready thread
492 168 rhoads
   for(threadBest = ThreadHead; threadBest; threadBest = threadBest->next)
493
   {
494 176 rhoads
      if(threadBest->state == THREAD_READY &&
495
         (threadBest->cpuLock == -1 || threadBest->cpuLock == (int)cpuIndex))
496 168 rhoads
         break;
497
   }
498 176 rhoads
 
499
   //Determine which thread should run
500
   threadCurrent = ThreadCurrent[cpuIndex];
501
   threadNext = threadCurrent;
502
   if(threadCurrent == NULL || threadCurrent->state == THREAD_PEND)
503
   {
504 168 rhoads
      threadNext = threadBest;
505 176 rhoads
   }
506
   else if(threadBest && threadCurrent->priority < threadBest->priority)
507
   {
508 168 rhoads
      threadNext = threadBest;
509 176 rhoads
   }
510 189 rhoads
   else if(roundRobin)
511 138 rhoads
   {
512 176 rhoads
      //Find the next ready thread
513
      for(threadAlt = threadCurrent->next; threadAlt; threadAlt = threadAlt->next)
514 168 rhoads
      {
515 176 rhoads
         if(threadAlt->state == THREAD_READY &&
516
            (threadAlt->cpuLock == -1 || threadAlt->cpuLock == (int)cpuIndex))
517 168 rhoads
            break;
518
      }
519 176 rhoads
      if(threadAlt && threadAlt->priority == threadCurrent->priority)
520
         threadNext = threadAlt;
521
      else if(threadBest && threadBest->priority >= threadCurrent->priority)
522 168 rhoads
         threadNext = threadBest;
523 138 rhoads
   }
524
 
525 167 rhoads
   if(threadNext != threadCurrent)
526 138 rhoads
   {
527
      //Swap threads
528 167 rhoads
      ThreadCurrent[cpuIndex] = threadNext;
529
      assert(threadNext);
530 168 rhoads
      if(threadCurrent)
531 138 rhoads
      {
532 168 rhoads
         assert(threadCurrent->magic[0] == THREAD_MAGIC); //check stack overflow
533
         threadCurrent->state = THREAD_READY;
534 176 rhoads
         threadCurrent->spinLocks = OS_SpinCountGet();
535 189 rhoads
         threadCurrent->cpuIndex = -1;
536 176 rhoads
         rc = setjmp(threadCurrent->env);   //ANSI C call to save registers
537 138 rhoads
         if(rc)
538
         {
539
            //Returned from longjmp()
540
            return;
541
         }
542
      }
543 168 rhoads
 
544 176 rhoads
      //Restore spin lock count
545 167 rhoads
      cpuIndex = OS_CpuIndex();             //removed warning
546
      threadNext = ThreadCurrent[cpuIndex]; //removed warning
547 176 rhoads
      threadNext->state = THREAD_RUNNING;
548
      OS_SpinCountSet(threadNext->spinLocks);
549 189 rhoads
      threadNext->cpuIndex = (int)cpuIndex;
550
      OS_ThreadRescheduleCheck();
551 176 rhoads
      longjmp(threadNext->env, 1);          //ANSI C call to restore registers
552 138 rhoads
   }
553 189 rhoads
   OS_ThreadRescheduleCheck();
554 138 rhoads
}
555
 
556
 
557 189 rhoads
/******************************************/
558 176 rhoads
void OS_ThreadCpuLock(OS_Thread_t *Thread, int CpuIndex)
559
{
560
   Thread->cpuLock = CpuIndex;
561
   if(Thread == OS_ThreadSelf() && CpuIndex != (int)OS_CpuIndex())
562
      OS_ThreadSleep(1);
563
}
564
 
565
#endif //#if OS_CPU_COUNT <= 1
566
 
567
 
568 138 rhoads
/******************************************/
569 189 rhoads
static void OS_ThreadInit(void *arg)
570 138 rhoads
{
571 167 rhoads
   uint32 cpuIndex = OS_CpuIndex();
572 189 rhoads
   (void)arg;
573 138 rhoads
 
574 168 rhoads
   OS_CriticalEnd(1);
575 167 rhoads
   ThreadCurrent[cpuIndex]->funcPtr(ThreadCurrent[cpuIndex]->arg);
576 138 rhoads
   OS_ThreadExit();
577
}
578
 
579
 
580
/******************************************/
581
//Stops warning "argument X might be clobbered by `longjmp'"
582
static void OS_ThreadRegsInit(jmp_buf env)
583
{
584
   setjmp(env); //ANSI C call to save registers
585
}
586
 
587
 
588
/******************************************/
589 189 rhoads
OS_Thread_t *OS_ThreadCreate(const char *name,
590
                             OS_FuncPtr_t funcPtr,
591
                             void *arg,
592
                             uint32 priority,
593
                             uint32 stackSize)
594 138 rhoads
{
595
   OS_Thread_t *thread;
596
   uint8 *stack;
597
   jmp_buf2 *env;
598
   uint32 state;
599
 
600
   OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
601
   if(NeedToFree)
602
      OS_HeapFree(NeedToFree);
603
   NeedToFree = NULL;
604
   OS_SemaphorePost(SemaphoreLock);
605
 
606 189 rhoads
   if(stackSize == 0)
607
      stackSize = STACK_SIZE_DEFAULT;
608
   if(stackSize < STACK_SIZE_MINIMUM)
609
      stackSize = STACK_SIZE_MINIMUM;
610
   thread = (OS_Thread_t*)OS_HeapMalloc(NULL, sizeof(OS_Thread_t) + stackSize);
611 138 rhoads
   assert(thread);
612
   if(thread == NULL)
613
      return NULL;
614 189 rhoads
   memset(thread, 0, sizeof(OS_Thread_t));
615 138 rhoads
   stack = (uint8*)(thread + 1);
616 189 rhoads
   memset(stack, 0xcd, stackSize);
617 138 rhoads
 
618 189 rhoads
   thread->name = name;
619 168 rhoads
   thread->state = THREAD_READY;
620 176 rhoads
   thread->cpuLock = -1;
621 189 rhoads
   thread->funcPtr = funcPtr;
622
   thread->arg = arg;
623
   thread->priority = priority;
624 138 rhoads
   thread->info = NULL;
625
   thread->semaphorePending = NULL;
626
   thread->returnCode = 0;
627 167 rhoads
   thread->spinLocks = 1;
628 189 rhoads
   if(OS_ThreadSelf())
629
   {
630
      thread->processId = OS_ThreadSelf()->processId;
631
      thread->heap = OS_ThreadSelf()->heap;
632
   }
633
   else
634
   {
635
      thread->processId = 0;
636
      thread->heap = NULL;
637
   }
638 138 rhoads
   thread->next = NULL;
639
   thread->prev = NULL;
640
   thread->nextTimeout = NULL;
641
   thread->prevTimeout = NULL;
642
   thread->magic[0] = THREAD_MAGIC;
643
 
644
   OS_ThreadRegsInit(thread->env);
645
   env = (jmp_buf2*)thread->env;
646 200 rhoads
   env->sp = (uint32)stack + stackSize - 24; //minimum stack frame size
647 138 rhoads
   env->pc = (uint32)OS_ThreadInit;
648
 
649
   state = OS_CriticalBegin();
650
   OS_ThreadPriorityInsert(&ThreadHead, thread);
651
   OS_ThreadReschedule(0);
652
   OS_CriticalEnd(state);
653
   return thread;
654
}
655
 
656
 
657
/******************************************/
658
void OS_ThreadExit(void)
659
{
660 167 rhoads
   uint32 state, cpuIndex = OS_CpuIndex();
661 138 rhoads
   OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
662
   if(NeedToFree)
663
      OS_HeapFree(NeedToFree);
664
   NeedToFree = NULL;
665
   OS_SemaphorePost(SemaphoreLock);
666
 
667
   state = OS_CriticalBegin();
668 167 rhoads
   OS_ThreadPriorityRemove(&ThreadHead, ThreadCurrent[cpuIndex]);
669
   NeedToFree = ThreadCurrent[cpuIndex];
670 138 rhoads
   OS_ThreadReschedule(0);
671
   OS_CriticalEnd(state);
672
}
673
 
674
 
675
/******************************************/
676
OS_Thread_t *OS_ThreadSelf(void)
677
{
678 167 rhoads
   return ThreadCurrent[OS_CpuIndex()];
679 138 rhoads
}
680
 
681
 
682
/******************************************/
683 189 rhoads
void OS_ThreadSleep(int ticks)
684 138 rhoads
{
685 189 rhoads
   OS_SemaphorePend(SemaphoreSleep, ticks);
686 138 rhoads
}
687
 
688
 
689
/******************************************/
690
uint32 OS_ThreadTime(void)
691
{
692
   return ThreadTime;
693
}
694
 
695
 
696
/******************************************/
697 189 rhoads
void OS_ThreadInfoSet(OS_Thread_t *thread, void *Info)
698 138 rhoads
{
699 189 rhoads
   thread->info = Info;
700 138 rhoads
}
701
 
702
 
703
/******************************************/
704 189 rhoads
void *OS_ThreadInfoGet(OS_Thread_t *thread)
705 138 rhoads
{
706 189 rhoads
   return thread->info;
707 138 rhoads
}
708
 
709
 
710
/******************************************/
711 189 rhoads
uint32 OS_ThreadPriorityGet(OS_Thread_t *thread)
712 138 rhoads
{
713 189 rhoads
   return thread->priority;
714 138 rhoads
}
715
 
716
 
717
/******************************************/
718 189 rhoads
void OS_ThreadPrioritySet(OS_Thread_t *thread, uint32 priority)
719 138 rhoads
{
720
   uint32 state;
721
   state = OS_CriticalBegin();
722 189 rhoads
   thread->priority = priority;
723
   if(thread->state != THREAD_PEND)
724 168 rhoads
   {
725 189 rhoads
      OS_ThreadPriorityRemove(&ThreadHead, thread);
726
      OS_ThreadPriorityInsert(&ThreadHead, thread);
727 168 rhoads
      OS_ThreadReschedule(0);
728
   }
729 138 rhoads
   OS_CriticalEnd(state);
730
}
731
 
732
 
733
/******************************************/
734 189 rhoads
void OS_ThreadProcessId(OS_Thread_t *thread, uint32 processId, OS_Heap_t *heap)
735
{
736
   thread->processId = processId;
737
   thread->heap = heap;
738
}
739
 
740
 
741
/******************************************/
742 138 rhoads
//Must be called with interrupts disabled
743
void OS_ThreadTick(void *Arg)
744
{
745
   OS_Thread_t *thread;
746
   OS_Semaphore_t *semaphore;
747
   int diff;
748
   (void)Arg;
749
 
750
   ++ThreadTime;
751
   while(TimeoutHead)
752
   {
753
      thread = TimeoutHead;
754
      diff = ThreadTime - thread->ticksTimeout;
755
      if(diff < 0)
756
         break;
757
      OS_ThreadTimeoutRemove(thread);
758
      semaphore = thread->semaphorePending;
759
      ++semaphore->count;
760
      thread->semaphorePending = NULL;
761
      thread->returnCode = -1;
762
      OS_ThreadPriorityRemove(&semaphore->threadHead, thread);
763
      OS_ThreadPriorityInsert(&ThreadHead, thread);
764
   }
765
   OS_ThreadReschedule(1);
766
}
767
 
768
 
769
 
770
/***************** Semaphore **************/
771
/******************************************/
772 189 rhoads
OS_Semaphore_t *OS_SemaphoreCreate(const char *name, uint32 count)
773 138 rhoads
{
774
   OS_Semaphore_t *semaphore;
775 189 rhoads
   static int semCount = 0;
776 138 rhoads
 
777
   if(semCount < SEM_RESERVED_COUNT)
778 189 rhoads
      semaphore = &SemaphoreReserved[semCount++];  //Heap not ready yet
779 138 rhoads
   else
780 189 rhoads
      semaphore = (OS_Semaphore_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Semaphore_t));
781 138 rhoads
   assert(semaphore);
782
   if(semaphore == NULL)
783
      return NULL;
784
 
785 189 rhoads
   semaphore->name = name;
786 138 rhoads
   semaphore->threadHead = NULL;
787 189 rhoads
   semaphore->count = count;
788 138 rhoads
   return semaphore;
789
}
790
 
791
 
792
/******************************************/
793 189 rhoads
void OS_SemaphoreDelete(OS_Semaphore_t *semaphore)
794 138 rhoads
{
795 189 rhoads
   while(semaphore->threadHead)
796
      OS_SemaphorePost(semaphore);
797
   OS_HeapFree(semaphore);
798 138 rhoads
}
799
 
800
 
801
/******************************************/
802 189 rhoads
int OS_SemaphorePend(OS_Semaphore_t *semaphore, int ticks)
803 138 rhoads
{
804 167 rhoads
   uint32 state, cpuIndex;
805 138 rhoads
   OS_Thread_t *thread;
806
   int returnCode=0;
807
 
808 189 rhoads
   assert(semaphore);
809 151 rhoads
   assert(InterruptInside == 0);
810 138 rhoads
   state = OS_CriticalBegin();
811 189 rhoads
   if(--semaphore->count < 0)
812 138 rhoads
   {
813 189 rhoads
      if(ticks == 0)
814 138 rhoads
      {
815 189 rhoads
         ++semaphore->count;
816 138 rhoads
         OS_CriticalEnd(state);
817
         return -1;
818
      }
819 189 rhoads
      cpuIndex = OS_CpuIndex();
820 167 rhoads
      thread = ThreadCurrent[cpuIndex];
821 189 rhoads
      assert(thread);
822
      thread->semaphorePending = semaphore;
823
      thread->ticksTimeout = ticks + OS_ThreadTime();
824 138 rhoads
      OS_ThreadPriorityRemove(&ThreadHead, thread);
825 189 rhoads
      OS_ThreadPriorityInsert(&semaphore->threadHead, thread);
826
      if(ticks != OS_WAIT_FOREVER)
827 138 rhoads
         OS_ThreadTimeoutInsert(thread);
828
      assert(ThreadHead);
829
      OS_ThreadReschedule(0);
830
      returnCode = thread->returnCode;
831
   }
832
   OS_CriticalEnd(state);
833
   return returnCode;
834
}
835
 
836
 
837
/******************************************/
838 189 rhoads
void OS_SemaphorePost(OS_Semaphore_t *semaphore)
839 138 rhoads
{
840
   uint32 state;
841 146 rhoads
   OS_Thread_t *thread;
842 138 rhoads
 
843 189 rhoads
   assert(semaphore);
844 138 rhoads
   state = OS_CriticalBegin();
845 189 rhoads
   if(++semaphore->count <= 0)
846 138 rhoads
   {
847 189 rhoads
      thread = semaphore->threadHead;
848 138 rhoads
      OS_ThreadTimeoutRemove(thread);
849 189 rhoads
      OS_ThreadPriorityRemove(&semaphore->threadHead, thread);
850 138 rhoads
      OS_ThreadPriorityInsert(&ThreadHead, thread);
851
      thread->semaphorePending = NULL;
852
      thread->returnCode = 0;
853 146 rhoads
      OS_ThreadReschedule(0);
854 138 rhoads
   }
855
   OS_CriticalEnd(state);
856
}
857
 
858
 
859
 
860
/***************** Mutex ******************/
861
/******************************************/
862 189 rhoads
OS_Mutex_t *OS_MutexCreate(const char *name)
863 138 rhoads
{
864
   OS_Mutex_t *mutex;
865
 
866 189 rhoads
   mutex = (OS_Mutex_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Mutex_t));
867 138 rhoads
   if(mutex == NULL)
868
      return NULL;
869 189 rhoads
   mutex->semaphore = OS_SemaphoreCreate(name, 1);
870 138 rhoads
   if(mutex->semaphore == NULL)
871
      return NULL;
872
   mutex->thread = NULL;
873
   mutex->count = 0;
874
   return mutex;
875
}
876
 
877
 
878
/******************************************/
879 189 rhoads
void OS_MutexDelete(OS_Mutex_t *mutex)
880 138 rhoads
{
881 189 rhoads
   OS_SemaphoreDelete(mutex->semaphore);
882
   OS_HeapFree(mutex);
883 138 rhoads
}
884
 
885
 
886
/******************************************/
887 189 rhoads
void OS_MutexPend(OS_Mutex_t *mutex)
888 138 rhoads
{
889
   OS_Thread_t *thread;
890
 
891 189 rhoads
   assert(mutex);
892 138 rhoads
   thread = OS_ThreadSelf();
893 189 rhoads
   if(thread == mutex->thread)
894 138 rhoads
   {
895 189 rhoads
      ++mutex->count;
896 138 rhoads
      return;
897
   }
898 189 rhoads
   OS_SemaphorePend(mutex->semaphore, OS_WAIT_FOREVER);
899
   mutex->thread = thread;
900
   mutex->count = 1;
901 138 rhoads
}
902
 
903
 
904
/******************************************/
905 189 rhoads
void OS_MutexPost(OS_Mutex_t *mutex)
906 138 rhoads
{
907 189 rhoads
   assert(mutex);
908
   assert(mutex->thread == OS_ThreadSelf());
909
   assert(mutex->count > 0);
910
   if(--mutex->count <= 0)
911 138 rhoads
   {
912 189 rhoads
      mutex->thread = NULL;
913
      OS_SemaphorePost(mutex->semaphore);
914 138 rhoads
   }
915
}
916
 
917
 
918
 
919
/***************** MQueue *****************/
920
/******************************************/
921 189 rhoads
OS_MQueue_t *OS_MQueueCreate(const char *name,
922
                             int messageCount,
923
                             int messageBytes)
924 138 rhoads
{
925
   OS_MQueue_t *queue;
926
   int size;
927
 
928 189 rhoads
   size = messageBytes / sizeof(uint32);
929
   queue = (OS_MQueue_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_MQueue_t) +
930
      messageCount * size * 4);
931 138 rhoads
   if(queue == NULL)
932
      return queue;
933 189 rhoads
   queue->name = name;
934
   queue->semaphore = OS_SemaphoreCreate(name, 0);
935 138 rhoads
   if(queue->semaphore == NULL)
936
      return NULL;
937 189 rhoads
   queue->count = messageCount;
938 138 rhoads
   queue->size = size;
939
   queue->used = 0;
940
   queue->read = 0;
941
   queue->write = 0;
942
   return queue;
943
}
944
 
945
 
946
/******************************************/
947 189 rhoads
void OS_MQueueDelete(OS_MQueue_t *mQueue)
948 138 rhoads
{
949 189 rhoads
   OS_SemaphoreDelete(mQueue->semaphore);
950
   OS_HeapFree(mQueue);
951 138 rhoads
}
952
 
953
 
954
/******************************************/
955 189 rhoads
int OS_MQueueSend(OS_MQueue_t *mQueue, void *message)
956 138 rhoads
{
957
   uint32 state, *dst, *src;
958
   int i;
959
 
960 189 rhoads
   assert(mQueue);
961
   src = (uint32*)message;
962 138 rhoads
   state = OS_CriticalBegin();
963 189 rhoads
   if(++mQueue->used > mQueue->count)
964 138 rhoads
   {
965 189 rhoads
      --mQueue->used;
966 138 rhoads
      OS_CriticalEnd(state);
967
      return -1;
968
   }
969 189 rhoads
   dst = (uint32*)(mQueue + 1) + mQueue->write * mQueue->size;
970
   for(i = 0; i < mQueue->size; ++i)
971 138 rhoads
      dst[i] = src[i];
972 189 rhoads
   if(++mQueue->write >= mQueue->count)
973
      mQueue->write = 0;
974 138 rhoads
   OS_CriticalEnd(state);
975 189 rhoads
   OS_SemaphorePost(mQueue->semaphore);
976 138 rhoads
   return 0;
977
}
978
 
979
 
980
/******************************************/
981 189 rhoads
int OS_MQueueGet(OS_MQueue_t *mQueue, void *message, int ticks)
982 138 rhoads
{
983
   uint32 state, *dst, *src;
984
   int i, rc;
985
 
986 189 rhoads
   assert(mQueue);
987
   dst = (uint32*)message;
988
   rc = OS_SemaphorePend(mQueue->semaphore, ticks);
989 138 rhoads
   if(rc)
990
      return rc;
991
   state = OS_CriticalBegin();
992 189 rhoads
   --mQueue->used;
993
   src = (uint32*)(mQueue + 1) + mQueue->read * mQueue->size;
994
   for(i = 0; i < mQueue->size; ++i)
995 138 rhoads
      dst[i] = src[i];
996 189 rhoads
   if(++mQueue->read >= mQueue->count)
997
      mQueue->read = 0;
998 138 rhoads
   OS_CriticalEnd(state);
999
   return 0;
1000
}
1001
 
1002
 
1003
 
1004 223 rhoads
/***************** Jobs *******************/
1005
/******************************************/
1006
typedef void (*JobFunc_t)();
1007
static OS_MQueue_t *jobQueue;
1008
static OS_Thread_t *jobThread;
1009
 
1010
static void JobThread(void *arg)
1011
{
1012
   uint32 message[4];
1013
   JobFunc_t funcPtr;
1014
   (void)arg;
1015
   for(;;)
1016
   {
1017
      OS_MQueueGet(jobQueue, message, OS_WAIT_FOREVER);
1018
      funcPtr = (JobFunc_t)message[0];
1019
      funcPtr(message[1], message[2], message[3]);
1020
   }
1021
}
1022
 
1023
 
1024
/******************************************/
1025
void OS_Job(void (*funcPtr)(), void *arg0, void *arg1, void *arg2)
1026
{
1027
   uint32 message[4];
1028
   int rc;
1029
 
1030
   if(jobThread == NULL)
1031
   {
1032
      jobQueue = OS_MQueueCreate("job", 100, 16);
1033
      jobThread = OS_ThreadCreate("job", JobThread, NULL, 150, 4000);
1034
   }
1035
   message[0] = (uint32)funcPtr;
1036
   message[1] = (uint32)arg0;
1037
   message[2] = (uint32)arg1;
1038
   message[3] = (uint32)arg2;
1039
   do
1040
   {
1041
      rc = OS_MQueueSend(jobQueue, message);
1042
      if(rc)
1043
         OS_ThreadSleep(1);
1044
   } while(rc);
1045
}
1046
 
1047
 
1048 138 rhoads
/***************** Timer ******************/
1049
/******************************************/
1050 189 rhoads
static void OS_TimerThread(void *arg)
1051 138 rhoads
{
1052
   uint32 timeNow;
1053
   int diff, ticks;
1054
   uint32 message[8];
1055
   OS_Timer_t *timer;
1056 189 rhoads
   (void)arg;
1057 138 rhoads
 
1058
   timeNow = OS_ThreadTime();
1059
   for(;;)
1060
   {
1061
      //Determine how long to sleep
1062
      OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
1063
      if(TimerHead)
1064
         ticks = TimerHead->ticksTimeout - timeNow;
1065
      else
1066
         ticks = OS_WAIT_FOREVER;
1067
      OS_SemaphorePost(SemaphoreLock);
1068
      OS_SemaphorePend(SemaphoreTimer, ticks);
1069
 
1070
      //Send messages for all timed out timers
1071
      timeNow = OS_ThreadTime();
1072
      for(;;)
1073
      {
1074 189 rhoads
         timer = NULL;
1075 138 rhoads
         OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
1076 189 rhoads
         if(TimerHead)
1077 138 rhoads
         {
1078 189 rhoads
            diff = timeNow - TimerHead->ticksTimeout;
1079
            if(diff >= 0)
1080
               timer = TimerHead;
1081 138 rhoads
         }
1082 189 rhoads
         OS_SemaphorePost(SemaphoreLock);
1083
         if(timer == NULL)
1084 138 rhoads
            break;
1085
         if(timer->ticksRestart)
1086
            OS_TimerStart(timer, timer->ticksRestart, timer->ticksRestart);
1087
         else
1088
            OS_TimerStop(timer);
1089
 
1090 218 rhoads
         if(timer->callback)
1091
            timer->callback(timer, timer->info);
1092
         else
1093
         {
1094
            //Send message
1095
            message[0] = MESSAGE_TYPE_TIMER;
1096
            message[1] = (uint32)timer;
1097
            message[2] = timer->info;
1098
            OS_MQueueSend(timer->mqueue, message);
1099
         }
1100 138 rhoads
      }
1101
   }
1102
}
1103
 
1104
 
1105
/******************************************/
1106 189 rhoads
OS_Timer_t *OS_TimerCreate(const char *name, OS_MQueue_t *mQueue, uint32 info)
1107 138 rhoads
{
1108
   OS_Timer_t *timer;
1109
   int startThread=0;
1110
 
1111
   OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
1112
   if(SemaphoreTimer == NULL)
1113
   {
1114
      SemaphoreTimer = OS_SemaphoreCreate("Timer", 0);
1115
      startThread = 1;
1116
   }
1117
   OS_SemaphorePost(SemaphoreLock);
1118
   if(startThread)
1119
      OS_ThreadCreate("Timer", OS_TimerThread, NULL, 250, 2000);
1120
 
1121 189 rhoads
   timer = (OS_Timer_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Timer_t));
1122 138 rhoads
   if(timer == NULL)
1123
      return NULL;
1124 189 rhoads
   timer->name = name;
1125 218 rhoads
   timer->callback = NULL;
1126 189 rhoads
   timer->mqueue = mQueue;
1127 138 rhoads
   timer->next = NULL;
1128
   timer->prev = NULL;
1129 189 rhoads
   timer->info = info;
1130 138 rhoads
   timer->active = 0;
1131
   return timer;
1132
}
1133
 
1134
 
1135
/******************************************/
1136 189 rhoads
void OS_TimerDelete(OS_Timer_t *timer)
1137 138 rhoads
{
1138 189 rhoads
   OS_TimerStop(timer);
1139
   OS_HeapFree(timer);
1140 138 rhoads
}
1141
 
1142
 
1143
/******************************************/
1144 218 rhoads
void OS_TimerCallback(OS_Timer_t *timer, OS_TimerFuncPtr_t callback)
1145
{
1146
   timer->callback = callback;
1147
}
1148
 
1149
 
1150
/******************************************/
1151 138 rhoads
//Must not be called from an ISR
1152 189 rhoads
void OS_TimerStart(OS_Timer_t *timer, uint32 ticks, uint32 ticksRestart)
1153 138 rhoads
{
1154
   OS_Timer_t *node, *prev;
1155
   int diff, check=0;
1156
 
1157 189 rhoads
   assert(timer);
1158 167 rhoads
   assert(InterruptInside == 0);
1159 189 rhoads
   ticks += OS_ThreadTime();
1160
   if(timer->active)
1161
      OS_TimerStop(timer);
1162 138 rhoads
   OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
1163 189 rhoads
   if(timer->active)
1164
   {
1165
      //Prevent race condition
1166
      OS_SemaphorePost(SemaphoreLock);
1167
      return;
1168
   }
1169
   timer->ticksTimeout = ticks;
1170
   timer->ticksRestart = ticksRestart;
1171
   timer->active = 1;
1172 138 rhoads
   prev = NULL;
1173
   for(node = TimerHead; node; node = node->next)
1174
   {
1175 189 rhoads
      diff = ticks - node->ticksTimeout;
1176 138 rhoads
      if(diff <= 0)
1177
         break;
1178
      prev = node;
1179
   }
1180 189 rhoads
   timer->next = node;
1181
   timer->prev = prev;
1182 138 rhoads
   if(node)
1183 189 rhoads
      node->prev = timer;
1184 138 rhoads
   if(prev == NULL)
1185
   {
1186 189 rhoads
      TimerHead = timer;
1187 138 rhoads
      check = 1;
1188
   }
1189
   else
1190 189 rhoads
      prev->next = timer;
1191 138 rhoads
   OS_SemaphorePost(SemaphoreLock);
1192
   if(check)
1193
      OS_SemaphorePost(SemaphoreTimer);
1194
}
1195
 
1196
 
1197
/******************************************/
1198
//Must not be called from an ISR
1199 189 rhoads
void OS_TimerStop(OS_Timer_t *timer)
1200 138 rhoads
{
1201 189 rhoads
   assert(timer);
1202 167 rhoads
   assert(InterruptInside == 0);
1203 138 rhoads
   OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
1204 189 rhoads
   if(timer->active)
1205 138 rhoads
   {
1206 189 rhoads
      timer->active = 0;
1207
      if(timer->prev == NULL)
1208
         TimerHead = timer->next;
1209 138 rhoads
      else
1210 189 rhoads
         timer->prev->next = timer->next;
1211
      if(timer->next)
1212
         timer->next->prev = timer->prev;
1213 138 rhoads
   }
1214
   OS_SemaphorePost(SemaphoreLock);
1215
}
1216
 
1217
 
1218
/***************** ISR ********************/
1219
/******************************************/
1220 189 rhoads
void OS_InterruptServiceRoutine(uint32 status, uint32 *stack)
1221 138 rhoads
{
1222
   int i;
1223 167 rhoads
   uint32 state;
1224 138 rhoads
 
1225 189 rhoads
   if(status == 0 && Isr[31])
1226
      Isr[31](stack);                   //SYSCALL or BREAK
1227
 
1228 138 rhoads
   InterruptInside = 1;
1229
   i = 0;
1230
   do
1231
   {
1232 189 rhoads
      if(status & 1)
1233 138 rhoads
      {
1234
         if(Isr[i])
1235 189 rhoads
            Isr[i](stack);
1236 138 rhoads
         else
1237
            OS_InterruptMaskClear(1 << i);
1238
      }
1239 189 rhoads
      status >>= 1;
1240 138 rhoads
      ++i;
1241 189 rhoads
   } while(status);
1242 138 rhoads
   InterruptInside = 0;
1243
 
1244 167 rhoads
   state = OS_SpinLock();
1245 138 rhoads
   if(ThreadNeedReschedule)
1246
      OS_ThreadReschedule(ThreadNeedReschedule & 1);
1247 167 rhoads
   OS_SpinUnlock(state);
1248 138 rhoads
}
1249
 
1250
 
1251
/******************************************/
1252 189 rhoads
void OS_InterruptRegister(uint32 mask, OS_FuncPtr_t funcPtr)
1253 138 rhoads
{
1254
   int i;
1255
 
1256
   for(i = 0; i < 32; ++i)
1257
   {
1258 189 rhoads
      if(mask & (1 << i))
1259
         Isr[i] = funcPtr;
1260 138 rhoads
   }
1261
}
1262
 
1263
 
1264
/******************************************/
1265
//Plasma hardware dependent
1266
uint32 OS_InterruptStatus(void)
1267
{
1268
   return MemoryRead(IRQ_STATUS);
1269
}
1270
 
1271
 
1272
/******************************************/
1273
//Plasma hardware dependent
1274 189 rhoads
uint32 OS_InterruptMaskSet(uint32 mask)
1275 138 rhoads
{
1276 189 rhoads
   uint32 state;
1277 138 rhoads
   state = OS_CriticalBegin();
1278 189 rhoads
   mask |= MemoryRead(IRQ_MASK);
1279 138 rhoads
   MemoryWrite(IRQ_MASK, mask);
1280
   OS_CriticalEnd(state);
1281
   return mask;
1282
}
1283
 
1284
 
1285
/******************************************/
1286
//Plasma hardware dependent
1287 189 rhoads
uint32 OS_InterruptMaskClear(uint32 mask)
1288 138 rhoads
{
1289 189 rhoads
   uint32 state;
1290 138 rhoads
   state = OS_CriticalBegin();
1291 189 rhoads
   mask = MemoryRead(IRQ_MASK) & ~mask;
1292 138 rhoads
   MemoryWrite(IRQ_MASK, mask);
1293
   OS_CriticalEnd(state);
1294
   return mask;
1295
}
1296
 
1297
 
1298
/**************** Init ********************/
1299
/******************************************/
1300
static volatile uint32 IdleCount;
1301 189 rhoads
static void OS_IdleThread(void *arg)
1302 138 rhoads
{
1303 189 rhoads
   (void)arg;
1304 138 rhoads
 
1305 151 rhoads
   //Don't block in the idle thread!
1306 138 rhoads
   for(;;)
1307
   {
1308
      ++IdleCount;
1309
   }
1310
}
1311
 
1312
 
1313
/******************************************/
1314
#ifndef DISABLE_IRQ_SIM
1315 189 rhoads
static void OS_IdleSimulateIsr(void *arg)
1316 138 rhoads
{
1317
   uint32 count=0, value;
1318 189 rhoads
   (void)arg;
1319 138 rhoads
 
1320
   for(;;)
1321
   {
1322
      MemoryRead(IRQ_MASK + 4);       //calls Sleep(10)
1323
#if WIN32
1324
      while(OS_InterruptMaskSet(0) & IRQ_UART_WRITE_AVAILABLE)
1325 176 rhoads
         OS_InterruptServiceRoutine(IRQ_UART_WRITE_AVAILABLE, 0);
1326 138 rhoads
#endif
1327 189 rhoads
      value = OS_InterruptMaskSet(0) & 0xf;
1328
      if(value)
1329
         OS_InterruptServiceRoutine(value, 0);
1330 138 rhoads
      ++count;
1331
   }
1332
}
1333
#endif //DISABLE_IRQ_SIM
1334
 
1335
 
1336
/******************************************/
1337
//Plasma hardware dependent
1338 189 rhoads
static void OS_ThreadTickToggle(void *arg)
1339 138 rhoads
{
1340 167 rhoads
   uint32 status, mask, state;
1341 138 rhoads
 
1342 189 rhoads
   //Toggle looking for IRQ_COUNTER18 or IRQ_COUNTER18_NOT
1343 167 rhoads
   state = OS_SpinLock();
1344 138 rhoads
   status = MemoryRead(IRQ_STATUS) & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT);
1345
   mask = MemoryRead(IRQ_MASK) | IRQ_COUNTER18 | IRQ_COUNTER18_NOT;
1346
   mask &= ~status;
1347
   MemoryWrite(IRQ_MASK, mask);
1348 189 rhoads
   OS_ThreadTick(arg);
1349 167 rhoads
   OS_SpinUnlock(state);
1350 138 rhoads
}
1351
 
1352
 
1353
/******************************************/
1354 189 rhoads
void OS_Init(uint32 *heapStorage, uint32 bytes)
1355 138 rhoads
{
1356 168 rhoads
   int i;
1357 138 rhoads
   OS_AsmInterruptInit();               //Patch interrupt vector
1358
   OS_InterruptMaskClear(0xffffffff);   //Disable interrupts
1359 189 rhoads
   HeapArray[0] = OS_HeapCreate("Default", heapStorage, bytes);
1360
   HeapArray[1] = HeapArray[0];
1361 138 rhoads
   SemaphoreSleep = OS_SemaphoreCreate("Sleep", 0);
1362
   SemaphoreLock = OS_SemaphoreCreate("Lock", 1);
1363 168 rhoads
   for(i = 0; i < OS_CPU_COUNT; ++i)
1364
      OS_ThreadCreate("Idle", OS_IdleThread, NULL, 0, 256);
1365 138 rhoads
#ifndef DISABLE_IRQ_SIM
1366
   if((OS_InterruptStatus() & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT)) == 0)
1367
   {
1368
      //Detected that running in simulator so create SimIsr thread
1369
      UartPrintfCritical("SimIsr\n");
1370
      OS_ThreadCreate("SimIsr", OS_IdleSimulateIsr, NULL, 1, 0);
1371
   }
1372
#endif //DISABLE_IRQ_SIM
1373
 
1374
   //Plasma hardware dependent
1375 189 rhoads
   OS_InterruptRegister(IRQ_COUNTER18 | IRQ_COUNTER18_NOT, OS_ThreadTickToggle);
1376 138 rhoads
   OS_InterruptMaskSet(IRQ_COUNTER18 | IRQ_COUNTER18_NOT);
1377
}
1378
 
1379
 
1380
/******************************************/
1381
void OS_Start(void)
1382
{
1383
   ThreadSwapEnabled = 1;
1384 167 rhoads
   (void)OS_SpinLock();
1385 138 rhoads
   OS_ThreadReschedule(1);
1386
}
1387
 
1388
 
1389
/******************************************/
1390
//Place breakpoint here
1391
void OS_Assert(void)
1392
{
1393
}
1394
 
1395
 
1396 167 rhoads
#if OS_CPU_COUNT > 1
1397
static uint8 SpinLockArray[OS_CPU_COUNT];
1398
/******************************************/
1399
uint32 OS_CpuIndex(void)
1400
{
1401
   return 0; //0 to OS_CPU_COUNT-1
1402
}
1403
 
1404
 
1405
/******************************************/
1406
//Symmetric Multiprocessing Spin Lock Mutex
1407
uint32 OS_SpinLock(void)
1408
{
1409 168 rhoads
   uint32 state, cpuIndex, i, j, ok, delay;
1410 167 rhoads
 
1411 168 rhoads
   cpuIndex = OS_CpuIndex();
1412
   delay = cpuIndex + 8;
1413 167 rhoads
   state = OS_AsmInterruptEnable(0);
1414
   do
1415
   {
1416
      ok = 1;
1417 168 rhoads
      if(++SpinLockArray[cpuIndex] == 1)
1418 167 rhoads
      {
1419
         for(i = 0; i < OS_CPU_COUNT; ++i)
1420
         {
1421 168 rhoads
            if(i != cpuIndex && SpinLockArray[i])
1422 167 rhoads
               ok = 0;
1423
         }
1424
         if(ok == 0)
1425
         {
1426 168 rhoads
            SpinLockArray[cpuIndex] = 0;
1427
            for(j = 0; j < delay; ++j)  //wait a bit
1428 167 rhoads
               ++i;
1429 168 rhoads
            if(delay < 128)
1430
               delay <<= 1;
1431 167 rhoads
         }
1432
      }
1433
   } while(ok == 0);
1434
   return state;
1435
}
1436
 
1437
 
1438
/******************************************/
1439
void OS_SpinUnlock(uint32 state)
1440
{
1441 168 rhoads
   uint32 cpuIndex;
1442
   cpuIndex = OS_CpuIndex();
1443
   if(--SpinLockArray[cpuIndex] == 0)
1444 167 rhoads
      OS_AsmInterruptEnable(state);
1445 168 rhoads
 
1446
   assert(SpinLockArray[cpuIndex] < 10);
1447 167 rhoads
}
1448
 
1449
 
1450
/******************************************/
1451
//Must be called with interrupts disabled and spin locked
1452 176 rhoads
uint32 OS_SpinCountGet(void)
1453 167 rhoads
{
1454 168 rhoads
   uint32 cpuIndex, count;
1455
   cpuIndex = OS_CpuIndex();
1456
   count = SpinLockArray[cpuIndex];
1457 167 rhoads
   return count;
1458
}
1459
 
1460
 
1461
/******************************************/
1462
//Must be called with interrupts disabled and spin locked
1463 176 rhoads
void OS_SpinCountSet(uint32 count)
1464 167 rhoads
{
1465 168 rhoads
   uint32 cpuIndex;
1466
   cpuIndex = OS_CpuIndex();
1467
   SpinLockArray[cpuIndex] = (uint8)count;
1468
   assert(count);
1469 167 rhoads
}
1470 176 rhoads
 
1471
 
1472
/******************************************/
1473
void OS_CpuInterrupt(uint32 cpuIndex, uint32 bitfield)
1474
{
1475 189 rhoads
   //Request other CPU to reschedule threads
1476 176 rhoads
   (void)cpuIndex;
1477
   (void)bitfield;
1478
}
1479
 
1480
 
1481
/******************************************/
1482 189 rhoads
void OS_CpuInterruptServiceRoutine(void *arg)
1483 176 rhoads
{
1484
   uint32 state;
1485 189 rhoads
   (void)arg;
1486 176 rhoads
   state = OS_SpinLock();
1487
   OS_ThreadReschedule(0);
1488
   OS_SpinUnlock(state);
1489
}
1490 167 rhoads
#endif
1491
 
1492
 
1493 138 rhoads
/************** WIN32 Support *************/
1494
#ifdef WIN32
1495
//Support RTOS inside Windows
1496 233 rhoads
#undef kbhit
1497
#undef getch
1498
#undef putch
1499 138 rhoads
extern int kbhit();
1500
extern int getch(void);
1501
extern int putch(int);
1502
extern void __stdcall Sleep(unsigned long value);
1503
 
1504
static uint32 Memory[8];
1505
 
1506 189 rhoads
uint32 MemoryRead(uint32 address)
1507 138 rhoads
{
1508 189 rhoads
   Memory[2] |= IRQ_UART_WRITE_AVAILABLE;    //IRQ_STATUS
1509
   switch(address)
1510 138 rhoads
   {
1511
   case UART_READ:
1512
      if(kbhit())
1513 189 rhoads
         Memory[0] = getch();                //UART_READ
1514 138 rhoads
      Memory[2] &= ~IRQ_UART_READ_AVAILABLE; //clear bit
1515
      return Memory[0];
1516
   case IRQ_MASK:
1517 189 rhoads
      return Memory[1];                      //IRQ_MASK
1518 138 rhoads
   case IRQ_MASK + 4:
1519
      Sleep(10);
1520
      return 0;
1521
   case IRQ_STATUS:
1522
      if(kbhit())
1523
         Memory[2] |= IRQ_UART_READ_AVAILABLE;
1524
      return Memory[2];
1525
   }
1526
   return 0;
1527
}
1528
 
1529 189 rhoads
void MemoryWrite(uint32 address, uint32 value)
1530 138 rhoads
{
1531 189 rhoads
   switch(address)
1532 138 rhoads
   {
1533
   case UART_WRITE:
1534 189 rhoads
      putch(value);
1535 138 rhoads
      break;
1536
   case IRQ_MASK:
1537 189 rhoads
      Memory[1] = value;
1538 138 rhoads
      break;
1539
   case IRQ_STATUS:
1540 189 rhoads
      Memory[2] = value;
1541 138 rhoads
      break;
1542
   }
1543
}
1544
 
1545 189 rhoads
uint32 OS_AsmInterruptEnable(uint32 enableInterrupt)
1546 138 rhoads
{
1547 189 rhoads
   return enableInterrupt;
1548 138 rhoads
}
1549
 
1550
void OS_AsmInterruptInit(void)
1551
{
1552
}
1553
#endif  //WIN32
1554
 
1555
 
1556
/**************** Example *****************/
1557
#ifndef NO_MAIN
1558 218 rhoads
#ifdef WIN32
1559 138 rhoads
static uint8 HeapSpace[1024*512];
1560 218 rhoads
#endif
1561 138 rhoads
 
1562 218 rhoads
int main(int programEnd, char *argv[])
1563 138 rhoads
{
1564 218 rhoads
   (void)programEnd;  //Pointer to end of used memory
1565
   (void)argv;
1566 138 rhoads
   UartPrintfCritical("Starting RTOS\n");
1567 218 rhoads
#ifdef WIN32
1568 138 rhoads
   OS_Init((uint32*)HeapSpace, sizeof(HeapSpace));
1569 218 rhoads
#else
1570
   //Remaining space after program in 1MB external RAM
1571
   OS_Init((uint32*)programEnd,
1572
           RAM_EXTERNAL_BASE + RAM_EXTERNAL_SIZE - programEnd);
1573
#endif
1574 138 rhoads
   UartInit();
1575 223 rhoads
   OS_ThreadCreate("Main", MainThread, NULL, 100, 4000);
1576 138 rhoads
   OS_Start();
1577
   return 0;
1578
}
1579
#endif
1580
 

powered by: WebSVN 2.1.0

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