#include	<stdio.h>
#include	<stdlib.h>

static char *rcsid = "$Id: atari_custom.c,v 1.7 1996/02/05 18:16:20 david Exp $";

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

#define	FALSE	0
#define	TRUE	1

#define PF_COLPF0 0x04
#define PF_COLPF1 0x05
#define PF_COLPF2 0x06
#define PF_COLPF3 0x07
#define PF_COLBK 0x08

/*
 * These are defined for Word (2 Byte) memory accesses. I have not
 * defined Longword (4 Byte) values since the Sparc architecture
 * requires that Longword are on a longword boundry.
 *
 * Words accesses don't appear to be a problem because the first
 * pixel plotted on a line will always be at an even offset, and
 * hence on a word boundry.
 *
 * Note: HSCROL is in colour clocks whereas the pixels are emulated
 *       down to a half colour clock - the first pixel plotted is
 *       moved across by 2*HSCROL
 */

#define PF2_COLPF0 0x0404
#define PF2_COLPF1 0x0505
#define PF2_COLPF2 0x0606
#define PF2_COLPF3 0x0707
#define PF2_COLBK 0x0808

#define PF4_COLPF0 0x04040404
#define PF4_COLPF1 0x05050505
#define PF4_COLPF2 0x06060606
#define PF4_COLPF3 0x07070707
#define PF4_COLBK 0x08080808

static UBYTE singleline;
static int dlicount;
static int scroll_offset;
static int ypos;
static UBYTE pm_dma_enabled;

int countdown_rate = 4000;
int refresh_rate = 4;
int frame = 0;
int wsync_halt = 0;

/*
   =============================================================
   Define screen as ULONG to ensure that it is Longword aligned.
   This allows special optimisations under certain conditions.
   -------------------------------------------------------------
   The extra 16 scanlines is used as an overflow buffer and has
   enough room for any extra mode line. It is needed on the
   occasions that a valid JVB instruction is not found in the
   display list - An automatic break out will occur when ypos
   is greater than the ATARI_HEIGHT, if its one less than this
   there must be enough space for another mode line.
   =============================================================
*/

int colour_translation_table[256];
ULONG *atari_screen = NULL;
static UBYTE *scrn_ptr;

/*
   =========================================
   Allocate variables for Hardware Registers
   =========================================
*/

UBYTE	ALLPOT;
UBYTE	CHACTL;
UBYTE	CHBASE;
UBYTE	COLBK;
UBYTE	DLISTH;
UBYTE	DLISTL;
UBYTE	DMACTL;
UBYTE	GRACTL;
UBYTE	GRAFM;
UBYTE	GRAFP0;
UBYTE	GRAFP1;
UBYTE	GRAFP2;
UBYTE	GRAFP3;
UBYTE	HSCROL;
UBYTE	IRQEN;
UBYTE	IRQST;
UBYTE	KBCODE;
UBYTE	M0PF;
UBYTE	M0PL;
UBYTE	M1PF;
UBYTE	M1PL;
UBYTE	M2PF;
UBYTE	M2PL;
UBYTE	M3PF;
UBYTE	M3PL;
UBYTE	NMIEN;
UBYTE	NMIST;
UBYTE	P0PF;
UBYTE	P0PL;
UBYTE	P1PF;
UBYTE	P1PL;
UBYTE	P2PF;
UBYTE	P2PL;
UBYTE	P3PF;
UBYTE	P3PL;
UBYTE	PACTL;
UBYTE	PAL;
UBYTE	PBCTL;
UBYTE	PENH;
UBYTE	PENV;
UBYTE	PMBASE;
UBYTE	PORTA;
UBYTE	PORTB;
UBYTE	POTGO;
UBYTE	PRIOR;
UBYTE	SERIN;
UBYTE	SEROUT;
UBYTE	SKCTL;
UBYTE	SKREST;
UBYTE	SKSTAT;
UBYTE	STIMER;
UBYTE	VDELAY;
UBYTE	VSCROL;

extern UBYTE	*cart_image;
extern int	cart_type;

/*
	============================================================
	atari_basic and under_basic are required for XL/XE emulation
	============================================================
*/

int	rom_inserted;
UBYTE	atari_basic[8192];
UBYTE	atarixl_os[16384];
UBYTE	under_atari_basic[8192];
UBYTE	under_atarixl_os[16384];
UBYTE   atarixe_memory[65536];
UBYTE   atarixe_16kbuffer[16384];

int xe_bank = -1;

static int	PM_XPos[256];
static UBYTE	PM_Width[4] = { 2, 4, 2, 8 };

#ifndef BASIC
static UBYTE pm_scanline[ATARI_WIDTH];
#endif

UBYTE Atari800_GetByte (UWORD addr);
void  Atari800_PutByte (UWORD addr, UBYTE byte);

void Atari800_Initialise (int *argc, char *argv[])
{
  int	i, j;

  for (i=j=1;i<*argc;i++)
    {
      if (strcmp(argv[i],"-refresh") == 0)
	sscanf (argv[++i],"%d", &refresh_rate);
      else if (strcmp(argv[i],"-countdown") == 0)
	sscanf (argv[++i],"%d", &countdown_rate);
      else
	{
	  if (strcmp(argv[i],"-help") == 0)
	    {
	      printf ("\t-refresh %%d   Specify screen refresh rate\n");
	      printf ("\t-countdown %%d Specify CPU cycles during vertical blank period\n");
	    }

	  argv[j++] = argv[i];
	}
    }

  *argc = j;

  Atari_Initialise (argc, argv);

  if (refresh_rate < 1)
    refresh_rate = 1;

  if (countdown_rate < 1)
    countdown_rate = 1;

  if (!atari_screen)
    {
      atari_screen = (ULONG*)malloc((ATARI_HEIGHT+16) * ATARI_WIDTH);
      for (i=0;i<256;i++)
	colour_translation_table[i] = i;
    }

  for (i=0;i<65536;i++)
    {
      memory[i] = 0;
    }
/*
	=========================================================
	Initialise tables for Player Missile Horizontal Positions
	=========================================================
*/
#ifndef BASIC
  for (i=0;i<256;i++)
    {
      PM_XPos[i] = (i - 0x20) << 1;
    }
#endif

/*
	=============================
	Initialise Hardware Registers
	=============================
*/

  PORTA = 0xff;
  PORTB = 0xff;

#ifndef BASIC
  SetPrior (0);
#endif
}

void Atari800_Exit (int run_monitor)
{
  Atari_Exit (run_monitor);
  printf ("Number of frames = %d\n", frame);
}

/*
	*****************************************************************
	*								*
	*	Section			:	Player Missile Graphics	*
	*	Original Author		:	David Firth		*
	*	Date Written		:	28th May 1995		*
	*	Version			:	1.0			*
	*								*
	*****************************************************************
*/

static int global_hposp0;
static int global_hposp1;
static int global_hposp2;
static int global_hposp3;
static int global_hposm0;
static int global_hposm1;
static int global_hposm2;
static int global_hposm3;
static int global_sizep0;
static int global_sizep1;
static int global_sizep2;
static int global_sizep3;
static int global_sizem;

/*
	=========================================
	Width of each bit within a Player/Missile
	=========================================
*/

#ifndef BASIC

#define PRIOR_TAB_SIZE (1024+256)

static UBYTE colreg_lookup[PRIOR_TAB_SIZE];
static UBYTE colour_lookup[9];

SetPrior (int new_prior)
{
  UBYTE prior[9];
  int pixel;

  PRIOR = new_prior;

  switch (PRIOR & 0x0f)
    {
    default :
    case 0x01 :
      prior[0] = 8; prior[1] = 7; prior[2] = 6; prior[3] = 5;
      prior[4] = 4; prior[5] = 3; prior[6] = 2; prior[7] = 1;
      prior[8] = 0;
      break;
    case 0x02 :
      prior[0] = 8; prior[1] = 7; prior[2] = 2; prior[3] = 1;
      prior[4] = 6; prior[5] = 5; prior[6] = 4; prior[7] = 3;
      prior[8] = 0;
      break;
    case 0x04 :
      prior[0] = 4; prior[1] = 3; prior[2] = 2; prior[3] = 1;
      prior[4] = 8; prior[5] = 7; prior[6] = 6; prior[7] = 5;
      prior[8] = 0;
      break;
    case 0x08 :
      prior[0] = 6; prior[1] = 5; prior[2] = 4; prior[3] = 3;
      prior[4] = 8; prior[5] = 7; prior[6] = 2; prior[7] = 1;
      prior[8] = 0;
      break;
    }
      
  for (pixel=0;pixel<PRIOR_TAB_SIZE;pixel++)
    {
      UBYTE colreg;
      UBYTE curpri;

      switch (pixel & 0x700)
	{
	case 0x000 :
	  colreg = PF_COLPF0;
	  curpri = prior[4];
	  break;
	case 0x100 :
	  colreg = PF_COLPF1;
	  curpri = prior[5];
	  break;
	case 0x200 :
	  colreg = PF_COLPF2;
	  curpri = prior[6];
	  break;
	case 0x300 :
	  colreg = PF_COLPF3;
	  curpri = prior[7];
	  break;
	case 0x400 :
	  colreg = PF_COLBK;
	  curpri = prior[8];
	  break;
	default :
	  printf ("Invalid Playfield\n");
	  exit (1);
      }

      if (pixel & 0xf0) /* Check for Missile Pixels */
	{
	  if ((pixel & 0x80) && (prior[3] > curpri)) /* COLPM3 */
	    {
	      colreg = 3;
	      curpri = prior[3];
	    }

	  if ((pixel & 0x40) && (prior[2] > curpri)) /* COLPM2 */
	    {
	      colreg = 2;
	      curpri = prior[2];
	    }

	  if ((pixel & 0x20) && (prior[1] > curpri)) /* COLPM1 */
	    {
	      colreg = 1;
	      curpri = prior[1];
	    }

	  if ((pixel & 0x10) && (prior[0] > curpri)) /* COLPM0 */
	    {
	      colreg = 0;
	      curpri = prior[0];
	    }

	  if (PRIOR & 0x10)
	    colreg = 7;
	}

      if ((pixel & 0x08) && (prior[3] > curpri))
	{
	  colreg = 3;
	  curpri = prior[3];
	}

      if ((pixel & 0x04) && (prior[2] > curpri))
	{
	  colreg = 2;
	  curpri = prior[2];
	}

      if ((pixel & 0x02) && (prior[1] > curpri))
	{
	  colreg = 1;
	  curpri = prior[1];
	}

      if ((pixel & 0x01) && (prior[0] > curpri))
	{
	  colreg = 0;
	  curpri = prior[0];
	}
      
      colreg_lookup[pixel] = colreg;
    }
}

