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

Subversion Repositories plasma

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

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

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

powered by: WebSVN 2.1.0

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