#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<fcntl.h>
#include	<ctype.h>
#include	<signal.h>

#ifdef VMS
#include	<file.h>
#endif

static char *rcsid = "$Id: atari.c,v 1.7 1996/01/26 23:09:52 david Exp $";

#define FALSE   0
#define TRUE    1

#include	"system.h"
#include	"cpu.h"
#include	"atari.h"

Machine machine = Atari;

static int os = 2;
static int enable_c000 = FALSE;
static int ffp_patch = FALSE;
static int sio_patch = TRUE;

extern int	rom_inserted;
extern UBYTE	atari_basic[8192];
extern UBYTE	atarixl_os[16384];

UBYTE	*cart_image;	/* For cartridge memory */
int	cart_type;

static char *atari_library = ATARI_LIBRARY;

void Atari800_OS ();
void Atari800_ESC (UBYTE code);

int load_cart (char *filename, int type);

static char *rom_filename = NULL;

void sigint_handler ()
{
  int restart;
  int diskno;

  restart = Atari800_Exit (TRUE);
  if (restart)
    {
      signal (SIGINT, sigint_handler);
      return;
    }

  for (diskno=1;diskno<8;diskno++)
    SIO_Dismount (diskno);

  exit (0);
}

int GetBinaryWord (int fd, unsigned short *word)
{
  unsigned char hi;
  unsigned char lo;
  unsigned short t_word;
  int status = FALSE;

  if (read (fd, &lo, 1) == 1)
    if (read (fd, &hi, 1) == 1)
      {
	t_word = ((unsigned short)hi << 8) | (unsigned short)lo;
	*word = t_word;
	status = TRUE;
      }

  return status;
}

int BinaryLoad (char *filename)
{
  int status;
  int fd;

  fd = open (filename, O_RDONLY, 0777);
  if (fd != -1)
    {
      unsigned short gash;
      unsigned short block_start;
      unsigned short block_end;
      int finished = FALSE;

      status = GetBinaryWord (fd, &gash);

      while (!finished)
	{
	  finished = TRUE;

	  status = GetBinaryWord (fd, &block_start);
	  if (status)
	    {
	      status = GetBinaryWord (fd, &block_end);
	      if (status)
		{
		  int nbytes;

		  nbytes = block_end - block_start  + 1;
		  read (fd, &memory[block_start], nbytes);

		  finished = FALSE;
		}
	    }
	}

      close (fd);
      status = TRUE;
    }
  else
    {
      status = FALSE;
    }

  return status;
}

void Install_EmuOS (void)
{
  char filename[64];
  int status;
  int i;

  if (machine != Atari)
    {
      printf ("Sorry Emulated OS only runs in standard Atari 800 mode\n");
      Atari800_Exit (FALSE);
    }

  sprintf (filename, "%s/charset.dat", atari_library);
  status = load_image (filename, 0xe000, 0x0400);
  if (!status)
    {
      printf ("%s not installed properly\n", filename);
      exit (1);
    }

  for (i=0xe400;i<=0xffff;i++)
    memory[i] = 0xff;
/*
 * Load Emulated OS into memory - development version expected in current
 * directory, production version expected in atari_library directory
 */
  status = BinaryLoad ("emuos.obj");
  if (!status)
    {
      sprintf (filename, "%s/emuos.obj", atari_library);

      status = BinaryLoad (filename);
      if (!status)
	{
	  printf ("%s not installed properly\n", filename);
	  exit (1);
	}
    }

  SetRAM (0x0000, 0xffff);
  SetHARDWARE (0xd000, 0xd7ff);
  SetROM (0xd800, 0xffff);
}

