.module rlpos.c .area data 0000 _task_ptr:: 0000 .blkw 1 .area idata 0000 0000 .word _shell .area data 0002 .blkw 1 .area idata 0002 0000 .word _task1 .area data 0004 .blkw 1 .area idata 0004 0000 .word _task2 .area data 0006 _main_frame_ptr:: 0006 .blkb 2 .area idata 0006 0000 .word 0 .area data 0008 _main_frame_x_ptr:: 0008 .blkb 2 .area idata 0008 0000 .word 0 .area data 000A _temp_task_frame_ptr:: 000A .blkb 2 .area idata 000A 0000 .word 0 .area data .area text ; lreg1 -> -4,x ; lreg2 -> -8,x ; ?temp -> -26,x ; ?temp -> -26,x ; ?temp -> -26,x ; result -> -24,x ; temp_heap_ptr -> -22,x ; last_task -> -20,x ; temp -> -18,x ; temp_heap_size -> -17,x ; priority_check -> -15,x ; deadline -> -14,x ; i -> -10,x 0000 _main:: 0000 34 pshx 0001 B775 tfr s,x 0003 1BF1E0 leas -32,sp 0006 ; /* RLPOS: RLPotter Operating System 0006 ; 0006 ; Version 0.5 for the 68HC12D60A microcontroller 0006 ; by Ryan Potter 0006 ; ryan@rlpotter.com 0006 ; 0006 ; 0006 ; 0006 ; v0.5 April 16, 2003: 8759 bytes 0006 ; - added priority preemption 0006 ; - finished kernel task state switcher 0006 ; - it is now officially a legitimate 0006 ; rate monotonic 0006 ; priority preemptive 0006 ; multitasking 0006 ; Real Time Operating System :) 0006 ; - made kernel.c and semlib.c consistent with the 0006 ; rest of the kernel 0006 ; - included the early framework for a task message system 0006 ; 0006 ; v0.4 April 13, 2003: 8096 bytes 0006 ; - gerneralized the shell command-line input parser: 0006 ; cmd (up to 32 chars) 0006 ; - added kernel and shell functions 0006 ; 0006 ; v0.3 April 12, 2003: 6155 bytes 0006 ; - added a beginning shell user interface. 0006 ; - added a resource control block and basic semaphore functions. 0006 ; - added basic kernel functions 0006 ; 0006 ; v0.2 April 9, 2003: 0006 ; - able to round-robin with RTI interrupt. 0006 ; - bonified/certified multitasking with 3 tasks. :) 0006 ; 0006 ; v0.1 April 3, 2003: 0006 ; - able to round-robin without interrupts. 0006 ; - not multitasking, really. 0006 ; 0006 ; v0.0 started April 1, 2003; 0 bytes 0006 ; - no idea where to start. 0006 ; - don't want to look at anyone else's work. ;0) 0006 ; 0006 ; 0006 ; 0006 ; 0006 ; Architecture/C assumptions: 0006 ; 1) 'D' register is the accumulator 0006 ; 2) 'X' register points to the top of the current stack 0006 ; 3) 'Y' register is for general use in indexed operations 0006 ; 4) the heap grows upward and mem segments allocated by malloc, 0006 ; realloc, and calloc are linear and contiguous. 0006 ; 5) the stack grows downwards, and there is no boundary checking. 0006 ; 0006 ; Potential problem areas: 0006 ; 1) 'running' section of the kernel get's compiled using extra 0006 ; push and pop instructions 0006 ; 2) run out of ram (global + stack + heap) 0006 ; 0006 ; */ 0006 ; 0006 ; 0006 ; 0006 ; #include <912d60.h> 0006 ; #include 0006 ; #include 0006 ; #include "kernel.h" 0006 ; 0006 ; 0006 ; 0006 ; 0006 ; // FUNCTION PROTOTYPES 0006 ; void RTI_handler(void); 0006 ; void shell(void); 0006 ; void task1(void); 0006 ; void task2(void); 0006 ; void (*task_ptr[])(void) = {&shell, &task1, &task2}; 0006 ; 0006 ; 0006 ; 0006 ; 0006 ; // GLOBAL VARIABLES 0006 ; unsigned char *main_frame_ptr = NULL; // bottom of main() frame 0006 ; unsigned char *main_frame_x_ptr = NULL; // top of main() frame (x-reg ptr) 0006 ; unsigned char *temp_task_frame_ptr = NULL; // temp CCR pointer for RTI 0006 ; 0006 ; 0006 ; extern unsigned int current; // current task id number 0006 ; extern unsigned long int system_tick; 0006 ; 0006 ; 0006 ; // task control block 0006 ; extern struct task_block { 0006 ; unsigned char id; // ID of task 0006 ; enum task_state state; // State 0006 ; unsigned char priority; // Priority 0006 ; unsigned long int period_tick; // for determining if deadline is up 0006 ; unsigned int interrupt_msg_box; // flags for pending interrupts 0006 ; enum message_box message; // misc flags 0006 ; unsigned char message_data[8]; // data for misc_msg_box flags 0006 ; unsigned char *heap_ptr; // heap addr while not current task 0006 ; unsigned int heap_size; // heap size 0006 ; unsigned char *frame_ptr; // CCR pointer 0006 ; }; 0006 ; 0006 ; 0006 ; // resource control block 0006 ; extern struct resource_block { 0006 ; unsigned char id; // ID of resource 0006 ; enum resource_state state; // State (busy, free...) 0006 ; unsigned char user; // Current resource user/owner 0006 ; signed char queue[3]; // Tasks waiting on resource 0006 ; unsigned char queue_pos; // Next free spot in queue 0006 ; }; 0006 ; 0006 ; 0006 ; extern struct task_block task[numtasks]; 0006 ; extern struct resource_block resource[numresources]; 0006 ; 0006 ; 0006 ; 0006 ; 0006 ; 0006 ; 0006 ; main() { 0006 ; 0006 ; // LOCAL VARIABLES 0006 ; int result; 0006 ; unsigned int i, temp_heap_size; 0006 ; unsigned int last_task = 0; 0006 CC0000 ldd #0 0009 6CE1EC std -20,x 000C ; unsigned char *temp_heap_ptr, temp, priority_check; 000C ; unsigned long int deadline; 000C ; 000C ; extern int _bss_end, _textmode; 000C ; extern unsigned int current; 000C ; extern unsigned long int system_tick; 000C ; 000C ; _textmode = 1; // maps '\n' to "CR/LF" for Windows terminals 000C CC0001 ldd #1 000F 7C0000 std __textmode 0012 ; current = 0; // start the shell first 0012 CC0000 ldd #0 0015 7C0000 std _current 0018 CC0000 ldd #0 001B 6C16 std -10,x 001D 18200082 lbra L7 0021 L4: 0021 CC0018 ldd #24 0024 ED16 ldy -10,x 0026 13 emul 0027 C30000 addd #_task 002A B7C6 xgdy 002C EC16 ldd -10,x 002E 6B40 stab 0,y 0030 CC0018 ldd #24 0033 ED16 ldy -10,x 0035 13 emul 0036 C30001 addd #_task+1 0039 B7C6 xgdy 003B 6940 clr 0,y 003D CC0018 ldd #24 0040 ED16 ldy -10,x 0042 13 emul 0043 C30002 addd #_task+2 0046 B7C6 xgdy 0048 C6FE ldab #254 004A 6B40 stab 0,y 004C CC0018 ldd #24 004F ED16 ldy -10,x 0051 13 emul 0052 C30003 addd #_task+3 0055 B7C6 xgdy 0057 35 pshy ; spill 0058 CD0492 ldy #L11 005B 1802401C movw 0,y,-4,x 005F 1802421E movw 2,y,-2,x 0063 31 puly ; reload 0064 18021C40 movw -4,x,0,y 0068 18021E42 movw -2,x,2,y 006C CC0018 ldd #24 006F ED16 ldy -10,x 0071 13 emul 0072 C30012 addd #_task+18 0075 B7C6 xgdy 0077 CC0000 ldd #0 007A 6C40 std 0,y 007C CC0018 ldd #24 007F ED16 ldy -10,x 0081 13 emul 0082 C30014 addd #_task+20 0085 B7C6 xgdy 0087 CC0000 ldd #0 008A 6C40 std 0,y 008C CC0018 ldd #24 008F ED16 ldy -10,x 0091 13 emul 0092 C30016 addd #_task+22 0095 B7C6 xgdy 0097 CC0000 ldd #0 009A 6C40 std 0,y 009C L5: 009C EC16 ldd -10,x 009E C30001 addd #1 00A1 6C16 std -10,x 00A3 L7: 00A3 ; 00A3 ; 00A3 ; 00A3 ; // initialize the task structures 00A3 ; for (i=0; i= numtasks) 0184 ; next_task = 0; 0184 ; current = next_task;*/ 0184 ; 0184 ; 0184 ; 0184 ; 0184 ; // RT PRIORITY BLOCK: 0184 ; // set the current task id based on priority and deadline 0184 ; 0184 ; // determine if the deadline is up for idle tasks 0184 ; /* deadline, is equal to period plus an initial time (t0) reference 0184 ; (t0 = system_tick). Period = priority + 1. 0184 ; Changing the state from idle to pending occurs here. */ 0184 ; for (i=0; i= deadline) { 01C7 1912 leay -14,x 01C9 18024018 movw 0,y,-8,x 01CD 1802421A movw 2,y,-6,x 01D1 CD0000 ldy #_system_tick 01D4 1802401C movw 0,y,-4,x 01D8 1802421E movw 2,y,-2,x 01DC 160000 jsr __lcmp 01DF 250F blo L46 01E1 ; task[i].state = pending; // change state at deadline 01E1 CC0018 ldd #24 01E4 ED16 ldy -10,x 01E6 13 emul 01E7 C30001 addd #_task+1 01EA B7C6 xgdy 01EC C601 ldab #1 01EE 6B40 stab 0,y 01F0 ; //puts("promote"); 01F0 ; } 01F0 L46: 01F0 ; } 01F0 L41: 01F0 L38: 01F0 EC16 ldd -10,x 01F2 C30001 addd #1 01F5 6C16 std -10,x 01F7 L40: 01F7 EC16 ldd -10,x 01F9 8C0003 cpd #3 01FC 1825FF84 lblo L37 0200 ; // if (task[i].message) {} 0200 ; } 0200 ; 0200 ; 0200 ; // set current = highest priority pending/running task. 0200 ; priority_check = 255; // lowest possible 0200 C6FF ldab #255 0202 6B11 stab -15,x 0204 CC0000 ldd #0 0207 6C16 std -10,x 0209 204E bra L52 020B L49: 020B ; for (i=0; i -4,x 0377 ; lreg2 -> -8,x 0377 ; ?temp -> -16,x 0377 ; local_thp -> -14,x 0377 ; frame_size -> -12,x 0377 ; i -> -10,x 0377 _RTI_handler:: 0377 34 pshx 0378 B775 tfr s,x 037A 1BF1EC leas -20,sp 037D ; 037D ; 037D ; 037D ; #pragma interrupt_handler RTI_handler() 037D ; 037D ; void RTI_handler(void) { 037D ; 037D ; size_t frame_size; 037D ; unsigned int i; 037D ; unsigned char *local_thp; 037D ; 037D ; 037D ; //ACKNOWLEDGE THE INTERRUPT 037D ; INTR_OFF(); // redundant. automatically done by the processor 037D 1410 sei 037F 037F ; RTIFLG = 0x0080; // acknowledge/clear the interrupt 037F C680 ldab #128 0381 7B0015 stab 0x15 0384 ; 0384 ; 0384 ; //putchar('.'); 0384 ; 0384 ; 0384 ; // SET THE FRAME POINTER for the interupted task. 0384 ; // should point to the CCR entry on the stack. 0384 ; asm("TFR x,d"); // start of RTI stack 0384 B754 TFR x,d 0386 0386 ; asm("ADDD #2"); // adjust to CCR stack entry 0386 C30002 ADDD #2 0389 0389 ; asm("STD _temp_task_frame_ptr"); // put into task_frame_ptr 0389 7C000A STD _temp_task_frame_ptr 038C 038C ; task[current].frame_ptr = temp_task_frame_ptr; 038C CC0018 ldd #24 038F FD0000 ldy _current 0392 13 emul 0393 C30016 addd #_task+22 0396 B7C6 xgdy 0398 FC000A ldd _temp_task_frame_ptr 039B 6C40 std 0,y 039D ; 039D ; 039D ; 039D ; //PLACE CURRENT TASK CONTEXT ONTO THE HEAP 039D ; // determine size of heap segment needed 039D ; frame_size = main_frame_ptr - temp_task_frame_ptr; // always positive 039D FC0006 ldd _main_frame_ptr 03A0 B3000A subd _temp_task_frame_ptr 03A3 6C14 std -12,x 03A5 ; task[current].heap_size = (int)frame_size; 03A5 CC0018 ldd #24 03A8 FD0000 ldy _current 03AB 13 emul 03AC C30014 addd #_task+20 03AF B7C6 xgdy 03B1 EC14 ldd -12,x 03B3 6C40 std 0,y 03B5 ; 03B5 ; // reallocate heap memory 03B5 ; task[current].heap_ptr = realloc(task[current].heap_ptr, frame_size); 03B5 18021480 movw -12,x,0,sp 03B9 CC0018 ldd #24 03BC FD0000 ldy _current 03BF 13 emul 03C0 6C10 std -16,x 03C2 C30012 addd #_task+18 03C5 B7C6 xgdy 03C7 EC40 ldd 0,y 03C9 160000 jsr _realloc 03CC 6CE1EE std -18,x 03CF EC10 ldd -16,x 03D1 C30012 addd #_task+18 03D4 B7C6 xgdy 03D6 ECE1EE ldd -18,x 03D9 6C40 std 0,y 03DB ; local_thp = task[current].heap_ptr; 03DB CC0018 ldd #24 03DE FD0000 ldy _current 03E1 13 emul 03E2 C30012 addd #_task+18 03E5 B7C6 xgdy 03E7 ED40 ldy 0,y 03E9 6D12 sty -14,x 03EB ; 03EB ; if (local_thp == NULL) { 03EB EC12 ldd -14,x 03ED 260C bne L88 03EF ; puts("out of heap space!"); 03EF CC0457 ldd #L90 03F2 160000 jsr _puts 03F5 ; exit(0); 03F5 CC0000 ldd #0 03F8 160000 jsr _exit 03FB ; } 03FB L88: 03FB CC0000 ldd #0 03FE 6C16 std -10,x 0400 201A bra L94 0402 L91: 0402 EC16 ldd -10,x 0404 F3000A addd _temp_task_frame_ptr 0407 B7C6 xgdy 0409 E640 ldab 0,y 040B 3B pshd ; spill 040C EC16 ldd -10,x 040E E312 addd -14,x 0410 B7C6 xgdy 0412 3A puld ; reload 0413 6B40 stab 0,y 0415 L92: 0415 EC16 ldd -10,x 0417 C30001 addd #1 041A 6C16 std -10,x 041C L94: 041C ; 041C ; // transfer task frame to the heap one byte at a time. 041C ; // assumes the heap grows from low to high addr. 041C ; for(i=0; i