/*
 * rti.c
 *
 * $Id: rti.c,v 1.9 2002/08/02 20:05:07 tomdean Exp $
 *
 * The rti rate is 4.096 msec
 * 24*60*60/.004096
 * 21093750.00000000000000000000 ticks per day
 * (24*60*60/.004096) - ((24*(60*(60*244+8)+26))+6)  == 0
 *                                       ^  ^    ^
 *                                       |  |    |
 * minute adjustment---------------------+  |    |
 * hour adjustment--------------------------+    |
 * day adjustment--------------------------------+
 *
 */
#include <sys/ports_def.h>   /* ports definition */
#include <sys/regs.h>        /* soft registers */
#include <os.h>
#include <lcd.h>             /* current task display location */

m6811_clock_t m6811_clock;

/* defined in swi.c */
void dequeue_msg();


extern unsigned char tocks;

/*
 * At the entrance to swi(), after the current soft
 * registers are saved on the stack, we have
 *
 *  |         |
 *  +---------+-------
 *  |  PC     |
 *  +---------+
 *  |  Y      |
 *  +---------+  interrupt saves these
 *  |  X      |
 *  +---------+
 *  |  D      |
 *  +---------+
 *  |  CCR    |
 *  +---------+--------
 *  | _.tmp   |
 *  +---------+
 *  | _.z     |
 *  +---------+ pushed in rti()'s preamble
 *  | _.xy    | these will be removed at the
 *  +---------+ bottom of swi()
 *  | _.frame |
 *  +---------+--------
 *  | _d1     | --> _.frame
 *  +---------+
 *  |         |  push _.d2 thru _.d8 to save full context
 *  
 * The address of the previous frame, if any, is at _.frame+1
 *
 * THE RTI FUNCTION DEPENDS ON THE CONTENTS OF THE STACK DOWN TO THE
 * POINT WHERE THE SP IS SAVED, 'SAV_SP(context[cur_task]->sp);'.
 * IF CHANGES ARE MADE BETWEEN THE TOP OF THE FUNCTION AND THE
 * POINT WHERE THE SP IS SAVED, THAT CHANGE THE CONTENTS OF THE STACK,
 * EITHER ADJUST THE STACK, OR, CHANGE THE ENTIRE CONTEXT SWITCH PROCESS.
 *
 */

void rti() {
	   
  /* XXX fix me - debugging remove for production */
  DEBUG_ON(BIT07);
  
  /* acknowledge the interrupt */
  _io_ports[M6811_TFLG2] |= M6811_RTIF;

  /* tocks */
  if (--tocks == 0) {
	tocks = TICKS_PER_TOCK;
	/*
	 * do a context switch
	 * XXX fix me - what about the range of cur_task should we check it?
	 * _.tmp ... _.d1 are pushed as part of preamble
	 */
	PSH_SOFT_REG(__d2);
	PSH_SOFT_REG(__d3);
	PSH_SOFT_REG(__d4);
	PSH_SOFT_REG(__d5);
	PSH_SOFT_REG(__d6);
	PSH_SOFT_REG(__d7);
	PSH_SOFT_REG(__d8);
	SAV_SP(context[cur_task]->sp);

	/* mark task as ready to run */
	if (context[cur_task]->state == run) context[cur_task]->state = ready;
  }
  /*
   * any changes to the soft registers between here and the
   * pop's at the bottom are lost in the completion of the context
   * switch.
   */
  /* set clock values */
#if 0
  m6811_clock.ticks--;
  if (m6811_clock.ticks == 0) {
	m6811_clock.ticks = 244; /* approx 61 ticks per second */
	m6811_clock.seconds++;  
	if (m6811_clock.seconds == 60) { 
	  m6811_clock.seconds = 0; 
	  m6811_clock.ticks += 8; /* 8 ticks per minute adjustment */
	  m6811_clock.minutes++; 
	  if (m6811_clock.minutes == 60) { 
		m6811_clock.minutes = 0; 
		m6811_clock.ticks += 7; /* 26 ticks per hour adjustment */
		m6811_clock.hours++; 
		if (m6811_clock.hours == 24) { 
		  m6811_clock.hours = 0; 
		  m6811_clock.ticks += 6; /* 6 ticks per day adjustment */
		  m6811_clock.days++; 
		}
	  }
	}
  }
#endif

  /*
   * tick counters
   */
  tick_count++;
  /*
   * using the soft registers avoids making room for variables on the stack
   *
   * XXX fix me - this should be at the top, so we can do a context
   * switch as soon as we discover the timer has expired.
   */
  for (__d8=1; __d8<NUM_TASK+1; __d8++) {
	if (timer[__d8]) {
	  error1[29] = (unsigned char)__d8+'0';
	  hex_to_ascii_4(timer[__d8], error1+31);
	  if ((--timer[__d8] == 0) && (context[__d8]->state == wait_timer)) {
		context[__d8]->state = ready;
	  }
	}
  }

  if (tocks == TICKS_PER_TOCK) {
	/*
	 * complete the last half of the context switch
	 */

	/*
	 * find a runable task
	 * XXX fix me - when we discover the timer has expired, switch
	 * to that task.
	 */
	__d8 = cur_task;
	while (++cur_task != __d8) {
	  if (cur_task > 8) cur_task = 1;
	  dequeue_msg();
	  if (context[cur_task]->state == ready) break;
	}
	if ((cur_task == __d8) && (context[cur_task]->state != ready)) {
	  cur_task = 0; /* null task is always ready to run */
	}

	/*
	 * display current task number
	 */
	*(char *)(CUR_TASK_LOC) = cur_task + '0';

	/* mark task as run */
	context[cur_task]->state = run;

	/*
	 * last half of the context switch.  pop soft registers
	 * from the new task.  rti()'s post-amble will pop the rest
	 */
	SET_SP(context[cur_task]->sp);
	POP_SOFT_REG(__d8);
	POP_SOFT_REG(__d7);
	POP_SOFT_REG(__d6);
	POP_SOFT_REG(__d5);
	POP_SOFT_REG(__d4);
	POP_SOFT_REG(__d3);
	POP_SOFT_REG(__d2);
	/*
	 * _.d1 ... _.tmp are popped as part of post-amble
	 */
  }
  
  /* XXX fix me - debugging remove for production */
  DEBUG_OFF(BIT07);  /* time rti() */
}
