/* RLPOS: RLPotter Operating System Version 0.4 for the 68HC12D60A microcontroller by Ryan Potter ryan@rlpotter.com v0.4 April 13, 2004: 8043 bytes - gerneralized the shell command-line input parser: cmd (up to 32 chars) - added kernel and shell functions v0.3 April 12, 2003: 6090 bytes - added a beginning shell user interface. - added a resource control block and basic semaphore functions. - added basic kernel functions v0.2 April 9, 2003: - able to round-robin with RTI interrupt. - bonified/certified multitasking with 3 tasks. :) v0.1 April 3, 2003: - able to round-robin without interrupts. - not multitasking, really. v0.0 started April 1, 2003; 0 bytes - no idea where to start. - don't want to look at anyone else's work. ;0) Architecture/C assumptions: 1) 'D' register is the accumulator 2) 'X' register points to the top of the current stack 3) 'Y' register is for general use in indexed operations 4) the heap grows upward and mem segments allocated by malloc, realloc, and calloc are linear and contiguous. Potential problem areas: 1) 'running' section of the kernel get's compiled using extra push and pop instructions 2) run out of ram (global + stack + heap) 3) kernel takes up too large a fraction of the processing time */ #include <912d60.h> #include #include #include "kernel.h" // FUNCTION PROTOTYPES void RTI_handler(void); void shell(void); void task1(void); void task2(void); void (*task_ptr[])(void) = {&shell, &task1, &task2}; // GLOBAL VARIABLES unsigned char *main_frame_ptr = NULL; // bottom of main() frame unsigned char *main_frame_x_ptr = NULL; // top of main() frame (x-reg ptr) unsigned char *temp_task_frame_ptr = NULL; // temp CCR pointer for RTI extern unsigned int current; // current task id number extern unsigned long int system_tick; // task control block extern struct task_block { unsigned char id; // ID of task enum task_state state; // State unsigned char priority; // Priority unsigned char *heap_ptr; // heap addr while not current task unsigned int heap_size; // heap size unsigned char *frame_ptr; // CCR pointer }; // resource control block extern struct resource_block { unsigned char id; // ID of resource enum resource_state state; // State (busy, free...) unsigned char user; // Current resource user/owner signed char queue[4]; // Tasks waiting on resource unsigned char queue_pos; // Next free spot in queue }; extern struct task_block task[numtasks]; extern struct resource_block resource[numresources]; main() { // LOCAL VARIABLES int result; unsigned int i, temp_heap_size; unsigned int last_task = 0; unsigned int next_task = 0; unsigned char *temp_heap_ptr, temp; // INITIALIZE GLOBAL VARIABLES extern int _bss_end, _textmode; extern unsigned int current; extern unsigned long int system_tick; _textmode = 1; current = 0; system_tick = 0; // initialize the task structures for (i=0; i= numtasks) next_task = 0; // diagnostic //putchar(':'); } // end 'while(1)' return 0; } #pragma interrupt_handler RTI_handler() void RTI_handler(void) { size_t frame_size; unsigned int i; unsigned char *local_thp; //ACKNOWLEDGE THE INTERRUPT INTR_OFF(); // redundant. automatically done by the processor RTIFLG = 0x0080; // acknowledge/clear the interrupt //putchar('I'); //putchar(current + 48); //putchar('('); // SET THE FRAME POINTER for the interupted task. // should point to the CCR entry on the stack. asm("TFR x,d"); // start of RTI stack asm("ADDD #2"); // adjust to CCR stack entry asm("STD _temp_task_frame_ptr"); // put into task_frame_ptr task[current].frame_ptr = temp_task_frame_ptr; //PLACE CURRENT TASK CONTEXT ONTO THE HEAP // determine size of heap segment needed frame_size = main_frame_ptr - temp_task_frame_ptr; // always positive task[current].heap_size = (int)frame_size; // reallocate heap memory task[current].heap_ptr = realloc(task[current].heap_ptr, frame_size); local_thp = task[current].heap_ptr; if (local_thp == NULL) { puts("out of heap space!"); exit(0); } // transfer task frame to the heap one byte at a time. // assumes the heap grows from low to high addr. for(i=0; i