main (int argc, char **argv)
{
  int error;
  int diskno = 1;
  int i;
  int j;
  char *ptr;

  ptr = getenv ("ATARI_LIBRARY");
  if (ptr) atari_library = ptr;

  for (i=j=1;i<argc;i++)
    {
      if (strcmp(argv[i],"-atari") == 0)
	machine = Atari;
      else if (strcmp(argv[i],"-xl") == 0)
	machine = AtariXL;
      else if (strcmp(argv[i],"-xe") == 0)
	machine = AtariXE;
      else
	argv[j++] = argv[i];
    }

  argc = j;

  Atari800_Initialise (&argc, argv);
  Device_Initialise (&argc, argv);

  signal (SIGINT, sigint_handler);

  error = FALSE;

  for (i=1;i<argc;i++)
    {
      if (strcmp(argv[i],"-ffp") == 0)
	{
	  ffp_patch = TRUE;
	}
      else if (strcmp(argv[i],"-rom") == 0)
	{
	  rom_filename = argv[++i];
	  cart_type = NORMAL8_CART;
	}
      else if (strcmp(argv[i],"-rom16") == 0)
	{
	  rom_filename = argv[++i];
	  cart_type = NORMAL16_CART;
	}
      else if (strcmp(argv[i],"-oss") == 0)
	{
	  rom_filename = argv[++i];
	  cart_type = OSS_SUPERCART;
	}
      else if (strcmp(argv[i],"-db") == 0)	/* db 16/32 superduper cart */
	{
	  rom_filename = argv[++i];
	  cart_type = DB_SUPERCART;
	}
      else if (strcmp(argv[i],"-nopatch") == 0)
	{
	  sio_patch = FALSE;
	}
      else if (strcmp(argv[i],"-emuos") == 0)
	{
	  os = 0;
	  ffp_patch = TRUE;
	}
      else if (strcmp(argv[i],"-help") == 0)
	{
	  printf ("\t-atari        Standard Atari 800 mode\n");
	  printf ("\t-xl           Atari XL mode\n");
	  printf ("\t-xe           Atari XE mode (Currently same as -xl)\n");
	  printf ("\t-ffp          Use Fast Floating Point routines\n");
	  printf ("\t-rom          Install standard 8K Cartridge\n");
	  printf ("\t-rom16        Install standard 16K Cartridge\n");
	  printf ("\t-oss %%s       Install OSS Super Cartridge\n");
	  printf ("\t-db %%s        Install DB's 16/32K Cartridge (not for normal use)\n");
	  printf ("\t-nopatch      Don't patch SIO routine in OS (Ongoing Development)\n");
	  printf ("\t-emuos         Load emulated operating system (Ongoing Development)\n");
	  printf ("\t-a            Use A OS\n");
	  printf ("\t-b            Use B OS\n");
	  printf ("\t-c            Enable RAM between 0xc000 and 0xd000\n");
	  printf ("\t-v            Show version/release number\n");
	}
      else if (*argv[i] == '-')
	{
	  switch (*(argv[i]+1))
	    {
	    case 'a' :
	      os = 1;
	      break;
	    case 'b' :
	      os = 2;
	      break;
	    case 'c' :
	      enable_c000 = TRUE;
	      break;
	    case 'v' :
	      printf ("%s\n", ATARI_TITLE);
	      Atari800_Exit (FALSE);
	      exit (1);
	    default :
	      error = TRUE;
	      break;
	    }
	}
      else
	{
	  if (!SIO_Mount (diskno++, argv[i]))
	    {
	      printf ("Disk File %s not found\n", argv[i]);
	    }
	}
    }

  if (error)
    {
      printf ("Usage: %s [-rom filename] [-oss filename] [diskfile1...diskfile8]\n", argv[0]);
      printf ("\t-help         Extended Help\n");
      Atari800_Exit (FALSE);
      exit (1);
    }
/*
 * =================================
 * Install Operating System and ROMs
 * =================================
 */
  if (os > 0)
    Atari800_OS ();
  else
    Install_EmuOS ();

  if (ffp_patch)
    {
      add_esc (0xd800, ESC_AFP);
      add_esc (0xd8e6, ESC_FASC);
      add_esc (0xd9aa, ESC_IFP);
      add_esc (0xd9d2, ESC_FPI);
      add_esc (0xda66, ESC_FADD);
      add_esc (0xda60, ESC_FSUB);
      add_esc (0xdadb, ESC_FMUL);
      add_esc (0xdb28, ESC_FDIV);
      add_esc (0xdecd, ESC_LOG);
      add_esc (0xded1, ESC_LOG10);
      add_esc (0xddc0, ESC_EXP);
      add_esc (0xddcc, ESC_EXP10);
      add_esc (0xdd40, ESC_PLYEVL);
      add_esc (0xda44, ESC_ZFR0);
      add_esc (0xda46, ESC_ZF1);
      add_esc (0xdd89, ESC_FLD0R);
      add_esc (0xdd8d, ESC_FLD0P);
      add_esc (0xdd98, ESC_FLD1R);
      add_esc (0xdd9c, ESC_FLD1P);
      add_esc (0xdda7, ESC_FST0R);
      add_esc (0xddab, ESC_FST0P);
      add_esc (0xddb6, ESC_FMOVE);
    }

  if (sio_patch)
    add_esc (0xe459, ESC_SIOV);
/*
 * ================================
 * Install requested ROM cartridges
 * ================================
 */
  if (rom_filename)
    {
      int status;

      status = load_cart(rom_filename, cart_type);
      if (!status)
	{
	  printf ("Unable to load %s\n", rom_filename);
	  Atari800_Exit (FALSE);
	  exit (1);
	}

      switch (cart_type)
	{
	case OSS_SUPERCART :
	  memcpy (memory+0xa000,cart_image,0x1000);
	  memcpy (memory+0xb000,cart_image+0x3000,0x1000);
	  SetROM (0xa000, 0xbfff);
	  break;
	case DB_SUPERCART :
	  memcpy (memory+0x8000,cart_image,0x2000);
	  memcpy (memory+0xa000,cart_image+0x6000,0x2000);
	  SetROM (0x8000, 0xbfff);
	  break;
	case NORMAL8_CART :
	  memcpy (memory+0xa000,cart_image,0x2000);
	  SetROM (0xa000, 0xbfff);
	  free (cart_image);
	  cart_image = NULL;
	  break;
	case NORMAL16_CART :
	  memcpy (memory+0x8000,cart_image,0x4000);
	  SetROM (0x8000, 0xbfff);
	  free (cart_image);
	  cart_image = NULL;
	  break;
	}

      rom_inserted = TRUE;
    }
  else
    {
      rom_inserted = FALSE;
    }
/*
 * ======================================
 * Reset CPU and start hardware emulation
 * ======================================
 */
  CPU_Reset ();
  Atari800_Hardware ();
}

