	.module kernel.c
	.area data
_main_frame_ptr::
	.blkb 2
	.area idata
	.word 0
	.area data
_main_frame_x_ptr::
	.blkb 2
	.area idata
	.word 0
	.area data
_temp_task_frame_ptr::
	.blkb 2
	.area idata
	.word 0
	.area data
_kdb_trace::
	.blkb 2
	.area idata
	.word 1
	.area data
_kdb_trace_cycle::
	.blkb 2
	.area idata
	.word 0
	.area data
	.area text
_error_msg::
	.byte 'u,'n,'i,'m,'p,'l,'i,'m,'e,'n,'t,'e,'d,32,'f,'u
	.byte 'n,'c,'t,'i,'o,'n,0
	.byte 0,0
	.byte 's,'y,'n,'t,'a,'x,32,'e,'r,'r,'o,'r,0
	.word 0,0,0,0,0
	.byte 0,0
	.byte 'i,'l,'l,'e,'g,'a,'l,32,'t,'a,'s,'k,32,'I,'D,0
	.byte 0,0,0,0,0,0,0,0,0
	.byte 'i,'l,'l,'e,'g,'a,'l,32,'t,'a,'s,'k,32,'s,'t,'a
	.byte 't,'e,0
	.byte 0,0,0,0,0,0
	.byte 'i,'l,'l,'e,'g,'a,'l,32,'t,'a,'s,'k,32,'p,'r,'i
	.byte 'o,'r,'i,'t,'y,0
	.byte 0,0,0
	.byte 'o,'u,'t,32,'o,'f,32,'m,'e,'m,'o,'r,'y,0
	.word 0,0,0,0,0
	.byte 0
	.byte 'i,'l,'l,'e,'g,'a,'l,32,'m,'u,'t,'e,'x,32,'I,'D
	.byte 0
	.byte 0,0,0,0,0,0,0,0
	.byte 'i,'l,'l,'e,'g,'a,'l,32,'m,'u,'t,'e,'x,32,'s,'t
	.byte 'a,'t,'e,0
	.byte 0,0,0,0,0
	.byte 'c,'a,'n,'n,'o,'t,32,'c,'r,'e,'a,'t,'e,32,'t,'a
	.byte 's,'k,0
	.byte 0,0,0,0,0,0
_error_src::
	.byte 'k,'e,'r,'n,'e,'l,32,'e,'r,'r,'o,'r,58,0
	.byte 0,0,0,0
	.byte 'k,'e,'r,'n,'e,'l,46,'c,32,'e,'r,'r,'o,'r,58,0
	.byte 0,0
	.byte 'k,'e,'r,'n,'e,'l,32,'R,'T,'I,32,'e,'r,'r,'o,'r
	.byte 58,0
	.byte 's,'h,'e,'l,'l,32,'e,'r,'r,'o,'r,58,0
	.byte 0,0,0,0,0
;  lreg1 -> -4,x
;  lreg2 -> -8,x
;          ?temp -> -19,x
;          ?temp -> -19,x
;          ?temp -> -19,x
;          ?temp -> -21,x
;          ?temp -> -19,x
;             id -> -17,x
;         result -> -15,x
; priority_check -> -13,x
;       deadline -> -12,x
;              i -> -10,x
_main::
	pshx
	tfr s,x
	leas -22,sp
