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

Subversion Repositories mlite

[/] [mlite/] [trunk/] [kernel/] [rtos.c] - Blame information for rev 240

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

powered by: WebSVN 2.1.0

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