void Atari800_OS ()
{
  const unsigned short	o_open = 0;
  const unsigned short	o_close = 2;
  const unsigned short	o_read = 4;
  const unsigned short	o_write = 6;
  const unsigned short	o_status = 8;
  const unsigned short	o_special = 10;
  const unsigned short	o_init = 12;

  unsigned short	addr;
  unsigned short	entry;
  unsigned short	devtab;

  char filename[128];

  int	status;
  int	i;
/*
   ======================================================
   Load Floating Point Package, Font and Operating System
   ======================================================
*/
  switch (machine)
    {
    case Atari :
      if (os == 1)
	{
	  sprintf (filename, "%s/atariosa.rom", atari_library);
	  status = load_image (filename, 0xd800, 0x2800);
	}
      else
	{
	  sprintf (filename, "%s/atariosb.rom", atari_library);
	  status = load_image (filename, 0xd800, 0x2800);
	}
      if (!status)
	{
	  printf ("Operating System not available (%s)\n", filename);
	  printf ("Use -emuos to enable Emulated OS\n");
	  Atari800_Exit (FALSE);
	  exit (1);
	}
      break;
    case AtariXL :
    case AtariXE :
      sprintf (filename, "%s/atarixl.rom", atari_library);
      status = load_image (filename, 0xc000, 0x4000);
      if (!status)
	{
	  printf ("Operating System not available (%s)\n", filename);
	  printf ("Use -emuos to enable Emulated OS\n");
	  Atari800_Exit (FALSE);
	  exit (1);
	}

      memcpy (atarixl_os, memory+0xc000, 0x4000);
      
      sprintf (filename, "%s/ataribas.rom", atari_library);
      status = load_image (filename, 0xa000, 0x2000);
      if (!status)
	{
	  printf ("Unable to load %s\n", filename);
	  Atari800_Exit (FALSE);
	  exit (1);
	}
      memcpy (atari_basic, memory+0xa000, 0x2000);
      break;
    default :
      printf ("Fatal Error in atari.c\n");
      Atari800_Exit (FALSE);
      exit (1);
    }

/*
   =====================
   Disable Checksum Test
   =====================
*/
  switch (machine)
    {
    case Atari :
      break;
    case AtariXL :
    case AtariXE :
      memory[0xc314] = 0x8e;
      memory[0xc315] = 0xff;
      memory[0xc319] = 0x8e;
      memory[0xc31a] = 0xff;
      break;
    }
/*
   ==========================================
   Patch O.S. - Modify Handler Table (HATABS)
   ==========================================
*/
  switch (machine)
    {
    case Atari :
      addr = 0xf0e3;
      break;
    case AtariXL :
    case AtariXE :
      addr = 0xc42e;
      break;
    }

  for (i=0;i<5;i++)
    {
      devtab = (memory[addr+2] << 8) | memory[addr+1];

      switch (memory[addr])
	{
	case 'P' :
	  entry = (memory[devtab+o_open+1] << 8) | memory[devtab+o_open];
	  add_esc (entry+1, ESC_PHOPEN);
	  entry = (memory[devtab+o_close+1] << 8) | memory[devtab+o_close];
	  add_esc (entry+1, ESC_PHCLOS);
/*
	  entry = (memory[devtab+o_read+1] << 8) | memory[devtab+o_read];
	  add_esc (entry+1, ESC_PHREAD);
*/
	  entry = (memory[devtab+o_write+1] << 8) | memory[devtab+o_write];
	  add_esc (entry+1, ESC_PHWRIT);
	  entry = (memory[devtab+o_status+1] << 8) | memory[devtab+o_status];
	  add_esc (entry+1, ESC_PHSTAT);
/*
	  entry = (memory[devtab+o_special+1] << 8) | memory[devtab+o_special];
	  add_esc (entry+1, ESC_PHSPEC);
*/
	  memory[devtab+o_init] = 0xd2;
	  memory[devtab+o_init+1] = ESC_PHINIT;
	  break;
	case 'C' :
	  memory[addr] = 'H';
	  entry = (memory[devtab+o_open+1] << 8) | memory[devtab+o_open];
	  add_esc (entry+1, ESC_HHOPEN);
	  entry = (memory[devtab+o_close+1] << 8) | memory[devtab+o_close];
	  add_esc (entry+1, ESC_HHCLOS);
	  entry = (memory[devtab+o_read+1] << 8) | memory[devtab+o_read];
	  add_esc (entry+1, ESC_HHREAD);
	  entry = (memory[devtab+o_write+1] << 8) | memory[devtab+o_write];
	  add_esc (entry+1, ESC_HHWRIT);
	  entry = (memory[devtab+o_status+1] << 8) | memory[devtab+o_status];
	  add_esc (entry+1, ESC_HHSTAT);
	  break;
	case 'E' :
#ifdef BASIC
	  printf ("Editor Device\n");
	  entry = (memory[devtab+o_open+1] << 8) | memory[devtab+o_open];
	  add_esc (entry+1, ESC_E_OPEN);
	  entry = (memory[devtab+o_read+1] << 8) | memory[devtab+o_read];
	  add_esc (entry+1, ESC_E_READ);
	  entry = (memory[devtab+o_write+1] << 8) | memory[devtab+o_write];
	  add_esc (entry+1, ESC_E_WRITE);
#endif
	  break;
	case 'S' :
	  break;
	case 'K' :
#ifdef BASIC
	  printf ("Keyboard Device\n");
	  entry = (memory[devtab+o_read+1] << 8) | memory[devtab+o_read];
	  add_esc (entry+1, ESC_K_READ);
#endif
	  break;
	default :
	  break;
	}

      addr += 3;	/* Next Device in HATABS */
    }
/*
   ======================
   Set O.S. Area into ROM
   ======================
*/
  switch (machine)
    {
    case Atari :
      SetROM (0xd800, 0xffff);
      SetHARDWARE (0xd000, 0xd7ff);
      if (enable_c000)
	SetRAM (0xc000, 0xcfff);
      else
	SetROM (0xc000, 0xcfff);
      break;
    case AtariXL :
    case AtariXE :
      SetROM (0xc000, 0xffff);
      SetHARDWARE (0xd000, 0xd7ff);
      break;
    }
}