static UWORD	pl0adr;
static UWORD	pl1adr;
static UWORD	pl2adr;
static UWORD	pl3adr;
static UWORD	m0123adr;

void PM_ScanLine ()
{
  static UBYTE pf_collision_bit[9] =
    {
      0x00, 0x00, 0x00, 0x00,
      0x01, 0x02, 0x04, 0x08,
      0x00
    };

  int dirty = FALSE;
/*
   ==================
   PMG DMA if enabled
   ==================
*/
    if (pm_dma_enabled)
      {
	int	nextdata;

	GRAFP0 = memory[pl0adr];
	GRAFP1 = memory[pl1adr];
	GRAFP2 = memory[pl2adr];
	GRAFP3 = memory[pl3adr];
	GRAFM = memory[m0123adr];

	if (singleline)
	  nextdata = TRUE;
	else
	  nextdata = (ypos & 0x01);

	if (nextdata)
	  {
	    pl0adr++;
	    pl1adr++;
	    pl2adr++;
	    pl3adr++;
	    m0123adr++;
	  }
      }
/*
   =============================
   Display graphics for Player 0
   =============================
*/
  if (GRAFP0)
    {
      UBYTE grafp0 = GRAFP0;
      int sizep0 = global_sizep0;
      int hposp0 = global_hposp0;
      int i;

      for (i=0;i<8;i++)
	{
	  if (grafp0 & 0x80)
	    {
	      int j;

	      for (j=0;j<sizep0;j++)
		{
		  if ((hposp0 >= 0) && (hposp0 < ATARI_WIDTH))
		    {
		      UBYTE playfield = scrn_ptr[hposp0];

		      pm_scanline[hposp0] |= 0x01;

		      P0PF |= pf_collision_bit[playfield];
		      dirty = TRUE;
		    }
		  hposp0++;
		}
	    }
	  else
	    {
	      hposp0 += sizep0;
	    }

	  grafp0 = grafp0 << 1;
	}
    }
/*
   =============================
   Display graphics for Player 1
   =============================
*/
  if (GRAFP1)
    {
      UBYTE grafp1 = GRAFP1;
      int sizep1 = global_sizep1;
      int hposp1 = global_hposp1;
      int i;

      for (i=0;i<8;i++)
	{
	  if (grafp1 & 0x80)
	    {
	      int j;

	      for (j=0;j<sizep1;j++)
		{
		  if ((hposp1 >= 0) && (hposp1 < ATARI_WIDTH))
		    {
		      UBYTE playfield = scrn_ptr[hposp1];
		      UBYTE player = pm_scanline[hposp1];

		      pm_scanline[hposp1] |= 0x02;

		      P1PF |= pf_collision_bit[playfield];
		      P1PL |= player;

		      if (player & 0x01)
			P0PL |= 0x02;

		      dirty = TRUE;
		    }
		  hposp1++;
		}
	    }
	  else
	    {
	      hposp1 += sizep1;
	    }

	  grafp1 = grafp1 << 1;
	}
    }
/*
   =============================
   Display graphics for Player 2
   =============================
*/
  if (GRAFP2)
    {
      UBYTE grafp2 = GRAFP2;
      int sizep2 = global_sizep2;
      int hposp2 = global_hposp2;
      int i;

      for (i=0;i<8;i++)
	{
	  if (grafp2 & 0x80)
	    {
	      int j;

	      for (j=0;j<sizep2;j++)
		{
		  if ((hposp2 >= 0) && (hposp2 < ATARI_WIDTH))
		    {
		      UBYTE playfield = scrn_ptr[hposp2];
		      UBYTE player = pm_scanline[hposp2];

		      pm_scanline[hposp2] |= 0x04;

		      P2PF |= pf_collision_bit[playfield];
		      P2PL |= player;

		      if (player & 0x01)
			P0PL |= 0x04;
		      if (player & 0x02)
			P1PL |= 0x04;

		      dirty = TRUE;
		    }
		  hposp2++;
		}
	    }
	  else
	    {
	      hposp2 += sizep2;
	    }

	  grafp2 = grafp2 << 1;
	}
    }
/*
   =============================
   Display graphics for Player 3
   =============================
*/
  if (GRAFP3)
    {
      UBYTE grafp3 = GRAFP3;
      int sizep3 = global_sizep3;
      int hposp3 = global_hposp3;
      int i;

      for (i=0;i<8;i++)
	{
	  if (grafp3 & 0x80)
	    {
	      int j;

	      for (j=0;j<sizep3;j++)
		{
		  if ((hposp3 >= 0) && (hposp3 < ATARI_WIDTH))
		    {
		      UBYTE playfield = scrn_ptr[hposp3];
		      UBYTE player = pm_scanline[hposp3];

		      pm_scanline[hposp3] |= 0x08;

		      P3PF |= pf_collision_bit[playfield];
		      P3PL |= player;

		      if (player & 0x01)
			P0PL |= 0x08;
		      if (player & 0x02)
			P1PL |= 0x08;
		      if (player & 0x04)
			P2PL |= 0x08;

		      dirty = TRUE;
		    }
		  hposp3++;
		}
	    }
	  else
	    {
	      hposp3 += sizep3;
	    }

	  grafp3 = grafp3 << 1;
	}
    }
/*
   =============================
   Display graphics for Missiles
   =============================
*/
  if (GRAFM)
    {
      UBYTE grafm = GRAFM;
      int hposm0 = global_hposm0;
      int hposm1 = global_hposm1;
      int hposm2 = global_hposm2;
      int hposm3 = global_hposm3;
      int sizem = global_sizem;
      int i;

      for (i=0;i<8;i++)
	{
	  if (grafm & 0x80)
	    {
	      int j;

	      for (j=0;j<sizem;j++)
		{
		  switch (i & 0x06)
		    {
		    case 0x00 :
		      if ((hposm3 >= 0) && (hposm3 < ATARI_WIDTH))
			{
			  UBYTE playfield = scrn_ptr[hposm3];
			  UBYTE player = pm_scanline[hposm3];

			  pm_scanline[hposm3] |= 0x80;

			  M3PF |= pf_collision_bit[playfield];
			  M3PL |= player;
			  dirty = TRUE;
			}
		      hposm3++;
		      break;
		    case 0x02 :
		      if ((hposm2 >= 0) && (hposm2 < ATARI_WIDTH))
			{
			  UBYTE playfield = scrn_ptr[hposm2];
			  UBYTE player = pm_scanline[hposm2];

			  pm_scanline[hposm2] |= 0x40;

			  M2PF |= pf_collision_bit[playfield];
			  M2PL |= player;
			  dirty = TRUE;
			}
		      hposm2++;
		      break;
		    case 0x04 :
		      if ((hposm1 >= 0) && (hposm1 < ATARI_WIDTH))
			{
			  UBYTE playfield = scrn_ptr[hposm1];
			  UBYTE player = pm_scanline[hposm1];

			  pm_scanline[hposm1] |= 0x20;

			  M1PF |= pf_collision_bit[playfield];
			  M1PL |= player;
			  dirty = TRUE;
			}
		      hposm1++;
		      break;
		    case 0x06 :
		      if ((hposm0 >= 0) && (hposm0 < ATARI_WIDTH))
			{
			  UBYTE playfield = scrn_ptr[hposm0];
			  UBYTE player = pm_scanline[hposm0];

			  pm_scanline[hposm0] |= 0x10;

			  M0PF |= pf_collision_bit[playfield];
			  M0PL |= player;
			  dirty = TRUE;
			}
		      hposm0++;
		      break;
		    }
		}
	    }
	  else
	    {
	      switch (i & 0x06)
		{
		case 0x00 :
		  hposm3 += sizem;
		  break;
		case 0x02 :
		  hposm2 += sizem;
		  break;
		case 0x04 :
		  hposm1 += sizem;
		  break;
		case 0x06 :
		  hposm0 += sizem;
		  break;
		}
	    }
      
	  grafm = grafm << 1;
	}
    }
/*
   ======================================
   Plot Player/Missile Data onto Scanline
   ======================================
*/
  if (dirty)
    {
      UBYTE *t_scrn_ptr;
      UBYTE *pm_pixel_ptr;
      int xpos;

      t_scrn_ptr = scrn_ptr;
      pm_pixel_ptr = pm_scanline;

      for (xpos=0;xpos<ATARI_WIDTH;xpos++)
	{
	  UBYTE pm_pixel;

	  pm_pixel = *pm_pixel_ptr++;
	  if (pm_pixel)
	    {
	      UBYTE pf_pixel;
	      UBYTE colreg;
	      UBYTE colour;

	      pf_pixel = *t_scrn_ptr;
	      colreg = colreg_lookup[((pf_pixel-4) << 8) | pm_pixel];
	      *t_scrn_ptr++ = colreg;
	    }
	  else
	    {
	      t_scrn_ptr++;
	    }
	}

      memset (pm_scanline, 0, ATARI_WIDTH);
    }
}

