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

Subversion Repositories plasma

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

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 256 rhoads
#define INFO_COUNT 4
24 138 rhoads
#define HEAP_COUNT 8
25
 
26 167 rhoads
 
27 138 rhoads
/*************** Structures ***************/
28
#ifdef WIN32
29 189 rhoads
   #define setjmp _setjmp
30 138 rhoads
   //x86 registers
31
   typedef struct jmp_buf2 {
32
      uint32 Ebp, Ebx, Edi, Esi, sp, pc, extra[10];
33
   } jmp_buf2;
34 189 rhoads
#elif defined(ARM_CPU)
35
   //ARM registers
36
   typedef struct jmp_buf2 {
37
      uint32 r[13], sp, lr, pc, cpsr, extra[5];
38 256 rhoads
   } jmp_buf2;
39 138 rhoads
#else  
40
   //Plasma registers
41
   typedef struct jmp_buf2 {
42
      uint32 s[9], gp, sp, pc;
43
   } jmp_buf2;
44
#endif
45
 
46
typedef struct HeapNode_s {
47
   struct HeapNode_s *next;
48
   int size;
49
} HeapNode_t;
50
 
51
struct OS_Heap_s {
52
   uint32 magic;
53
   const char *name;
54
   OS_Semaphore_t *semaphore;
55
   HeapNode_t *available;
56
   HeapNode_t base;
57
   struct OS_Heap_s *alternate;
58
};
59
//typedef struct OS_Heap_s OS_Heap_t;
60
 
61 168 rhoads
typedef enum {
62 256 rhoads
   THREAD_PEND    = 0,       //Thread in semaphore's linked list
63
   THREAD_READY   = 1,       //Thread in ThreadHead linked list
64
   THREAD_RUNNING = 2        //Thread == ThreadCurrent[cpu]
65 168 rhoads
} OS_ThreadState_e;
66
 