; /*	RLPOS: RLPotter Operating System
; 
; 		   Version 0.8 for the 68HC12D60A microcontroller
; 		   by Ryan Potter
; 		   ryan@rlpotter.com
; 		   
; 		   Compiled with the ImageCraft ICC12 compiler v6.15A
; 		   			- 912D60 Single Chip Mode
; 					- printf option: long
; 		   
; 
; 		   
; 	v0.8 April 29, 2003: 
; 		   - made mutexes dynamic, and much more powerfull and complete.  I had
; 		   	 been calling them semaphores, but they've evolved into mutexes.
; 		   - implemented the TOF_handler interrupt for use with sysTime.  
; 		   	 brings time resolution from 64 ms to 16 ms.
; 		   - added kernel funct: get_sysTime(), set_sysTime(); shell cmd: time.
; 		   - now tasks are 'int f()', and must return a value to the kernel 
; 		   	 when exiting.  kernel doesn't handle it yet, though.
; 		   - in shell, now names of tasks are shell commands (dynamic).
; 		   - put all kernel initialization code into kernel_init().
; 		   - added kernel funct: remove_task().
; 		   
; 	
; 	v0.7 April 25, 2003: 11174 bytes:
; 		   - combined kernel.c & semlib.c with rlpos.c to make one big kernel.c.
; 		   - changed context switch mechanism to give each task a dedicated
; 		   	 stack, making the kernel context switches >400% faster.
; 		   - added a basic timer task that will eventually keep system time/date.
; 		   
; 	v0.6 April 24, 2003: 11042 bytes
; 		   - made the task block and the task control block dynamic, so that
; 		   	 now tasks can create tasks, and can also start/stop them.
; 		   - implemented the sysInit() task for kicking off a user system.
; 		   - implemented a kernel debug command for tracing code execution.
; 		   - implemented small msg box system in kernel for tasks.
; 		   - implemented COP watchdog reset timer.
; 		   - added system resources to semlib.
; 		   - added skeleton ISR_handler() code for the other interrupts.
; 		   - implemented _HC12Setup.c to initialize/harden the system.
; 		   
; 	v0.5 April 16, 2003:
; 		   - added priority preemption.
; 		   - finished kernel task state switcher.
; 		   - it is now officially a legitimate
; 		   	 	rate monotonic
; 				priority preemptive
; 				multitasking
; 				Real Time Operating System  :)
; 		   - made kernel.c and semlib.c consistent with the 
; 		   	 rest of the kernel.
; 		   - included the early framework for a msg box system.
; 			 
; 	v0.4 April 13, 2003: 8096 bytes
; 		   - gerneralized the shell command-line input parser: 
; 		   	 cmd <arg1, arg2, ... argn> (up to 32 chars).
; 		   - added kernel and shell functions.
; 		   
; 	v0.3 April 12, 2003: 6155 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.
; 		5) the stack grows downwards, and there is no boundary checking.
; 		6) chars are one byte
; 		   ints are two bytes
; 		   longs are 4 bytes
; 		7) only 1536 (1.5k) of the 2k ram are available
; 		8) register base is 0x0000
; 		   
; 	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)
; 		
; */
; 	
; 	
; 	
; #include <912d60.h>
; #include <stdio.h>
; #include <stdlib.h>
; #include <string.h>
; #include "kernel.h"
; 
; 
; 
; // FUNCTION PROTOTYPES
; void RTI_handler(void);
; int sysInit(void);
; int shell(void);
; int idleTask(void);
; int (*task_ptr[MAXTASKS])(void);
; 
; 
; 
; 
; // 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
; 
; 
; unsigned int current;		   	 		    // current task id number
; unsigned long int system_tick;
; unsigned int cop_cycle;
; 
; unsigned long int time_tick;  				// one tick every x microseconds
; 
; 
; // task control block
; typedef struct task_block {
; 	 	int (*address)();			   		// Address of the task
; 	 	unsigned char id; 			  		// ID of task
; 		char name[9];	  					// Name
; 		enum task_state state;				// State
; 		unsigned char priority;				// Priority
; 		unsigned long int period_tick;		// for determining if deadline is up
; 		unsigned int interrupt_msg_box;		// flags for pending interrupts
; 		enum message_box message;			// misc flags
; 		unsigned char message_data[2];		// data for misc_msg_box flags
; 		unsigned int stack_size;			// heap allocated for task stack
; 	 	unsigned char *top_of_stack;		// top of task stack in the heap
; 		unsigned char *frame_ptr;			// CCR pointer in idle stack
; 		};
; 
; 
; // mutex control block
; typedef struct mutex_block {
; 		unsigned char id;	   				// ID of mutex instance
; 		unsigned char type;					// COM1, ATD1, etc
; 		char name[5];	  					// Name of mutex
; 		enum mutex_state state;			// State (busy, free...)
; 		signed char owner;					// Current mutex owner
; 		signed char queue[3];				// Tasks waiting on mutex
; 		unsigned char queue_ptr;			// Next free spot in queue
; 		};
; 		
; 		
; struct task_block *task[MAXTASKS];
; struct mutex_block *mutex[MAXMUTEXES];
; 
; 
; 
; int kdb_trace = 1;
; int kdb_trace_cycle = 0;
; 			  
; 
; struct time {
; 	   char hours;
; 	   char minutes;
; 	   char seconds;
; 	   int milliseconds;
; 	   };
; 	   
; int exit_status;
; 			  
; 			  
; 
; // global interrupt flags
; //unsigned int interrupt_flags_ADC;
; //unsigned int interrupt_flags_TC;
; 
; 
; 
; 
; // error massages
; const char error_msg[][25] = {"unimplimented function",	// error 0 
; 	 				  	"syntax error",				// error 1 
; 						"illegal task ID",			// error 2 
; 						"illegal task state",		// error 3 
; 						"illegal task priority",	// error 4 
; 						"out of memory",			// error 5 
; 						"illegal mutex ID",			// error 6
; 						"illegal mutex state",		// error 7
; 						"cannot create task"		// error 8
; 						};
; const char error_src[][18] = {"kernel error:",		// source 0
; 	 				  	"kernel.c error:",			// source 1
; 						"kernel RTI error:",		// source 2
; 						"shell error:",				// source 3
; 						};
; 						
; 						
; 
; 
; 
; void main(void) {
; 
; 	 // LOCAL VARIABLES
; 	 int result, id, i;
; 	 unsigned char priority_check;
; 	 unsigned int deadline;	   	 		
; 
; 	 
; 	 
; 	 // INITIALIZE the kernel
; 	 kernel_init();
	jsr _kernel_init
; 	 
; 	 
;  	 // save SP value for use in the RTI
; 	 asm("TFR s,d");
		TFR s,d

; 	 asm("STD _main_frame_ptr");
		STD _main_frame_ptr

; 	 // save X reg value for use in the RTI
; 	 asm("TFR x,d");
		TFR x,d

; 	 asm("STD _main_frame_x_ptr");
		STD _main_frame_x_ptr

	lbra L5
L4:
; 	 
; 	 
; 	 
; 	 // MULTITASKING KERNEL: Priority Preemptive, Real Time, multitasking 
; 		// KDB_TRACE Section 2
; 	 while(1) {	 
; 	 	
; 		//-------------------------------
; 		/* REENTRY POINT after either 
; 		   	   1) task finishes, or 
; 		   	   2) RTI
; 		*/
; 		//-------------------------------
; 		
; 		
; 		if (kdb_trace_cycle >= KDB_CYCLES)
	ldd _kdb_trace_cycle
	cpd #4
	blt L7
; 		   kdb_trace = 0;
	ldd #0
	std _kdb_trace
L7:
; 		
; 		#ifdef KDB_TRACE_LEVEL_1
; 			if (kdb_trace) puts("kDB2.1");	 
; 		#endif
; 		   
; 		   		
; 		/* No RTI interrupts allowed inside of main().  Only allowed
; 		   inside of non-critical sections of tasks */ 
; 	 	//INTR_OFF();	
; 		
; 		
; 		// PET THE DOG: cop watchdog reset timer (pet freq = 2x COP freq)
; 		if (cop_cycle == 4) {
	ldd _cop_cycle
	cpd #4
	bne L9
; 		   COP_PET(0x55);
	ldab #85
	stab 0x17
; 		   COP_PET(0xAA);
	ldab #170
	stab 0x17
; 		   cop_cycle = 0;
	ldd #0
	std _cop_cycle
; 		   //putchar(':');
; 		   }
L9:
	ldd #0
	std -10,x
L11:
; 		#ifdef KDB_TRACE_LEVEL_1
; 			if (kdb_trace) puts("kDB2.2-1");	 
; 		#endif
; 		
; 		
; 		
; 		// CHANGE STATES ACCORDING TO MESSAGES
; 		// 'waiting' needs to have highest precedence here
; 		for (i=0; i<MAXTASKS; i++) {
; 			if (task[i] == NULL)
	ldd -10,x
	lsld
	addd #_task
	xgdy
	ldd 0,y
	bne L15
; 			   continue;
	bra L12
L15:
; 			if (task[i]->message && STATE_FLAG) {  
	ldd -10,x
	lsld
	addd #_task
	xgdy
	ldy 0,y
	tst 20,y
	beq L17
; 			   // set task state to what the message says
; 		   	   task[i]->state = task[i]->message_data[STATE_BOX];
	ldd -10,x
	lsld
	addd #_task
	xgdy
	ldy 0,y
	sty -19,x
	ldy -19,x
	ldab 21,y
	ldy -19,x
	stab 12,y
; 			   // clear the STATE_FLAG
; 			   task[i]->message &= ~(STATE_FLAG);
	ldd -10,x
	lsld
	addd #_task
	xgdy
	ldd 0,y
	addd #20
	std -21,x
	tfr d,y
	pshy ; spill
	ldy -21,x
	puly ; reload
	bclr 0,y,#0x1
; 			   #ifdef KDB_TRACE_LEVEL_2
; 				if (kdb_trace) puts("kDB2.3-2a");	 
; 			   #endif
; 			   }
L17:
L12:
	ldd -10,x
	addd #1
	std -10,x
	ldd -10,x
	cpd #8
	blt L11
	ldd #0
	std -10,x
L19:
; 			#ifdef KDB_TRACE_LEVEL_2
; 				if (kdb_trace) puts("kDB2.3-2b");	 
; 			#endif
; 			}
; 		#ifdef KDB_TRACE_LEVEL_1
; 			if (kdb_trace) puts("kDB2.3-1");	 
; 		#endif
; 		
; 			
; 
; 		// RT PRIORITY BLOCK:
; 		// set the current task id based on priority and deadline
; 		
; 		// determine if the deadline is up for idle tasks
; 		/* deadline, is equal to period plus an initial time (t0) reference
; 		   (t0 = system_tick).  Period = priority + 1.  
; 		   Changing the state from idle to PENDING occurs here.  */
; 		for (i=0; i<MAXTASKS; i++) {
; 			if (task[i]->state == IDLE) {
	ldd -10,x
	lsld
	addd #_task
	xgdy
	ldy 0,y
	tst 12,y
	bne L23
; 			   deadline = task[i]->period_tick + (task[i]->priority + 1);
	ldd -10,x
	lsld
	addd #_task
	xgdy
	ldy 0,y
	sty -19,x
	ldy -19,x
	ldab 13,y
	clra
	addd #1
	jsr __d2lreg2
	ldy -19,x
	leay 14,y
	movw 0,y,-4,x
	movw 2,y,-2,x
	jsr __ladd
	jsr __lreg2d
	std -12,x
; 			   if (system_tick >= deadline) {
	ldy #_system_tick
	movw 0,y,-4,x
	movw 2,y,-2,x
	ldd -12,x
	std -6,x
	movw #0,-8,x
	jsr __lcmp
	blo L25
; 			   	  task[i]->state = PENDING; 	  // change state at deadline
	ldd -10,x
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab #1
	stab 12,y
; 				  #ifdef KDB_TRACE_LEVEL_2
; 					if (kdb_trace) puts("kDB2.4-2");	 
; 				  #endif
; 			   	  } 	
L25:
; 				}
L23:
L20:
	ldd -10,x
	addd #1
	std -10,x
	ldd -10,x
	cpd #8
	blt L19
; 			 // if (task[i]->message) {} ???		
; 			 }
; 		#ifdef KDB_TRACE_LEVEL_1
; 			if (kdb_trace) puts("kDB2.4-1");	 
; 		#endif			
; 		
; 		
; 		// set current = to highest priority pending/running task.
; 		priority_check = 255;   	  	  // lowest possible
	ldab #255
	stab -13,x
	ldd #0
	std -10,x
L27:
; 		
; 		for (i=0; i<MAXTASKS; i++) {
; 			if (!(task[i] == NULL)) {
	ldd -10,x
	lsld
	addd #_task
	xgdy
	ldd 0,y
	beq L31
	ldd -10,x
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 12,y
	clra
	std -19,x
	cpd #1
	beq L35
	ldd -19,x
	cpd #2
	bne L33
L35:
; 			   if ((task[i]->state == PENDING) || (task[i]->state == RUNNING)) {
; 			   	  if (task[i]->priority <= priority_check) {
	ldd -10,x
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 13,y
	cmpb -13,x
	bhi L36
; 				  	 current = i;
	ldd -10,x
	std _current
; 				 	 priority_check = task[i]->priority;
	ldd -10,x
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 13,y
	stab -13,x
; 				 	 #ifdef KDB_TRACE_LEVEL_2
; 						if (kdb_trace) puts("kDB2.5-2");	 
; 				  	 #endif 
; 			   	 	 }
L36:
; 			   	   }
L33:
; 				}
L31:
L28:
	ldd -10,x
	addd #1
	std -10,x
	ldd -10,x
	cpd #8
	blt L27
	ldd _current
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 12,y
	clra
	std -19,x
	lbeq L39
	ldd -19,x
	cpd #1
	beq L42
	ldd -19,x
	cpd #2
	lbeq L43
	ldd -19,x
	cpd #3
	lbeq L39
	ldd -19,x
	cpd #4
	lbeq L39
	lbra L38
X0:
; 			 }
; 		#ifdef KDB_TRACE_LEVEL_1
; 			if (kdb_trace) puts("kDB2.5-1");	 
; 		#endif
; 		
; 		
; 		
; 		// DISPATCH, or otherwise deal with the current task
; 			// KDB_TRACE Section 3
; 
; 		#ifdef KDB_TRACE_LEVEL_2
; 		if (kdb_trace) {
; 			printf("task[%d]->state = %d\n", current, task[current]->state);
; 			printf("task[%d]->prior = %d\n", current, task[current]->priority);
; 			}
; 		#endif
; 		
; 		switch (task[current]->state) {
; 			   case IDLE:			   // skip task
; 					#ifdef KDB_TRACE_LEVEL_1
; 						if (kdb_trace) puts("kDB3.1-1");
; 					#endif
; 					break;
L42:
; 			   case PENDING:		   // ready and waiting to run
; 					#ifdef KDB_TRACE_LEVEL_1
; 						if (kdb_trace) puts("kDB3.2-1");
; 					#endif
; 					#ifdef KDB_TRACE_LEVEL_2
; 						if (kdb_trace) {
; 							//puts("kDB3.2-2");
; 							putchar('S');
; 							putchar(current+48);
; 							putchar('\n');
; 						    }
; 					#endif  
; 					task[current]->state = RUNNING;
	ldd _current
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab #2
	stab 12,y
; 					task[current]->period_tick = system_tick;
	ldd _current
	lsld
	addd #_task
	xgdy
	ldy 0,y
	leay 14,y
	pshy ; spill
	ldy #_system_tick
	movw 0,y,-4,x
	movw 2,y,-2,x
	puly ; reload
	movw -4,x,0,y
	movw -2,x,2,y
; 					temp_task_frame_ptr = task[current]->top_of_stack;
	ldd _current
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldy 25,y
	sty _temp_task_frame_ptr
; 					asm("LDS _temp_task_frame_ptr");		// set the SP
		LDS _temp_task_frame_ptr

; 			   		exit_status = (*task_ptr[current])();	// start the task
	ldd _current
	lsld
	addd #_task_ptr
	xgdy
	ldy 0,y
	jsr 0,y
	std _exit_status
; 					asm("LDS _main_frame_ptr");				// reset the SP
		LDS _main_frame_ptr

; 					task[current]->state = IDLE;			// task finished
	ldd _current
	lsld
	addd #_task
	xgdy
	ldy 0,y
	clr 12,y
; 					#ifdef KDB_TRACE_LEVEL_1
; 						if (kdb_trace) puts("kDB3.3-1");
; 					#endif
; 					#ifdef KDB_TRACE_LEVEL_2
; 						if (kdb_trace) {
; 							//puts("kDB3.3-2");
; 							putchar('F');
; 							putchar(current+48);
; 							putchar('\n');
; 						    }
; 					#endif  				
; 			   		break;
	bra L39
L43:
; 			   case RUNNING:			// interrupted. continue running.
; 					// restore context and run
; 					temp_task_frame_ptr = task[current]->frame_ptr;
	ldd _current
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldy 27,y
	sty _temp_task_frame_ptr
; 					asm("LDS _temp_task_frame_ptr");
		LDS _temp_task_frame_ptr

; 					asm("RTI");
		RTI

; 			   		break;
	bra L39
X1:
; 			   case WAITING:   		   // waiting on a mutex
; 					#ifdef KDB_TRACE_LEVEL_1
; 						if (kdb_trace) puts("kDB3.5-1");
; 					#endif
; 			   		break;
; 			   case STOPPED:		   // done running until later
; 					#ifdef KDB_TRACE_LEVEL_1
; 						if (kdb_trace) puts("kDB3.6-1");
; 					#endif
; 			   		break;
L38:
; 			   default:	  			   // shouldn't happen, but, error if so.
; 			   		puts("KERNEL: task state error\n");
	ldd #L46
	jsr _puts
; 			   		exit(1);
	ldd #1
	jsr _exit
; 				}	// end switch
L39:
L5:
	lbra L4
X2:
; 		
; 		
; 		
; 			// exit_status HANDLER
; 			//...
; 			
; 			
; 			
; 	 		}		// end while(1)
; 			
; 	 
; }			 		// end main()
L3:
	tfr x,s
	pulx
	.dbline 0 ; func end
	rts