void Atari_ScanLine (void)
{
  dlicount--;
  if (dlicount == 0)
    {
      NMIST |= 0x80;
      INTERRUPT |= NMI_MASK;
    }

  if (!wsync_halt)
    {
      ncycles=48;
      GO();
    }

  PM_ScanLine ();

  if (PRIOR & 0xc0)
    {
      UBYTE *t_scrn_ptr1; /* Input Pointer */
      UBYTE *t_scrn_ptr2; /* Output Pointer */
      UBYTE *pm_pixel_ptr;
      int xpos;
      int nibble;

      t_scrn_ptr1 = scrn_ptr;
      t_scrn_ptr2 = scrn_ptr;
      pm_pixel_ptr = pm_scanline;

      for (xpos=0;xpos<ATARI_WIDTH;xpos++)
	{
	  UBYTE pf_pixel;
	  UBYTE pm_pixel;
	  UBYTE colreg;
	  UBYTE colour;

	  pf_pixel = *t_scrn_ptr1++;
	  pm_pixel = *pm_pixel_ptr++;

	  if ((xpos & 0x03) == 0x00)
	    nibble = 0;

	  nibble <<= 1;

	  if (pf_pixel == PF_COLPF1)
	    nibble += 1;

	  if ((xpos & 0x03) == 0x03)
	    {
	      switch (PRIOR & 0xc0)
		{
		case 0x40 :
		  colour = (COLBK & 0xf0) | nibble;
		  break;
		case 0x80 :
		  if (nibble >= 8)
		    nibble -= 9;
		  colour = colour_lookup[nibble];
		  break;
		case 0xc0 :
		  colour = (nibble << 4) | (COLBK & 0x0f);
		  break;
		}

	      *t_scrn_ptr2++ = colour;
	      *t_scrn_ptr2++ = colour;
	      *t_scrn_ptr2++ = colour;
	      *t_scrn_ptr2++ = colour;
	    }
	}

      scrn_ptr = t_scrn_ptr2;
    }
  else
    {
      UBYTE *t_scrn_ptr;
      int xpos;

      t_scrn_ptr = scrn_ptr;

      for (xpos=0;xpos<ATARI_WIDTH;xpos+=8)
	{
	  UBYTE colreg;
	  UBYTE colour;

	  colreg = *t_scrn_ptr;
	  colour = colour_lookup[colreg];
	  *t_scrn_ptr++ = colour;

	  colreg = *t_scrn_ptr;
	  colour = colour_lookup[colreg];
	  *t_scrn_ptr++ = colour;

	  colreg = *t_scrn_ptr;
	  colour = colour_lookup[colreg];
	  *t_scrn_ptr++ = colour;

	  colreg = *t_scrn_ptr;
	  colour = colour_lookup[colreg];
	  *t_scrn_ptr++ = colour;

	  colreg = *t_scrn_ptr;
	  colour = colour_lookup[colreg];
	  *t_scrn_ptr++ = colour;

	  colreg = *t_scrn_ptr;
	  colour = colour_lookup[colreg];
	  *t_scrn_ptr++ = colour;

	  colreg = *t_scrn_ptr;
	  colour = colour_lookup[colreg];
	  *t_scrn_ptr++ = colour;

	  colreg = *t_scrn_ptr;
	  colour = colour_lookup[colreg];
	  *t_scrn_ptr++ = colour;
	}

      scrn_ptr = t_scrn_ptr;
    }

  ypos++;

  if (wsync_halt)
    {
      if (!(--wsync_halt))
	{
	  ncycles = 3;
	  GO ();
	}
    }
  else
    {
      ncycles = 3;
      GO ();
    }
}
#endif

/*
	*****************************************************************
	*								*
	*	Section			:	Antic Display Modes	*
	*	Original Author		:	David Firth		*
	*	Date Written		:	28th May 1995		*
	*	Version			:	1.0			*
	*								*
	*								*
	*   Description							*
	*   -----------							*
	*								*
	*   Section that handles Antic display modes. Not required	*
	*   for BASIC version.						*
	*								*
	*****************************************************************
*/

static UWORD chbase_40; /* CHBASE for 40 character mode */
static UWORD chbase_20; /* CHBASE for 20 character mode */

static int dmactl_xmin_noscroll;
static int dmactl_xmax_noscroll;
static int dmactl_xmin_scroll;
static int dmactl_xmax_scroll;

static int char_delta;
static int char_offset;
static int invert_mask;
static int blank_mask;

#ifndef BASIC
#ifndef CURSES

static UWORD	screenaddr;

static UWORD lookup1[256];
static UWORD lookup2[256];

static int xmin;
static int xmax;

void antic_blank (int nlines)
{
  if (nlines > 0)
    {
      int nbytes;
      int i;

      if (dlicount)
	dlicount = nlines;

      nbytes = nlines * ATARI_WIDTH;

      memset (scrn_ptr, PF_COLBK, nbytes);

      for (i=0;i<nlines;i++)
	{
	  Atari_ScanLine ();
	}
    }
}

static int vskipbefore = 0;
static int vskipafter = 0;

void antic_2 ()
{
  UWORD t_screenaddr = screenaddr;
  char *t_scrn_ptr = &scrn_ptr[xmin+scroll_offset];
  int nchars = (xmax - xmin) >> 3;
  int i;

  if (dlicount)
    dlicount = 8;

  lookup1[0x00] = PF_COLPF2;
  lookup1[0x80] = lookup1[0x40] = lookup1[0x20] =
    lookup1[0x10] = lookup1[0x08] = lookup1[0x04] =
      lookup1[0x02] = lookup1[0x01] = PF_COLPF1;

  for (i=0;i<nchars;i++)
    {
      UBYTE screendata = memory[t_screenaddr++];
      UWORD chaddr;
      UBYTE invert;
      UBYTE blank;
      char *ptr = t_scrn_ptr;
      int j;

      chaddr = chbase_40 + char_offset + ((UWORD)(screendata & 0x7f) << 3);

      if (screendata & invert_mask)
	invert = 0xff;
      else
	invert = 0x00;

      if (screendata & blank_mask)
	blank = 0x00;
      else
	blank = 0xff;

      for (j=0;j<8;j++)
	{
	  UBYTE	chdata;

	  chdata = (memory[chaddr] ^ invert) & blank;
	  chaddr += char_delta;

	  if ((j >= vskipbefore) && (j <= vskipafter))
	    {
	      if (chdata)
		{
		  *ptr++ = lookup1[chdata & 0x80];
		  *ptr++ = lookup1[chdata & 0x40];
		  *ptr++ = lookup1[chdata & 0x20];
		  *ptr++ = lookup1[chdata & 0x10];
		  *ptr++ = lookup1[chdata & 0x08];
		  *ptr++ = lookup1[chdata & 0x04];
		  *ptr++ = lookup1[chdata & 0x02];
		  *ptr++ = lookup1[chdata & 0x01];
		}
	      else
		{
		  ULONG *l_ptr = (ULONG*)ptr;

		  *l_ptr++ = PF4_COLPF2;
		  *l_ptr++ = PF4_COLPF2;

		  ptr = (UBYTE*)l_ptr;
/*
		  *ptr++ = PF_COLPF2;
		  *ptr++ = PF_COLPF2;
		  *ptr++ = PF_COLPF2;
		  *ptr++ = PF_COLPF2;
		  *ptr++ = PF_COLPF2;
		  *ptr++ = PF_COLPF2;
		  *ptr++ = PF_COLPF2;
		  *ptr++ = PF_COLPF2;
*/
		}

	      ptr += (ATARI_WIDTH - 8);
	    }
	}

      t_scrn_ptr += 8;
    }

  for (i=0;i<8;i++)
    {
      if ((i >= vskipbefore) && (i <= vskipafter))
	{
	  int j;

	  for (j=0;j<xmin;j++)
	    scrn_ptr[j] = PF_COLBK;

	  for (j=xmax;j<ATARI_WIDTH;j++)
	    scrn_ptr[j] = PF_COLBK;

	  Atari_ScanLine ();
	}
    }

  screenaddr = t_screenaddr;
}

/*
 * Function to display Antic Mode 3
 */

void antic_3 ()
{
  char *t_scrn_ptr = &scrn_ptr[xmin+scroll_offset];
  int nchars = (xmax - xmin) >> 3;
  int i;

  if (dlicount)
    dlicount = 10;

  lookup1[0x00] = PF_COLPF2;
  lookup1[0x80] = lookup1[0x40] = lookup1[0x20] =
    lookup1[0x10] = lookup1[0x08] = lookup1[0x04] =
      lookup1[0x02] = lookup1[0x01] = PF_COLPF1;

  for (i=0;i<nchars;i++)
    {
      UBYTE screendata = memory[screenaddr++];
      UWORD chaddr;
      UBYTE invert;
      UBYTE blank;
      UBYTE lowercase;
      UBYTE first;
      UBYTE second;
      char *ptr = t_scrn_ptr;
      int j;

      chaddr = chbase_40 + ((UWORD)(screendata & 0x7f) << 3) + char_offset;

      if (screendata & invert_mask)
	invert = 0xff;
      else
	invert = 0x00;

      if (screendata & blank_mask)
	blank = 0x00;
      else
	blank = 0xff;

      if ((screendata & 0x60) == 0x60)
	lowercase = TRUE;
      else
	lowercase = FALSE;

      for (j=0;j<10;j++)
	{
	  UBYTE chdata;

	  if (lowercase)
	    {
	      switch (j)
		{
		case 0 :
		  first = memory[chaddr];
		  chaddr += char_delta;
		  chdata = 0;
		  break;
		case 1 :
		  second = memory[chaddr];
		  chaddr += char_delta;
		  chdata = 0;
		  break;
		case 8 :
		  chdata = first;
		  break;
		case 9 :
		  chdata = second;
		  break;
		default :
		  chdata = memory[chaddr];
		  chaddr += char_delta;
		  break;
		}
	    }
	  else if (j < 8)
	    {
	      chdata = memory[chaddr];
	      chaddr += char_delta;
	    }
	  else
	    {
	      chdata = 0;
	    }

	  chdata = (chdata ^ invert) & blank;

	  if (chdata)
	    {
	      *ptr++ = lookup1[chdata & 0x80];
	      *ptr++ = lookup1[chdata & 0x40];
	      *ptr++ = lookup1[chdata & 0x20];
	      *ptr++ = lookup1[chdata & 0x10];
	      *ptr++ = lookup1[chdata & 0x08];
	      *ptr++ = lookup1[chdata & 0x04];
	      *ptr++ = lookup1[chdata & 0x02];
	      *ptr++ = lookup1[chdata & 0x01];
	    }
	  else
	    {
	      *ptr++ = PF_COLPF2;
	      *ptr++ = PF_COLPF2;
	      *ptr++ = PF_COLPF2;
	      *ptr++ = PF_COLPF2;
	      *ptr++ = PF_COLPF2;
	      *ptr++ = PF_COLPF2;
	      *ptr++ = PF_COLPF2;
	      *ptr++ = PF_COLPF2;
	    }

	  ptr += (ATARI_WIDTH - 8);
	}

      t_scrn_ptr += 8;
    }

  for (i=0;i<10;i++)
    {
      int	j;
      int	xpos = xmin;

      for (j=0;j<xmin;j++)
	scrn_ptr[j] = PF_COLBK;

      for (j=xmax;j<ATARI_WIDTH;j++)
	scrn_ptr[j] = PF_COLBK;

      Atari_ScanLine ();
    }
}