67 138 rhoads
struct OS_Thread_s {
68 233 rhoads
   const char *name;         //Name of thread
69
   OS_ThreadState_e state;   //Pending, ready, or running
70
   int cpuIndex;             //Which CPU is running the thread
71
   int cpuLock;              //Lock the thread to a specific CPU
72
   jmp_buf env;              //Registers saved during context swap
73
   OS_FuncPtr_t funcPtr;     //First function called
74
   void *arg;                //Argument to first function called
75
   uint32 priority;          //Priority of thread (0=low, 255=high)
76
   uint32 ticksTimeout;      //Tick value when semaphore pend times out
77 256 rhoads
   void *info[INFO_COUNT];   //User storage
78 233 rhoads
   OS_Semaphore_t *semaphorePending;  //Semaphore thread is blocked on
79
   int returnCode;           //Return value from semaphore pend
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 256 rhoads
   struct OS_Thread_s *threadHead; //threads pending on semaphore
93 138 rhoads
   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 256 rhoads
static int InterruptInside[OS_CPU_COUNT];
127
static int ThreadNeedReschedule[OS_CPU_COUNT];
128
static OS_Thread_t *ThreadCurrent[OS_CPU_COUNT];  //Currently running thread(s)
129 189 rhoads
static OS_Thread_t *ThreadHead;   //Linked list of threads sorted by priority
130
static OS_Thread_t *TimeoutHead;  //Linked list of threads sorted by timeout
131 138 rhoads
static int ThreadSwapEnabled;
132 396 rhoads
static uint32 ThreadTime;         //Number of ~10ms ticks since reboot
133
static void *NeedToFree;          //Closed but not yet freed thread
134 138 rhoads
static OS_Semaphore_t SemaphoreReserved[SEM_RESERVED_COUNT];
135 189 rhoads
static OS_Semaphore_t *SemaphoreSleep;
136 256 rhoads
static OS_Semaphore_t *SemaphoreRelease;
137 189 rhoads
static OS_Semaphore_t *SemaphoreLock;
138
static OS_Semaphore_t *SemaphoreTimer;
139 138 rhoads
static OS_Timer_t *TimerHead;     //Linked list of timers sorted by timeout
140
static OS_FuncPtr_t Isr[32];
141
 
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 396 rhoads
//Modified from Kernighan & Ritchie "The C Programming Language"
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 256 rhoads
//The listed list is either ThreadHead (ready to run threads not including
274
//the currently running thread) or a list of threads waiting on a semaphore.
275 138 rhoads
//Must be called with interrupts disabled
276
static void OS_ThreadPriorityInsert(OS_Thread_t **head, OS_Thread_t *thread)
277
{
278
   OS_Thread_t *node, *prev;
279
 
280
   prev = NULL;
281
   for(node = *head; node; node = node->next)
282
   {
283 256 rhoads
      if(node->priority < thread->priority)
284 138 rhoads
         break;
285
      prev = node;
286
   }
287
 
288
   if(prev == NULL)
289
   {
290
      thread->next = *head;
291
      thread->prev = NULL;
292 256 rhoads
      if(*head)
293
         (*head)->prev = thread;
294 138 rhoads
      *head = thread;
295
   }
296
   else
297
   {
298
      if(prev->next)
299
         prev->next->prev = thread;
300
      thread->next = prev->next;
301
      thread->prev = prev;
302
      prev->next = thread;
303
   }
304
   assert(ThreadHead);
305 256 rhoads
   thread->state = THREAD_READY;
306 138 rhoads
}
307
 
308
 
309
/******************************************/
310
//Must be called with interrupts disabled
311
static void OS_ThreadPriorityRemove(OS_Thread_t **head, OS_Thread_t *thread)
312
{
313
   assert(thread->magic[0] == THREAD_MAGIC);  //check stack overflow
314
   if(thread->prev == NULL)
315
      *head = thread->next;
316
   else
317
      thread->prev->next = thread->next;
318
   if(thread->next)
319
      thread->next->prev = thread->prev;
320
   thread->next = NULL;
321
   thread->prev = NULL;
322
}
323
 
324
 
325
/******************************************/
326
//Linked list of threads sorted by timeout value
327
//Must be called with interrupts disabled
328
static void OS_ThreadTimeoutInsert(OS_Thread_t *thread)
329
{
330
   OS_Thread_t *node, *prev;
331
   int diff;
332
 
333
   prev = NULL;
334
   for(node = TimeoutHead; node; node = node->nextTimeout)
335
   {
336
      diff = thread->ticksTimeout - node->ticksTimeout;
337
      if(diff <= 0)
338
         break;
339
      prev = node;
340
   }
341
 
342
   if(prev == NULL)
343
   {
344
      thread->nextTimeout = TimeoutHead;
345
      thread->prevTimeout = NULL;
346 151 rhoads
      if(TimeoutHead)
347
         TimeoutHead->prevTimeout = thread;
348 138 rhoads
      TimeoutHead = thread;
349
   }
350
   else
351
   {
352
      if(prev->nextTimeout)
353
         prev->nextTimeout->prevTimeout = thread;
354
      thread->nextTimeout = prev->nextTimeout;
355
      thread->prevTimeout = prev;
356
      prev->nextTimeout = thread;
357
   }
358
}
359
 
360
 
361
/******************************************/
362
//Must be called with interrupts disabled
363
static void OS_ThreadTimeoutRemove(OS_Thread_t *thread)
364
{
365
   if(thread->prevTimeout == NULL && TimeoutHead != thread)
366
      return;         //not in list
367
   if(thread->prevTimeout == NULL)
368
      TimeoutHead = thread->nextTimeout;
369
   else
370
      thread->prevTimeout->nextTimeout = thread->nextTimeout;
371
   if(thread->nextTimeout)
372
      thread->nextTimeout->prevTimeout = thread->prevTimeout;
373
   thread->nextTimeout = NULL;
374
   thread->prevTimeout = NULL;
375
}
376
 
377
 
378
/******************************************/
379 256 rhoads
//Loads highest priority thread from the ThreadHead linked list
380
//The currently running thread isn't in the ThreadHead list
381 138 rhoads
//Must be called with interrupts disabled
382 189 rhoads
static void OS_ThreadReschedule(int roundRobin)
383 138 rhoads
{
384 256 rhoads
   OS_Thread_t *threadNext, *threadCurrent;
385
   int rc, cpuIndex = OS_CpuIndex();
386 138 rhoads
 
387 256 rhoads
   if(ThreadSwapEnabled == 0 || InterruptInside[cpuIndex])
388 138 rhoads
   {
389 256 rhoads
      ThreadNeedReschedule[cpuIndex] |= 2 + roundRobin;  //Reschedule later
390 138 rhoads
      return;
391 395 rhoads
   }
392
   ThreadNeedReschedule[cpuIndex] = 0;
393 138 rhoads
 
394
   //Determine which thread should run
395 256 rhoads
   threadNext = ThreadHead;
396
   while(threadNext && threadNext->cpuLock != -1 &&
397
         threadNext->cpuLock != cpuIndex)
398 396 rhoads
      threadNext = threadNext->next;         //Skip CPU locked threads
399 256 rhoads
   if(threadNext == NULL)
400 189 rhoads
      return;
401 176 rhoads
   threadCurrent = ThreadCurrent[cpuIndex];
402 138 rhoads
 
403 256 rhoads
   if(threadCurrent == NULL ||
404
      threadCurrent->state == THREAD_PEND ||
405
      threadCurrent->priority < threadNext->priority ||
406
      (roundRobin && threadCurrent->priority == threadNext->priority))
407 138 rhoads
   {
408
      //Swap threads
409 167 rhoads
      ThreadCurrent[cpuIndex] = threadNext;
410 168 rhoads
      if(threadCurrent)
411 138 rhoads
      {
412 168 rhoads
         assert(threadCurrent->magic[0] == THREAD_MAGIC); //check stack overflow
413 256 rhoads
         if(threadCurrent->state == THREAD_RUNNING)
414
            OS_ThreadPriorityInsert(&ThreadHead, threadCurrent);
415
         rc = setjmp(threadCurrent->env);  //ANSI C call to save registers
416 138 rhoads
         if(rc)
417 256 rhoads
            return;  //Returned from longjmp()
418 138 rhoads
      }
419 168 rhoads
 
420 256 rhoads
      //Remove the new running thread from the ThreadHead linked list
421
      threadNext = ThreadCurrent[OS_CpuIndex()]; //removed warning
422
      assert(threadNext->state == THREAD_READY);
423
      OS_ThreadPriorityRemove(&ThreadHead, threadNext);
424
      threadNext->state = THREAD_RUNNING;
425
      threadNext->cpuIndex = OS_CpuIndex();
426
      longjmp(threadNext->env, 1);         //ANSI C call to restore registers
427 138 rhoads
   }
428
}
429
 
430
 
431 189 rhoads
/******************************************/
432 256 rhoads
void OS_ThreadCpuLock(OS_Thread_t *thread, int cpuIndex)
433 176 rhoads
{
434 256 rhoads
   thread->cpuLock = cpuIndex;
435
   if(thread == OS_ThreadSelf() && cpuIndex != (int)OS_CpuIndex())
436 176 rhoads
      OS_ThreadSleep(1);
437
}
438
 
439
 
440 138 rhoads
/******************************************/
441 189 rhoads
static void OS_ThreadInit(void *arg)
442 138 rhoads
{
443 167 rhoads
   uint32 cpuIndex = OS_CpuIndex();
444 189 rhoads
   (void)arg;
445 138 rhoads
 
446 168 rhoads
   OS_CriticalEnd(1);
447 167 rhoads
   ThreadCurrent[cpuIndex]->funcPtr(ThreadCurrent[cpuIndex]->arg);
448 138 rhoads
   OS_ThreadExit();
449
}
450
 
451
 
452
/******************************************/
453
//Stops warning "argument X might be clobbered by `longjmp'"
454
static void OS_ThreadRegsInit(jmp_buf env)
455
{
456
   setjmp(env); //ANSI C call to save registers
457
}
458
 
459
 
460
/******************************************/
461 189 rhoads
OS_Thread_t *OS_ThreadCreate(const char *name,
462
                             OS_FuncPtr_t funcPtr,
463
                             void *arg,
464
                             uint32 priority,
465
                             uint32 stackSize)
466 138 rhoads
{
467
   OS_Thread_t *thread;
468
   uint8 *stack;
469
   jmp_buf2 *env;
470
   uint32 state;
471
 
472 256 rhoads
   OS_SemaphorePend(SemaphoreRelease, OS_WAIT_FOREVER);
473 138 rhoads
   if(NeedToFree)
474
      OS_HeapFree(NeedToFree);
475
   NeedToFree = NULL;
476 256 rhoads
   OS_SemaphorePost(SemaphoreRelease);
477 138 rhoads
 
478 189 rhoads
   if(stackSize == 0)
479
      stackSize = STACK_SIZE_DEFAULT;
480
   if(stackSize < STACK_SIZE_MINIMUM)
481
      stackSize = STACK_SIZE_MINIMUM;
482
   thread = (OS_Thread_t*)OS_HeapMalloc(NULL, sizeof(OS_Thread_t) + stackSize);
483 138 rhoads
   assert(thread);
484
   if(thread == NULL)
485
      return NULL;
486 189 rhoads
   memset(thread, 0, sizeof(OS_Thread_t));
487 138 rhoads
   stack = (uint8*)(thread + 1);
488 189 rhoads
   memset(stack, 0xcd, stackSize);
489 138 rhoads
 
490 189 rhoads
   thread->name = name;
491 168 rhoads
   thread->state = THREAD_READY;
492 176 rhoads
   thread->cpuLock = -1;
493 189 rhoads
   thread->funcPtr = funcPtr;
494
   thread->arg = arg;
495
   thread->priority = priority;
496 138 rhoads
   thread->semaphorePending = NULL;
497
   thread->returnCode = 0;
498 189 rhoads
   if(OS_ThreadSelf())
499
   {
500
      thread->processId = OS_ThreadSelf()->processId;
501
      thread->heap = OS_ThreadSelf()->heap;
502
   }
503
   else
504
   {
505
      thread->processId = 0;
506
      thread->heap = NULL;
507
   }
508 138 rhoads
   thread->next = NULL;
509
   thread->prev = NULL;
510
   thread->nextTimeout = NULL;
511
   thread->prevTimeout = NULL;
512
   thread->magic[0] = THREAD_MAGIC;
513
 
514
   OS_ThreadRegsInit(thread->env);
515
   env = (jmp_buf2*)thread->env;
516 200 rhoads
   env->sp = (uint32)stack + stackSize - 24; //minimum stack frame size
517 138 rhoads
   env->pc = (uint32)OS_ThreadInit;
518
 
519 396 rhoads
   //Add thread to linked list of ready to run threads
520 138 rhoads
   state = OS_CriticalBegin();
521
   OS_ThreadPriorityInsert(&ThreadHead, thread);
522 396 rhoads
   OS_ThreadReschedule(0);                   //run highest priority thread
523 138 rhoads
   OS_CriticalEnd(state);
524
   return thread;
525
}
526
 
527
 
528
/******************************************/
529
void OS_ThreadExit(void)
530
{
531 167 rhoads
   uint32 state, cpuIndex = OS_CpuIndex();
532 138 rhoads
 
533 306 rhoads
   for(;;)
534
   {
535 396 rhoads
      //Free the memory for closed but not yet freed threads
536 306 rhoads
      OS_SemaphorePend(SemaphoreRelease, OS_WAIT_FOREVER);
537
      if(NeedToFree)
538
         OS_HeapFree(NeedToFree);
539
      NeedToFree = NULL;
540
      OS_SemaphorePost(SemaphoreRelease);
541
 
542
      state = OS_CriticalBegin();
543
      if(NeedToFree)
544
      {
545
         OS_CriticalEnd(state);
546
         continue;
547
      }
548
      ThreadCurrent[cpuIndex]->state = THREAD_PEND;
549
      NeedToFree = ThreadCurrent[cpuIndex];
550
      OS_ThreadReschedule(0);
551
      OS_CriticalEnd(state);
552
   }
553 138 rhoads
}
554
 
555
 
556
/******************************************/
557 396 rhoads
//Return currently running thread
558 138 rhoads
OS_Thread_t *OS_ThreadSelf(void)
559
{
560 167 rhoads
   return ThreadCurrent[OS_CpuIndex()];
561 138 rhoads
}
562
 
563
 
564
/******************************************/
565 396 rhoads
//Sleep for ~10 msecs ticks
566 189 rhoads
void OS_ThreadSleep(int ticks)
567 138 rhoads
{
568 189 rhoads
   OS_SemaphorePend(SemaphoreSleep, ticks);
569 138 rhoads
}
570
 
571
 
572
/******************************************/
573 396 rhoads
//Return the number of ~10 msecs ticks since reboot
574 138 rhoads
uint32 OS_ThreadTime(void)
575
{
576
   return ThreadTime;
577
}
578
 
579
 
580
/******************************************/
581 396 rhoads
//Save thread unique values
582 256 rhoads
void OS_ThreadInfoSet(OS_Thread_t *thread, uint32 index, void *Info)
583 138 rhoads
{
584 256 rhoads
   if(index < INFO_COUNT)
585
      thread->info[index] = Info;
586 138 rhoads
}
587
 
588
 
589
/******************************************/
590 256 rhoads
void *OS_ThreadInfoGet(OS_Thread_t *thread, uint32 index)
591 138 rhoads
{
592 256 rhoads
   if(index < INFO_COUNT)
593
      return thread->info[index];
594
   return NULL;
595 138 rhoads
}
596
 
597
 
598
/******************************************/
599 189 rhoads
uint32 OS_ThreadPriorityGet(OS_Thread_t *thread)
600 138 rhoads
{
601 189 rhoads
   return thread->priority;
602 138 rhoads
}
603
 
604
 
605
/******************************************/
606 189 rhoads
void OS_ThreadPrioritySet(OS_Thread_t *thread, uint32 priority)
607 138 rhoads
{
608
   uint32 state;
609
   state = OS_CriticalBegin();
610 189 rhoads
   thread->priority = priority;
611 256 rhoads
   if(thread->state == THREAD_READY)
612 168 rhoads
   {
613 189 rhoads
      OS_ThreadPriorityRemove(&ThreadHead, thread);
614
      OS_ThreadPriorityInsert(&ThreadHead, thread);
615 168 rhoads
      OS_ThreadReschedule(0);
616
   }
617 138 rhoads
   OS_CriticalEnd(state);
618
}
619
 
620
 
621
/******************************************/
622 189 rhoads
void OS_ThreadProcessId(OS_Thread_t *thread, uint32 processId, OS_Heap_t *heap)
623
{
624
   thread->processId = processId;
625
   thread->heap = heap;
626
}
627
 
628
 
629
/******************************************/
630 396 rhoads
//Must be called with interrupts disabled every ~10 msecs
631
//Will wake up threads that have timed out waiting on a semaphore
632 138 rhoads
void OS_ThreadTick(void *Arg)
633
{
634
   OS_Thread_t *thread;
635
   OS_Semaphore_t *semaphore;
636
   int diff;
637
   (void)Arg;
638
 
639 396 rhoads
   ++ThreadTime;         //Number of ~10 msec ticks since reboot
640 138 rhoads
   while(TimeoutHead)
641
   {
642
      thread = TimeoutHead;
643
      diff = ThreadTime - thread->ticksTimeout;
644
      if(diff < 0)
645
         break;
646 396 rhoads
 
647
      //The thread has timed out waiting for a semaphore
648 138 rhoads
      OS_ThreadTimeoutRemove(thread);
649
      semaphore = thread->semaphorePending;
650
      ++semaphore->count;
651
      thread->semaphorePending = NULL;
652
      thread->returnCode = -1;
653
      OS_ThreadPriorityRemove(&semaphore->threadHead, thread);
654
      OS_ThreadPriorityInsert(&ThreadHead, thread);
655
   }
656 396 rhoads
   OS_ThreadReschedule(1);    //Run highest priority thread
657 138 rhoads
}
658
 
659
 
660
 
661
/***************** Semaphore **************/
662
/******************************************/
663 396 rhoads
//Create a counting semaphore
664 189 rhoads
OS_Semaphore_t *OS_SemaphoreCreate(const char *name, uint32 count)
665 138 rhoads
{
666
   OS_Semaphore_t *semaphore;
667 189 rhoads
   static int semCount = 0;
668 138 rhoads
 
669
   if(semCount < SEM_RESERVED_COUNT)
670 189 rhoads
      semaphore = &SemaphoreReserved[semCount++];  //Heap not ready yet
671 138 rhoads
   else
672 189 rhoads
      semaphore = (OS_Semaphore_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Semaphore_t));
673 138 rhoads
   assert(semaphore);
674
   if(semaphore == NULL)
675
      return NULL;
676
 
677 189 rhoads
   semaphore->name = name;
678 138 rhoads
   semaphore->threadHead = NULL;
679 189 rhoads
   semaphore->count = count;
680 138 rhoads
   return semaphore;
681
}
682
 