void add_esc (UWORD address, UBYTE esc_code)
{
  memory[address++] = 0xff;	/* ESC */
  memory[address++] = esc_code;	/* ESC CODE */
  memory[address] = 0x60;	/* RTS */
}

int load_image (char *filename, int addr, int nbytes)
{
  int	status = FALSE;
  int	fd;

  fd = open (filename, O_RDONLY, 0777);
  if (fd != -1)
    {
      status = read (fd, &memory[addr], nbytes);
      if (status != nbytes)
	{
	  printf ("Error reading %s\n", filename);
	  Atari800_Exit (FALSE);
	  exit (1);
	}

      close (fd);

      status = TRUE;
    }

  return status;
}

int load_cart (char *filename, int type)
{
  int fd;
  int len;
  int status;

  switch (type)
    {
    case OSS_SUPERCART :
      len = 0x4000;
      break;
    case DB_SUPERCART :
      len = 0x8000;
      break;
    case NORMAL8_CART :
      len = 0x4000;
      break;
    case NORMAL16_CART :
      len = 0x8000;
      break;
    }

  cart_image = (UBYTE*)malloc(len);
  if (!cart_image)
    {
      perror ("malloc");
      Atari800_Exit (FALSE);
      exit (1);
    }

  fd = open (filename, O_RDONLY, 0777);
  if (fd == -1)
    {
      perror (filename);
      Atari800_Exit (FALSE);
      exit (1);
    }

  read (fd, cart_image, len);

  close (fd);

  status = TRUE;

  return status;
}