/*
 * Funtion to display Antic Mode 4
 */

void antic_4 ()
{
  UWORD *t_scrn_ptr = (UWORD*)&scrn_ptr[xmin+scroll_offset];
  int nchars = (xmax - xmin) >> 3;
  int i;

  if (dlicount)
    dlicount = 8;
/*
   =================================
   Pixel values when character < 128
   =================================
*/
  lookup1[0x00] = PF2_COLBK;
  lookup1[0x40] = lookup1[0x10] = lookup1[0x04] =
    lookup1[0x01] = PF2_COLPF0;
  lookup1[0x80] = lookup1[0x20] = lookup1[0x08] =
    lookup1[0x02] = PF2_COLPF1;
  lookup1[0xc0] = lookup1[0x30] = lookup1[0x0c] =
    lookup1[0x03] = PF2_COLPF3;
/*
   ==================================
   Pixel values when character >= 128
   ==================================
*/
  lookup2[0x00] = PF2_COLBK;
  lookup2[0x40] = lookup2[0x10] = lookup2[0x04] =
    lookup2[0x01] = PF2_COLPF0;
  lookup2[0x80] = lookup2[0x20] = lookup2[0x08] =
    lookup2[0x02] = PF2_COLPF2;
  lookup2[0xc0] = lookup2[0x30] = lookup2[0x0c] =
    lookup2[0x03] = PF2_COLPF3;

  for (i=0;i<nchars;i++)
    {
      UBYTE screendata = memory[screenaddr++];
      UWORD chaddr;
      UWORD *lookup;
      UWORD *ptr = t_scrn_ptr;
      int j;

      chaddr = chbase_40 + ((UWORD)(screendata & 0x7f) << 3) + char_offset;

      if (screendata & 0x80)
	lookup = lookup2;
      else
	lookup = lookup1;

      for (j=0;j<8;j++)
	{
	  UBYTE chdata;

	  chdata = memory[chaddr];
	  chaddr += char_delta;

	  if ((j >= vskipbefore) && (j <= vskipafter))
	    {
	      if (chdata)
		{
		  UWORD colour;

		  colour = lookup[chdata & 0xc0];
		  *ptr++ = colour;

		  colour = lookup[chdata & 0x30];
		  *ptr++ = colour;

		  colour = lookup[chdata & 0x0c];
		  *ptr++ = colour;

		  colour = lookup[chdata & 0x03];
		  *ptr++ = colour;
		}
	      else
		{
		  *ptr++ = PF2_COLBK;
		  *ptr++ = PF2_COLBK;
		  *ptr++ = PF2_COLBK;
		  *ptr++ = PF2_COLBK;
		}

	      ptr += ((ATARI_WIDTH - 8) >> 1);
	    }
	}

      t_scrn_ptr += 4;
    }

  for (i=0;i<8;i++)
    {
      if ((i >= vskipbefore) && (i <= vskipafter))
	{
	  int j;

	  for (j=0;j<xmin;j++)
	    scrn_ptr[j] = PF_COLBK;

	  for (j=xmax;j<ATARI_WIDTH;j++)
	    scrn_ptr[j] = PF_COLBK;

	  Atari_ScanLine ();
	}
    }
}

/*
 * Function to Display Antic Mode 5
 */

void antic_5 ()
{
  UWORD *t_scrn_ptr1 = (UWORD*)&scrn_ptr[xmin+scroll_offset];
  UWORD *t_scrn_ptr2 = (UWORD*)&scrn_ptr[xmin+ATARI_WIDTH+scroll_offset];
  int nchars = nchars = (xmax - xmin) >> 3;
  int i;

  if (dlicount)
    dlicount = 16;
/*
   =================================
   Pixel values when character < 128
   =================================
*/
  lookup1[0x00] = PF2_COLBK;
  lookup1[0x40] = lookup1[0x10] = lookup1[0x04] =
    lookup1[0x01] = PF2_COLPF0;
  lookup1[0x80] = lookup1[0x20] = lookup1[0x08] =
    lookup1[0x02] = PF2_COLPF1;
  lookup1[0xc0] = lookup1[0x30] = lookup1[0x0c] =
    lookup1[0x03] = PF2_COLPF3;
/*
   ==================================
   Pixel values when character >= 128
   ==================================
*/
  lookup2[0x00] = PF2_COLBK;
  lookup2[0x40] = lookup2[0x10] = lookup2[0x04] =
    lookup2[0x01] = PF2_COLPF0;
  lookup2[0x80] = lookup2[0x20] = lookup2[0x08] =
    lookup2[0x02] = PF2_COLPF2;
  lookup2[0xc0] = lookup2[0x30] = lookup2[0x0c] =
    lookup2[0x03] = PF2_COLPF3;

  for (i=0;i<nchars;i++)
    {
      UBYTE screendata = memory[screenaddr++];
      UWORD chaddr;
      UWORD *lookup;
      UWORD *ptr1 = t_scrn_ptr1;
      UWORD *ptr2 = t_scrn_ptr2;
      int j;

      chaddr = chbase_40 + ((UWORD)(screendata & 0x7f) << 3) + char_offset;

      if (screendata & 0x80)
	lookup = lookup2;
      else
	lookup = lookup1;

      for (j=0;j<8;j++)
	{
	  UBYTE chdata;

	  chdata = memory[chaddr];
	  chaddr += char_delta;

	  if ((j >= vskipbefore) && (j <= vskipafter))
	    {
	      if (chdata)
		{
		  UWORD colour;

		  colour = lookup[chdata & 0xc0];
		  *ptr1++ = colour;
		  *ptr2++ = colour;

		  colour = lookup[chdata & 0x30];
		  *ptr1++ = colour;
		  *ptr2++ = colour;

		  colour = lookup[chdata & 0x0c];
		  *ptr1++ = colour;
		  *ptr2++ = colour;

		  colour = lookup[chdata & 0x03];
		  *ptr1++ = colour;
		  *ptr2++ = colour;
		}
	      else
		{
		  *ptr1++ = PF2_COLBK;
		  *ptr1++ = PF2_COLBK;
		  *ptr1++ = PF2_COLBK;
		  *ptr1++ = PF2_COLBK;

		  *ptr2++ = PF2_COLBK;
		  *ptr2++ = PF2_COLBK;
		  *ptr2++ = PF2_COLBK;
		  *ptr2++ = PF2_COLBK;
		}
	    }

	  ptr1 += ((ATARI_WIDTH + ATARI_WIDTH - 8) >> 1);
	  ptr2 += ((ATARI_WIDTH + ATARI_WIDTH - 8) >> 1);
	}

      t_scrn_ptr1 += (8 >> 1);
      t_scrn_ptr2 += (8 >> 1);
    }

  for (i=0;i<16;i++)
    {
      if ((i >= vskipbefore) && (i <= vskipafter))
	{
	  int j;

	  for (j=0;j<xmin;j++)
	    scrn_ptr[j] = PF_COLBK;

	  for (j=xmax;j<ATARI_WIDTH;j++)
	    scrn_ptr[j] = PF_COLBK;

	  Atari_ScanLine ();
	}
    }
}

/*
 * Function to Display Antic Mode 6
 */

void antic_6 ()
{
  UWORD *t_scrn_ptr = (UWORD*)&scrn_ptr[xmin+scroll_offset];
  int nchars = (xmax - xmin) >> 4; /* Divide by 16 */
  int i;

  if (dlicount)
    dlicount = 8;

  for (i=0;i<nchars;i++)
    {
      UBYTE screendata = memory[screenaddr++];
      UWORD chaddr;
      UWORD *ptr = t_scrn_ptr;
      UWORD colour;
      int j;

      chaddr = chbase_20 + ((UWORD)(screendata & 0x3f) << 3) + char_offset;

      switch (screendata & 0xc0)
	{
	case 0x00 :
	  colour = PF2_COLPF0;
	  break;
	case 0x40 :
	  colour = PF2_COLPF1;
	  break;
	case 0x80 :
	  colour = PF2_COLPF2;
	  break;
	case 0xc0 :
	  colour = PF2_COLPF3;
	  break;
	}

      for (j=0;j<8;j++)
	{
	  UBYTE chdata;
	  int k;

	  chdata = memory[chaddr];
	  chaddr += char_delta;

	  if ((j >= vskipbefore) && (j <= vskipafter))
	    {
	      for (k=0;k<8;k++)
		{
		  if (chdata & 0x80)
		    {
		      *ptr++ = colour;
		    }
		  else
		    {
		      *ptr++ = PF2_COLBK;
		    }
	      
		  chdata = chdata << 1;
		}

	      ptr += ((ATARI_WIDTH - 16) >> 1);
	    }
	}

      t_scrn_ptr += (16 >> 1);
    }

  for (i=0;i<8;i++)
    {
      if ((i >= vskipbefore) && (i <= vskipafter))
	{
	  int j;

	  for (j=0;j<xmin;j++)
	    scrn_ptr[j] = PF_COLBK;

	  for (j=xmax;j<ATARI_WIDTH;j++)
	    scrn_ptr[j] = PF_COLBK;

	  Atari_ScanLine ();
	}
    }
}

/*
 * Function to Display Antic Mode 7
 */

