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

Subversion Repositories plasma

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

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

powered by: WebSVN 2.1.0

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