;  lreg1 -> -4,x
;  lreg2 -> -8,x
_RTI_handler::
	pshx
	tfr s,x
	leas -8,sp
; 
; 
; 
; #pragma interrupt_handler RTI_handler()
; 
; void RTI_handler(void) {
; 	 
; 	 //ACKNOWLEDGE THE INTERRUPT
; 	 RTIFLG = 0x0080;  	// acknowledge/clear the interrupt
	ldab #128
	stab 0x15
; 	 
; 	 
; 	 #ifdef KDB_TRACE_LEVEL_1
; 	  	if (kdb_trace) putchar('.');
; 	 #endif
; 	 //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
		TFR x,d

; 	 asm("ADDD #2");				  	 // adjust to CCR stack entry
		ADDD #2

; 	 asm("STD _temp_task_frame_ptr");	 // put into task_frame_ptr
		STD _temp_task_frame_ptr

; 	 task[current]->frame_ptr = temp_task_frame_ptr;
	ldd _current
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldd _temp_task_frame_ptr
	std 27,y
; 	 
; 
; 	 
; 	 // update system time base and cop reset counter
; 	 system_tick++;
	ldy #_system_tick
	movw 0,y,-4,x
	movw 2,y,-2,x
	ldy #L48
	movw 0,y,-8,x
	movw 2,y,-6,x
	jsr __ladd
	ldy #_system_tick
	movw -4,x,0,y
	movw -2,x,2,y
; 	 cop_cycle++;
	ldd _cop_cycle
	addd #1
	std _cop_cycle
;  	 if (time_tick > TIME_TICKS_PER_DAY) {
	ldy #_time_tick
	movw 0,y,-4,x
	movw 2,y,-2,x
	ldy #L51
	movw 0,y,-8,x
	movw 2,y,-6,x
	jsr __lcmp
	bls L49
; 	 	time_tick = 0;
	ldy #L52
	movw 0,y,-4,x
	movw 2,y,-2,x
	ldy #_time_tick
	movw -4,x,0,y
	movw -2,x,2,y
; 		}
L49:
; 	 
; 	 
; 	 
; 	 // RETURN: simulate a RTS instruction
; 	 // set stack pointer for main()
; 	 asm("LDS _main_frame_ptr");
		LDS _main_frame_ptr

; 	 asm("LDX _main_frame_x_ptr");
		LDX _main_frame_x_ptr

; 	 /* return to main() at the reentry point
; 	    and must be adjusted after some kernel mods/compilations!!  */
; 	 asm("JMP $116A");
		JMP $116A

; 	 	 
; }
L47:
	tfr x,s
	pulx
	.dbline 0 ; func end
	rti