void antic_7 ()
{
  UWORD *t_scrn_ptr1 = (UWORD*)&scrn_ptr[xmin+scroll_offset];
  UWORD *t_scrn_ptr2 = (UWORD*)&scrn_ptr[xmin+ATARI_WIDTH+scroll_offset];
  int nchars = (xmax - xmin) >> 4; /* Divide by 16 */
  int i;

  if (dlicount)
    dlicount = 16;

  for (i=0;i<nchars;i++)
    {
      UBYTE screendata = memory[screenaddr++];
      UWORD chaddr;
      UWORD *ptr1 = t_scrn_ptr1;
      UWORD *ptr2 = t_scrn_ptr2;
      UWORD colour;
      int j;

      chaddr = chbase_20 + ((UWORD)(screendata & 0x3f) << 3) + char_offset;

      switch (screendata & 0xc0)
	{
	case 0x00 :
	  colour = PF2_COLPF0;
	  break;
	case 0x40 :
	  colour = PF2_COLPF1;
	  break;
	case 0x80 :
	  colour = PF2_COLPF2;
	  break;
	case 0xc0 :
	  colour = PF2_COLPF3;
	  break;
	}

      for (j=0;j<8;j++)
	{
	  UBYTE chdata;
	  int k;

	  chdata = memory[chaddr];
	  chaddr += char_delta;

	  if ((j >= vskipbefore) && (j <= vskipafter))
	    {
	      for (k=0;k<8;k++)
		{
		  if (chdata & 0x80)
		    {
		      *ptr1++ = colour;
		      *ptr2++ = colour;
		    }
		  else
		    {
		      *ptr1++ = PF2_COLBK;
		      *ptr2++ = PF2_COLBK;
		    }

		  chdata = chdata << 1;
		}

	      ptr1 += ((ATARI_WIDTH + ATARI_WIDTH - 16) >> 1);
	      ptr2 += ((ATARI_WIDTH + ATARI_WIDTH - 16) >> 1);
	    }
	}

      t_scrn_ptr1 += (16 >> 1);
      t_scrn_ptr2 += (16 >> 1);
    }

  for (i=0;i<16;i++)
    {
      if ((i >= vskipbefore) && (i <= vskipafter))
	{
	  int j;

	  for (j=0;j<xmin;j++)
	    scrn_ptr[j] = PF_COLBK;

	  for (j=xmax;j<ATARI_WIDTH;j++)
	    scrn_ptr[j] = PF_COLBK;

	  Atari_ScanLine ();
	}
    }
}

/*
 * Function to Display Antic Mode 8
 */

void antic_8 ()
{
  char *t_scrn_ptr = &scrn_ptr[xmin+scroll_offset];
  int nbytes = (xmax - xmin) >> 5; /* Divide by 32 */
  int	i;

  if (dlicount)
    dlicount = 8;

  lookup1[0x00] = PF_COLBK;
  lookup1[0x40] = PF_COLPF0;
  lookup1[0x80] = PF_COLPF1;
  lookup1[0xc0] = PF_COLPF2;

  for (i=0;i<nbytes;i++)
    {
      UBYTE screendata = memory[screenaddr++];
      int j;

      for (j=0;j<4;j++)
	{
	  UBYTE colour;
	  char *ptr = t_scrn_ptr;
	  int k;

	  colour = lookup1[screendata & 0xc0];

	  for (k=0;k<8;k++)
	    {
	      memset (ptr, colour, 8);
	      ptr += ATARI_WIDTH;
	    }

	  screendata = screendata << 2;
	  t_scrn_ptr += 8;
	}
    }

  for (i=0;i<8;i++)
    {
      int j;

      for (j=0;j<xmin;j++)
	scrn_ptr[j] = PF_COLBK;

      for (j=xmax;j<ATARI_WIDTH;j++)
	scrn_ptr[j] = PF_COLBK;

      Atari_ScanLine ();
    }
}

/*
 * Function to Display Antic Mode 9
 */

void antic_9 ()
{
  char *t_scrn_ptr = &scrn_ptr[xmin+scroll_offset];
  int nbytes = (xmax - xmin) >> 5; /* Divide by 32 */
  int i;

  if (dlicount)
    dlicount = 4;

  lookup1[0x00] = PF_COLBK;
  lookup1[0x80] = PF_COLPF0;

  for (i=0;i<nbytes;i++)
    {
      UBYTE screendata = memory[screenaddr++];
      int j;

      for (j=0;j<8;j++)
	{
	  UBYTE colour;
	  char *ptr = t_scrn_ptr;
	  int k;

	  colour = lookup1[screendata & 0x80];

	  for (k=0;k<4;k++)
	    {
	      memset (ptr, colour, 4);
	      ptr += ATARI_WIDTH;
	    }

	  screendata = screendata << 1;
	  t_scrn_ptr += 4;
	}
    }

  for (i=0;i<4;i++)
    {
      int j;

      for (j=0;j<xmin;j++)
	scrn_ptr[j] = PF_COLBK;

      for (j=xmax;j<ATARI_WIDTH;j++)
	scrn_ptr[j] = PF_COLBK;

      Atari_ScanLine ();
    }
}

/*
 * Function to Display Antic Mode a
 */

void antic_a ()
{
  char *t_scrn_ptr = &scrn_ptr[xmin+scroll_offset];
  int nbytes = (xmax - xmin) >> 4; /* Divide by 16 */
  int i;
  
  if (dlicount)
    dlicount = 4;

  lookup1[0x00] = PF_COLBK;
  lookup1[0x40] = PF_COLPF0;
  lookup1[0x80] = PF_COLPF1;
  lookup1[0xc0] = PF_COLPF2;

  for (i=0;i<nbytes;i++)
    {
      UBYTE screendata = memory[screenaddr++];
      int j;

      for (j=0;j<4;j++)
	{
	  UBYTE colour;
	  char *ptr = t_scrn_ptr;
	  int k;

	  colour = lookup1[screendata & 0xc0];

	  for (k=0;k<4;k++)
	    {
	      memset (ptr, colour, 4);
	      ptr += ATARI_WIDTH;
	    }

	  screendata = screendata << 2;
	  t_scrn_ptr += 4;
	}
    }

  for (i=0;i<4;i++)
    {
      int j;

      for (j=0;j<xmin;j++)
	scrn_ptr[j] = PF_COLBK;

      for (j=xmax;j<ATARI_WIDTH;j++)
	scrn_ptr[j] = PF_COLBK;

      Atari_ScanLine ();
    }
}

/*
 * Function to Display Antic Mode b
 */

void antic_b ()
{
  char *t_scrn_ptr1 = &scrn_ptr[xmin+scroll_offset];
  char *t_scrn_ptr2 = &scrn_ptr[xmin+ATARI_WIDTH+scroll_offset];
  int nbytes = (xmax - xmin) >> 4; /* Divide by 16 */
  int i;

  if (dlicount)
    dlicount = 2;

  lookup1[0x00] = PF_COLBK;
  lookup1[0x80] = PF_COLPF0;

  for (i=0;i<nbytes;i++)
    {
      UBYTE screendata = memory[screenaddr++];
      UWORD colour;
      int j;

      for (j=0;j<8;j++)
	{
	  colour = lookup1[screendata & 0x80];
	  *t_scrn_ptr1++ = colour;
	  *t_scrn_ptr1++ = colour;
	  *t_scrn_ptr2++ = colour;
	  *t_scrn_ptr2++ = colour;
	  screendata = screendata << 1;
	}
    }

  for (i=0;i<2;i++)
    {
      int j;

      for (j=0;j<xmin;j++)
	scrn_ptr[j] = PF_COLBK;

      for (j=xmax;j<ATARI_WIDTH;j++)
	scrn_ptr[j] = PF_COLBK;

      Atari_ScanLine ();
    }
}

/*
 * Function to Display Antic Mode c
 */

void antic_c ()
{
  char *t_scrn_ptr = &scrn_ptr[xmin+scroll_offset];
  int nbytes = (xmax - xmin) >> 4; /* Divide by 16 */
  int i;

  if (dlicount)
    dlicount = 1;

  lookup1[0x00] = PF_COLBK;
  lookup1[0x80] = lookup1[0x40] = lookup1[0x20] = lookup1[0x10] = PF_COLPF0;

  for (i=0;i<nbytes;i++)
    {
      UBYTE screendata = memory[screenaddr++];
      int j;

      for (j=0;j<2;j++)
	{
	  UBYTE colour;

	  colour = lookup1[screendata & 0x80];
	  *t_scrn_ptr++ = colour;
	  *t_scrn_ptr++ = colour;

	  colour = lookup1[screendata & 0x40];
	  *t_scrn_ptr++ = colour;
	  *t_scrn_ptr++ = colour;

	  colour = lookup1[screendata & 0x20];
	  *t_scrn_ptr++ = colour;
	  *t_scrn_ptr++ = colour;

	  colour = lookup1[screendata & 0x10];
	  *t_scrn_ptr++ = colour;
	  *t_scrn_ptr++ = colour;

	  screendata <<= 4;
	}
    }

  for (i=0;i<xmin;i++)
    scrn_ptr[i] = PF_COLBK;

  for (i=xmax;i<ATARI_WIDTH;i++)
    scrn_ptr[i] = PF_COLBK;

  Atari_ScanLine ();
}

/*
 * Function to Display Antic Mode d
 */

void antic_d ()
{
  UWORD *t_scrn_ptr1 = (UWORD*)&scrn_ptr[scroll_offset];
  UWORD *t_scrn_ptr2 = (UWORD*)&scrn_ptr[ATARI_WIDTH+scroll_offset];
  int nbytes = (xmax - xmin) >> 3;
  int i;

  if (dlicount)
    dlicount = 2;

  lookup1[0x00] = PF2_COLBK;
  lookup1[0x40] = PF2_COLPF0;
  lookup1[0x80] = PF2_COLPF1;
  lookup1[0xc0] = PF2_COLPF2;

  for (i=0;i<xmin;i+=2)
    {
      *t_scrn_ptr1++ = PF2_COLBK;
      *t_scrn_ptr2++ = PF2_COLBK;
    }

  for (i=0;i<nbytes;i++)
    {
      UBYTE	screendata;
      
      screendata = memory[screenaddr++];

      if (screendata)
	{
	  UWORD colour;

	  colour = lookup1[screendata & 0xc0];
	  *t_scrn_ptr1++ = colour;
	  *t_scrn_ptr2++ = colour;
	  screendata = screendata << 2;

	  colour = lookup1[screendata & 0xc0];
	  *t_scrn_ptr1++ = colour;
	  *t_scrn_ptr2++ = colour;
	  screendata = screendata << 2;

	  colour = lookup1[screendata & 0xc0];
	  *t_scrn_ptr1++ = colour;
	  *t_scrn_ptr2++ = colour;
	  screendata = screendata << 2;

	  colour = lookup1[screendata & 0xc0];
	  *t_scrn_ptr1++ = colour;
	  *t_scrn_ptr2++ = colour;
	  screendata = screendata << 2;
	}
      else
	{
	  *t_scrn_ptr1++ = PF2_COLBK;
	  *t_scrn_ptr1++ = PF2_COLBK;
	  *t_scrn_ptr1++ = PF2_COLBK;
	  *t_scrn_ptr1++ = PF2_COLBK;

	  *t_scrn_ptr2++ = PF2_COLBK;
	  *t_scrn_ptr2++ = PF2_COLBK;
	  *t_scrn_ptr2++ = PF2_COLBK;
	  *t_scrn_ptr2++ = PF2_COLBK;
	}
    }

  for (i=xmax;i<ATARI_WIDTH;i+=2)
    {
      *t_scrn_ptr1++ = PF2_COLBK;
      *t_scrn_ptr2++ = PF2_COLBK;
    }

  Atari_ScanLine ();
  Atari_ScanLine ();
}