683
 
684
/******************************************/
685 189 rhoads
void OS_SemaphoreDelete(OS_Semaphore_t *semaphore)
686 138 rhoads
{
687 189 rhoads
   while(semaphore->threadHead)
688
      OS_SemaphorePost(semaphore);
689
   OS_HeapFree(semaphore);
690 138 rhoads
}
691
 
692
 
693
/******************************************/
694 396 rhoads
//Sleep the number of ticks (~10ms) until the semaphore is acquired
695 189 rhoads
int OS_SemaphorePend(OS_Semaphore_t *semaphore, int ticks)
696 138 rhoads
{
697 167 rhoads
   uint32 state, cpuIndex;
698 138 rhoads
   OS_Thread_t *thread;
699
   int returnCode=0;
700
 
701 189 rhoads
   assert(semaphore);
702 256 rhoads
   assert(InterruptInside[OS_CpuIndex()] == 0);
703 396 rhoads
   state = OS_CriticalBegin();    //Disable interrupts
704 189 rhoads
   if(--semaphore->count < 0)
705 138 rhoads
   {
706 396 rhoads
      //Semaphore not available
707 189 rhoads
      if(ticks == 0)
708 138 rhoads
      {
709 189 rhoads
         ++semaphore->count;
710 138 rhoads
         OS_CriticalEnd(state);
711
         return -1;
712
      }
713 396 rhoads
 
714
      //Need to sleep until the semaphore is available
715 189 rhoads
      cpuIndex = OS_CpuIndex();
716 167 rhoads
      thread = ThreadCurrent[cpuIndex];
717 189 rhoads
      assert(thread);
718
      thread->semaphorePending = semaphore;
719
      thread->ticksTimeout = ticks + OS_ThreadTime();
720 396 rhoads
 
721 256 rhoads
      //FYI: The current thread isn't in the ThreadHead linked list
722 396 rhoads
      //Place the thread into a sorted linked list of pending threads
723 189 rhoads
      OS_ThreadPriorityInsert(&semaphore->threadHead, thread);
724 256 rhoads
      thread->state = THREAD_PEND;
725 189 rhoads
      if(ticks != OS_WAIT_FOREVER)
726 396 rhoads
         OS_ThreadTimeoutInsert(thread); //Check every ~10ms for timeouts
727 138 rhoads
      assert(ThreadHead);
728 396 rhoads
      OS_ThreadReschedule(0);           //Run highest priority thread
729
      returnCode = thread->returnCode;  //Will be -1 if timed out
730 138 rhoads
   }
731 396 rhoads
   OS_CriticalEnd(state);               //Re-enable interrupts
732 138 rhoads
   return returnCode;
733
}
734
 