;  lreg1 -> -4,x
;  lreg2 -> -8,x
;              i -> -10,x
_kernel_init::
	pshx
	tfr s,x
	leas -18,sp
; 
; 
; 
; 
; void kernel_init(void) {
; 
; 	 // LOCAL VARIABLES
; 	 extern int _bss_end, _textmode;
; 	 int i;
; 	 
; 	 
; 	 	
; 	 // START/INITIALIZE the os
; 		// KDB_TRACE Section 1
; 	
; 	
; 	 // initialize globals	
; 	 _textmode = 1;	 	  // maps '\n' to "CR/LF" for Windows terminals
	ldd #1
	std __textmode
; 
; 	 
; 	 // create and initialize the heap (for dynamic (runtime) var allocation)
; 	 _NewHeap(&_bss_end, (char *)(&_bss_end) + (INITIAL_HEAP_SIZE));
	ldd #__bss_end+1274
	std 0,sp
	ldd #__bss_end
	jsr __NewHeap
; 	 
; 	 
; 	 // set up the serial port
; 	 setbaud(BAUD38K);	 	  // actually running at 19K baud due to xtal speed
	ldd #13
	jsr _setbaud
; 	 #ifdef KDB_TRACE_LEVEL_1
; 		if (kdb_trace) puts("kDB1-0");	 
; 	 #endif
; 
; 	 
; 	 // print the opening comments
; 	 puts("rlpOS v0.8\n\n");
	ldd #L55
	jsr _puts
; 	 
; 		
; 	 // create the shell
; 	 if (create_task("shell", &shell, 0, PENDING, DEFAULT_SHELL_STACK_SIZE) < 0)
	ldd #350
	std 6,sp
	ldd #1
	std 4,sp
	ldd #0
	std 2,sp
	ldd #_shell
	std 0,sp
	ldd #L58
	jsr _create_task
	cpd #0
	bge L56
; 	 	puts("shell failure");
	ldd #L59
	jsr _puts
L56:
; 	 #ifdef KDB_TRACE_LEVEL_1
; 		if (kdb_trace) puts("kDB1-2");	 
; 	 #endif
; 	 
; 	 
; 	 if (create_task("idleTask", &idleTask, 255, PENDING, 32) < 0)
	ldd #32
	std 6,sp
	ldd #1
	std 4,sp
	ldd #255
	std 2,sp
	ldd #_idleTask
	std 0,sp
	ldd #L62
	jsr _create_task
	cpd #0
	bge L60
; 	 	puts("idleTask failure");
	ldd #L63
	jsr _puts
L60:
; 	 #ifdef KDB_TRACE_LEVEL_1
; 		if (kdb_trace) puts("kDB1-2");	 
; 	 #endif
; 	 	 
; 	 
; 	 // create the COM1 mutex
; 	 if (create_mutex(COM1, "COM1") < 0)
	ldd #L66
	std 0,sp
	ldd #3
	jsr _create_mutex
	cpd #0
	bge L64
; 	 	  puts("COM1 failure");
	ldd #L67
	jsr _puts
L64:
; 	 #ifdef KDB_TRACE_LEVEL_1
; 		if (kdb_trace) puts("kDB1-1");	 
; 	 #endif
; 	 
; 	 
; 	 system_tick = 0;
	ldy #L52
	movw 0,y,-4,x
	movw 2,y,-2,x
	ldy #_system_tick
	movw -4,x,0,y
	movw -2,x,2,y
; 	 current = 0;
	ldd #0
	std _current
; 	 cop_cycle = 0;
	ldd #0
	std _cop_cycle
; 	 COP_PET(0x55);
	ldab #85
	stab 0x17
; 	 COP_PET(0xAA);
	ldab #170
	stab 0x17
; 	 
; 	 
; 	 	 
; 	 /*// create the sysInit task
; 	 if (create_task("sysInit", &sysInit, 0, PENDING, 0) < 0)
; 	 	puts("sysInit failure");
; 	 #ifdef KDB_TRACE_LEVEL_1
; 		if (kdb_trace) puts("kDB1-1");	 
; 	 #endif*/
; 	 sysInit();
	jsr _sysInit
; 
; }
L53:
	tfr x,s
	pulx
	.dbline 0 ; func end
	rts
;             id -> 3,x
_if_task_exists::
	pshd
	pshx
	tfr s,x
