school/ecen425/yakc.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();
}