735
 
736
/******************************************/
737 396 rhoads
//Release a semaphore and possibly wake up a blocked thread
738 189 rhoads
void OS_SemaphorePost(OS_Semaphore_t *semaphore)
739 138 rhoads
{
740
   uint32 state;
741 146 rhoads
   OS_Thread_t *thread;
742 138 rhoads
 
743 189 rhoads
   assert(semaphore);
744 138 rhoads
   state = OS_CriticalBegin();
745 189 rhoads
   if(++semaphore->count <= 0)
746 138 rhoads
   {
747 396 rhoads
      //Wake up a thread that was waiting for this semaphore
748 189 rhoads
      thread = semaphore->threadHead;
749 138 rhoads
      OS_ThreadTimeoutRemove(thread);
750 189 rhoads
      OS_ThreadPriorityRemove(&semaphore->threadHead, thread);
751 138 rhoads
      OS_ThreadPriorityInsert(&ThreadHead, thread);
752
      thread->semaphorePending = NULL;
753
      thread->returnCode = 0;
754 146 rhoads
      OS_ThreadReschedule(0);
755 138 rhoads
   }
756
   OS_CriticalEnd(state);
757
}
758
 
759
 
760
 
761
/***************** Mutex ******************/
762
/******************************************/
763 396 rhoads
//Create a mutex (a thread aware semaphore)
764 189 rhoads
OS_Mutex_t *OS_MutexCreate(const char *name)
765 138 rhoads
{
766
   OS_Mutex_t *mutex;
767
 
768 189 rhoads
   mutex = (OS_Mutex_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Mutex_t));
769 138 rhoads
   if(mutex == NULL)
770
      return NULL;
771 189 rhoads
   mutex->semaphore = OS_SemaphoreCreate(name, 1);
772 138 rhoads
   if(mutex->semaphore == NULL)
773
      return NULL;
774
   mutex->thread = NULL;
775
   mutex->count = 0;
776
   return mutex;
777
}
778
 
779
 
780
/******************************************/
781 189 rhoads
void OS_MutexDelete(OS_Mutex_t *mutex)
782 138 rhoads
{
783 189 rhoads
   OS_SemaphoreDelete(mutex->semaphore);
784
   OS_HeapFree(mutex);
785 138 rhoads
}
786
 
787
 
788
/******************************************/
789 189 rhoads
void OS_MutexPend(OS_Mutex_t *mutex)
790 138 rhoads
{
791
   OS_Thread_t *thread;
792
 
793 189 rhoads
   assert(mutex);
794 138 rhoads
   thread = OS_ThreadSelf();
795 189 rhoads
   if(thread == mutex->thread)
796 138 rhoads
   {
797 189 rhoads
      ++mutex->count;
798 138 rhoads
      return;
799
   }
800 189 rhoads
   OS_SemaphorePend(mutex->semaphore, OS_WAIT_FOREVER);
801
   mutex->thread = thread;
802
   mutex->count = 1;
803 138 rhoads
}
804
 
805
 
806
/******************************************/
807 189 rhoads
void OS_MutexPost(OS_Mutex_t *mutex)
808 138 rhoads
{
809 189 rhoads
   assert(mutex);
810
   assert(mutex->thread == OS_ThreadSelf());
811
   assert(mutex->count > 0);
812
   if(--mutex->count <= 0)
813 138 rhoads
   {
814 189 rhoads
      mutex->thread = NULL;
815
      OS_SemaphorePost(mutex->semaphore);
816 138 rhoads
   }
817
}
818
 
819
 
820
 
821
/***************** MQueue *****************/
822
/******************************************/
823 396 rhoads
//Create a message queue
824 189 rhoads
OS_MQueue_t *OS_MQueueCreate(const char *name,
825
                             int messageCount,
826
                             int messageBytes)
827 138 rhoads
{
828
   OS_MQueue_t *queue;
829
   int size;
830
 
831 396 rhoads
   assert((messageBytes & 3) == 0);
832 189 rhoads
   size = messageBytes / sizeof(uint32);
833
   queue = (OS_MQueue_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_MQueue_t) +
834
      messageCount * size * 4);
835 138 rhoads
   if(queue == NULL)
836
      return queue;
837 189 rhoads
   queue->name = name;
838
   queue->semaphore = OS_SemaphoreCreate(name, 0);
839 138 rhoads
   if(queue->semaphore == NULL)
840
      return NULL;
841 189 rhoads
   queue->count = messageCount;
842 138 rhoads
   queue->size = size;
843
   queue->used = 0;
844
   queue->read = 0;
845
   queue->write = 0;
846
   return queue;
847
}
848
 
849
 
