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

Subversion Repositories plasma

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

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

powered by: WebSVN 2.1.0

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