/*
 * Function to display Antic Mode e
 */

void antic_e ()
{
  UWORD *t_scrn_ptr = (UWORD*)&scrn_ptr[xmin+scroll_offset];
  int nbytes = (xmax - xmin) >> 3;
  int i;

  if (dlicount)
    dlicount = 1;

#ifdef AMIGA_TEST
	antic_e_test (nbytes-1, &memory[screenaddr], t_scrn_ptr);
	screenaddr += nbytes;
#else

  lookup1[0x00] = PF2_COLBK;
  lookup1[0x01] = PF2_COLPF0;
  lookup1[0x02] = PF2_COLPF1;
  lookup1[0x03] = PF2_COLPF2;

  for (i=0;i<nbytes;i++)
    {
      UBYTE screendata = memory[screenaddr++];

      if (screendata)
	{
	  UWORD pixel0;
	  UWORD pixel1;
	  UWORD pixel2;
	  UWORD pixel3;

	  pixel0 = lookup1[screendata & 0x03];
	  screendata >>= 2;
	  pixel1 = lookup1[screendata & 0x03];
	  screendata >>= 2;
	  pixel2 = lookup1[screendata & 0x03];
	  screendata >>= 2;
	  pixel3 = lookup1[screendata & 0x03];

	  *t_scrn_ptr++ = pixel3;
	  *t_scrn_ptr++ = pixel2;
	  *t_scrn_ptr++ = pixel1;
	  *t_scrn_ptr++ = pixel0;
	}
      else
	{
	  ULONG *l_ptr  = (ULONG*)t_scrn_ptr;

	  *l_ptr++ = PF4_COLBK;
	  *l_ptr++ = PF4_COLBK;

	  t_scrn_ptr = (UWORD*)l_ptr;
/*
	  *t_scrn_ptr++ = PF2_COLBK;
	  *t_scrn_ptr++ = PF2_COLBK;
	  *t_scrn_ptr++ = PF2_COLBK;
	  *t_scrn_ptr++ = PF2_COLBK;
*/
	}
    }
#endif

  for (i=0;i<xmin;i++)
    scrn_ptr[i] = PF_COLBK;

  for (i=xmax;i<ATARI_WIDTH;i++)
    scrn_ptr[i] = PF_COLBK;

  Atari_ScanLine ();
}

/*
 * Function to display Antic Mode f
 */

void antic_f ()
{
  char *t_scrn_ptr = &scrn_ptr[scroll_offset];
  int nbytes = (xmax - xmin) >> 3;
  int i;

  if (dlicount)
    dlicount = 1;

  lookup1[0x00] = PF_COLPF2;
  lookup1[0x80] = lookup1[0x40] = lookup1[0x20] =
    lookup1[0x10] = lookup1[0x08] = lookup1[0x04] =
      lookup1[0x02] = lookup1[0x01] = PF_COLPF1;

  for (i=0;i<xmin;i++)
    *t_scrn_ptr++ = PF_COLBK;

  for (i=0;i<nbytes;i++)
    {
      UBYTE screendata = memory[screenaddr++];

      if (screendata)
	{
	  *t_scrn_ptr++ = lookup1[screendata & 0x80];
	  *t_scrn_ptr++ = lookup1[screendata & 0x40];
	  *t_scrn_ptr++ = lookup1[screendata & 0x20];
	  *t_scrn_ptr++ = lookup1[screendata & 0x10];
	  *t_scrn_ptr++ = lookup1[screendata & 0x08];
	  *t_scrn_ptr++ = lookup1[screendata & 0x04];
	  *t_scrn_ptr++ = lookup1[screendata & 0x02];
	  *t_scrn_ptr++ = lookup1[screendata & 0x01];
	}
      else
	{
	  *t_scrn_ptr++ = PF_COLPF2;
	  *t_scrn_ptr++ = PF_COLPF2;
	  *t_scrn_ptr++ = PF_COLPF2;
	  *t_scrn_ptr++ = PF_COLPF2;
	  *t_scrn_ptr++ = PF_COLPF2;
	  *t_scrn_ptr++ = PF_COLPF2;
	  *t_scrn_ptr++ = PF_COLPF2;
	  *t_scrn_ptr++ = PF_COLPF2;
	}
    }

  for (i=xmax;i<ATARI_WIDTH;i++)
    *t_scrn_ptr++ = PF_COLBK;

  Atari_ScanLine ();
}

/*
	*****************************************************************
	*								*
	*	Section			:	Display List		*
	*	Original Author		:	David Firth		*
	*	Date Written		:	28th May 1995		*
	*	Version			:	1.0			*
	*								*
	*   Description							*
	*   -----------							*
	*								*
	*   Section that handles Antic Display List. Not required for	*
	*   BASIC version.						*
	*                                                               *
	*   VCOUNT is equal to 8 at the start of the first mode line,   *
	*   and is compensated for in the Atari_ScanLine macro.         *
	*								*
	*****************************************************************
*/

void Atari800_UpdateScreen ()
{
  UWORD	dlist;
  UWORD pmbase;
  int JVB;
  int vscrol_flag;

  scrn_ptr = (UBYTE*)atari_screen;
  pmbase = PMBASE << 8;

  if (singleline)
    {
      m0123adr = pmbase + 768 + 8;
      pl0adr = pmbase + 1024 + 8;
      pl1adr = pmbase + 1280 + 8;
      pl2adr = pmbase + 1536 + 8;
      pl3adr = pmbase + 1792 + 8;
    }
  else
    {
      m0123adr = pmbase + 384 + 4;
      pl0adr = pmbase + 512 + 4;
      pl1adr = pmbase + 640 + 4;
      pl2adr = pmbase + 768 + 4;
      pl3adr = pmbase + 896 + 4;
    }

  ypos = 0;
  vscrol_flag = FALSE;

  dlist = (DLISTH << 8) | DLISTL;
  JVB = FALSE;

  while ((DMACTL & 0x20) && !JVB && (ypos < ATARI_HEIGHT))
    {
      UBYTE	IR;

      IR = memory[dlist++];

      dlicount = IR & NMIEN & 0x80;

      switch (IR & 0x0f)
	{
	case 0x00 :
	  {
	    int	nlines;

	    nlines = ((IR >> 4)  & 0x07) + 1;
	    antic_blank (nlines);
	  }
	  break;
	case 0x01 :
	  if (IR & 0x40)
	    {
	      JVB = TRUE;
	    }
	  else
	    {
	      dlist = (memory[dlist+1] << 8) | memory[dlist];
	      antic_blank (1);	/* Jump aparently uses 1 scan line */
	    }
	  break;
	default :
	  if (IR & 0x40)
	    {
	      screenaddr = (memory[dlist+1] << 8) | memory[dlist];
	      dlist += 2;
	    }
	  
	  if (IR & 0x20)
	    {
	      if (!vscrol_flag)
		{
		  vskipbefore = VSCROL;
		  vscrol_flag = TRUE;
		}
	    }
	  else if (vscrol_flag)
	    {
	      vskipafter = VSCROL - 1;
	      vscrol_flag = FALSE;
	    }

	  if (IR & 0x10)
	    {
	      xmin = dmactl_xmin_scroll;
	      xmax = dmactl_xmax_scroll;
	      scroll_offset = HSCROL + HSCROL;
	    }
	  else
	    {
	      xmin = dmactl_xmin_noscroll;
	      xmax = dmactl_xmax_noscroll;
	      scroll_offset = 0;
	    }
	  
	  switch (IR & 0x0f)
	    {
	    case 0x02 :
	      antic_2 ();
	      break;
	    case 0x03 :
	      antic_3 ();
	      break;
	    case 0x04 :
	      antic_4 ();
	      break;
	    case 0x05 :
	      antic_5 ();
	      break;
	    case 0x06 :
	      antic_6 ();
	      break;
	    case 0x07 :
	      antic_7 ();
	      break;
	    case 0x08 :
	      antic_8 ();
	      break;
	    case 0x09 :
	      antic_9 ();
	      break;
	    case 0x0a :
	      antic_a ();
	      break;
	    case 0x0b :
	      antic_b ();
	      break;
	    case 0x0c :
	      antic_c ();
	      break;
	    case 0x0d :
	      antic_d ();
	      break;
	    case 0x0e :
	      antic_e ();
	      break;
	    case 0x0f :
	      antic_f ();
	      break;
	    default :
	      JVB = TRUE;
	      break;
	    }

	  vskipbefore = 0;
	  vskipafter = 99;
	  break;
	}
    }

  dlicount = 0;
  antic_blank (ATARI_HEIGHT - ypos);

  Atari_DisplayScreen (atari_screen);
}

#endif
#endif

static int	SHIFT = 0x00;