/*
   ================================
   N = 0 : I/O Successful and Y = 1
   N = 1 : I/O Error and Y = error#
   ================================
*/

static CPU_Status	cpu_status;

K_Device (UBYTE esc_code)
{
  char	ch;

  CPU_GetStatus (&cpu_status);

  switch (esc_code)
    {
    case ESC_K_OPEN :
    case ESC_K_CLOSE :
      cpu_status.Y = 1;
      cpu_status.flag.N = 0;
      break;
    case ESC_K_WRITE :
    case ESC_K_STATUS :
    case ESC_K_SPECIAL :
      cpu_status.Y = 146;
      cpu_status.flag.N = 1;
      break;
    case ESC_K_READ :
      ch = getchar();
      switch (ch)
	{
	case '\n' :
	  ch = 0x9b;
	  break;
	default :
	  break;
	}
      cpu_status.A = ch;
      cpu_status.Y = 1;
      cpu_status.flag.N = 0;
      break;
    }

  CPU_PutStatus (&cpu_status);
}

E_Device (UBYTE esc_code)
{
  UBYTE	ch;

  CPU_GetStatus (&cpu_status);

  switch (esc_code)
    {
    case ESC_E_OPEN :
      printf ("Editor Open\n");
      cpu_status.Y = 1;
      cpu_status.flag.N = 0;
      break;
    case ESC_E_READ :
      ch = getchar();
      switch (ch)
	{
	case '\n' :
	  ch = 0x9b;
	  break;
	default :
	  break;
	}
      cpu_status.A = ch;
      cpu_status.Y = 1;
      cpu_status.flag.N = 0;
      break;
    case ESC_E_WRITE :
      ch = cpu_status.A;
      switch (ch)
	{
	case 0x7d :
	  putchar ('*');
	  break;
	case 0x9b :
	  putchar ('\n');
	  break;
	default :
	  putchar (ch & 0x7f);
	  break;
	}
      cpu_status.Y = 1;
      cpu_status.flag.N = 0;
      break;
    }

  CPU_PutStatus (&cpu_status);
}

DSKIN ()
{
  SIO ();
}

#define CDTMV1 0x0218