850
/******************************************/
851 189 rhoads
void OS_MQueueDelete(OS_MQueue_t *mQueue)
852 138 rhoads
{
853 189 rhoads
   OS_SemaphoreDelete(mQueue->semaphore);
854
   OS_HeapFree(mQueue);
855 138 rhoads
}
856
 
857
 
858
/******************************************/
859 396 rhoads
//Send a message that is messageBytes long (defined during create)
860 189 rhoads
int OS_MQueueSend(OS_MQueue_t *mQueue, void *message)
861 138 rhoads
{
862
   uint32 state, *dst, *src;
863
   int i;
864
 
865 189 rhoads
   assert(mQueue);
866
   src = (uint32*)message;
867 396 rhoads
   state = OS_CriticalBegin();           //Disable interrupts
868 189 rhoads
   if(++mQueue->used > mQueue->count)
869 138 rhoads
   {
870 396 rhoads
      //The message queue is full so discard the message
871 189 rhoads
      --mQueue->used;
872 138 rhoads
      OS_CriticalEnd(state);
873
      return -1;
874
   }
875 189 rhoads
   dst = (uint32*)(mQueue + 1) + mQueue->write * mQueue->size;
876 396 rhoads
   for(i = 0; i < mQueue->size; ++i)     //Copy the message into the queue
877 138 rhoads
      dst[i] = src[i];
878 189 rhoads
   if(++mQueue->write >= mQueue->count)
879
      mQueue->write = 0;
880 396 rhoads
   OS_CriticalEnd(state);                //Re-enable interrupts
881
   OS_SemaphorePost(mQueue->semaphore);  //Wakeup the receiving thread
882 138 rhoads
   return 0;
883
}
884
 
885
 
886
/******************************************/
887 396 rhoads
//Receive a message that is messageBytes long (defined during create)
888
//Wait at most ~10 msec ticks
889 189 rhoads
int OS_MQueueGet(OS_MQueue_t *mQueue, void *message, int ticks)
890 138 rhoads
{
891
   uint32 state, *dst, *src;
892
   int i, rc;
893
 
894 189 rhoads
   assert(mQueue);
895 396 rhoads
   rc = OS_SemaphorePend(mQueue->semaphore, ticks); //Wait for message
896 138 rhoads
   if(rc)
897 396 rhoads
      return rc;                         //Request timed out so rc = -1
898
   state = OS_CriticalBegin();           //Disable interrupts
899 189 rhoads
   --mQueue->used;
900 396 rhoads
   dst = (uint32*)message;
901 189 rhoads
   src = (uint32*)(mQueue + 1) + mQueue->read * mQueue->size;
902 396 rhoads
   for(i = 0; i < mQueue->size; ++i)     //Copy message from the queue
903 138 rhoads
      dst[i] = src[i];
904 189 rhoads
   if(++mQueue->read >= mQueue->count)
905
      mQueue->read = 0;
906 396 rhoads
   OS_CriticalEnd(state);                //Re-enable interrupts
907 138 rhoads
   return 0;
908
}
909
 
910
 
911
 
912 223 rhoads
/***************** Jobs *******************/
913
/******************************************/
914
typedef void (*JobFunc_t)();
915
static OS_MQueue_t *jobQueue;
916
static OS_Thread_t *jobThread;
917
 
918 396 rhoads
//This thread waits for jobs that request a function to be called
919 223 rhoads
static void JobThread(void *arg)
920
{
921
   uint32 message[4];
922
   JobFunc_t funcPtr;
923
   (void)arg;
924
   for(;;)
925
   {
926
      OS_MQueueGet(jobQueue, message, OS_WAIT_FOREVER);
927
      funcPtr = (JobFunc_t)message[0];
928
      funcPtr(message[1], message[2], message[3]);
929
   }
930
}
931
 
932
 
933
/******************************************/
934 396 rhoads
//Call a function using the job thread so the caller won't be blocked
935 223 rhoads
void OS_Job(void (*funcPtr)(), void *arg0, void *arg1, void *arg2)
936
{
937
   uint32 message[4];
938
   int rc;
939
 
940 256 rhoads
   OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
941 223 rhoads
   if(jobThread == NULL)
942
   {
943
      jobQueue = OS_MQueueCreate("job", 100, 16);
944
      jobThread = OS_ThreadCreate("job", JobThread, NULL, 150, 4000);
945
   }
946 256 rhoads
   OS_SemaphorePost(SemaphoreLock);
947
 
948 223 rhoads
   message[0] = (uint32)funcPtr;
949
   message[1] = (uint32)arg0;
950
   message[2] = (uint32)arg1;
951
   message[3] = (uint32)arg2;
952 304 rhoads
   rc = OS_MQueueSend(jobQueue, message);
953 223 rhoads
}
954
 
955
 
956 138 rhoads
/***************** Timer ******************/
957
/******************************************/
958 396 rhoads
//This thread polls the list of timers to see if any have timed out
959 189 rhoads
static void OS_TimerThread(void *arg)
960 138 rhoads
{
961
   uint32 timeNow;
962
   int diff, ticks;
963
   uint32 message[8];
964
   OS_Timer_t *timer;
965 189 rhoads
   (void)arg;
966 138 rhoads
 
967 396 rhoads
   timeNow = OS_ThreadTime();  //Number of ~10 msec ticks since reboot
968 138 rhoads
   for(;;)
969
   {
970
      //Determine how long to sleep
971
      OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
972
      if(TimerHead)
973
         ticks = TimerHead->ticksTimeout - timeNow;
974
      else
975
         ticks = OS_WAIT_FOREVER;
976
      OS_SemaphorePost(SemaphoreLock);
977
      OS_SemaphorePend(SemaphoreTimer, ticks);
978
 
979
      //Send messages for all timed out timers
980
      timeNow = OS_ThreadTime();
981
      for(;;)
982
      {
983 189 rhoads
         timer = NULL;
984 138 rhoads
         OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
985 189 rhoads
         if(TimerHead)
986 138 rhoads
         {
987 189 rhoads
            diff = timeNow - TimerHead->ticksTimeout;
988
            if(diff >= 0)
989
               timer = TimerHead;
990 138 rhoads
         }
991 189 rhoads
         OS_SemaphorePost(SemaphoreLock);
992
         if(timer == NULL)
993 138 rhoads
            break;
994
         if(timer->ticksRestart)
995
            OS_TimerStart(timer, timer->ticksRestart, timer->ticksRestart);
996
         else
997
            OS_TimerStop(timer);
998
 
999 218 rhoads
         if(timer->callback)
1000
            timer->callback(timer, timer->info);
1001
         else
1002
         {
1003
            //Send message
1004
            message[0] = MESSAGE_TYPE_TIMER;
1005
            message[1] = (uint32)timer;
1006
            message[2] = timer->info;
1007
            OS_MQueueSend(timer->mqueue, message);
1008
         }
1009 138 rhoads
      }
1010
   }
1011
}
1012
 
1013
 
