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

Subversion Repositories plasma

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

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

powered by: WebSVN 2.1.0

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