void Escape (UBYTE esc_code)
{
  int addr;

  switch (esc_code)
    {
    case ESC_SIOV :
      SIO ();
      break;
    case ESC_DSKINV :
      DSKIN ();
      break;
    case ESC_SETVBV :
      CPU_GetStatus (&cpu_status);
      printf ("SETVBV %d\n", cpu_status.A);
      addr = (CDTMV1 - 2) + (cpu_status.A * 2);
      memory[addr] = cpu_status.Y;
      memory[addr+1] = cpu_status.X;
      break;
    case ESC_AFP :
      ffp_afp() ;
      break;
    case ESC_FASC :
      ffp_fasc();
      break;
    case ESC_IFP :
      ffp_ifp();
      break;
    case ESC_FPI :
      ffp_fpi();
      break;
    case ESC_FADD :
      ffp_fadd();
      break;
    case ESC_FSUB :
      ffp_fsub();
      break;
    case ESC_FMUL :
      ffp_fmul();
      break;
    case ESC_FDIV :
      ffp_fdiv();
      break;
    case ESC_LOG :
      ffp_log();
      break;
    case ESC_LOG10 :
      ffp_log10();
      break;
    case ESC_EXP :
      ffp_exp();
      break;
    case ESC_EXP10 :
      ffp_exp10();
      break;
    case ESC_PLYEVL :
      ffp_plyevl();
      break;
    case ESC_ZFR0 :
      ffp_zfr0();
      break;
    case ESC_ZF1 :
      ffp_zf1();
      break;
    case ESC_FLD0R :
      ffp_fld0r();
      break;
    case ESC_FLD0P :
      ffp_fld0p();
      break;
    case ESC_FLD1R :
      ffp_fld1r();
      break;
    case ESC_FLD1P :
      ffp_fld1p();
      break;
    case ESC_FST0R :
      ffp_fst0r();
      break;
    case ESC_FST0P :
      ffp_fst0p();
      break;
    case ESC_FMOVE :
      ffp_fmove();
      break;
    case ESC_K_OPEN :
    case ESC_K_CLOSE :
    case ESC_K_READ :
    case ESC_K_WRITE :
    case ESC_K_STATUS :
    case ESC_K_SPECIAL :
      K_Device (esc_code);
      break;
    case ESC_E_OPEN :
    case ESC_E_READ :
    case ESC_E_WRITE :
      E_Device (esc_code);
      break;
    case ESC_KHOPEN :
      Device_KHOPEN ();
      break;
    case ESC_KHCLOS :
      Device_KHCLOS ();
      break;
    case ESC_KHREAD :
      Device_KHREAD ();
      break;
    case ESC_KHWRIT :
      Device_KHWRIT ();
      break;
    case ESC_KHSTAT :
      Device_KHSTAT ();
      break;
    case ESC_KHSPEC :
      Device_KHSPEC ();
      break;
    case ESC_KHINIT :
      Device_KHINIT ();
      break;
    case ESC_SHOPEN :
      Device_SHOPEN ();
      break;
    case ESC_SHCLOS :
      Device_SHCLOS ();
      break;
    case ESC_SHREAD :
      Device_SHREAD ();
      break;
    case ESC_SHWRIT :
      Device_SHWRIT ();
      break;
    case ESC_SHSTAT :
      Device_SHSTAT ();
      break;
    case ESC_SHSPEC :
      Device_SHSPEC ();
      break;
    case ESC_SHINIT :
      Device_SHINIT ();
      break;
    case ESC_EHOPEN :
      Device_EHOPEN ();
      break;
    case ESC_EHCLOS :
      Device_EHCLOS ();
      break;
    case ESC_EHREAD :
      Device_EHREAD ();
      break;
    case ESC_EHWRIT :
      Device_EHWRIT ();
      break;
    case ESC_EHSTAT :
      Device_EHSTAT ();
      break;
    case ESC_EHSPEC :
      Device_EHSPEC ();
      break;
    case ESC_EHINIT :
      Device_EHINIT ();
      break;
    case ESC_PHOPEN :
      Device_PHOPEN ();
      break;
    case ESC_PHCLOS :
      Device_PHCLOS ();
      break;
    case ESC_PHREAD :
      Device_PHREAD ();
      break;
    case ESC_PHWRIT :
      Device_PHWRIT ();
      break;
    case ESC_PHSTAT :
      Device_PHSTAT ();
      break;
    case ESC_PHSPEC :
      Device_PHSPEC ();
      break;
    case ESC_PHINIT :
      Device_PHINIT ();
      break;
    case ESC_HHOPEN :
      Device_HHOPEN ();
      break;
    case ESC_HHCLOS :
      Device_HHCLOS ();
      break;
    case ESC_HHREAD :
      Device_HHREAD ();
      break;
    case ESC_HHWRIT :
      Device_HHWRIT ();
      break;
    case ESC_HHSTAT :
      Device_HHSTAT ();
      break;
    case ESC_HHSPEC :
      Device_HHSPEC ();
      break;
    case ESC_HHINIT :
      Device_HHINIT ();
      break;
    default         :
      Atari800_Exit (FALSE);
      CPU_GetStatus (&cpu_status);
      printf ("Invalid ESC Code %x at Address %x\n",
	      esc_code, cpu_status.PC - 2);
      monitor();
      exit (1);
    }
}
