#include "exec/types.h"
#include "proto/dos.h"

#include "hp11/hp11.h"
#include "hp11/amiga/amiga.h"
#include "hp11/io.h"
#include "hp11/support.h"
#include "hp11/ins.h"
#include "hp11/codes.h"

#include <stdlib.h>

/* Values for Cback */
LONG _stack = 4000;
char *_procname = "HP11C";
LONG _BackGroundIO = 0;
LONG _priority = 0;

struct Regs hp11r;
int running, fast, error, skip;
int PC, retStack[MAXSTACK], retCnt;
int Flags;

int quit, on = TRUE; /* Set to false to quit */

static void ExecAction(int act) /* Execute an Action in normal mode */
{
   if (act >= IGTO_LINE) { /* GTO .nnn where act = IGTO_LINE + nnn */
      entering = FALSE; /* Digit entry disabled */
      GTOLine(act - IGTO_LINE);
   }
   else switch (act) {
      case ISST: SST(); break;
      case IBST: BST(); break;
      case IP_R: ProgramEntry(); break;
      case IUSER: USER(); break;
      case ICLR_PRGM: RTN(); break; /* Clear Prgm = RTN() in normal mode */
      case ION: on = !RelKey(); break; /* Allow user to change his mind */
      case IMEM: MEM(); break;
      case ICLR_PREFIX: PREFIX(); break;
      case IBACK:if (entering) EnterNum(-IBACK); /* Correct during digit entry */
		 else CLX();
		 break;
   }
}

void ExecIns(ins) /* Execute an instruction (normal or run mode) */
register int ins;
{
   skip = FALSE;

   if (ins < KCOMPLEX) (*insfunc[ins])(); /* miscellaneous ins */
   else if (ins < KFLAGS + OCF) SF(ins - (KFLAGS + OSF));
   else if (ins < KFLAGS + OSET) SF(ins - (KFLAGS + OSF));
   else if (ins < KFIG) SF(ins - (KFLAGS + OSF));
   else if (ins < KFIX) EnterNum(ins);
   else if (ins < KSCI) FIX(ins - KFIX);
   else if (ins < KENG) SCI(ins - KSCI);
   else if (ins < KLBL) ENG(ins - KENG);
   else if (ins < KGTO) ENABLE() /* LBL : ignore, just enable stack */;
   else if (ins < KGSB) GTO(ins - KGTO);
   else if (ins < KSTO) GSB(ins - KGSB);
   else if (ins < KRCL) STO((ins - KSTO) % OPLUS,
			    (enum StoTypes)((ins - KSTO) / OPLUS));
      /* compute type of operation to do : there are 21 regs per operation,
	 + indirect, the codes are sequential : all the stos, all the pluses ...
	 PLUS is first so it is 22, hence the division to determine the operation */
   else if (ins < KRCL + 22) RCL(ins - KRCL);

   X = Check(X); Y = Check(Y); /* Check the values in X & Y to conform to HP11
      limits. The testing is done here to save code space so that all the instructions
      don't have to include the check */
}

static BOOL Init(int argc, APTR argv) /* Initialize the calculator, return FALSE if it fails */
{
   DEG(); /* Initial state, all other values are zero */
   FIX(4);

   /* Computer specific intialisation, can load an initial program */
   return(AmigaInit(argc, argv));
}

static void CleanUp(void)
{
   AmigaCleanUp();
}

/* Standard version of sleep */
/* On Amiga, iconifies (special routine in amiga.c */
/* static void sleep()
{
   int key;

   Display("");

   while (!quit && !on) {
      key = PollKey(TRUE);
      RelKey();
      on = key == 30 (* ON *), replace ( with / if you uncomment this;
   }
} */

void main(int argc, char **argv)
{
   WORD code;
   enum KeyTypes type;

   if (Init(argc, (APTR)argv))
      do { /* while (!quit) */
	 while (on && !quit) { /* Exit when calculator turned off */
	    Disp();
	    error = FALSE; overflow = FALSE;

	    if (running) { /* Run mode */
	       if (PollKey(FALSE) != -1) { /* User pressed a key */
		  running = FALSE;
		  RelKey(); /* Wait for him to release it */
	       }
	       else {
		  if (!fast) Wait50(2L); /* Slow calculator down to make it more realistic (wait 2/50 s) */
		  ExecIns(Prog[PC]); /* Exec current ins */
		  if (error || overflow) running = FALSE; /* An error occured, halt */
		  else {
		     if (skip) PC++; /* A conditional instruction asked for the next
			instruction to be skipped */
		     PC++;
		     while (PC > lastIns) { /* There is an implicit return at the end of the program */
			RTN();
			PC++;
		     }
		  }
	       }
	    }
	    else { /* normal mode operation */
	       MenusOn();
	       EditOn();
	       type = ReadKey(&code);
	       EditOff();
	       switch (type) { /* Read an instruction/action */
		  case Action:
		     ExecAction(code); /* Execute corresponding action */
		     break;
		  case Instruction:
		     ExecIns(code); /* Interpret instruction */
		     break;
	       }
	       MenusOff();
	       RelKey();
	    }

	 }

	 if (!quit) {
	    sleep(); /* Wait till woken up */
	    ENABLE();
	 }
      } while (!quit);

   CleanUp();
}

