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

Subversion Repositories plasma

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

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

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

powered by: WebSVN 2.1.0

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