; 
; 
; 
; // KERNEL FUNCTIONS
; 
; int if_task_exists(unsigned char id) {
; 
; 	if (task[id] == NULL)
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	bne L69
; 	   return -1;
	ldd #-1
	bra L68
L69:
; 	else
; 	   return task[id]->id;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 2,y
	clra
L68:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;             id -> 3,x
_get_task_address::
	pshd
	pshx
	tfr s,x
; 
; }
; 
; 
; 
; 
; int get_task_address(unsigned char id) {
; 
; 	return (int)task[id]->address;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd [0,y]
L71:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
_get_task_id::
; 
; }
; 
; 
; 
; 
; char get_task_id() { 
; 	 
; 	 return task[current]->id;
	ldd _current
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 2,y
	clra
L72:
	.dbline 0 ; func end
	rts
;             id -> 3,x
_get_task_name::
	pshd
	pshx
	tfr s,x
; }
; 
; 
; 
; char *get_task_name(unsigned char id) {
; 	 if (task[id] == NULL)
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	bne L74
; 	 	return NULL;
	ldd #0
	bra L73
L74:
; 	 else
; 	 	return task[id]->name; 
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	addd #3
L73:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;             id -> 3,x
_get_task_state::
	pshd
	pshx
	tfr s,x
; }
; 
; 
; 
; 
; int get_task_state(unsigned char id) { 
; 
; 	if (task[id] == NULL)
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	bne L77
; 	   return -1;
	ldd #-1
	bra L76
L77:
; 	else if (id < MAXTASKS)
	ldab 3,x
	cmpb #8
	bhs L79
; 	 	return task[id]->state;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 12,y
	clra
	bra L76
L79:
; 	else {
; 	 	  #ifdef KERNEL_ERROR_MSG
; 	 	  puts(error_src[1]); puts(error_msg[3]);
; 		  #endif
; 		  return -1;
	ldd #-1
L76:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;             id -> 3,x
_get_task_messages::
	pshd
	pshx
	tfr s,x
; 		  }
; 		  
; }
; 
; 
; 
; int get_task_messages(unsigned char id) {
; 
; 	if (task[id] == NULL)
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	bne L82
; 	   return -1;
	ldd #-1
	bra L81
L82:
; 	else if (id < MAXTASKS)
	ldab 3,x
	cmpb #8
	bhs L84
; 	   return task[id]->message;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 20,y
	clra
	bra L81
L84:
; 	else {
; 		 #ifdef KERNEL_ERROR_MSG
; 	 	 puts(error_src[1]); puts(error_msg[3]);
; 		 #endif
; 		 return -1;
	ldd #-1
L81:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;             id -> 3,x
_get_task_priority::
	pshd
	pshx
	tfr s,x
; 		 }
; 
; }
; 
; 
; 
; int get_task_priority(unsigned char id) { 
; 
; 		 INTR_OFF();
		sei

; 		 
; 		 if (id < MAXTASKS) {
	ldab 3,x
	cmpb #8
	bhs L87
; 		 	INTR_ON();
		cli

; 		 	return task[id]->priority;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 13,y
	clra
	bra L86
L87:
; 			}
; 		 else {
; 	 	 	#ifdef KERNEL_ERROR_MSG
; 	 	 	puts(error_src[1]); puts(error_msg[4]);
; 			#endif
; 			INTR_ON();
		cli

; 			return -1;
	ldd #-1
L86:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;          ?temp -> -4,x
;          ?temp -> -4,x
;          ?temp -> -4,x
;          ?temp -> -4,x
;          ?temp -> -4,x
;          ?temp -> -2,x
;       newstate -> 7,x
;             id -> 3,x
_set_task_state::
	pshd
	pshx
	tfr s,x
	leas -4,sp
; 		 	}
; 
; }
; 
; 
; 
; int set_task_state(unsigned char id, unsigned char newstate) {
; 	
; 	
; 	INTR_OFF();
		sei

; 	
; 	
; 	// check id validity
; 	if (id < MAXTASKS) {
	ldab 3,x
	cmpb #8
	lbhs L90
; 
; 	   if (task[id] == NULL) {
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	bne L92
; 	   	  #ifdef KERNEL_ERROR_MSG
; 	 	  puts(error_src[1]); puts(error_msg[2]);
; 		  #endif
; 		  INTR_ON();
		cli

; 	 	  return -1;
	ldd #-1
	lbra L89
L92:
; 	   	  }
; 		  
; 		  
; 	   // check newstate validity
; 	   if ((newstate == RUNNING) || 
	ldab 7,x
	cmpb #2
	beq L97
	ldab 7,x
	cmpb #3
	beq L97
	ldab 7,x
	cmpb #4
	bls L94
L97:
; 	   	  (newstate == WAITING)  ||
; 	   	  (newstate > STOPPED)) { 
; 	      		 #ifdef KERNEL_ERROR_MSG
; 	 	 	  	 puts(error_src[1]); puts(error_msg[3]);
; 			  	 #endif
; 				 INTR_ON();
		cli

; 	 	  		 return -1;
	ldd #-1
	lbra L89
L94:
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 12,y
	clra
	std -2,x
	beq L101
	ldd -2,x
	cpd #1
	lbeq L108
	ldd -2,x
	cpd #2
	lbeq L115
	ldd -2,x
	cpd #4
	lbeq L118
	lbra L98
X3:
; 	   			 }
; 	 
; 	 		// referenced to the task's current state:
; 	   		switch (task[id]->state) {
L101:
; 		   	  	   case IDLE:
; 				   		if (newstate == IDLE) {	   // no change
	tst 7,x
	bne L102
; 						   INTR_ON();
		cli

; 				 		   return 0;
	ldd #0
	lbra L89
L102:
; 						   }
; 				 		else if (newstate == PENDING) {
	ldab 7,x
	cmpb #1
	bne L104
; 				 		   // pass msg to task[id]->msgbox;
; 						   task[id]->message |= STATE_FLAG;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	addd #20
	std -4,x
	tfr d,y
	pshy ; spill
	ldy -4,x
	puly ; reload
	bset 0,y,#1
; 		  				   task[id]->message_data[STATE_BOX] = PENDING;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab #1
	stab 21,y
; 						   INTR_ON();
		cli

; 					  	   return 0;
	ldd #0
	lbra L89
L104:
; 				 		   }
; 						else if (newstate == STOPPED) {
	ldab 7,x
	cmpb #4
	bne L106
; 							// pass msg to task[id]->msgbox;
; 						    task[id]->message |= STATE_FLAG;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	addd #20
	std -4,x
	tfr d,y
	pshy ; spill
	ldy -4,x
	puly ; reload
	bset 0,y,#1
; 		  					task[id]->message_data[STATE_BOX] = STOPPED;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab #4
	stab 21,y
; 							INTR_ON();
		cli

; 					  		return 0; 
	ldd #0
	lbra L89
L106:
; 						    }
; 				 		else {	  // nothing else is legal;
; 						   	 #ifdef KERNEL_ERROR_MSG
; 	 	 	  			   	 puts(error_src[1]); puts(error_msg[3]);
; 			  			   	 #endif
; 							 INTR_ON();
		cli

; 					  		 return -1;
	ldd #-1
	lbra L89
X4:
; 				 			 }
; 				 		break;
L108:
; 		   			case PENDING:
; 						 if (newstate == PENDING) {	// no change
	ldab 7,x
	cmpb #1
	bne L109
; 						 	INTR_ON();
		cli

; 				 		 	return 0;
	ldd #0
	lbra L89
L109:
; 							}
; 						 else if (newstate == IDLE) {
	tst 7,x
	bne L111
; 				   		 	  // pass msg to task[id]->msgbox;
; 						   	  #ifdef KERNEL_ERROR_MSG
; 	 	 	  			   	  puts(error_src[1]); puts(error_msg[0]);
; 			  			   	  #endif
; 							  INTR_ON();
		cli

; 					  		  return -1;
	ldd #-1
	lbra L89
L111:
; 							  }
; 						 else if (newstate == STOPPED) {
	ldab 7,x
	cmpb #4
	bne L113
; 				   		 	  	 // pass msg to task[id]->msgbox;
; 							  	 task[id]->message |= STATE_FLAG;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	addd #20
	std -4,x
	tfr d,y
	pshy ; spill
	ldy -4,x
	puly ; reload
	bset 0,y,#1
; 		  					  	 task[id]->message_data[STATE_BOX] = STOPPED;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab #4
	stab 21,y
; 							  	 INTR_ON();
		cli

; 					  		  	 return 0;
	ldd #0
	lbra L89
L113:
; 						 	  	 }	
; 						 else {
; 				   		 	  #ifdef KERNEL_ERROR_MSG
; 							  puts(error_src[1]); puts(error_msg[3]);
; 							  #endif
; 							  INTR_ON();
		cli

; 							  return -1;
	ldd #-1
	lbra L89
X5:
; 						 	  }
; 						 break;
L115:
; 					case RUNNING:
; 						 if (newstate == STOPPED) {
	ldab 7,x
	cmpb #4
	bne L116
; 						 	// pass msg to task[id]->msgbox;
; 							task[id]->message |= STATE_FLAG;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	addd #20
	std -4,x
	tfr d,y
	pshy ; spill
	ldy -4,x
	puly ; reload
	bset 0,y,#1
; 		  					task[id]->message_data[STATE_BOX] = STOPPED;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab #4
	stab 21,y
; 							
; 							INTR_ON();
		cli

; 					  		return 0;
	ldd #0
	lbra L89
L116:
; 						 	}
; 						 else {
; 				   		 	  #ifdef KERNEL_ERROR_MSG
; 							  puts(error_src[1]); puts(error_msg[3]);
; 							  #endif
; 							  INTR_ON();
		cli

; 							  return -1;
	ldd #-1
	lbra L89
X6:
; 						 	  }
; 						 break;
L118:
; 		   			case STOPPED:
; 		   				 if (newstate == STOPPED)	{ 	// no change
	ldab 7,x
	cmpb #4
	bne L119
; 				   		 	INTR_ON();
		cli

; 							return 0;
	ldd #0
	lbra L89
L119:
; 							}
; 						 else if (newstate == PENDING) {
	ldab 7,x
	cmpb #1
	bne L121
; 				   		 	  // pass msg to task[id]->msgbox;
; 							  task[id]->message |= STATE_FLAG;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	addd #20
	std -4,x
	tfr d,y
	pshy ; spill
	ldy -4,x
	puly ; reload
	bset 0,y,#1
; 		  					  task[id]->message_data[STATE_BOX] = PENDING;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab #1
	stab 21,y
; 							  INTR_ON();
		cli

; 					  		  return 0;
	ldd #0
	bra L89
L121:
; 							  }
; 						 else {
; 					 	 	  #ifdef KERNEL_ERROR_MSG
; 							  puts(error_src[1]); puts(error_msg[3]);
; 							  #endif
; 							  INTR_ON();
		cli

; 							  return -1;
	ldd #-1
	bra L89
X7:
; 							  }
; 						 break;
L98:
; 		   			default:
; 		   		   			#ifdef KERNEL_ERROR_MSG
; 							puts(error_src[1]); puts(error_msg[3]);
; 							#endif
; 							INTR_ON();
		cli

; 							return -1;
	ldd #-1
	bra L89
X8:
; 				   			break;
L90:
; 							
; 	 				}	// end switch (task[id]->state)
; 					
; 	 		}		// if (id < MAXTASKS)
; 			
; 		   else {
; 		   		#ifdef KERNEL_ERROR_MSG
; 				puts(error_src[1]); puts(error_msg[2]);
; 				#endif
; 				INTR_ON();
		cli

; 				return -1;
	ldd #-1
	bra L89
X9:
; 				}
; 
; 	 INTR_ON();
		cli

; 	 return 0;
	ldd #0
L89:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;       priority -> 7,x
;             id -> 3,x
_set_task_priority::
	pshd
	pshx
	tfr s,x
; 
; }
; 
; 
; 
; int set_task_priority(unsigned char id, unsigned char priority) {
; 
; 	 if (priority == 0) 			 // priority 0 is reserved for the shell
	tst 7,x
	bne L124
; 	 	priority = 1;
	ldab #1
	stab 7,x
L124:
; 		
; 	 if (id >= (MAXTASKS)) {
	ldab 3,x
	cmpb #8
	blo L126
; 	 	#ifdef KERNEL_ERROR_MSG
; 		puts(error_src[1]); puts(error_msg[4]);
; 		#endif
; 		return -1;
	ldd #-1
	bra L123
L126:
	ldab 7,x
	cmpb #255
	bhi L130
	tst 7,x
	bhs L128
L130:
; 		}
; 	 else if ((priority > 255) || (priority < 0)) {
; 	 	#ifdef KERNEL_ERROR_MSG
; 		puts(error_src[1]); puts(error_msg[4]);
; 		#endif
; 		return -1;
	ldd #-1
	bra L123
L128:
; 		}
; 	 else {
; 	 	 task[id]->priority = priority;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 7,x
	stab 13,y
; 		 return 0;
	ldd #0
L123:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;  lreg1 -> -4,x
;  lreg2 -> -8,x
;          ?temp -> -15,x
;          ?temp -> -13,x
;          ?temp -> -11,x
;             id -> -9,x
;     stack_size -> 12,x
;          state -> 10,x
;       priority -> 9,x
;           addr -> 6,x
;           name -> 2,x
_create_task::
	pshd
	pshx
	tfr s,x
	leas -22,sp
; 		 }
; }
; 
; 
; 
; 
; int create_task(char *name, 
; 				int (*addr)(), 
; 				unsigned char priority, 
; 				int state,
; 				int stack_size) {
; 
; 	// LOCAL VARIABLES
; 	unsigned char id;
; 	
; 	
; 	INTR_OFF();	  // critical section	  
		sei

	clr -9,x
	bra L135
L132:
	ldab -9,x
	clra
	lsld
	addd #_task_ptr
	xgdy
	ldd 0,y
	beq L134
L133:
	ldab -9,x
	clra
	addd #1
	stab -9,x
L135:
; 	
; 	
; 	//if (get_free_memory() > 64) {
; 	
; 	// determine lowest free id available to assign to this task
; 	for (id=0; id<MAXTASKS; id++) {
	ldab -9,x
	cmpb #8
	blo L132
L134:
; 		if (task_ptr[id] != NULL)
; 		   continue;
; 		else
; 		   break;
; 		 }
; 
; 	
; 	// create task block
; 	if ((task[id] = malloc(sizeof(struct task_block))) == NULL) {
	ldd #29
	jsr _malloc
	std -18,x
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldd -18,x
	std 0,y
	ldd -18,x
	bne L138
; 	   #ifdef KERNEL_ERROR_MSG
; 	   puts(error_src[1]); puts(error_msg[5]);
; 	   #endif
; 	   INTR_ON();
		cli

; 	   return -1;
	ldd #-1
	lbra L131
L138:
; 	   }
; 	else { 
; 	 	 // put addr entry into task_ptr[]
; 		 task_ptr[id] = addr;
	ldab -9,x
	clra
	lsld
	addd #_task_ptr
	xgdy
	ldd 6,x
	std 0,y
; 		 
; 		 
; 	 	 // initialize the task structures
; 	 	 task[id]->address = addr;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldd 6,x
	std 0,y
; 		 task[id]->id = id;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab -9,x
	stab 2,y
; 		 strcpy(task[id]->name, name);
	movw 2,x,0,sp
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	addd #3
	jsr _strcpy
;  		 task[id]->state = state;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldd 10,x
	stab 12,y
; 		 task[id]->priority = priority;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab 9,x
	stab 13,y
; 		 task[id]->period_tick = 0;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	leay 14,y
	pshy ; spill
	ldy #L52
	movw 0,y,-4,x
	movw 2,y,-2,x
	puly ; reload
	movw -4,x,0,y
	movw -2,x,2,y
; 		 task[id]->interrupt_msg_box = NULL;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldd #0
	std 18,y
; 		 task[id]->message = NULL;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	clr 20,y
; 		 task[id]->message_data[0] = NULL;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	clr 21,y
; 		 task[id]->message_data[1] = NULL;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	clr 22,y
; 		 if (stack_size <= 0) 
	ldd 12,x
	bgt L140
; 		 	stack_size = DEFAULT_STACK_SIZE; 
	ldd #64
	std 12,x
L140:
; 		 task[id]->stack_size = stack_size;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldd 12,x
	std 23,y
; 		 task[id]->top_of_stack = malloc(task[id]->stack_size); 
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	sty -11,x
	ldy -11,x
	ldd 23,y
	jsr _malloc
	std -20,x
	ldy -11,x
	ldd -20,x
	std 25,y
; 		 task[id]->top_of_stack += task[id]->stack_size;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	sty -13,x
	ldd -13,x
	addd #25
	std -15,x
	ldy -13,x
	ldd 23,y
	addd [-15,x]
	ldy -15,x
	std 0,y
; 		 task[id]->frame_ptr = NULL;
	ldab -9,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldd #0
	std 27,y
; 	
; 	}
; 	//}
; 	INTR_ON();
		cli

; 	 
; 	return id;
	ldab -9,x
	clra
L131:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;          ?temp -> -2,x
;             id -> 3,x
_remove_task::
	pshd
	pshx
	tfr s,x
	leas -2,sp
; 	 
; }
; 
; 
; 
; int remove_task(unsigned char id) {
; 
; 	if (task[id] == NULL)
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	bne L143
; 	   return -1;
	ldd #-1
	bra L142
L143:
; 	   
; 
; 	free(task[id]->top_of_stack - task[id]->stack_size);
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldy 0,y
	sty -2,x
	ldy -2,x
	ldd 25,y
	ldy -2,x
	subd 23,y
	jsr _free
; 	free(task[id]);
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd 0,y
	jsr _free
; 	task[id] = NULL;
	ldab 3,x
	clra
	lsld
	addd #_task
	xgdy
	ldd #0
	std 0,y
; 	task_ptr[id] = NULL;
	ldab 3,x
	clra
	lsld
	addd #_task_ptr
	xgdy
	ldd #0
	std 0,y
; 	
; 	return 0;
	ldd #0
L142:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;             id -> 3,x
_get_mutex_name::
	pshd
	pshx
	tfr s,x
; 
; }
; 
; 
; 
; char *get_mutex_name(unsigned char id) {
; 
; 	 if (mutex[id] == NULL)
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldd 0,y
	bne L146
; 	 	return NULL;
	ldd #0
	bra L145
L146:
; 	 else
; 	 	return mutex[id]->name;
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldd 0,y
	addd #2
L145:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;             id -> 3,x
_get_mutex_state::
	pshd
	pshx
	tfr s,x
; }
; 
; 
; 
; 
; int get_mutex_state(unsigned char id) {
; 
; 	if (id < MAXMUTEXES) {
	ldab 3,x
	cmpb #4
	bhs L149
; 	 	return mutex[id]->state;
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab 7,y
	clra
	bra L148
L149:
; 		}
; 	else {
; 		 #ifdef KERNEL_ERROR_MSG
; 	 	 puts(error_src[1]); puts(error_msg[6]);
; 		 #endif
; 		 return -1;
	ldd #-1
L148:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;             id -> 3,x
_get_mutex_owner::
	pshd
	pshx
	tfr s,x
; 		 }
; 
; }
; 
; 
; 
; 
; 
; int get_mutex_owner(unsigned char id) {
; 
; 	if (id < MAXMUTEXES) {
	ldab 3,x
	cmpb #4
	bhs L152
; 	 	return mutex[id]->owner;
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab 8,y
	tfr b,d
	bra L151
L152:
; 		}
; 	else {
; 		 #ifdef KERNEL_ERROR_MSG
; 	 	 puts(error_src[1]); puts(error_msg[6]);
; 		 #endif
; 		 return -1;
	ldd #-1
L151:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;             id -> 3,x
_get_mutex_queuelen::
	pshd
	pshx
	tfr s,x
; 		 }
; 
; }
; 
; 
; 
; 
; int get_mutex_queuelen(unsigned char id) {
; 
; 	if (id < MAXMUTEXES) {
	ldab 3,x
	cmpb #4
	bhs L155
; 	 	return mutex[id]->queue_ptr;
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab 12,y
	clra
	bra L154
L155:
; 		}
; 	else {
; 		 #ifdef KERNEL_ERROR_MSG
; 	 	 puts(error_src[1]); puts(error_msg[6]);
; 		 #endif
; 		 return -1;
	ldd #-1
L154:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;             id -> -1,x
;           name -> 6,x
;           type -> 3,x
_create_mutex::
	pshd
	pshx
	tfr s,x
	leas -6,sp
; 		 }
; 
; }
; 
; 
; 
; 
; int create_mutex(unsigned char type, char *name) {
; 
; 	// LOCAL VARIABLES
; 	unsigned char id;
; 	
; 	
; 	INTR_OFF();		  // critical section
		sei

	clr -1,x
	bra L161
L158:
; 	
; 	
; 	// determine if the type already exists
; 	for (id=0; id<MAXMUTEXES; id++) {
; 		if (mutex[id] == NULL)
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldd 0,y
	bne L162
; 		   continue;
	bra L159
L162:
; 		if (mutex[id]->type == type) {
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab 1,y
	cmpb 3,x
	bne L164
; 		   INTR_ON();
		cli

; 		   return 0;
	ldd #0
	lbra L157
L164:
L159:
	ldab -1,x
	clra
	addd #1
	stab -1,x
L161:
	ldab -1,x
	cmpb #4
	blo L158
	clr -1,x
	bra L169
L166:
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldd 0,y
	beq L168
L167:
	ldab -1,x
	clra
	addd #1
	stab -1,x
L169:
; 		   }
; 		}
; 	
; 	
; 	// determine lowest free id available to assign to this task
; 	for (id=0; id<MAXMUTEXES; id++) {
	ldab -1,x
	cmpb #4
	blo L166
L168:
; 		if (mutex[id] != NULL)
; 		   continue;
; 		else
; 		   break;
; 		 }
; 	
; 	// create mutex block
; 	if ((mutex[id] = malloc(sizeof(struct mutex_block))) == NULL) {
	ldd #13
	jsr _malloc
	std -4,x
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldd -4,x
	std 0,y
	ldd -4,x
	bne L172
; 	   #ifdef KERNEL_ERROR_MSG
; 	   puts(error_src[1]); puts(error_msg[5]);
; 	   #endif
; 	   INTR_ON();
		cli

; 	   return -1;
	ldd #-1
	lbra L157
L172:
; 	   }
; 	else { 
; 	 	 // initialize the mutex structures
; 	 	 mutex[id]->id = id;
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab -1,x
	stab 0,y
; 		 mutex[id]->type = type;
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab 3,x
	stab 1,y
; 		 strcpy(mutex[id]->name, name);
	movw 6,x,0,sp
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldd 0,y
	addd #2
	jsr _strcpy
; 		 mutex[id]->state = NOTBUSY;
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	clr 7,y
; 		 mutex[id]->owner = -1;
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab #-1
	stab 8,y
; 		 mutex[id]->queue[0] = -1;
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab #-1
	stab 9,y
; 		 mutex[id]->queue[1] = -1;
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab #-1
	stab 10,y
; 		 mutex[id]->queue[2] = -1;
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab #-1
	stab 11,y
; 		 mutex[id]->queue_ptr = 0;
	ldab -1,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	clr 12,y
; 		 }	
; 		
; 	
; 	INTR_ON();
		cli

; 	
; 	return id;
	ldab -1,x
	clra
L157:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;          ?temp -> -8,x
;          ?temp -> -6,x
;          ?temp -> -4,x
;             id -> -2,x
;           type -> 3,x
_get_mutex::
	pshd
	pshx
	tfr s,x
	leas -10,sp
; 
; }
; 
; 
; 
; 
; int get_mutex(unsigned char type) {
; 
; 	 /* Gives a mutex to a requesting task.
; 	 	returns the mutex id number (0,1,2,...) if free.
; 	 	otherwise returns -1.
; 		
; 		At this point, mutexs are a procedural control
; 		that the tasks have to follow to avoid resource contention.
; 		There is no kernel control over resources yet.  */
; 	 
; 	 
; 	 // LOCAL VARIABLES
; 	 int id;
; 	 
; 	 
; 	 
; 	 // critical section
; 	 INTR_OFF();
		sei

	ldd #0
	std -2,x
L175:
; 	 
; 	 
; 	 // find id for mutex type
; 	 for (id=0; id<MAXMUTEXES; id++) {
; 	 	 if (mutex[id] == NULL)
	ldd -2,x
	lsld
	addd #_mutex
	xgdy
	ldd 0,y
	bne L179
; 		 	continue;
	bra L176
L179:
; 		 if (mutex[id]->type == type)
	ldd -2,x
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab 1,y
	cmpb 3,x
	bne L181
; 		 	break;
	bra L177
L181:
L176:
	ldd -2,x
	addd #1
	std -2,x
	ldd -2,x
	cpd #4
	blt L175
L177:
; 	 	 }
; 	 
; 	 
; 	 // GET mutex
; 	 
; 	 // if mutex isn't taken, give it to the requesting task
; 	 if (mutex[id]->state == NOTBUSY) {
	ldd -2,x
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	tst 7,y
	bne L183
; 	 	mutex[id]->state = BUSY;
	ldd -2,x
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab #1
	stab 7,y
; 		mutex[id]->owner = current;
	ldd -2,x
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab _current+1
	stab 8,y
; 		
; 		INTR_ON();
		cli

; 		return id;
	ldd -2,x
	lbra L174
L183:
; 	 	}
; 	 
; 	 // mutex is taken/busy so make task wait
; 	 else {
; 		  // put waiting task into the mutexs queue if there's space
; 		  if (mutex[id]->queue_ptr < 3) {
	ldd -2,x
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab 12,y
	cmpb #3
	lbhs L185
; 		  	 task[current]->message |= STATE_FLAG;
	ldd _current
	lsld
	addd #_task
	xgdy
	ldd 0,y
	addd #20
	std -4,x
	tfr d,y
	pshy ; spill
	ldy -4,x
	puly ; reload
	bset 0,y,#1
; 		  	 task[current]->message_data[STATE_BOX] = WAITING;
	ldd _current
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab #3
	stab 21,y
; 		   	 mutex[id]->queue[mutex[id]->queue_ptr] = current;
	ldd -2,x
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	sty -6,x
	ldy -6,x
	ldab 12,y
	clra
	pshd ; spill
	ldd -6,x
	addd #9
	std -10,x
	puld ; reload
	addd -10,x
	xgdy
	ldab _current+1
	stab 0,y
; 			 mutex[id]->queue_ptr++;
	ldd -2,x
	lsld
	addd #_mutex
	xgdy
	ldd 0,y
	addd #12
	std -8,x
	tfr d,y
	ldab 0,y
	clra
	addd #1
	ldy -8,x
	stab 0,y
; 			 INTR_ON();
		cli

; 			 asm("JMP $116A");
		JMP $116A

; 			 return 0;
	ldd #0
	bra L174
L185:
; 		   	 }
; 		  else {  // can't give mutex
; 		  	   INTR_ON();
		cli

; 		  	   return -1;
	ldd #-1
L174:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;          ?temp -> -10,x
;          ?temp -> -8,x
;          ?temp -> -6,x
;          ?temp -> -4,x
;          ?temp -> -2,x
;             id -> 3,x
_give_mutex::
	pshd
	pshx
	tfr s,x
	leas -10,sp
; 			   }
; 	 	  } 	
; 		  
; }
; 
; 
; 
; 
; int give_mutex(char id) {
; 
; 	/* Takes a mutex back from a task.
; 	   will (eventually) pass a message to a waiting task.  
; 	   
; 	   	At this point, mutexs are a procedural control
; 		that the tasks have to follow to avoid resource contention.
; 		There is no kernel control over resources yet.  */
; 	
; 	
; 	// critical section
; 	INTR_OFF();
		sei

; 	
; 
; 	// if any tasks are waiting on the mutex, give it to them
; 	if (mutex[id]->queue_ptr > 0) {
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	tst 12,y
	lbls L188
; 	   //mutex[id]->state = BUSY;
; 	   mutex[id]->owner = mutex[id]->queue[0];
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	sty -2,x
	ldy -2,x
	ldab 9,y
	ldy -2,x
	stab 8,y
; 	   
; 	   // take the receiving task out of the waiting state
; 	   task[current]->message |= STATE_FLAG;
	ldd _current
	lsld
	addd #_task
	xgdy
	ldd 0,y
	addd #20
	std -4,x
	tfr d,y
	pshy ; spill
	ldy -4,x
	puly ; reload
	bset 0,y,#1
; 	   task[current]->message_data[STATE_BOX] = RUNNING;
	ldd _current
	lsld
	addd #_task
	xgdy
	ldy 0,y
	ldab #2
	stab 21,y
; 		  
; 	   // shift the queue
; 	   mutex[id]->queue[0] = mutex[id]->queue[1];
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	sty -6,x
	ldy -6,x
	ldab 10,y
	ldy -6,x
	stab 9,y
; 	   mutex[id]->queue[1] = mutex[id]->queue[2];
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	sty -8,x
	ldy -8,x
	ldab 11,y
	ldy -8,x
	stab 10,y
; 	   mutex[id]->queue_ptr--;
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldd 0,y
	addd #12
	std -10,x
	tfr d,y
	ldab 0,y
	clra
	subd #1
	ldy -10,x
	stab 0,y
; 	   
; 	   INTR_ON();
		cli

; 	   return 0;
	ldd #0
	bra L187
L188:
; 	   }
; 	else {
; 		 // return the mutex
; 		 mutex[id]->state = NOTBUSY;
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	clr 7,y
; 		 mutex[id]->owner = -1;
	ldab 3,x
	clra
	lsld
	addd #_mutex
	xgdy
	ldy 0,y
	ldab #-1
	stab 8,y
; 		 INTR_ON();
		cli

; 		 return 0;
	ldd #0
L187:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;  lreg1 -> -4,x
;  lreg2 -> -8,x
;           slop -> -12,x
_get_sysTime::
	pshx
	tfr s,x
	leas -12,sp
; 		 }
; 	  
; }
; 
; 
; 
; unsigned long int get_sysTime(void) { 
; 			
; 	   // LOCAL VARIABLES
; 	   unsigned long int slop;
; 	   
; 	     
; 	   // returns the number of milliseconds since midnight (time_tick=0);
; 	   slop = time_tick / 40;
	ldy #_time_tick
	movw 0,y,-4,x
	movw 2,y,-2,x
	ldy #L191
	movw 0,y,-8,x
	movw 2,y,-6,x
	jsr __ludiv
	leay -12,x
	movw -4,x,0,y
	movw -2,x,2,y
; 	   return (time_tick * ms_PER_TIME_TICK + slop);
	ldy #L192
	movw 0,y,-4,x
	movw 2,y,-2,x
	ldy #_time_tick
	movw 0,y,-8,x
	movw 2,y,-6,x
	jsr __lmul
	leay -12,x
	movw 0,y,-8,x
	movw 2,y,-6,x
	jsr __ladd
	jsr __lret
L190:
	tfr x,s
	pulx
	.dbline 0 ; func end
	rts
;  lreg1 -> -4,x
;  lreg2 -> -8,x
;           slop -> -12,x
;        seconds -> 8,x
;        minutes -> 6,x
;          hours -> 2,x
_set_sysTime::
	pshd
	pshx
	tfr s,x
	leas -14,sp
; 	   
; }
; 
; 
; 
; void set_sysTime(unsigned int hours, unsigned int minutes, unsigned int seconds) {
; 
; 	 // LOCAL VARIABLES
; 	 extern unsigned long int time_tick;
; 	 unsigned long int slop;
; 	 
; 	 
; 	 time_tick = ((hours*3600)+(minutes*60)+(seconds)) * TIME_TICKS_PER_SECOND;
	ldd #60
	ldy 6,x
	emul
	std -14,x
	ldd #3600
	ldy 2,x
	emul
	addd -14,x
	addd 8,x
	std -6,x
	movw #0,-8,x
	ldy #L194
	movw 0,y,-4,x
	movw 2,y,-2,x
	jsr __lmul
	ldy #_time_tick
	movw -4,x,0,y
	movw -2,x,2,y
; 	 slop = time_tick / 40;
	ldy #_time_tick
	movw 0,y,-4,x
	movw 2,y,-2,x
	ldy #L191
	movw 0,y,-8,x
	movw 2,y,-6,x
	jsr __ludiv
	leay -12,x
	movw -4,x,0,y
	movw -2,x,2,y
; 	 time_tick += slop;
	leay -12,x
	movw 0,y,-8,x
	movw 2,y,-6,x
	ldy #_time_tick
	movw 0,y,-4,x
	movw 2,y,-2,x
	jsr __ladd
	ldy #_time_tick
	movw -4,x,0,y
	movw -2,x,2,y
; 
; }
L193:
	tfr x,s
	pulx
	leas 2,sp
	.dbline 0 ; func end
	rts