1014
/******************************************/
1015 396 rhoads
//Create a timer that will send a message upon timeout
1016 189 rhoads
OS_Timer_t *OS_TimerCreate(const char *name, OS_MQueue_t *mQueue, uint32 info)
1017 138 rhoads
{
1018
   OS_Timer_t *timer;
1019
 
1020
   OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
1021
   if(SemaphoreTimer == NULL)
1022
   {
1023
      SemaphoreTimer = OS_SemaphoreCreate("Timer", 0);
1024 256 rhoads
      OS_ThreadCreate("Timer", OS_TimerThread, NULL, 250, 2000);
1025 138 rhoads
   }
1026
   OS_SemaphorePost(SemaphoreLock);
1027
 
1028 189 rhoads
   timer = (OS_Timer_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Timer_t));
1029 138 rhoads
   if(timer == NULL)
1030
      return NULL;
1031 189 rhoads
   timer->name = name;
1032 218 rhoads
   timer->callback = NULL;
1033 189 rhoads
   timer->mqueue = mQueue;
1034 138 rhoads
   timer->next = NULL;
1035
   timer->prev = NULL;
1036 189 rhoads
   timer->info = info;
1037 138 rhoads
   timer->active = 0;
1038
   return timer;
1039
}
1040
 
1041
 
1042
/******************************************/
1043 189 rhoads
void OS_TimerDelete(OS_Timer_t *timer)
1044 138 rhoads
{
1045 189 rhoads
   OS_TimerStop(timer);
1046
   OS_HeapFree(timer);
1047 138 rhoads
}
1048
 
1049
 
1050
/******************************************/
1051 218 rhoads
void OS_TimerCallback(OS_Timer_t *timer, OS_TimerFuncPtr_t callback)
1052
{
1053
   timer->callback = callback;
1054
}
1055
 
1056
 
1057
/******************************************/
1058 138 rhoads
//Must not be called from an ISR
1059 396 rhoads
//In ~10 msec ticks send a message (or callback)
1060 189 rhoads
void OS_TimerStart(OS_Timer_t *timer, uint32 ticks, uint32 ticksRestart)
1061 138 rhoads
{
1062
   OS_Timer_t *node, *prev;
1063
   int diff, check=0;
1064
 
1065 189 rhoads
   assert(timer);
1066 256 rhoads
   assert(InterruptInside[OS_CpuIndex()] == 0);
1067 189 rhoads
   ticks += OS_ThreadTime();
1068
   if(timer->active)
1069
      OS_TimerStop(timer);
1070 138 rhoads
   OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
1071 189 rhoads
   if(timer->active)
1072
   {
1073
      //Prevent race condition
1074
      OS_SemaphorePost(SemaphoreLock);
1075
      return;
1076
   }
1077
   timer->ticksTimeout = ticks;
1078
   timer->ticksRestart = ticksRestart;
1079
   timer->active = 1;
1080 138 rhoads
   prev = NULL;
1081
   for(node = TimerHead; node; node = node->next)
1082
   {
1083 189 rhoads
      diff = ticks - node->ticksTimeout;
1084 138 rhoads
      if(diff <= 0)
1085
         break;
1086
      prev = node;
1087
   }
1088 189 rhoads
   timer->next = node;
1089
   timer->prev = prev;
1090 138 rhoads
   if(node)
1091 189 rhoads
      node->prev = timer;
1092 138 rhoads
   if(prev == NULL)
1093
   {
1094 189 rhoads
      TimerHead = timer;
1095 138 rhoads
      check = 1;
1096
   }
1097
   else
1098 189 rhoads
      prev->next = timer;
1099 138 rhoads
   OS_SemaphorePost(SemaphoreLock);
1100
   if(check)
1101 396 rhoads
      OS_SemaphorePost(SemaphoreTimer);  //Wakeup OS_TimerThread
1102 138 rhoads
}
1103
 
1104
 
1105
/******************************************/
1106
//Must not be called from an ISR
1107 189 rhoads
void OS_TimerStop(OS_Timer_t *timer)
1108 138 rhoads
{
1109 189 rhoads
   assert(timer);
1110 256 rhoads
   assert(InterruptInside[OS_CpuIndex()] == 0);
1111 138 rhoads
   OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER);
1112 189 rhoads
   if(timer->active)
1113 138 rhoads
   {
1114 189 rhoads
      timer->active = 0;
1115
      if(timer->prev == NULL)
1116
         TimerHead = timer->next;
1117 138 rhoads
      else
1118 189 rhoads
         timer->prev->next = timer->next;
1119
      if(timer->next)
1120
         timer->next->prev = timer->prev;
1121 138 rhoads
   }
1122
   OS_SemaphorePost(SemaphoreLock);
1123
}
1124
 
1125
 
1126
/***************** ISR ********************/
1127
/******************************************/
1128 189 rhoads
void OS_InterruptServiceRoutine(uint32 status, uint32 *stack)
1129 138 rhoads
{
1130
   int i;
1131 256 rhoads
   uint32 state, cpuIndex = OS_CpuIndex();
1132 138 rhoads
 
1133 189 rhoads
   if(status == 0 && Isr[31])
1134
      Isr[31](stack);                   //SYSCALL or BREAK
1135
 
1136 256 rhoads
   InterruptInside[cpuIndex] = 1;
1137 138 rhoads
   i = 0;
1138
   do
1139
   {
1140 189 rhoads
      if(status & 1)
1141 138 rhoads
      {
1142
         if(Isr[i])
1143 189 rhoads
            Isr[i](stack);
1144 138 rhoads
         else
1145
            OS_InterruptMaskClear(1 << i);
1146
      }
1147 189 rhoads
      status >>= 1;
1148 138 rhoads
      ++i;
1149 189 rhoads
   } while(status);
1150 256 rhoads
   InterruptInside[cpuIndex] = 0;
1151 138 rhoads
 
1152 167 rhoads
   state = OS_SpinLock();
1153 256 rhoads
   if(ThreadNeedReschedule[cpuIndex])
1154
      OS_ThreadReschedule(ThreadNeedReschedule[cpuIndex] & 1);
1155 167 rhoads
   OS_SpinUnlock(state);
1156 138 rhoads
}
1157
 
1158
 
1159
/******************************************/
1160 189 rhoads
void OS_InterruptRegister(uint32 mask, OS_FuncPtr_t funcPtr)
1161 138 rhoads
{
1162
   int i;
1163
 
1164
   for(i = 0; i < 32; ++i)
1165
   {
1166 189 rhoads
      if(mask & (1 << i))
1167
         Isr[i] = funcPtr;
1168 138 rhoads
   }
1169
}
1170
 
1171
 
1172
/******************************************/
1173
//Plasma hardware dependent
1174
uint32 OS_InterruptStatus(void)
1175
{
1176
   return MemoryRead(IRQ_STATUS);
1177
}
1178
 
1179
 
1180
/******************************************/
1181
//Plasma hardware dependent
1182 189 rhoads
uint32 OS_InterruptMaskSet(uint32 mask)
1183 138 rhoads
{
1184 189 rhoads
   uint32 state;
1185 138 rhoads
   state = OS_CriticalBegin();
1186 189 rhoads
   mask |= MemoryRead(IRQ_MASK);
1187 138 rhoads
   MemoryWrite(IRQ_MASK, mask);
1188
   OS_CriticalEnd(state);
1189
   return mask;
1190
}
1191
 
