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

Subversion Repositories plasma

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

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

powered by: WebSVN 2.1.0

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