;           last -> -6,x
;         memory -> -4,x
;              i -> -2,x
_get_free_memory::
	pshx
	tfr s,x
	leas -8,sp
; 
; 
; 
; 
; int get_free_memory(void) {
; 
; 	// LOCAL VARIABLES
; 	char *memory, *last;
; 	int i;
; 	
; 	
; 	INTR_OFF();
		sei

	ldd #0
	std -2,x
L196:
; 	// check for largest free memory block
; 	for (i=0; i<INITIAL_HEAP_SIZE; i+=32) {
; 		if ((memory = malloc(i)) != NULL)
	ldd -2,x
	jsr _malloc
	std -8,x
	std -4,x
	ldd -8,x
	beq L198
; 		   last = memory;
	movw -4,x,-6,x
; 		else
; 		   break;
L201:
	ldd -6,x
	jsr _free
L197:
	ldd -2,x
	addd #32
	std -2,x
	ldd -2,x
	cpd #1274
	blt L196
L198:
; 		free(last);
; 		}
; 		
; 	INTR_ON();
		cli

; 	//printf("%d bytes\n", i);
; 	
; 	return (i-32);
	ldd -2,x
	subd #32
L195:
	tfr x,s
	pulx
	.dbline 0 ; func end
	rts
	.area bss
_exit_status::
	.blkb 2
_mutex::
	.blkb 8
_task::
	.blkb 16
_time_tick::
	.blkb 4
_cop_cycle::
	.blkb 2
_system_tick::
	.blkb 4
_current::
	.blkb 2
_task_ptr::
	.blkb 16
	.area text
L194:
	.word 0,61
L192:
	.word 0,16
L191:
	.word 0,40
L67:
	.byte 'C,'O,'M,49,32,'f,'a,'i,'l,'u,'r,'e,0
L66:
	.byte 'C,'O,'M,49,0
L63:
	.byte 'i,'d,'l,'e,'T,'a,'s,'k,32,'f,'a,'i,'l,'u,'r,'e
	.byte 0
L62:
	.byte 'i,'d,'l,'e,'T,'a,'s,'k,0
L59:
	.byte 's,'h,'e,'l,'l,32,'f,'a,'i,'l,'u,'r,'e,0
L58:
	.byte 's,'h,'e,'l,'l,0
L55:
	.byte 'r,'l,'p,'O,'S,32,'v,48,46,56,10,10,0
L52:
	.word 0,0
L51:
	.word 80,27520
L48:
	.word 0,1
L46:
	.byte 'K,'E,'R,'N,'E,'L,58,32,'t,'a,'s,'k,32,'s,'t,'a
	.byte 't,'e,32,'e,'r,'r,'o,'r,10,0