1192
 
1193
/******************************************/
1194
//Plasma hardware dependent
1195 189 rhoads
uint32 OS_InterruptMaskClear(uint32 mask)
1196 138 rhoads
{
1197 189 rhoads
   uint32 state;
1198 138 rhoads
   state = OS_CriticalBegin();
1199 189 rhoads
   mask = MemoryRead(IRQ_MASK) & ~mask;
1200 138 rhoads
   MemoryWrite(IRQ_MASK, mask);
1201
   OS_CriticalEnd(state);
1202
   return mask;
1203
}
1204
 
1205
 
1206
/**************** Init ********************/
1207
/******************************************/
1208 396 rhoads
//If there aren't any other ready to run threads then spin here
1209 138 rhoads
static volatile uint32 IdleCount;
1210 189 rhoads
static void OS_IdleThread(void *arg)
1211 138 rhoads
{
1212 189 rhoads
   (void)arg;
1213 138 rhoads
 
1214 151 rhoads
   //Don't block in the idle thread!
1215 138 rhoads
   for(;;)
1216
   {
1217
      ++IdleCount;
1218
   }
1219
}
1220
 
1221
 
1222
/******************************************/
1223
#ifndef DISABLE_IRQ_SIM
1224 396 rhoads
//Simulate the hardware interrupts
1225 189 rhoads
static void OS_IdleSimulateIsr(void *arg)
1226 138 rhoads
{
1227
   uint32 count=0, value;
1228 189 rhoads
   (void)arg;
1229 138 rhoads
 
1230
   for(;;)
1231
   {
1232
      MemoryRead(IRQ_MASK + 4);       //calls Sleep(10)
1233
#if WIN32
1234
      while(OS_InterruptMaskSet(0) & IRQ_UART_WRITE_AVAILABLE)
1235 176 rhoads
         OS_InterruptServiceRoutine(IRQ_UART_WRITE_AVAILABLE, 0);
1236 138 rhoads
#endif
1237 189 rhoads
      value = OS_InterruptMaskSet(0) & 0xf;
1238
      if(value)
1239
         OS_InterruptServiceRoutine(value, 0);
1240 138 rhoads
      ++count;
1241
   }
1242
}
1243
#endif //DISABLE_IRQ_SIM
1244
 
1245
 
1246
/******************************************/
1247
//Plasma hardware dependent
1248 396 rhoads
//ISR called every ~10 msecs when bit 18 of the counter register toggles
1249 189 rhoads
static void OS_ThreadTickToggle(void *arg)
1250 138 rhoads
{
1251 167 rhoads
   uint32 status, mask, state;
1252 138 rhoads
 
1253 189 rhoads
   //Toggle looking for IRQ_COUNTER18 or IRQ_COUNTER18_NOT
1254 167 rhoads
   state = OS_SpinLock();
1255 138 rhoads
   status = MemoryRead(IRQ_STATUS) & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT);
1256
   mask = MemoryRead(IRQ_MASK) | IRQ_COUNTER18 | IRQ_COUNTER18_NOT;
1257
   mask &= ~status;
1258
   MemoryWrite(IRQ_MASK, mask);
1259 189 rhoads
   OS_ThreadTick(arg);
1260 167 rhoads
   OS_SpinUnlock(state);
1261 138 rhoads
}
1262
 
1263
 
1264
/******************************************/
1265 396 rhoads
//Initialize the OS by setting up the system heap and the tick interrupt
1266 189 rhoads
void OS_Init(uint32 *heapStorage, uint32 bytes)
1267 138 rhoads
{
1268 393 rhoads
   int i;
1269
   if((int)OS_Init > 0x10000000)        //Running from DDR?
1270
      OS_AsmInterruptInit();            //Patch interrupt vector
1271 138 rhoads
   OS_InterruptMaskClear(0xffffffff);   //Disable interrupts
1272 189 rhoads
   HeapArray[0] = OS_HeapCreate("Default", heapStorage, bytes);
1273
   HeapArray[1] = HeapArray[0];
1274 138 rhoads
   SemaphoreSleep = OS_SemaphoreCreate("Sleep", 0);
1275 256 rhoads
   SemaphoreRelease = OS_SemaphoreCreate("Release", 1);
1276 138 rhoads
   SemaphoreLock = OS_SemaphoreCreate("Lock", 1);
1277 168 rhoads
   for(i = 0; i < OS_CPU_COUNT; ++i)
1278
      OS_ThreadCreate("Idle", OS_IdleThread, NULL, 0, 256);
1279 138 rhoads
#ifndef DISABLE_IRQ_SIM
1280
   if((OS_InterruptStatus() & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT)) == 0)
1281
   {
1282
      //Detected that running in simulator so create SimIsr thread
1283
      UartPrintfCritical("SimIsr\n");
1284
      OS_ThreadCreate("SimIsr", OS_IdleSimulateIsr, NULL, 1, 0);
1285
   }
1286
#endif //DISABLE_IRQ_SIM
1287 396 rhoads
   //Plasma hardware dependent (register for OS tick interrupt every ~10 msecs)
1288 189 rhoads
   OS_InterruptRegister(IRQ_COUNTER18 | IRQ_COUNTER18_NOT, OS_ThreadTickToggle);
1289 138 rhoads
   OS_InterruptMaskSet(IRQ_COUNTER18 | IRQ_COUNTER18_NOT);
1290
}
1291
 
1292
 
1293
/******************************************/
1294 396 rhoads
//Start thread swapping
1295 138 rhoads
void OS_Start(void)
1296
{
1297
   ThreadSwapEnabled = 1;
1298 167 rhoads
   (void)OS_SpinLock();
1299 138 rhoads
   OS_ThreadReschedule(1);
1300
}
1301
 
1302
 
1303
/******************************************/
1304
//Place breakpoint here
1305
void OS_Assert(void)
1306
{
1307
}
1308
 
1309
 
1310 167 rhoads
#if OS_CPU_COUNT > 1
1311
static uint8 SpinLockArray[OS_CPU_COUNT];
1312
/******************************************/
1313
uint32 OS_CpuIndex(void)
1314
{
1315
   return 0; //0 to OS_CPU_COUNT-1
1316
}
1317
 
1318
 
1319
/******************************************/
1320
//Symmetric Multiprocessing Spin Lock Mutex
1321
uint32 OS_SpinLock(void)
1322
{
1323 168 rhoads
   uint32 state, cpuIndex, i, j, ok, delay;
1324 167 rhoads
 
1325 168 rhoads
   cpuIndex = OS_CpuIndex();
1326
   delay = cpuIndex + 8;
1327 167 rhoads
   state = OS_AsmInterruptEnable(0);
1328 396 rhoads
   //Spin until only this CPU has the spin lock
1329 167 rhoads
   do
1330
   {
1331
      ok = 1;
1332 168 rhoads
      if(++SpinLockArray[cpuIndex] == 1)
1333 167 rhoads
      {
1334
         for(i = 0; i < OS_CPU_COUNT; ++i)
1335
         {
1336 168 rhoads
            if(i != cpuIndex && SpinLockArray[i])
1337 396 rhoads
               ok = 0;   //Another CPU has the spin lock
1338 167 rhoads
         }
1339
         if(ok == 0)
1340
         {
1341 168 rhoads
            SpinLockArray[cpuIndex] = 0;
1342
            for(j = 0; j < delay; ++j)  //wait a bit
1343 167 rhoads
               ++i;
1344 168 rhoads
            if(delay < 128)
1345
               delay <<= 1;
1346 167 rhoads
         }
1347
      }
1348
   } while(ok == 0);
1349
   return state;
1350
}
1351
 
