207 lines
3.6 KiB
C
207 lines
3.6 KiB
C
#include "clib.h"
|
|
#include "yakk.h"
|
|
#include "yaku.h"
|
|
#include "PriorityQueue.h"
|
|
#include "DelayQueue.h"
|
|
|
|
//User Accessible Variables
|
|
unsigned int YKCtxSwCount = 0;
|
|
unsigned int YKIdleCount = 0;
|
|
unsigned int YKTickCounter = 0;
|
|
|
|
//Kernel Accessible Variables
|
|
static unsigned int ISRCallDepth = 0;
|
|
TCB* currentTask = null;
|
|
PriorityQueue readyQueue;
|
|
DelayQueue delayQueue;
|
|
static TaskBlock taskBlock;
|
|
static SemBlock semBlock;
|
|
static MsgQueueBlock msgQueueBlock;
|
|
static int idleTaskStack[IDLETASKSTACKSIZE];
|
|
static enum KernelState kernelState = K_BLOCKED;
|
|
|
|
unsigned int getYKCtxSwCount() {
|
|
return YKCtxSwCount;
|
|
}
|
|
|
|
unsigned int getYKIdleCount() {
|
|
return YKIdleCount;
|
|
}
|
|
|
|
unsigned int getYKTickNum() {
|
|
return YKTickCounter;
|
|
}
|
|
|
|
void setYKIdleCount(int value) {
|
|
YKIdleCount = value;
|
|
}
|
|
|
|
void setYKCtxSwCount(int value) {
|
|
YKCtxSwCount = value;
|
|
}
|
|
|
|
void YKEnterISR(void) {
|
|
YKEnterMutex();
|
|
ISRCallDepth++;
|
|
YKExitMutex();
|
|
}
|
|
|
|
void YKExitISR(void) {
|
|
YKEnterMutex();
|
|
ISRCallDepth--;
|
|
if (ISRCallDepth == 0) {
|
|
YKExitMutex();
|
|
YKScheduler();
|
|
}
|
|
YKExitMutex();
|
|
}
|
|
|
|
unsigned int YKGetISRCallDepth(void) {
|
|
|
|
return ISRCallDepth;
|
|
}
|
|
|
|
void YKInitialize(void) {
|
|
|
|
YKEnterMutex();
|
|
|
|
//Set up queues
|
|
initializePriorityQueue(&readyQueue);
|
|
initializeDelayQueue();
|
|
|
|
//Set up Task Block
|
|
taskBlock.nextFreeTCB == 0;
|
|
//
|
|
|
|
//Set up Idle Task
|
|
YKNewTask(YKIdleTask, &idleTaskStack[IDLETASKSTACKSIZE], 100);
|
|
//
|
|
|
|
YKExitMutex();
|
|
return;
|
|
|
|
}
|
|
|
|
void YKScheduler(void) {
|
|
|
|
TCB* readyTask;
|
|
YKEnterMutex();
|
|
if (kernelState == K_BLOCKED) return;
|
|
readyTask = peekPriorityQueue(&readyQueue);
|
|
if (readyTask == null) exit(READY_QUEUE_EMPTY);
|
|
if (readyTask != currentTask) {
|
|
currentTask = readyTask;
|
|
currentTask->state = T_READY;
|
|
YKCtxSwCount++;
|
|
readyTask->state = T_RUNNING;
|
|
YKDispatcher(readyTask);
|
|
YKExitMutex();
|
|
return;
|
|
}
|
|
YKExitMutex();
|
|
return;
|
|
}
|
|
|
|
void YKNewTask(void (*task)(void), void* taskStack, unsigned char priority) {
|
|
|
|
TCB* newTask;
|
|
|
|
//Obtain a TCB
|
|
newTask = getNewTCB();
|
|
if (newTask == null) exit(NEW_TASK_FAILED);
|
|
|
|
//Fill TCB
|
|
newTask->tid = 0;
|
|
newTask->priority = priority;
|
|
newTask->stackPointer = ((void*)((int*) taskStack - 12));
|
|
newTask->state = T_READY;
|
|
newTask->delayCount = 0;
|
|
newTask->next = null;
|
|
newTask->prev = null;
|
|
|
|
//Set up Stack
|
|
asm("push bx");
|
|
asm("push cx");
|
|
asm("mov bx, [bp+6]"); //Get address of stack
|
|
asm("mov cx, [bp+4]"); //Get address of function pointer
|
|
asm("mov [bx-2], word 0x0200"); //Move flag register onto the stack
|
|
asm("mov [bx-4], word 0x0");
|
|
asm("mov [bx-6], cx");
|
|
asm("pop cx");
|
|
asm("pop bx");
|
|
|
|
insertPriorityQueue(&readyQueue, newTask);
|
|
asm("int 0x20");
|
|
return;
|
|
|
|
}
|
|
|
|
TCB* getNewTCB(void) {
|
|
|
|
TCB* task;
|
|
if (taskBlock.nextFreeTCB < MAX_TASKS + 1) {
|
|
task = &taskBlock.TCBPool[taskBlock.nextFreeTCB++];
|
|
return task;
|
|
} else {
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
YKSEM* getNewSem(void) {
|
|
|
|
YKSEM* semaphore;
|
|
if (semBlock.nextFreeSem < MAX_SEMS) {
|
|
semaphore = &semBlock.SemPool[semBlock.nextFreeSem++];
|
|
return semaphore;
|
|
} else {
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
YKQ* getNewQueue(void) {
|
|
|
|
YKQ* messageQueue;
|
|
if (msgQueueBlock.nextFreeQueue < MAX_QUEUES) {
|
|
messageQueue = &msgQueueBlock.QueuePool[msgQueueBlock.nextFreeQueue++];
|
|
return messageQueue;
|
|
} else {
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
void YKRun(void) {
|
|
|
|
YKEnterMutex();
|
|
kernelState = K_RUNNING;
|
|
YKScheduler();
|
|
YKExitMutex();
|
|
return;
|
|
|
|
}
|
|
|
|
void YKDelayTask(unsigned int count) {
|
|
|
|
TCB* delayedTask;
|
|
|
|
if (count == 0) return;
|
|
|
|
delayedTask = removePriorityQueue(&readyQueue);
|
|
delayedTask->state = T_BLOCKED;
|
|
delayedTask->delayCount = count;
|
|
insertDelayQueue(delayedTask);
|
|
asm("int 0x20");
|
|
return;
|
|
|
|
}
|
|
|
|
void YKTickHandler(void) {
|
|
|
|
tickClock();
|
|
|
|
}
|
|
|
|
|