UBYTE Atari800_GetByte (UWORD addr)
{
  UBYTE	byte;
/*
	============================================================
	GTIA, POKEY, PIA and ANTIC do not fully decode their address
	------------------------------------------------------------
	PIA (At least) is fully decoded when emulating the XL/XE
	============================================================
*/
  switch (addr & 0xff00)
    {
    case 0xd000:        /* GTIA */
      addr &= 0xff1f;
      break;
    case 0xd200:        /* POKEY */
      addr &= 0xff0f;
      break;
    case 0xd300:        /* PIA */
      if (machine == Atari)
	addr &= 0xff03;
      break;
    case 0xd400:        /* ANTIC */
      addr &= 0xff0f;
      break;
    default:
      break;
    }

  switch (addr)
    {
    case _CHBASE :
      byte = CHBASE;
      break;
    case _CHACTL :
      byte = CHACTL;
      break;
    case _CONSOL :
      byte = Atari_CONSOL ();
      break;
    case _DLISTL :
      byte = DLISTL;
      break;
    case _DLISTH :
      byte = DLISTH;
      break;
    case _DMACTL :
      byte = DMACTL;
      break;
    case _KBCODE :
      byte = KBCODE;
      break;
    case _IRQST :
      byte = IRQST;
      break;
    case _M0PF :
      byte = M0PF;
      break;
    case _M1PF :
      byte = M1PF;
      break;
    case _M2PF :
      byte = M2PF;
      break;
    case _M3PF :
      byte = M3PF;
      break;
    case _M0PL :
      byte = M0PL;
      break;
    case _M1PL :
      byte = M1PL;
      break;
    case _M2PL :
      byte = M2PL;
      break;
    case _M3PL :
      byte = M3PL;
      break;
    case _P0PF :
      byte = P0PF;
      break;
    case _P1PF :
      byte = P1PF;
      break;
    case _P2PF :
      byte = P2PF;
      break;
    case _P3PF :
      byte = P3PF;
      break;
    case _P0PL :
      byte = P0PL & 0xfe;
      break;
    case _P1PL :
      byte = P1PL & 0xfd;
      break;
    case _P2PL :
      byte = P2PL & 0xfb;
      break;
    case _P3PL :
      byte = P3PL & 0xf7;
      break;
    case _PACTL :
      byte = PACTL;
      break;
    case _PAL :
      byte = 0;
      break;
    case _PBCTL :
      byte = PBCTL;
      break;
    case _PENH :
    case _PENV :
      byte = 0x00;
      break;
    case _PORTA :
      byte = Atari_PORT (0);
      break;
    case _PORTB :
      switch (machine)
	{
	case Atari :
	  byte = Atari_PORT (1);
	  break;
	case AtariXL :
	case AtariXE :
	  byte = PORTB;
	  break;
	}
      break;
    case _POT0 :
      byte = Atari_POT (0);
      break;
    case _POT1 :
      byte = Atari_POT (1);
      break;
    case _POT2 :
      byte = Atari_POT (2);
      break;
    case _POT3 :
      byte = Atari_POT (3); 
      break;
    case _POT4 :
      byte = Atari_POT (4);
      break;
    case _POT5 :
      byte = Atari_POT (5);
      break;
    case _POT6 :
      byte = Atari_POT (6);
      break;
    case _POT7 :
      byte = Atari_POT (7);
      break;
    case _RANDOM :
      byte = rand();
      break;
    case _TRIG0 :
      byte = Atari_TRIG (0);
      break;
    case _TRIG1 :
      byte = Atari_TRIG (1);
      break;
    case _TRIG2 :
      byte = Atari_TRIG (2);
      break;
    case _TRIG3 :
      byte = Atari_TRIG (3);
      break;
    case _VCOUNT :
/*
   The first line occurs when VCOUNT is equal to 4
*/
      byte = (ypos + 8) >> 1;
      break;
    case _NMIEN :
      byte = NMIEN;
      break;
    case _NMIST :
      byte = NMIST;
      break;
    case _SERIN :
      byte = SIO_SERIN ();
      break;
    case _SKSTAT :
      byte = 0xff;
      if (SHIFT)
	byte &= 0xf5;
      else
	byte &= 0xfd;
      break;
    case _WSYNC :
      wsync_halt++;
      ncycles = 0;
      byte = 0;
      break;
    default :
#ifdef DEBUG
      fprintf (stderr, "read from %04x\n", addr);
#endif
      byte = 0;
      break;
    }

  return byte;
}