1352
 
1353
/******************************************/
1354
void OS_SpinUnlock(uint32 state)
1355
{
1356 168 rhoads
   uint32 cpuIndex;
1357
   cpuIndex = OS_CpuIndex();
1358
   if(--SpinLockArray[cpuIndex] == 0)
1359 167 rhoads
      OS_AsmInterruptEnable(state);
1360 168 rhoads
 
1361
   assert(SpinLockArray[cpuIndex] < 10);
1362 167 rhoads
}
1363 256 rhoads
#endif  //OS_CPU_COUNT > 1
1364 167 rhoads
 
1365
 
1366 336 rhoads
/************** WIN32/Linux Support *************/
1367 138 rhoads
#ifdef WIN32
1368 336 rhoads
#ifdef LINUX
1369
#define putch putchar
1370
#undef _LIBC
1371
#undef kbhit
1372
#undef getch
1373
#define UartPrintf UartPrintf2
1374
#define UartScanf UartScanf2
1375
#include <stdio.h>
1376
#include <stdlib.h>
1377
#include <termios.h>
1378
#include <unistd.h>
1379 396 rhoads
//Support RTOS inside Linux
1380 336 rhoads
void Sleep(unsigned int value)
1381
{
1382
   usleep(value * 1000);
1383
}
1384
 
1385
int kbhit(void)
1386
{
1387
   struct termios oldt, newt;
1388
   struct timeval tv;
1389
   fd_set read_fd;
1390
 
1391
   tcgetattr(STDIN_FILENO, &oldt);
1392
   newt = oldt;
1393
   newt.c_lflag &= ~(ICANON | ECHO);
1394
   tcsetattr(STDIN_FILENO, TCSANOW, &newt);
1395
   tv.tv_sec=0;
1396
   tv.tv_usec=0;
1397
   FD_ZERO(&read_fd);
1398
   FD_SET(0,&read_fd);
1399
   if(select(1, &read_fd, NULL, NULL, &tv) == -1)
1400
      return 0;
1401
   if(FD_ISSET(0,&read_fd))
1402
      return 1;
1403
   return 0;
1404
}
1405
 
1406
int getch(void)
1407
{
1408
   struct termios oldt, newt;
1409
   int ch;
1410
 
1411
   tcgetattr(STDIN_FILENO, &oldt);
1412
   newt = oldt;
1413
   newt.c_lflag &= ~(ICANON | ECHO);
1414
   tcsetattr(STDIN_FILENO, TCSANOW, &newt);
1415
   ch = getchar();
1416
   return ch;
1417
}
1418
#else
1419 138 rhoads
//Support RTOS inside Windows
1420 233 rhoads
#undef kbhit
1421
#undef getch
1422
#undef putch
1423 138 rhoads
extern int kbhit();
1424
extern int getch(void);
1425
extern int putch(int);
1426
extern void __stdcall Sleep(unsigned long value);
1427 336 rhoads
#endif
1428 138 rhoads
 
1429
static uint32 Memory[8];
1430
 
1431 396 rhoads
//Simulates device register memory reads
1432 189 rhoads
uint32 MemoryRead(uint32 address)
1433 138 rhoads
{
1434 189 rhoads
   Memory[2] |= IRQ_UART_WRITE_AVAILABLE;    //IRQ_STATUS
1435
   switch(address)
1436 138 rhoads
   {
1437
   case UART_READ:
1438
      if(kbhit())
1439 189 rhoads
         Memory[0] = getch();                //UART_READ
1440 138 rhoads
      Memory[2] &= ~IRQ_UART_READ_AVAILABLE; //clear bit
1441
      return Memory[0];
1442
   case IRQ_MASK:
1443 189 rhoads
      return Memory[1];                      //IRQ_MASK
1444 138 rhoads
   case IRQ_MASK + 4:
1445
      Sleep(10);
1446
      return 0;
1447
   case IRQ_STATUS:
1448
      if(kbhit())
1449
         Memory[2] |= IRQ_UART_READ_AVAILABLE;
1450
      return Memory[2];
1451
   }
1452
   return 0;
1453
}
1454
 
1455 396 rhoads
//Simulates device register memory writes
1456 189 rhoads
void MemoryWrite(uint32 address, uint32 value)
1457 138 rhoads
{
1458 189 rhoads
   switch(address)
1459 138 rhoads
   {
1460
   case UART_WRITE:
1461 189 rhoads
      putch(value);
1462 138 rhoads
      break;
1463
   case IRQ_MASK:
1464 189 rhoads
      Memory[1] = value;
1465 138 rhoads
      break;
1466
   case IRQ_STATUS:
1467 189 rhoads
      Memory[2] = value;
1468 138 rhoads
      break;
1469
   }
1470
}
1471
 
1472 189 rhoads
uint32 OS_AsmInterruptEnable(uint32 enableInterrupt)
1473 138 rhoads
{
1474 189 rhoads
   return enableInterrupt;
1475 138 rhoads
}
1476
 
1477
void OS_AsmInterruptInit(void)
1478
{
1479
}
1480
#endif  //WIN32
1481
 
1482
 
1483
/**************** Example *****************/
1484
#ifndef NO_MAIN
1485 218 rhoads
#ifdef WIN32
1486 396 rhoads
static uint8 HeapSpace[1024*512];  //For simulation on a PC
1487 218 rhoads
#endif
1488 138 rhoads
 
1489 218 rhoads
int main(int programEnd, char *argv[])
1490 138 rhoads
{
1491 218 rhoads
   (void)programEnd;  //Pointer to end of used memory
1492
   (void)argv;
1493 256 rhoads
 
1494 138 rhoads
   UartPrintfCritical("Starting RTOS\n");
1495 218 rhoads
#ifdef WIN32
1496 396 rhoads
   OS_Init((uint32*)HeapSpace, sizeof(HeapSpace));  //For PC simulation
1497 218 rhoads
#else
1498 396 rhoads
   //Create heap in remaining space after program in 1MB external RAM
1499 218 rhoads
   OS_Init((uint32*)programEnd,
1500
           RAM_EXTERNAL_BASE + RAM_EXTERNAL_SIZE - programEnd);
1501
#endif
1502 138 rhoads
   UartInit();
1503 223 rhoads
   OS_ThreadCreate("Main", MainThread, NULL, 100, 4000);
1504 138 rhoads
   OS_Start();
1505
   return 0;
1506
}
1507 256 rhoads
#endif  //NO_MAIN
1508 138 rhoads
 

powered by: WebSVN 2.1.0

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