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

Subversion Repositories plasma

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

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

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

powered by: WebSVN 2.1.0

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