void Atari800_PutByte (UWORD addr, UBYTE byte)
{
/*
	============================================================
	GTIA, POKEY, PIA and ANTIC do not fully decode their address
	------------------------------------------------------------
	PIA (At least) is fully decoded when emulating the XL/XE
	============================================================
*/
  switch (addr & 0xff00)
    {
    case 0xd000:        /* GTIA */
      addr &= 0xff1f;
      break;
    case 0xd200:        /* POKEY */
      addr &= 0xff0f;
      break;
    case 0xd300:        /* PIA */
      if (machine == Atari)
	addr &= 0xff03;
      break;
    case 0xd400:        /* ANTIC */
      addr &= 0xff0f;
      break;
    case 0xd500:        /* Super Cartridges */
      switch (cart_type)
	{
	case OSS_SUPERCART :
	  switch (addr & 0xff0f)
	    {
	    case 0xd500 :
	      if (cart_image)
		memcpy (memory+0xa000, cart_image, 0x1000);
	      break;
	    case 0xd504 :
	      if (cart_image)
		memcpy (memory+0xa000, cart_image+0x1000, 0x1000);
	      break;
	    case 0xd503 :
	    case 0xd507 :
	      if (cart_image)
		memcpy (memory+0xa000, cart_image+0x2000, 0x1000);
	      break;
	    }
	  break;
	case DB_SUPERCART :
	  switch (addr & 0xff07)
	    {
	    case 0xd500 :
	      if (cart_image)
		memcpy (memory+0x8000, cart_image, 0x2000);
	      break;
	    case 0xd501 :
	      if (cart_image)
		memcpy (memory+0x8000, cart_image+0x2000, 0x2000);
	      break;
	    case 0xd506 :
	      if (cart_image)
		memcpy (memory+0x8000, cart_image+0x4000, 0x2000);
	      break;
	    }
	  break;
	default :
	  break;
	}
      break;
    default:
      break;
    }


  switch (addr)
    {
    case _AUDC1 :
      Atari_AUDC (1, byte);
      break;
    case _AUDC2 :
      Atari_AUDC (2, byte);
      break;
    case _AUDC3 :
      Atari_AUDC (3, byte);
      break;
    case _AUDC4 :
      Atari_AUDC (4, byte);
      break;
    case _AUDCTL :
      Atari_AUDCTL (byte);
      break;
    case _AUDF1 :
      Atari_AUDF (1, byte);
      break;
    case _AUDF2 :
      Atari_AUDF (2, byte);
      break;
    case _AUDF3 :
      Atari_AUDF (3, byte);
      break;
    case _AUDF4 :
      Atari_AUDF (4, byte);
      break;
    case _CHBASE :
      CHBASE = byte;
      chbase_40 = (byte << 8) & 0xfc00;
      chbase_20 = (byte << 8) & 0xfe00;
      break;
    case _CHACTL :
      CHACTL = byte;
/*
   =================================================================
   Check for vertical reflect, video invert and character blank bits
   =================================================================
*/
	switch (CHACTL & 0x07)
	  {
	  case 0x00 :
	    char_offset = 0;
	    char_delta = 1;
	    invert_mask = 0x00;
	    blank_mask = 0x00;
	    break;
	  case 0x01 :
	    char_offset = 0;
	    char_delta = 1;
	    invert_mask = 0x00;
	    blank_mask = 0x80;
	    break;
	  case 0x02 :
	    char_offset = 0;
	    char_delta = 1;
	    invert_mask = 0x80;
	    blank_mask = 0x00;
	    break;
	  case 0x03 :
	    char_offset = 0;
	    char_delta = 1;
	    invert_mask = 0x80;
	    blank_mask = 0x80;
	    break;
	  case 0x04 :
	    char_offset = 7;
	    char_delta = -1;
	    invert_mask = 0x00;
	    blank_mask = 0x00;
	    break;
	  case 0x05 :
	    char_offset = 7;
	    char_delta = -1;
	    invert_mask = 0x00;
	    blank_mask = 0x80;
	    break;
	  case 0x06 :
	    char_offset = 7;
	    char_delta = -1;
	    invert_mask = 0x80;
	    blank_mask = 0x00;
	    break;
	  case 0x07 :
	    char_offset = 7;
	    char_delta = -1;
	    invert_mask = 0x80;
	    blank_mask = 0x80;
	    break;
	  }
	break;
#ifndef BASIC
    case _COLBK :
      COLBK = byte;
      colour_lookup[8] = colour_translation_table[byte];
      break;
    case _COLPF0 :
      colour_lookup[4] = colour_translation_table[byte];
      break;
    case _COLPF1 :
      colour_lookup[5] = colour_translation_table[byte];
      break;
    case _COLPF2 :
      colour_lookup[6] = colour_translation_table[byte];
      break;
    case _COLPF3 :
      colour_lookup[7] = colour_translation_table[byte];
      break;
    case _COLPM0 :
      colour_lookup[0] = colour_translation_table[byte];
      break;
    case _COLPM1 :
      colour_lookup[1] = colour_translation_table[byte];
      break;
    case _COLPM2 :
      colour_lookup[2] = colour_translation_table[byte];
      break;
    case _COLPM3 :
      colour_lookup[3] = colour_translation_table[byte];
      break;
#endif
    case _CONSOL :
      break;
    case _DLISTL :
      DLISTL = byte;
      break;
    case _DLISTH :
      DLISTH = byte;
      break;
    case _DMACTL :
      DMACTL = byte;
      switch (DMACTL & 0x03)
	{
	case 0x00 :
	  dmactl_xmin_noscroll = dmactl_xmax_noscroll = 0;
	  dmactl_xmin_scroll = dmactl_xmax_scroll = 0;
	  break;
	case 0x01 :
	  dmactl_xmin_noscroll = 64;
	  dmactl_xmax_noscroll = ATARI_WIDTH - 64;
	  dmactl_xmin_scroll = 32;
	  dmactl_xmax_scroll = ATARI_WIDTH - 32;
	  break;
	case 0x02 :
	  dmactl_xmin_noscroll = 32;
	  dmactl_xmax_noscroll = ATARI_WIDTH - 32;
	  dmactl_xmin_scroll = 0;
	  dmactl_xmax_scroll = ATARI_WIDTH;
	  break;
	case 0x03 :
	  dmactl_xmin_noscroll = dmactl_xmin_scroll = 0;
	  dmactl_xmax_noscroll = dmactl_xmax_scroll = ATARI_WIDTH;
	  break;
	}

      if (DMACTL & 0x0c)
	pm_dma_enabled = TRUE;
      else
	pm_dma_enabled = FALSE;

      if (DMACTL & 0x10)
	singleline = TRUE;
      else
	singleline = FALSE;
      break;
    case _GRAFM :
      GRAFM = byte;
      break;
    case _GRAFP0 :
      GRAFP0 = byte;
      break;
    case _GRAFP1 :
      GRAFP1 = byte;
      break;
    case _GRAFP2 :
      GRAFP2 = byte;
      break;
    case _GRAFP3 :
      GRAFP3 = byte;
      break;
    case _HITCLR :
      M0PF = M1PF = M2PF = M3PF = 0;
      P0PF = P1PF = P2PF = P3PF = 0; 
      M0PL = M1PL = M2PL = M3PL = 0; 
      P0PL = P1PL = P2PL = P3PL = 0;
      break;
    case _HPOSM0 :
      global_hposm0 = PM_XPos[byte];
      break;
    case _HPOSM1 :
      global_hposm1 = PM_XPos[byte];
      break;
    case _HPOSM2 :
      global_hposm2 = PM_XPos[byte];
      break;
    case _HPOSM3 :
      global_hposm3 = PM_XPos[byte];
      break;
    case _HPOSP0 :
      global_hposp0 = PM_XPos[byte];
      break;
    case _HPOSP1 :
      global_hposp1 = PM_XPos[byte];
      break;
    case _HPOSP2 :
      global_hposp2 = PM_XPos[byte];
      break;
    case _HPOSP3 :
      global_hposp3 = PM_XPos[byte];
      break;
    case _HSCROL :
      HSCROL = byte & 0x0f;
      break;
    case _IRQEN :
      IRQEN = byte;
      IRQST |= (~byte);
      if (IRQEN & 0x08)
	{
	  IRQST &= 0xf7;
	  INTERRUPT |= IRQ_MASK;
	}
      if (IRQEN &0x20)
	{
	  IRQST &= 0xdf;
	  INTERRUPT |= IRQ_MASK;
	}
      break;
    case _NMIEN :
      NMIEN = byte;
      break;
    case _NMIRES :
      NMIST = 0x00;
      break;
    case _PACTL :
      PACTL = byte;
      break;
    case _PBCTL :
      PBCTL = byte;
      break;
    case _PMBASE :
      PMBASE = byte;
      break;
    case _PORTB :
      switch (machine)
	{
	case Atari :
	  break;
	case AtariXE :
	  {
	    int cpu_flag = (byte & 0x10);
	    int antic_flag = (byte & 0x20);
	    int bank = (byte & 0x0c) >> 2;

#ifdef DEBUG
	    printf ("CPU = %d, ANTIC = %d, XE BANK = %d\n",
		    cpu_flag, antic_flag, bank);
#endif

/*
 * Possible Bank Transitions
 *
 * Main        -> Main
 * Main        -> Bank1,2,3,4
 * Bank1,2,3,4 -> Main
 * Bank1,2,3,4 -> Bank1,2,3,4
 */
	    if (cpu_flag)
	      {
		if (xe_bank != -1)
		  {
		    memcpy (&atarixe_memory[xe_bank*16384],
			    &memory[0x4000],
			    16384);
		    memcpy (&memory[0x4000], atarixe_16kbuffer, 16384);
		    xe_bank = -1;
		  }
	      }
	    else if (bank != xe_bank)
	      {
		if (xe_bank == -1)
		  {
		    memcpy (atarixe_16kbuffer,
			    &memory[0x4000],
			    16384);
		  }
		else
		  {
		    memcpy (&atarixe_memory[xe_bank*16384],
			    &memory[0x4000],
			    16384);
		  }

		memcpy (&memory[0x4000],
			&atarixe_memory[bank*16384],
			16384);
		xe_bank = bank;
	      }
	  }
	case AtariXL :
#ifdef DEBUG
	  printf ("Storing %x to PORTB\n", byte);
#endif
	  if ((byte ^ PORTB) & 0x01)
	    {
	      if (byte & 0x01)
		{
#ifdef DEBUG
		  printf ("\tEnable ROM at $c000-$cfff and $d800-$ffff\n");
#endif
		  memcpy (under_atarixl_os, memory+0xc000, 0x1000);
		  memcpy (under_atarixl_os+0x1800, memory+0xd800, 0x2800);
		  memcpy (memory+0xc000, atarixl_os, 0x1000);
		  memcpy (memory+0xd800, atarixl_os+0x1800, 0x2800);
		  SetROM (0xc000, 0xcfff);
		  SetROM (0xd800, 0xffff);
		}
	      else
		{
#ifdef DEBUG
		  printf ("\tEnable RAM at $c000-$cfff and $d800-$ffff\n");
#endif
		  memcpy (memory+0xc000, under_atarixl_os, 0x1000);
		  memcpy (memory+0xd800, under_atarixl_os+0x1800, 0x2800);
		  SetRAM (0xc000, 0xcfff);
		  SetRAM (0xd800, 0xffff);
		}
	    }
/*
	=====================================
	An Atari XL/XE can only disable Basic
	Other cartridge cannot be disable
	=====================================
*/
	  if (!rom_inserted)
	    {
	      if ((byte ^ PORTB) & 0x02)
		{
		  if (byte & 0x02)
		    {
#ifdef DEBUG
		      printf ("\tDisable BASIC\n");
#endif
		      memcpy (memory+0xa000, under_atari_basic, 0x2000);
		      SetRAM (0xa000, 0xbfff);
		    }
		  else
		    {
#ifdef DEBUG
		      printf ("\tEnable BASIC at $a000-$bfff\n");
#endif
		      memcpy (under_atari_basic, memory+0xa000, 0x2000);
		      memcpy (memory+0xa000, atari_basic, 0x2000);
		      SetROM (0xa000, 0xbfff);
		    }
		}
	    }

	  if ((byte ^ PORTB) & 0x80)
	    {
	      if (byte & 0x80)
		{
#ifdef DEBUG
		  printf ("\tEnable RAM at $5000-$57ff (Self Test)\n");
#endif
		  memcpy (memory+0x5000, under_atarixl_os+0x1000, 0x0800);
		  SetRAM (0x5000, 0x57ff);
		}
	      else
		{
#ifdef DEBUG
		  printf ("\tEnable ROM at $5000-$57ff (Self Test)\n");
#endif
		  memcpy (under_atarixl_os+0x1000, memory+0x5000, 0x800);
		  memcpy (memory+0x5000, atarixl_os+0x1000, 0x800);
		  SetROM (0x5000, 0x57ff);
		}
	    }
	  PORTB = byte;
	  break;
	}
      break;
    case _POTGO :
      break;
#ifndef BASIC
    case _PRIOR :
      if (byte != PRIOR)
	{
	  SetPrior (byte);
	}
      break;
#endif
    case _SEROUT :
      {
	int cmd_flag = (PBCTL & 0x08) ? 0 : 1;

	SIO_SEROUT (byte, cmd_flag);
      }
      break;
    case _SIZEM :
      global_sizem = PM_Width[byte & 0x03];
      break;
    case _SIZEP0 :
      global_sizep0 = PM_Width[byte & 0x03];
      break;
    case _SIZEP1 :
      global_sizep1 = PM_Width[byte & 0x03];
      break;
    case _SIZEP2 :
      global_sizep2 = PM_Width[byte & 0x03];
      break;
    case _SIZEP3 :
      global_sizep3 = PM_Width[byte & 0x03];
      break;
    case _VSCROL :
      VSCROL = byte & 0x0f;
      break;
    case _WSYNC :
      wsync_halt++;
      ncycles = 0;
      break;
    default :
#ifdef DEBUG
      fprintf (stderr, "write %02x to %04x\n", byte, addr);
#endif
      break;
    }
}

void Atari800_Hardware (void)
{
  static int	pil_on = FALSE;

  while (TRUE)
    {
      static int	test_val = 0;

      int	keycode;

      NMIST = 0x00;

#ifndef BASIC
      keycode = Atari_Keyboard ();

      switch (keycode)
	{
	case AKEY_COLDSTART :
	  memory[0x244] = 1;
	case AKEY_WARMSTART :
	  if (machine == Atari)
	    {
	      NMIST |= 0x20;
	      INTERRUPT |= NMI_MASK;
	    }
	  else
	    {
	      CPU_Reset ();
	    }
	  break;
	case AKEY_EXIT :
	  Atari800_Exit (FALSE);
	  exit (1);
	case AKEY_BREAK :
	  IRQST &= 0x7f;
	  INTERRUPT |= IRQ_MASK;
	  break;
	case AKEY_PIL :
	  if (pil_on)
	    {
	      SetRAM (0x8000, 0xbfff);
	      pil_on = FALSE;
	    }
	  else
	    {
	      SetROM (0x8000, 0xbfff);
	      pil_on = TRUE;
	    }
	  break;
	case AKEY_NONE :
	  break;
	default :
	  KBCODE = keycode;
	  IRQST &= 0xbf;
	  INTERRUPT |= IRQ_MASK;
	  break;
	}
#endif

      if (NMIEN & 0x40)
	{
	  NMIST |= 0x40;
	  INTERRUPT |= NMI_MASK;
	}
/*
	=========================
	Execute Some Instructions
	=========================
*/
      ncycles = countdown_rate;
      GO ();
/*
	=================
	Regenerate Screen
	=================
*/
#ifndef BASIC
#ifdef CURSES
      {
	int i;

	Atari_DisplayScreen ();

	for (i=0;i<ATARI_HEIGHT;i++)
	  {
	    ncycles = 48;
	    GO ();
	  }
      }
#else
/*
   VCOUNT must equal zero for some games but first line to
   display starts when VCOUNT = 4. This portion processes
   when VCOUNT = 0, 1, 2 and 3.
*/
      wsync_halt = 0;

      for (ypos=-8;ypos!=0;ypos++)
	{
	  ncycles=48;
	  GO();
	}

      if (++test_val == refresh_rate)
	{
	  Atari800_UpdateScreen ();
	  test_val = 0;
	}
      else
	{
	  for (ypos=0;ypos<ATARI_HEIGHT;ypos++)
	    {
	      ncycles = 48;
	      GO ();
	    }
	}
#endif
#endif
      frame++;
    }
}

