/******************************************************************************
*
* Copyright (C) 2004-2017  Brian Berlin
* 
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************
*
* FILENAME: antic.c
*
* DESCRIPTION:  This contains functions for emulating the ANTIC video chip
*
* AUTHORS:  bberlin
*
* CHANGE LOG
*
*  VER     DATE     CHANGED BY   DESCRIPTION OF CHANGE
* ------  --------  ----------   --------------------------------------------
* 0.1     07/18/04  bberlin      Creation
* 0.2     12/09/05  bberlin      Changed PM to write values directly to
*                                  GTIA instead of using write_register.  This
*                                  will allow the write register to do 
*                                  transfers (Kaboom fix)
* 0.2     02/22/06  bberlin      Initialize VBI Enable to 0 to prevent crashes
* 0.2.3   03/19/06  bberlin      Increase dli_count to 14 in 'antic_init' 
* 0.3.0   04/06/06  bberlin      Make dli_count 14 for Football only
* 0.4.0   04/23/06  bberlin      Take out dli_count 14 for Football.
* 0.4.0   04/23/06  bberlin      Change JVB to use blank line cycle map.
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "antic.h"
#include "gtia.h"
#include "memory.h"
#include "debug.h"

/* Values associated with registers */
#define PL_WD  0x03 
#define M_DMA  0x04 
#define P_DMA  0x08 
#define PM_REZ 0x10
#define DL_DMA 0x20

#define OPAQUE  0x01
#define INV_VID 0x02
#define UP_VID  0x04

extern t_cpu cpu6502;
extern t_gtia gtia;
t_antic antic;

static int m_shift;
static void ( *antic_refresh_ptr ) ( void ) = antic_do_nothing;

typedef enum {
    AC_CPU,
    AC_RM,
    AC_RP,
    AC_DL,
    AC_INIT,
    AC_END,
    AC_CH_FIRST,
    AC_CH_DATA,
    AC_MAP_RD,
    AC_MAP_DRAW,
    AC_DLI,
    AC_BLANK,
    AC_REFRESH
} antic_cycle_fn;

typedef struct {
    const int *cycles;
    const antic_cycle_fn *funcs;
    int count;
} antic_cycle_row;

#define HSCROLL_STEPS 8
#define HSCROLL_BEGIN 0
#define HSCROLL_END   1

#define HS_ROW(B, T0, T1, T2, T3, T4, T5, T6, T7) \
    { { (B) + 0, (T0) }, { (B) + 1, (T1) }, \
      { (B) + 2, (T2) }, { (B) + 3, (T3) }, \
      { (B) + 4, (T4) }, { (B) + 5, (T5) }, \
      { (B) + 6, (T6) }, { (B) + 7, (T7) } }

static int *antic_hscroll_cycle_ptr[5][MAX_INSTR][4][2];
static int *antic_hscroll_active_ptr[2];
static const int ( *antic_hscroll_active_values )[2];

static const int antic_mode_to_type[16] = {
    0, 1, MODE_2_TO_5, MODE_2_TO_5, MODE_2_TO_5, MODE_2_TO_5,
    MODE_6_7, MODE_6_7, MODE_8_9, MODE_8_9,
    MODE_A_B_C, MODE_A_B_C, MODE_A_B_C,
    MODE_D_E, MODE_D_E, MODE_F
};

/*
 * Absolute cycle values used while HSCROL is active:
 * [width][mode_type][ml_type][hscroll_index][0=begin, 1=end].
 *
 * HS_ROW takes the hscroll=0 begin CPU value followed by the eight tail CPU
 * values. The begin value advances by one CPU cycle for each hscroll index.
 * Tail values are intentionally explicit because wide rows often should not
 * repay the begin shift from the final CPU slot.
 */
static const int antic_hscroll_cycle_values[5][MAX_INSTR][4][HSCROLL_STEPS][2] = {
    [0] = {
        [MODE_2_TO_5] = {
            [ML_FIRST]      = HS_ROW ( 20, 13, 12, 11, 10, 9, 8, 7, 6 ),
            [ML_NORMAL]     = HS_ROW ( 22, 16, 15, 14, 13, 12, 11, 10, 9 ),
            [ML_LAST]       = HS_ROW ( 22, 16, 15, 14, 13, 12, 11, 10, 9 ),
            [ML_FIRST_LAST] = HS_ROW ( 20, 13, 12, 11, 10, 9, 8, 7, 6 )
        },
        [MODE_6_7] = {
            [ML_FIRST]      = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_NORMAL]     = HS_ROW ( 22, 18, 17, 16, 15, 14, 13, 12, 11 ),
            [ML_LAST]       = HS_ROW ( 22, 18, 17, 16, 15, 14, 13, 12, 11 ),
            [ML_FIRST_LAST] = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 )
        },
        [MODE_8_9] = {
            [ML_FIRST]      = HS_ROW ( 18, 23, 22, 21, 20, 19, 18, 17, 16 ),
            [ML_NORMAL]     = HS_ROW ( 18, 23, 22, 21, 20, 19, 18, 17, 16 ),
            [ML_LAST]       = HS_ROW ( 18, 23, 22, 21, 20, 19, 18, 17, 16 ),
            [ML_FIRST_LAST] = HS_ROW ( 18, 23, 22, 21, 20, 19, 18, 17, 16 )
        },
        [MODE_A_B_C] = {
            [ML_FIRST]      = HS_ROW ( 18, 22, 21, 20, 19, 18, 17, 16, 15 ),
            [ML_NORMAL]     = HS_ROW ( 18, 22, 21, 20, 19, 18, 17, 16, 15 ),
            [ML_LAST]       = HS_ROW ( 18, 22, 21, 20, 19, 18, 17, 16, 15 ),
            [ML_FIRST_LAST] = HS_ROW ( 18, 22, 21, 20, 19, 18, 17, 16, 15 )
        },
        [MODE_D_E] = {
            [ML_FIRST]      = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_NORMAL]     = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_LAST]       = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_FIRST_LAST] = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 )
        },
        [MODE_F] = {
            [ML_FIRST]      = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_NORMAL]     = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_LAST]       = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_FIRST_LAST] = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 )
        }
    },
    [1] = {
        [MODE_2_TO_5] = {
            [ML_FIRST]      = HS_ROW ( 20, 13, 12, 11, 10, 9, 8, 7, 6 ),
            [ML_NORMAL]     = HS_ROW ( 22, 16, 15, 14, 13, 12, 11, 10, 9 ),
            [ML_LAST]       = HS_ROW ( 22, 16, 15, 14, 13, 12, 11, 10, 9 ),
            [ML_FIRST_LAST] = HS_ROW ( 20, 13, 12, 11, 10, 9, 8, 7, 6 )
        },
        [MODE_6_7] = {
            [ML_FIRST]      = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_NORMAL]     = HS_ROW ( 22, 18, 17, 16, 15, 14, 13, 12, 11 ),
            [ML_LAST]       = HS_ROW ( 22, 18, 17, 16, 15, 14, 13, 12, 11 ),
            [ML_FIRST_LAST] = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 )
        },
        [MODE_8_9] = {
            [ML_FIRST]      = HS_ROW ( 18, 23, 22, 21, 20, 19, 18, 17, 16 ),
            [ML_NORMAL]     = HS_ROW ( 18, 23, 22, 21, 20, 19, 18, 17, 16 ),
            [ML_LAST]       = HS_ROW ( 18, 23, 22, 21, 20, 19, 18, 17, 16 ),
            [ML_FIRST_LAST] = HS_ROW ( 18, 23, 22, 21, 20, 19, 18, 17, 16 )
        },
        [MODE_A_B_C] = {
            [ML_FIRST]      = HS_ROW ( 18, 22, 21, 20, 19, 18, 17, 16, 15 ),
            [ML_NORMAL]     = HS_ROW ( 18, 22, 21, 20, 19, 18, 17, 16, 15 ),
            [ML_LAST]       = HS_ROW ( 18, 22, 21, 20, 19, 18, 17, 16, 15 ),
            [ML_FIRST_LAST] = HS_ROW ( 18, 22, 21, 20, 19, 18, 17, 16, 15 )
        },
        [MODE_D_E] = {
            [ML_FIRST]      = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_NORMAL]     = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_LAST]       = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_FIRST_LAST] = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 )
        },
        [MODE_F] = {
            [ML_FIRST]      = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_NORMAL]     = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_LAST]       = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 ),
            [ML_FIRST_LAST] = HS_ROW ( 18, 20, 19, 18, 17, 16, 15, 14, 13 )
        }
    },
    [2] = {
        [MODE_2_TO_5] = {
            [ML_FIRST]      = HS_ROW ( 13, 5, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_NORMAL]     = HS_ROW ( 15, 8, 7, 6, 5, 4, 3, 3, 3 ),
            [ML_LAST]       = HS_ROW ( 15, 8, 7, 6, 5, 4, 3, 3, 3 ),
            [ML_FIRST_LAST] = HS_ROW ( 13, 5, 4, 3, 2, 1, 0, 0, 0 )
        },
        [MODE_6_7] = {
            [ML_FIRST]      = HS_ROW ( 11, 12, 11, 10, 9, 8, 7, 6, 5 ),
            [ML_NORMAL]     = HS_ROW ( 15, 10, 9, 8, 7, 6, 5, 4, 3 ),
            [ML_LAST]       = HS_ROW ( 15, 10, 9, 8, 7, 6, 5, 4, 3 ),
            [ML_FIRST_LAST] = HS_ROW ( 11, 12, 11, 10, 9, 8, 7, 6, 5 )
        },
        [MODE_8_9] = {
            [ML_FIRST]      = HS_ROW ( 11, 15, 14, 13, 12, 11, 10, 9, 8 ),
            [ML_NORMAL]     = HS_ROW ( 11, 15, 14, 13, 12, 11, 10, 9, 8 ),
            [ML_LAST]       = HS_ROW ( 11, 15, 14, 13, 12, 11, 10, 9, 8 ),
            [ML_FIRST_LAST] = HS_ROW ( 11, 15, 14, 13, 12, 11, 10, 9, 8 )
        },
        [MODE_A_B_C] = {
            [ML_FIRST]      = HS_ROW ( 11, 14, 13, 12, 11, 10, 9, 8, 7 ),
            [ML_NORMAL]     = HS_ROW ( 11, 14, 13, 12, 11, 10, 9, 8, 7 ),
            [ML_LAST]       = HS_ROW ( 11, 14, 13, 12, 11, 10, 9, 8, 7 ),
            [ML_FIRST_LAST] = HS_ROW ( 11, 14, 13, 12, 11, 10, 9, 8, 7 )
        },
        [MODE_D_E] = {
            [ML_FIRST]      = HS_ROW ( 11, 12, 11, 10, 9, 8, 7, 6, 5 ),
            [ML_NORMAL]     = HS_ROW ( 11, 12, 11, 10, 9, 8, 7, 6, 5 ),
            [ML_LAST]       = HS_ROW ( 11, 12, 11, 10, 9, 8, 7, 6, 5 ),
            [ML_FIRST_LAST] = HS_ROW ( 11, 12, 11, 10, 9, 8, 7, 6, 5 )
        },
        [MODE_F] = {
            [ML_FIRST]      = HS_ROW ( 11, 12, 11, 10, 9, 8, 7, 6, 5 ),
            [ML_NORMAL]     = HS_ROW ( 11, 12, 11, 10, 9, 8, 7, 6, 5 ),
            [ML_LAST]       = HS_ROW ( 11, 12, 11, 10, 9, 8, 7, 6, 5 ),
            [ML_FIRST_LAST] = HS_ROW ( 11, 12, 11, 10, 9, 8, 7, 6, 5 )
        }
    },
    [3] = {
        [MODE_2_TO_5] = {
            [ML_FIRST]      = HS_ROW ( 5, -2, -2, -2, -2, -2, -2, -2, -2 ),
            [ML_NORMAL]     = HS_ROW ( 7, -1, -1, -1, -1, -1, -1, -1, -1 ),
            [ML_LAST]       = HS_ROW ( 7, -1, -1, -1, -1, -1, -1, -1, -1 ),
            [ML_FIRST_LAST] = HS_ROW ( 5, -2, -2, -2, -2, -2, -2, -2, -2 )
        },
        [MODE_6_7] = {
            [ML_FIRST]      = HS_ROW ( 3, 3, 2, 1, 1, 1, 1, 1, 1 ),
            [ML_NORMAL]     = HS_ROW ( 7, 2, 1, 0, 0, 0, 0, 0, 0 ),
            [ML_LAST]       = HS_ROW ( 7, 2, 1, 0, 0, 0, 0, 0, 0 ),
            [ML_FIRST_LAST] = HS_ROW ( 3, 3, 2, 1, 1, 1, 1, 1, 1 )
        },
        [MODE_8_9] = {
            [ML_FIRST]      = HS_ROW ( 3, 7, 6, 5, 4, 3, 3, 3, 3 ),
            [ML_NORMAL]     = HS_ROW ( 3, 7, 6, 5, 4, 3, 3, 3, 3 ),
            [ML_LAST]       = HS_ROW ( 3, 7, 6, 5, 4, 3, 3, 3, 3 ),
            [ML_FIRST_LAST] = HS_ROW ( 3, 7, 6, 5, 4, 3, 3, 3, 3 )
        },
        [MODE_A_B_C] = {
            [ML_FIRST]      = HS_ROW ( 3, 6, 6, 5, 4, 3, 2, 1, 0 ),
            [ML_NORMAL]     = HS_ROW ( 3, 6, 6, 5, 4, 3, 2, 1, 0 ),
            [ML_LAST]       = HS_ROW ( 3, 6, 6, 5, 4, 3, 2, 1, 6 ),
            [ML_FIRST_LAST] = HS_ROW ( 3, 6, 6, 5, 4, 3, 2, 1, 0 )
        },
        [MODE_D_E] = {
            [ML_FIRST]      = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_NORMAL]     = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_LAST]       = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_FIRST_LAST] = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 )
        },
        [MODE_F] = {
            [ML_FIRST]      = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_NORMAL]     = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_LAST]       = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_FIRST_LAST] = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 )
        }
    },
    [4] = {
        [MODE_2_TO_5] = {
            [ML_FIRST]      = HS_ROW ( 5, -2, -2, -2, -2, -2, -2, -2, -2 ),
            [ML_NORMAL]     = HS_ROW ( 7, -1, -1, -1, -1, -1, -1, -1, -1 ),
            [ML_LAST]       = HS_ROW ( 7, -1, -1, -1, -1, -1, -1, -1, -1 ),
            [ML_FIRST_LAST] = HS_ROW ( 5, -2, -2, -2, -2, -2, -2, -2, -2 )
        },
        [MODE_6_7] = {
            [ML_FIRST]      = HS_ROW ( 3, 3, 2, 1, 1, 1, 1, 1, 1 ),
            [ML_NORMAL]     = HS_ROW ( 7, 2, 1, 0, 0, 0, 0, 0, 0 ),
            [ML_LAST]       = HS_ROW ( 7, 2, 1, 0, 0, 0, 0, 0, 0 ),
            [ML_FIRST_LAST] = HS_ROW ( 3, 3, 2, 1, 1, 1, 1, 1, 1 )
        },
        [MODE_8_9] = {
            [ML_FIRST]      = HS_ROW ( 3, 7, 6, 5, 4, 3, 3, 3, 3 ),
            [ML_NORMAL]     = HS_ROW ( 3, 7, 6, 5, 4, 3, 3, 3, 3 ),
            [ML_LAST]       = HS_ROW ( 3, 7, 6, 5, 4, 3, 3, 3, 3 ),
            [ML_FIRST_LAST] = HS_ROW ( 3, 7, 6, 5, 4, 3, 3, 3, 3 )
        },
        [MODE_A_B_C] = {
            [ML_FIRST]      = HS_ROW ( 3, 6, 6, 5, 4, 3, 2, 1, 0 ),
            [ML_NORMAL]     = HS_ROW ( 3, 6, 6, 5, 4, 3, 2, 1, 0 ),
            [ML_LAST]       = HS_ROW ( 3, 6, 6, 5, 4, 3, 2, 1, 6 ),
            [ML_FIRST_LAST] = HS_ROW ( 3, 6, 6, 5, 4, 3, 2, 1, 0 )
        },
        [MODE_D_E] = {
            [ML_FIRST]      = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_NORMAL]     = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_LAST]       = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_FIRST_LAST] = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 )
        },
        [MODE_F] = {
            [ML_FIRST]      = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_NORMAL]     = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_LAST]       = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 ),
            [ML_FIRST_LAST] = HS_ROW ( 3, 4, 4, 3, 2, 1, 0, 0, 0 )
        }
    }
};

static void antic_init_hscroll_tables ( void );
static void antic_dump_hscroll_cycle_values ( FILE *fp );
static void antic_dump_cycle_maps ( const char *path );

#define ANTIC_ARRAY_COUNT(a) ((int)(sizeof(a) / sizeof((a)[0])))
#define ANTIC_ROW(c, f) { c, f, ANTIC_ARRAY_COUNT(c) }
#define CPU AC_CPU
#define RM AC_RM
#define RP AC_RP
#define DL AC_DL
#define INIT AC_INIT
#define END AC_END
#define CHF AC_CH_FIRST
#define CHD AC_CH_DATA
#define MRD AC_MAP_RD
#define MDR AC_MAP_DRAW
#define DLI AC_DLI
#define BLK AC_BLANK
#define REF AC_REFRESH

static void antic_update_playfield_start ( void ) {

    antic.normal_pixel_start = antic.pixel_start[antic.pl_width];
    antic.hscroll_pixel_start = antic.pixel_start[antic.pl_width+1] +
                                             antic.hscroll_reg_value;
}

static int antic_playfield_start_deadline ( KBYTE width ) {

    switch ( width & PL_WD ) {
        case 1: return 24;
        case 2: return 16;
        case 3: return 8;
        default: return -1;
    }
}

static int antic_dmactl_width_in_time ( KBYTE width ) {

    int deadline;

    width &= PL_WD;

    /*
     * Disabling PF DMA affects display immediately. The more detailed
     * mid-line line-buffer clocking behavior can be handled separately.
     */
    if ( !width )
        return 1;

    deadline = antic_playfield_start_deadline ( width );

    /*
     * With horizontal scrolling, the start deadline is delayed one cycle
     * for each increase by two in HSCROL. hscroll_reg_value is HSCROL*2.
     */
    if ( gtia.pf_x_start_ptr == &antic.hscroll_pixel_start )
        deadline += antic.hscroll_reg_value >> 2;

    return antic.sl_cycle_count <= deadline;
}

void antic_read_or_draw_map ( void ) {

    if ( antic.pl_width )
        antic.antic_map_read_and_draw_ptr ();
    else
        antic.antic_map_draw_ptr ();
}

/******************************************************************************
**  Function   :  antic_reset
**                            
**  Objective  :  This function initializes ANTIC registers
**
**  Parameters :  NONE
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void antic_reset ( void ) {

    int i = 0;

    /*
     * Initialize Registers
     */
    antic.pixel_start[0] = 128;
    antic.pixel_start[1] = 128;
    antic.pixel_start[2] = 96;
    antic.pixel_start[3] = 64;
    antic.pixel_start[4] = 64;
    antic.hscroll_pixel_start = 96;
    antic.normal_pixel_start = 96;
    antic.pl_width = 0;
    antic.next_pl_width = 0;

    antic.dli_count = 6;

    antic.nmi_vbi_en = 0;
    antic.wsync_late = 0;
    antic.wsync_cycle_adjust = 0;

    antic.vscroll_taking_place = 0;
    antic.vblank_sl_time = 114;

    /*
     * Initialize Function Pointers
     */
    antic.run_6502_ptr = antic_run_6502;
    antic.antic_read_char_data_ptr = antic_read_char_data_mode_2;
    antic.antic_read_data_ptr = antic_read_data_mode_2;
    antic.antic_map_read_and_draw_ptr = antic_read_and_draw_mode_8;
    antic.antic_map_draw_ptr = antic_draw_mode_8;
    antic.antic_map_read_or_draw_ptr = antic_read_or_draw_map;
    antic.antic_blank_ptr = antic_send_byte_mode_blank;
    antic.antic_bit1_char_ptr = antic_read_byte_mode_4_bit_1;
    antic.antic_char_pf0_ptr = antic_read_byte_mode_6_pf0;
    antic.antic_char_pf1_ptr = antic_read_byte_mode_6_pf1;
    antic.antic_char_pf2_ptr = antic_read_byte_mode_6_pf2;
    antic.antic_char_pf3_ptr = antic_read_byte_mode_6_pf3;
    antic.antic_set_dli_ptr = antic_do_nothing;
    antic.antic_read_even_missle_ptr = antic_run_6502;
    antic.antic_read_even_player_ptr = antic_run_6502;
    antic.antic_read_missle_ptr = antic.antic_read_even_missle_ptr;
    antic.antic_read_player_ptr = antic.antic_read_even_player_ptr;
    antic.antic_read_odd_missle_ptr = antic_run_6502;
    antic.antic_read_odd_player_ptr = antic_run_6502;
    antic.antic_do_dl_instr_ptr = antic_no_dma;

    antic.pm_counter_ptr = &antic.vcount;

    antic.antic_init_scanline_ptr = gtia_init_scanline;
    antic.antic_end_scanline_ptr = gtia_end_scanline;
    antic.antic_draw_blank_line_ptr = gtia_set_blank_line;

    /*
     * Initialize Variable Pointers
     */
    antic.dl_mode_line_ptr = &antic.dl_mode_line;
    antic.ch_base_ptr = &antic.ch_base_40_mode; 

    /*
     * Initialize OP Code Array
     */

    /* 
     * Blank Line
     */
    for ( i = 0x00; i < 0x100; ++i ) {
        antic.do_instruct[ i & 0xf0 ] = antic_blank_line;
    }

    /* 
     * Jump and JVB
     */
    for ( i = 0x01; i < 0x100; ++i ) {
        if ( (i & 0x0f) == 0x1 ) {
            if ( i & 0x40 )
                antic.do_instruct[ i ] = antic_jvb;
            else
                antic.do_instruct[ i ] = antic_jump;
        }
    }

    /* 
     * Graphics Line
     */
    for ( i = 0x02; i < 0x100; ++i ) {

        if ( (i & 0x0f) == 0x0 )
            continue;
        if ( (i & 0x0f) == 0x1 )
            continue;

        if ( (i & 0x0f) == 0x2 )
            antic.do_instruct[ i ] = antic_graphics_mode_2;
        if ( (i & 0x0f) == 0x3 )
            antic.do_instruct[ i ] = antic_graphics_mode_3;
        if ( (i & 0x0f) == 0x4 )
            antic.do_instruct[ i ] = antic_graphics_mode_4;
        if ( (i & 0x0f) == 0x5 )
            antic.do_instruct[ i ] = antic_graphics_mode_5;
        if ( (i & 0x0f) == 0x6 )
            antic.do_instruct[ i ] = antic_graphics_mode_6;
        if ( (i & 0x0f) == 0x7 )
            antic.do_instruct[ i ] = antic_graphics_mode_7;
        if ( (i & 0x0f) == 0x8 )
            antic.do_instruct[ i ] = antic_graphics_mode_8;
        if ( (i & 0x0f) == 0x9 )
            antic.do_instruct[ i ] = antic_graphics_mode_9;
        if ( (i & 0x0f) == 0xa )
            antic.do_instruct[ i ] = antic_graphics_mode_a;
        if ( (i & 0x0f) == 0xb )
            antic.do_instruct[ i ] = antic_graphics_mode_b;
        if ( (i & 0x0f) == 0xc )
            antic.do_instruct[ i ] = antic_graphics_mode_c;
        if ( (i & 0x0f) == 0xd )
            antic.do_instruct[ i ] = antic_graphics_mode_d;
        if ( (i & 0x0f) == 0xe )
            antic.do_instruct[ i ] = antic_graphics_mode_e;
        if ( (i & 0x0f) == 0xf )
            antic.do_instruct[ i ] = antic_graphics_mode_f;
        if (i & 0x40)
            antic.do_instruct[ i ] = antic_lms;
    }

    /*
     * Create Cycle Maps for each mode
     */
    antic_create_cycle_maps ( );

    /*
     * Assign Read Memory functions for DMA
     *   These can change for bank switched RAM in the XE
     */
    for ( i = 0; i < 0x100; ++i )
        antic.read_mem[i] = cpu6502.read_mem[i];

    return;

} /* end antic_reset */

/******************************************************************************
**  Function   :  antic_read_register
**                            
**  Objective  :  This function reads from the input register
**
**  Parameters :  addr - 6502 memory address of the register
**                                                
**  return     :  value at register
**      
******************************************************************************/ 
KBYTE antic_read_register ( KWORD addr ) {

    switch ( addr & 0x0f ) {
        case VCOUNT:
            if (!(antic.dl_scanline & 1)) {
                int elapsed = antic.sl_cycle_count - (cpu6502.i_cnt + antic.refresh_cycles);
                if (elapsed < 7) {
                    if (antic.dl_scanline == 0) {
                        //if (elapsed == 5)
                        //    return (gtia.pal_or_ntsc==PAL) ? 0x9c : 0x83;
                        //else
                            return (gtia.pal_or_ntsc==PAL) ? 0x9b : 0x82;
                    }
                    return (antic.dl_scanline - 1) >> 1;
                }
                if (antic.dl_scanline == 0 && elapsed == 7)
                    return (gtia.pal_or_ntsc==PAL) ? 0x9c : 0x83;
            }
            return antic.vcount;
            break;

        case PENH: return 0x00; break;
        case PENV: return 0x00; break;
        case NMIST: return antic.nmi_status_reg; break;
    }

    return 0xff;

} /* end antic_read_register */

KBYTE antic_read_register_debug ( KWORD addr ) {

    debug_search_for_breakpoint (BK_MEM, addr );

    return antic_read_register ( addr );
}

/*
 * Compute current_ch_base for 8-row character modes (2, 3, 4, 6).
 * For normal display:   font_row = dl_mode_line
 * For UP_VID (reflect): font_row = dl_mode_line ^ 7
 * Blank/descender decisions must use dl_mode_line (physical row) separately.
 */
static KWORD antic_current_8row_ch_base ( void ) {
    KBYTE row = ( antic.dl_mode_line_ptr == &antic.dl_mode_line_opp )
                ? ((antic.dl_mode_line ^ 7) & 0x7)
                : (antic.dl_mode_line & 0x7);
    return *antic.ch_base_ptr | row;
}

/******************************************************************************
**  Function   :  antic_write_register
**
**  Objective  :  This function performs actions caused by writes to the
**                registers the input register
**
**  Parameters :  addr - 6502 memory address of the register
**                value - value to write to register
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void antic_write_register ( KWORD addr, KBYTE value ) {

    KWORD temp_pm_base_address;

    switch ( addr & 0x0f ) {
        case DMACTL: 

            antic.dmactl_reg = value;

            /*
             * Check Playfield DMA
             */
            if ( value & DL_DMA )
                antic.antic_do_dl_instr_ptr = antic_do_display_list_instruction;
            else
                antic.antic_do_dl_instr_ptr = antic_no_dma;

            /*
             * Check PM DMA
             */
            if ( value & P_DMA ) {
                antic.antic_read_even_missle_ptr = antic_read_missle;
                antic.antic_read_even_player_ptr = antic_read_player;
            }
            else if ( value & M_DMA ) {
                antic.antic_read_even_missle_ptr = antic_read_missle;
                antic.antic_read_even_player_ptr = antic_run_6502;
                /* gtia_write_register ( GRAFP0, 0 ); */
                /* gtia_write_register ( GRAFP1, 0 ); */
                /* gtia_write_register ( GRAFP2, 0 ); */
                /* gtia_write_register ( GRAFP3, 0 ); */
            }
            else {
                antic.antic_read_even_missle_ptr = antic_run_6502;
                antic.antic_read_even_player_ptr = antic_run_6502;
                /* gtia_write_register ( GRAFP0, 0 ); */
                /* gtia_write_register ( GRAFP1, 0 ); */
                /* gtia_write_register ( GRAFP2, 0 ); */
                /* gtia_write_register ( GRAFP3, 0 ); */
                /* gtia_write_register ( GRAFM, 0 ); */
            }

            /*
             * Setup VBLANK time
             */
            if ( value & (DL_DMA | P_DMA | M_DMA) )
                antic.vblank_sl_time = 105;
            else
                antic.vblank_sl_time = 114;

            /*
             * PM DMA occurs on every scanline. The resolution bit only changes
             * which vertical counter is used for the DMA address.
             */
            antic.antic_read_odd_missle_ptr = antic.antic_read_even_missle_ptr;
            antic.antic_read_odd_player_ptr = antic.antic_read_even_player_ptr;

            /*
             * Update player-missle start based on size
             */
            antic.pm_resolution = (value & PM_REZ) >> 4;

            if ( antic.pm_resolution ) {
                antic.pm_counter_ptr = &antic.dl_scanline;
                temp_pm_base_address = antic.pm_base_address & 0xf800;
                antic.m_start = temp_pm_base_address | 0x0300;
                antic.p_0_start = temp_pm_base_address | 0x0400;
                antic.p_1_start = temp_pm_base_address | 0x0500;
                antic.p_2_start = temp_pm_base_address | 0x0600;
                antic.p_3_start = temp_pm_base_address | 0x0700;
            }
            else {
                antic.pm_counter_ptr = &antic.vcount;
                temp_pm_base_address = antic.pm_base_address & 0xfc00;
                antic.m_start = temp_pm_base_address | 0x0180;
                antic.p_0_start = temp_pm_base_address | 0x0200;
                antic.p_1_start = temp_pm_base_address | 0x0280;
                antic.p_2_start = temp_pm_base_address | 0x0300;
                antic.p_3_start = temp_pm_base_address | 0x0380;
            }

            /*
             * Use playfield width to set pointer to correct cycle array
             * FIXME: I am assuming this won't happen in a mode line??  
             */
            antic.next_pl_width = value & PL_WD;
            if ( antic_dmactl_width_in_time ( antic.next_pl_width ) ) {
                antic.pl_width = antic.next_pl_width;
                antic_update_playfield_start ();
            }

            /*
             * Update PM function pointers
             */
            if ( antic.dl_scanline & 0x1 ) {
                antic.antic_read_missle_ptr = antic.antic_read_odd_missle_ptr;
                antic.antic_read_player_ptr = antic.antic_read_odd_player_ptr;
            }
            else {
                antic.antic_read_missle_ptr = antic.antic_read_even_missle_ptr;
                antic.antic_read_player_ptr = antic.antic_read_even_player_ptr;
            }

            break;

        case CHACTL: 

            antic.chactl_reg = value;

            /*
             * This affects character with bit 7 set in modes 2 and 3
             * FIXME: I assume this won't happen in a mode line?
             */
            if ( (value & (OPAQUE | INV_VID)) == (OPAQUE | INV_VID) )
                antic.antic_charctl_ptr = &antic.antic_inv_blank_ptr;
            else if ( value & OPAQUE )
                antic.antic_charctl_ptr = &antic.antic_blank_char_ptr;
            else if ( value & INV_VID )
                antic.antic_charctl_ptr = &antic.antic_inv_video_ptr;
            else
                antic.antic_charctl_ptr = &antic.antic_normal_char_ptr;

            /*
             * Setup for up side down characters
             */
            if ( value & UP_VID )
                antic.dl_mode_line_ptr = &antic.dl_mode_line_opp;
            else
                antic.dl_mode_line_ptr = &antic.dl_mode_line;

            break;
        case DLISTL: 
            antic.dlistl_reg = value;
            antic.pc = (antic.pc & 0xff00) | value;
            break;
        case DLISTH: 
            antic.dlisth_reg = value;
            antic.pc = (antic.pc & 0x00ff) | (value << 8);
            antic.pc_fixed = antic.pc & 0xfc00;
            break;
        case HSCROL: 
            /*
             * Shift by one for pixels    
             * Subtract from 32 for actual horizontal start 
             * FIXME:  Test for vblank so we know to change PM transfer start 
             */
            antic.hscroll_reg_value = (value & 0xf) << 1;
            antic_update_playfield_start ();
            break;
        case VSCROL: 
            antic.vscroll_reg_value = value;
            break;
        case PMBASE: 
            antic.pm_base_address = value << 8;

            /*
             * Update Player-Missle start based on size
             */
            if ( antic.pm_resolution ) {
                temp_pm_base_address = antic.pm_base_address & 0xf800;
                antic.m_start = temp_pm_base_address | 0x0300;
                antic.p_0_start = temp_pm_base_address | 0x0400;
                antic.p_1_start = temp_pm_base_address | 0x0500;
                antic.p_2_start = temp_pm_base_address | 0x0600;
                antic.p_3_start = temp_pm_base_address | 0x0700;
            }
            else {
                temp_pm_base_address = antic.pm_base_address & 0xfc00;
                antic.m_start = temp_pm_base_address | 0x0180;
                antic.p_0_start = temp_pm_base_address | 0x0200;
                antic.p_1_start = temp_pm_base_address | 0x0280;
                antic.p_2_start = temp_pm_base_address | 0x0300;
                antic.p_3_start = temp_pm_base_address | 0x0380;
            }

            break;
        case CHBASE:
            antic.ch_base_address = value << 8;
            antic.ch_base_20_mode = antic.ch_base_address & 0xfe00;
            antic.ch_base_40_mode = antic.ch_base_address & 0xfc00;
            antic.current_ch_base = antic_current_8row_ch_base ();
            antic.current_ch_base_16_line = *antic.ch_base_ptr |
                                                 ((*antic.dl_mode_line_ptr>>1) & 0x7);
            break;
        case WSYNC:

            /*
             * Check for too-late write before modifying i_cnt.
             */
            antic.wsync_cycle_adjust = 0;

            int elapsed = antic.sl_cycle_count - (cpu6502.i_cnt + antic.refresh_cycles);
            if (antic.refresh_cycles && elapsed >= 66)
                elapsed +=9;

            if ( elapsed >= 114 ) {
                antic.wsync_late = 1;
                antic.wsync_cycle_adjust = 1;
            }

            /*
             * Make sure we actually have enough cycles to finish this or we are late
             */
            else if (cpu6502.i_cnt < 0) {
                int cpu_cycles = cpu6502.i_cnt;
                //int display_slot_context =
                //    antic.dl_scanline > 7 &&
                //    antic.dl_scanline < 248 &&
                //    antic.sl_map &&
                //    antic.ml_cycles[antic.mode_line];

                // Normalize elapsed back to slot
                elapsed += cpu6502.i_cnt;

                for (int slot = antic.scan_change+1; (!antic.refresh_cycles) && antic.sl_map[slot]; ++slot) {
                    elapsed += antic.ml_cycles[antic.mode_line][slot];

                    if (antic.sl_map[slot][0] == antic_run_6502) {
                        cpu_cycles += antic.ml_cycles[antic.mode_line][slot];
                        if (cpu_cycles >= 0)
                            break;
                    }
                }
                if (cpu_cycles < 0 || (elapsed - cpu_cycles) >= 114) {
                //if (cpu_cycles < 0) {
                    antic.wsync_late = 1;
                    antic.wsync_cycle_adjust = 1;
                }
            }

            if ( !antic.wsync_late ) {
                if ( antic.dmactl_reg & (DL_DMA | P_DMA | M_DMA) ) {
                    int drawing = !antic.refresh_cycles;
                    KBYTE mode = antic.dl_current_byte & 0x0f;
                    if (drawing && (mode >= 0x02 && mode <= 0x05) && antic.width_array >= 3) {
                        if (antic.mode_line == 0)
                            antic.wsync_cycle_adjust = -1;
                        else
                            antic.wsync_cycle_adjust = 0;
                    }
                    else if (drawing &&(mode >= 0x06 && mode <= 0x07) && antic.width_array >= 3) {
                        if (antic.mode_line == 0)
                            antic.wsync_cycle_adjust = 0;
                        else
                            antic.wsync_cycle_adjust = 1;
                    }
                    else {
                        antic.wsync_cycle_adjust = 1;
                        switch(elapsed) { // check for normal memory refresh
                            case 34:
                            case 38:
                            case 42:
                            case 46:
                            case 50:
                            case 54:
                            case 58:
                            case 62:
                            case 66:
                                antic.wsync_cycle_adjust = 0;
                                break;
                        }
                    }
                }
                else {
                    antic.wsync_cycle_adjust = 1;
                }
            }
            /* Check for RMW instruction using next cycle for 2nd write */
            if (!antic.wsync_late && antic.wsync_cycle_adjust == 1) {
                if (cpu_op_is_rmw_wsync_opcode(cpu6502.opcode))
                    antic.wsync_cycle_adjust = 0;
            }

            /*
             * Replace any 6502 function with do nothing
             */
            antic.run_6502_ptr = antic_do_nothing;

            /*
             * Make sure no more ops are done
             */
            cpu6502.i_cnt = 0;

            if (antic.antic_read_missle_ptr == antic_run_6502 )
                antic.antic_read_missle_ptr = antic_do_nothing;
            if (antic.antic_read_player_ptr == antic_run_6502 )
                antic.antic_read_player_ptr = antic_do_nothing;

            if (cpu6502.nmi_pending) {
                cpu6502.nmi_countdown = antic.wsync_cycle_adjust;
            }
            break;
        case NMIEN:

            antic.nmi_dli_en = value & 0x80;
            if ( antic.nmi_dli_en )
                antic.antic_set_dli_ptr = antic_set_dli;
            else
                antic.antic_set_dli_ptr = antic_set_dli_status;

            // DLI delayed by 1 on this exact cycle
            if ((antic.sl_cycle_count-cpu6502.i_cnt) == 17)
                antic.dli_count = 7;
            else
                antic.dli_count = 6;
            antic.nmi_vbi_en = value & 0x40;
            antic.nmi_reset_en = value & 0x20;
            break;
        case NMIRES:
            antic.nmi_status_reg = 0x1f;
            break;
    }

} /* end antic_write_register */

void antic_write_register_debug ( KWORD addr, KBYTE value ) {

    debug_search_for_breakpoint (BK_MEM, addr );

    antic_write_register ( addr, value );
}

/******************************************************************************
**  Function   :  antic_do_display_list_instruction
**                            
**  Objective  :  This function runs the next instructions in the antic 
**                display list.  It controls the cycle map used in main. 
**
**  Parameters :  NONE
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void antic_do_display_list_instruction ( void ) {

    int lines_for_mode;
    KBYTE vscroll_mask;
    KBYTE vscroll_row;

    /*
     * Read the instruction
     */
    antic.dl_current_byte = rd_antic(antic.pc);

    /*
     * Figure out mode lines for this mode
     */
    switch ( antic.dl_current_byte & 0xf ) {
        case 0: 
            lines_for_mode = (antic.dl_current_byte >> 4) & 0x7;
            vscroll_mask = 0x7;
            break;
        case 1: lines_for_mode = 1; vscroll_mask = 0x7; break;
        case 2: lines_for_mode = 8; vscroll_mask = 0x7; break;
        case 3: lines_for_mode = 10; vscroll_mask = 0x7; break;
        case 4: lines_for_mode = 8; vscroll_mask = 0x7; break;
        case 5: lines_for_mode = 16; vscroll_mask = 0xf; break;
        case 6: lines_for_mode = 8; vscroll_mask = 0x7; break;
        case 7: lines_for_mode = 16; vscroll_mask = 0xf; break;
        case 8: lines_for_mode = 8; vscroll_mask = 0x7; break;
        case 9: lines_for_mode = 4; vscroll_mask = 0x7; break;
        case 0xa: lines_for_mode = 4; vscroll_mask = 0x7; break;
        case 0xb: lines_for_mode = 2; vscroll_mask = 0x7; break;
        case 0xc: lines_for_mode = 1; vscroll_mask = 0x7; break;
        case 0xd: lines_for_mode = 2; vscroll_mask = 0x7; break;
        case 0xe: lines_for_mode = 1; vscroll_mask = 0x7; break;
        case 0xf: lines_for_mode = 1; vscroll_mask = 0x7; break;
        default: lines_for_mode = 1; vscroll_mask = 0x7; break;
    }

    /*
     * If this is a regular graphics mode
     */
    if ( (antic.dl_current_byte & 0xf) > 1 ) {

        /*
         * Check for HSRCOLL - GTIA will handle this
         */
        if ( (antic.dl_current_byte & 0x10) && antic.pl_width ) {
            gtia.pf_x_start_ptr = &antic.hscroll_pixel_start;
            antic.width_array = antic.pl_width + 1;
        }
        else {
            gtia.pf_x_start_ptr = &antic.normal_pixel_start;
            antic.width_array = antic.pl_width;
        }
    
        /*
         * Check for VSCROLL and whether or not to skip mode line 
         */
        if ( antic.dl_current_byte & 0x20 ) {
            /* VSCROL uses a 4-bit row counter for region timing in all modes. */
            vscroll_row = antic.vscroll_reg_value & 0x0f;
            if ( antic.vscroll_taking_place ) {
                antic.dl_mode_line = 0;
                antic.dl_mode_line_opp = lines_for_mode-1;
                antic.num_lines = lines_for_mode;
            }
            else {
                antic.num_lines = ((lines_for_mode - 1 - vscroll_row) & 0x0f) + 1;
                if ( antic.dl_scanline > 7 && antic.dl_scanline < 247 ) {
                    int visible_lines_remaining = 248 - antic.dl_scanline;
                    if ( antic.num_lines > visible_lines_remaining )
                        antic.num_lines = visible_lines_remaining;
                }
                antic.dl_mode_line = vscroll_row;
                antic.dl_mode_line_opp = lines_for_mode - (vscroll_row & vscroll_mask) - 1;
                antic.vscroll_taking_place = 1;
            }
        }

        else {
            if ( antic.vscroll_taking_place ) {
                antic.num_lines = (antic.vscroll_reg_value & 0x0f) + 1;
                antic.vscroll_taking_place = 0;
            }
            else {
                antic.num_lines = lines_for_mode;
            }
            antic.dl_mode_line = 0;
            antic.dl_mode_line_opp = lines_for_mode-1;
        }

    } /* end if this is a regular mode */

    else {
        if ( antic.vscroll_taking_place ) {
            antic.num_lines = antic.vscroll_reg_value & 0x0f;
            antic.vscroll_taking_place = 0;
        }
        else {
            antic.num_lines = lines_for_mode;
        }
    }

    /*
     * Used for debug information
     */
    antic.dl_pc[antic.dl_byte_number] = antic.pc;
    antic.dl[antic.dl_byte_number++] = antic.dl_current_byte;

    /*
     * Do the instruction
     */
    antic.do_instruct [ antic.dl_current_byte ] ();
    if ( antic.mode_line == 0 )
        antic_apply_hscroll ();

} /* end antic_do_display_list_instruction */

/******************************************************************************
**  Function   :  antic_do_nothing
**                            
**  Objective  :  This function is a placeholder for the cycle map
**
**  Parameters :  NONE
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void antic_do_nothing ( void ) {

} /* end antic_do_nothing */

/******************************************************************************
**  Function   :  antic_set_dli_status
**
**  Objective  :  Sets the DLI status bit in NMIST without firing the NMI.
**                Used when DLIs are disabled in NMIEN — hardware still sets
**                the status bit even when the interrupt is suppressed.
**
**  Parameters :  NONE
**
**  return     :  NONE
******************************************************************************/
void antic_set_dli_status ( void ) {

    /* DLI sets bit 7 and clears bit 6 (VBI) — they are mutually exclusive */
    antic.nmi_status_reg = (antic.nmi_status_reg | 0x80) & ~0x40;

} /* end antic_set_dli_status */

/******************************************************************************
**  Function   :  antic_set_dli
**
**  Objective  :  This function sets up a display list interupt
**
**  Parameters :  NONE
**
**  return     :  NONE
**
******************************************************************************/
void antic_set_dli ( void ) {

    /*
     * Interupt 6502 after DLI cycles
     * DLI sets bit 7 and clears bit 6 (VBI) — they are mutually exclusive
     */
    //antic.nmi_status_reg = (antic.nmi_status_reg | 0x80) & ~0x40;
    //antic.nmi_status_reg = (antic.nmi_status_reg & ~0x40) | 0x80;
    antic.dli_count = antic.dli_count - ((antic.sl_cycle_count-cpu6502.i_cnt) - 13);
    cpu_nmi_edge ( antic.dl_scanline, antic.sl_cycle_count, NMI_REQUEST_DLI, (antic.nmi_status_reg & ~0x40) | 0x80, antic.dli_count );
    antic.dli_count = 6;

    /*
     * Make sure i count is 0 if cpu not running
     */
    if ( antic.run_6502_ptr == antic_do_nothing ) {
        cpu6502.i_cnt = 0;
        cpu6502.nmi_countdown = antic.wsync_cycle_adjust;
    }

} /* end antic_set_dli */

/******************************************************************************
**  Function   :  antic_set_reset 
**                            
**  Objective  :  This function sets up a reset interupt   
**
**  Parameters :  NONE
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void antic_set_reset ( void ) {

    /*
     * Interupt 6502 after DLI cycles
     */
    antic.nmi_status_reg = 0x3f;
    set_int_6502 ( INT_NMI );
    int_6502 ();

    /*
     * Make sure i count is 0 if cpu not running
     */
    if ( antic.run_6502_ptr == antic_do_nothing )
        cpu6502.i_cnt = 0;

} /* end antic_set_reset */

/******************************************************************************
**  Function   :  antic_run_6502  
**                            
**  Objective  :  This function sets cycle count and runs 6502   
**
**  Parameters :  NONE
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void antic_run_6502 ( void ) {

    cpu6502.i_cnt += antic.ml_cycles[antic.mode_line][antic.scan_change];

    run_6502 ();

} /* end antic_run_6502 */

/******************************************************************************
**  Function   :  antic_set_vbi   
**                            
**  Objective  :  This function sets up a vertical blank interupt 
**
**  Parameters :  NONE
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void antic_set_vbi ( void ) {

    //antic.nmi_status_reg = 0x5f;
    /*antic.nmi_status_reg |= 0x40;*/

    antic.dli_count = antic.dli_count - ((antic.sl_cycle_count-cpu6502.i_cnt) - 13);
    cpu_nmi_edge ( antic.dl_scanline, antic.sl_cycle_count, NMI_REQUEST_VBI, 0x5f, 5 );
    antic.dli_count = 5;

    if ( antic.run_6502_ptr == antic_do_nothing ) {
        cpu6502.i_cnt = 0;
        cpu6502.nmi_countdown = antic.wsync_cycle_adjust;
    }

} /* end antic_set_vbi */

void antic_set_vbi_status ( void ) {

    /* VBI sets bit 6 and clears bit 7 (DLI) — they are mutually exclusive */
    antic.nmi_status_reg = (antic.nmi_status_reg | 0x40) & ~0x80;

} /* end antic_set_vbi_status */

int antic_wsync_cycle_adjust ( void ) {

    int adjust = antic.wsync_cycle_adjust;

    antic.wsync_cycle_adjust = 0;
    return adjust;

} /* end antic_take_wsync_cycle_adjust */

int antic_scanline_wsync_state ( int assign_pm_slots ) {

    int wsync_hold = antic.wsync_late;

    antic.wsync_late = 0;
    if ( wsync_hold ) {
        antic.run_6502_ptr = antic_do_nothing;
        if ( assign_pm_slots ) {
            antic.antic_read_missle_ptr = antic_do_nothing;
            antic.antic_read_player_ptr = antic_do_nothing;
        }
        //antic.wsync_cycle_adjust = 0;
        return 1;
    }

    antic.run_6502_ptr = antic_run_6502;
    if ( assign_pm_slots ) {
        if ( antic.dl_scanline & 0x1 ) {
            antic.antic_read_missle_ptr = antic.antic_read_odd_missle_ptr;
            antic.antic_read_player_ptr = antic.antic_read_odd_player_ptr;
        }
        else {
            antic.antic_read_missle_ptr = antic.antic_read_even_missle_ptr;
            antic.antic_read_player_ptr = antic.antic_read_even_player_ptr;
        }
    }

    return 0;

} /* end antic_scanline_wsync_state */

/**********************************
 * ANITC graphics mode functions  *
 **********************************/
void antic_read_player ( void ) {

    /*
     * Read pm bytes into gtia grafp registers
     */
    if ( gtia.player_dma ) {
        gtia.graph_p0_reg = rd_antic (antic.p_0_start | *antic.pm_counter_ptr);
        gtia.graph_p1_reg = rd_antic (antic.p_1_start | *antic.pm_counter_ptr);
        gtia.graph_p2_reg = rd_antic (antic.p_2_start | *antic.pm_counter_ptr);
        gtia.graph_p3_reg = rd_antic (antic.p_3_start | *antic.pm_counter_ptr);
    }

} /* antic_read_player */

/*
 * If missle DMA set but not player read only missle 
 * If player DMA is set both are read 
 */

void antic_read_missle ( void ) {

    /*
     * Read pm bytes into gtia grafp registers 
     */
    if ( gtia.missle_dma ) {
        gtia.graph_m_reg = rd_antic( antic.m_start | *antic.pm_counter_ptr);
    }

} /* antic_read_missle */

void antic_read_char_data_mode_2 ( void ) {

        int i;
        KWORD address;

        /*
         *  40 character mode is special read all on line 1
         */
        for ( i = 0; i < (antic.ml_cycles[antic.mode_line][antic.scan_change]>>3); ++i ) {

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read number of bytes from RAM and store in cache
         *  Also, go ahead and figure out addresses 
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            address = (antic.msc++ & 0x0fff) | antic.msc_fixed;
            antic.screen_cache[++antic.byte_count] = rd_antic ( address );

            /*
             * Setup for bit 7 set
             * FIXME:  Make char_ptr and address in case charctl changes 
             */
            if ( (antic.screen_cache[antic.byte_count] & 0x80) )
                antic.antic_char_ptr[antic.byte_count] = antic.antic_charctl_ptr[0];
            else
                antic.antic_char_ptr[antic.byte_count] = antic.antic_normal_char_ptr;

            antic.screen_offset[antic.byte_count] = 
                (antic.screen_cache[antic.byte_count] & 0x7f) << 3;

            /*
             * Read the data
             */
            antic.antic_char_ptr[antic.byte_count] ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia.gtia_set_byte_mode_2_ptr ( );

        }

} /* antic_read_char_data_mode_2 */

void antic_read_char_data_mode_3 ( void ) {

        int i;
        KWORD address;

        /*
         *  40 character mode is special read all on line 1
         */
        for ( i = 0; i < (antic.ml_cycles[antic.mode_line][antic.scan_change]>>3); ++i ) {

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read number of bytes from RAM and store in cache
         *  Also, go ahead and figure out addresses 
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            address = (antic.msc++ & 0x0fff) | antic.msc_fixed;
            antic.screen_cache[++antic.byte_count] = rd_antic ( address );

            /*
             * Setup for bit 7 set
             * FIXME:  Make char_ptr and address in case charctl changes 
             */
            if ( (antic.screen_cache[antic.byte_count] & 0x80) )
                antic.antic_char_ptr[antic.byte_count] = antic.antic_charctl_ptr[0];
            else
                antic.antic_char_ptr[antic.byte_count] = antic.antic_normal_char_ptr;

            antic.screen_offset[antic.byte_count] = 
                (antic.screen_cache[antic.byte_count] & 0x7f) << 3;

            /*
             * Check for lower case on first two lines, upper on last two 
             * Don't worry about last two lines for lower 
             * ch_base is set by dl_mode_line & 0x7 so last 2 are first 2
             */
            if ( (antic.screen_cache[antic.byte_count] & 0x60) == 0x60 ) {
                if ( antic.dl_mode_line < 2 ) {
                    if ( antic.antic_char_ptr[antic.byte_count] == antic.antic_inv_video_ptr ||
                         antic.antic_char_ptr[antic.byte_count] == antic.antic_inv_blank_ptr )
                        antic.antic_inv_blank_ptr ();
                    else
                        antic.antic_blank_char_ptr ();
                }
                else
                    antic.antic_char_ptr[antic.byte_count] ();
            }
            else {
                if ( antic.dl_mode_line & 0x08 ) {
                    if ( antic.antic_char_ptr[antic.byte_count] == antic.antic_inv_video_ptr ||
                         antic.antic_char_ptr[antic.byte_count] == antic.antic_inv_blank_ptr )
                        antic.antic_inv_blank_ptr ();
                    else
                        antic.antic_blank_char_ptr ();
                }
                else
                    antic.antic_char_ptr[antic.byte_count] ();
            }
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia.gtia_set_byte_mode_2_ptr ( );

    }

} /* antic_read_char_data_mode_3 */

void antic_read_char_data_mode_4 ( void ) {

        int i;
        KWORD address;

        /*
         *  40 character mode is special read all on line 1
         */
        for ( i = 0; i < (antic.ml_cycles[antic.mode_line][antic.scan_change]>>3); ++i ) {

        /*
         * Reset gtia bytes  
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read number of bytes from RAM and store in cache
         *  Also, go ahead and figure out addresses
         */ 
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            address = (antic.msc++ & 0x0fff) | antic.msc_fixed;
            antic.screen_cache[++antic.byte_count] = rd_antic ( address );

            /*
             * Setup for bit 7 set
             */
            if ( (antic.screen_cache[antic.byte_count] & 0x80) )
                antic.antic_char_ptr[antic.byte_count] = antic.antic_bit1_char_ptr;
            else
                antic.antic_char_ptr[antic.byte_count] = antic.antic_normal_char_ptr;

            antic.screen_offset[antic.byte_count] = 
                (antic.screen_cache[antic.byte_count] & 0x7f) << 3;

            /*
             * Read the data
             */
            antic.antic_char_ptr[antic.byte_count] ();
        }

        /*
         * Now write 32 bits to gtia 
         */
        gtia_set_byte_mode_4 ( );

    }

} /* antic_read_char_data_mode_4 */

void antic_read_char_data_mode_6 ( void ) {

        KWORD address;

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read number of bytes from RAM and store in cache
         *  Also, go ahead and figure out addresses 
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            address = (antic.msc++ & 0x0fff) | antic.msc_fixed;
            antic.screen_cache[++antic.byte_count] = rd_antic ( address );

            /*
             * Setup for bits 6 and 7
             */
            switch ( antic.screen_cache[antic.byte_count] & 0xc0 ) {
                case 0x00:
                    antic.antic_char_ptr[antic.byte_count] = antic.antic_char_pf0_ptr;
                    break;
                case 0x40:
                    antic.antic_char_ptr[antic.byte_count] = antic.antic_char_pf1_ptr;
                    break;
                case 0x80:
                    antic.antic_char_ptr[antic.byte_count] = antic.antic_char_pf2_ptr;
                    break;
                case 0xc0:
                    antic.antic_char_ptr[antic.byte_count] = antic.antic_char_pf3_ptr;
                    break;
            }

            antic.screen_offset[antic.byte_count] = 
                (antic.screen_cache[antic.byte_count] & 0x3f) << 3;

            /*
             * Read the data 
             */
            antic.antic_char_ptr[antic.byte_count] ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia_set_byte_mode_4 ( );

} /* antic_read_char_data_mode_6 */

void antic_read_data_mode_2 ( void ) {

        /*
         * Reset gtia bytes 
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read from cache
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {
            antic.antic_char_ptr[++antic.byte_count] ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia.gtia_set_byte_mode_2_ptr ( );

} /* antic_read_data_mode_2 */

void antic_read_data_mode_4 ( void ) {

        /*
         * Reset gtia bytes 
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read from cache
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {
            antic.antic_char_ptr[++antic.byte_count] ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia_set_byte_mode_4 ( );

} /* antic_read_data_mode_4 */

void antic_read_data_mode_3 ( void ) {

        /*
         * Reset gtia bytes 
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read from cache
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            /*
             * Check for lower case on first two lines, upper on last two
             * Don't worry about last two lines for lower 
             * ch_base is set by dl_mode_line & 0x7 so last 2 are first 2
             */
            if ( (antic.screen_cache[++antic.byte_count] & 0x60) == 0x60 ) {
                if ( antic.dl_mode_line < 2 ) {
                    if ( antic.antic_char_ptr[antic.byte_count] == antic.antic_inv_video_ptr ||
                         antic.antic_char_ptr[antic.byte_count] == antic.antic_inv_blank_ptr )
                        antic.antic_inv_blank_ptr ();
                    else
                        antic.antic_blank_char_ptr ();
                }
                else
                    antic.antic_char_ptr[antic.byte_count] ();
            }
            else {
                if ( antic.dl_mode_line & 0x08 ) {
                    if ( antic.antic_char_ptr[antic.byte_count] == antic.antic_inv_video_ptr ||
                         antic.antic_char_ptr[antic.byte_count] == antic.antic_inv_blank_ptr )
                        antic.antic_inv_blank_ptr ();
                    else
                        antic.antic_blank_char_ptr ();
                }
                else
                    antic.antic_char_ptr[antic.byte_count] ();
            }
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia.gtia_set_byte_mode_2_ptr ( );

} /* antic_read_data_mode_3 */

void antic_read_byte_mode_2 ( void ) {

        /*
         * Read current screen byte , 8 pixels
         */
        gtia.pf_byte[PF2_BYTE] |= (rd_antic ( antic.current_ch_base | 
                              antic.screen_offset[antic.byte_count] )) << m_shift;
            
} /* antic_read_byte_mode_2 */

void antic_read_byte_inv_mode_2 ( void ) {

        /*
         * Read current screen byte , then invert
         */
        gtia.pf_byte[PF2_BYTE] |= (~(rd_antic ( antic.current_ch_base | 
                              antic.screen_offset[antic.byte_count] )) & 0xffu) << m_shift;
            
} /* antic_read_byte_inv_mode_2 */

void antic_read_byte_blank_mode_2 ( void ) {

} /* antic_read_byte_blank_mode_2 */

void antic_read_byte_inv_blank_mode_2 ( void ) {

        /*
         * Gtia byte = ff for inverse blank 
         */
        gtia.pf_byte[PF2_BYTE] |= (0xffu) << m_shift;
            
} /* antic_read_byte_blank_mode_2 */

void antic_read_byte_mode_4_bit_0 ( void ) {

        KBYTE temp_byte;

        /*
         * Read current screen byte , 8 pixels
         */
        temp_byte = rd_antic ( antic.current_ch_base | 
                              antic.screen_offset[antic.byte_count] );

        /*
         * Assign GTIA colors 
         */
        gtia.pf_byte[temp_byte & 0x03] |= 0x03u << m_shift;
        gtia.pf_byte[(temp_byte & 0x0c) >> 2] |= 0x0cu << m_shift;
        gtia.pf_byte[(temp_byte & 0x30) >> 4] |= 0x30u << m_shift;
        gtia.pf_byte[(temp_byte & 0xc0) >> 6] |= 0xc0u << m_shift;

} /* antic_read_byte_mode_4_bit_0 */

void antic_read_byte_mode_4_bit_1 ( void ) {

        KBYTE temp_byte;
        KBYTE pixel_0,pixel_1,pixel_2,pixel_3;

        /*
         * Read current screen byte , 8 pixels 
         */
        temp_byte = rd_antic ( antic.current_ch_base | 
                              antic.screen_offset[antic.byte_count] );

        /*
         * Assign pixels and test for 0x3
         */
        pixel_0 = temp_byte & 0x03;
        pixel_1 = temp_byte & 0x0c;
        pixel_2 = temp_byte & 0x30;
        pixel_3 = temp_byte & 0xc0;

        /*
         * Assign GTIA colors
         */
        gtia.pf_byte[pixel_0 + (pixel_0 == 0x03 ? 1:0)] |= 0x03u << m_shift;
        gtia.pf_byte[(pixel_1 >> 2) + (pixel_1 == 0x0c ? 1:0)] |= 0x0cu << m_shift;
        gtia.pf_byte[(pixel_2 >> 4) + (pixel_2 == 0x30 ? 1:0)] |= 0x30u << m_shift;
        gtia.pf_byte[(pixel_3 >> 6) + (pixel_3 == 0xc0 ? 1:0)] |= 0xc0u << m_shift;

} /* antic_read_byte_mode_4_bit_1 */

void antic_read_byte_mode_5_bit_0 ( void ) {

        KBYTE temp_byte;

        /*
         * Read current screen byte , 8 pixels
         */
        temp_byte = rd_antic ( antic.current_ch_base_16_line | 
                              antic.screen_offset[antic.byte_count] );

        /*
         * Assign GTIA colors 
         */
        gtia.pf_byte[temp_byte & 0x03] |= 0x03u << m_shift;
        gtia.pf_byte[(temp_byte & 0x0c) >> 2] |= 0x0cu << m_shift;
        gtia.pf_byte[(temp_byte & 0x30) >> 4] |= 0x30u << m_shift;
        gtia.pf_byte[(temp_byte & 0xc0) >> 6] |= 0xc0u << m_shift;

} /* antic_read_byte_mode_5_bit_0 */

void antic_read_byte_mode_5_bit_1 ( void ) {

        KBYTE temp_byte;
        KBYTE pixel_0,pixel_1,pixel_2,pixel_3;

        /*
         * Read current screen byte , 8 pixels
         */
        temp_byte = rd_antic ( antic.current_ch_base_16_line | 
                              antic.screen_offset[antic.byte_count] );

        /*
         * Assign pixels and test for 0x3
         */
        pixel_0 = temp_byte & 0x03;
        pixel_1 = temp_byte & 0x0c;
        pixel_2 = temp_byte & 0x30;
        pixel_3 = temp_byte & 0xc0;

        /*
         * Assign GTIA colors
         */
        gtia.pf_byte[pixel_0 + (pixel_0 == 0x03 ? 1:0)] |= 0x03u << m_shift;
        gtia.pf_byte[(pixel_1 >> 2) + (pixel_1 == 0x0c ? 1:0)] |= 0x0cu << m_shift;
        gtia.pf_byte[(pixel_2 >> 4) + (pixel_2 == 0x30 ? 1:0)] |= 0x30u << m_shift;
        gtia.pf_byte[(pixel_3 >> 6) + (pixel_3 == 0xc0 ? 1:0)] |= 0xc0u << m_shift;

} /* antic_read_byte_mode_5_bit_1 */

void antic_read_byte_mode_6_pf0 ( void ) {

        KBYTE temp_byte;

        /*
         * Read current screen byte , 8 pixels
         */
        temp_byte = rd_antic ( antic.current_ch_base | 
                              antic.screen_offset[antic.byte_count] );

        /*
         * Go through first 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x80) ? PF0_BYTE : BAK_BYTE)] |= 0xc0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x40) ? PF0_BYTE : BAK_BYTE)] |= 0x30u << m_shift;
        gtia.pf_byte[((temp_byte & 0x20) ? PF0_BYTE : BAK_BYTE)] |= 0x0cu << m_shift;
        gtia.pf_byte[((temp_byte & 0x10) ? PF0_BYTE : BAK_BYTE)] |= 0x03u << m_shift;

        m_shift -=8;

        /*
         * Go through last 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x08) ? PF0_BYTE : BAK_BYTE)] |= 0xc0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x04) ? PF0_BYTE : BAK_BYTE)] |= 0x30u << m_shift;
        gtia.pf_byte[((temp_byte & 0x02) ? PF0_BYTE : BAK_BYTE)] |= 0x0cu << m_shift;
        gtia.pf_byte[((temp_byte & 0x01) ? PF0_BYTE : BAK_BYTE)] |= 0x03u << m_shift;

} /* antic_read_byte_mode_6_pf0 */

void antic_read_byte_mode_6_pf1 ( void ) {

        KBYTE temp_byte;

        /*
         * Read current screen byte , 8 pixels
         */
        temp_byte = rd_antic ( antic.current_ch_base | 
                              antic.screen_offset[antic.byte_count] );

        /*
         * Go through first 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x80) ? PF1_BYTE : BAK_BYTE)] |= 0xc0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x40) ? PF1_BYTE : BAK_BYTE)] |= 0x30u << m_shift;
        gtia.pf_byte[((temp_byte & 0x20) ? PF1_BYTE : BAK_BYTE)] |= 0x0cu << m_shift;
        gtia.pf_byte[((temp_byte & 0x10) ? PF1_BYTE : BAK_BYTE)] |= 0x03u << m_shift;

        m_shift -= 8;

        /*
         * Go through last 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x08) ? PF1_BYTE : BAK_BYTE)] |= 0xc0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x04) ? PF1_BYTE : BAK_BYTE)] |= 0x30u << m_shift;
        gtia.pf_byte[((temp_byte & 0x02) ? PF1_BYTE : BAK_BYTE)] |= 0x0cu << m_shift;
        gtia.pf_byte[((temp_byte & 0x01) ? PF1_BYTE : BAK_BYTE)] |= 0x03u << m_shift;

} /* antic_read_byte_mode_6_pf1 */

void antic_read_byte_mode_6_pf2 ( void ) {

        KBYTE temp_byte;

        /*
         * Read current screen byte , 8 pixels
         */
        temp_byte = rd_antic ( antic.current_ch_base | 
                              antic.screen_offset[antic.byte_count] );

        /*
         * Go through first 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x80) ? PF2_BYTE : BAK_BYTE)] |= 0xc0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x40) ? PF2_BYTE : BAK_BYTE)] |= 0x30u << m_shift;
        gtia.pf_byte[((temp_byte & 0x20) ? PF2_BYTE : BAK_BYTE)] |= 0x0cu << m_shift;
        gtia.pf_byte[((temp_byte & 0x10) ? PF2_BYTE : BAK_BYTE)] |= 0x03u << m_shift;

        m_shift -= 8;

        /*
         * Go through last 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x08) ? PF2_BYTE : BAK_BYTE)] |= 0xc0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x04) ? PF2_BYTE : BAK_BYTE)] |= 0x30u << m_shift;
        gtia.pf_byte[((temp_byte & 0x02) ? PF2_BYTE : BAK_BYTE)] |= 0x0cu << m_shift;
        gtia.pf_byte[((temp_byte & 0x01) ? PF2_BYTE : BAK_BYTE)] |= 0x03u << m_shift;

} /* antic_read_byte_mode_6_pf2 */

void antic_read_byte_mode_6_pf3 ( void ) {

        KBYTE temp_byte;

        /*
         * Read current screen byte , 8 pixels
         */
        temp_byte = rd_antic ( antic.current_ch_base | 
                              antic.screen_offset[antic.byte_count] );

        /*
         * Go through first 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x80) ? PF3_BYTE : BAK_BYTE)] |= 0xc0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x40) ? PF3_BYTE : BAK_BYTE)] |= 0x30u << m_shift;
        gtia.pf_byte[((temp_byte & 0x20) ? PF3_BYTE : BAK_BYTE)] |= 0x0cu << m_shift;
        gtia.pf_byte[((temp_byte & 0x10) ? PF3_BYTE : BAK_BYTE)] |= 0x03u << m_shift;

        m_shift -=8;

        /*
         * Go through last 4 bits 
         */
        gtia.pf_byte[((temp_byte & 0x08) ? PF3_BYTE : BAK_BYTE)] |= 0xc0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x04) ? PF3_BYTE : BAK_BYTE)] |= 0x30u << m_shift;
        gtia.pf_byte[((temp_byte & 0x02) ? PF3_BYTE : BAK_BYTE)] |= 0x0cu << m_shift;
        gtia.pf_byte[((temp_byte & 0x01) ? PF3_BYTE : BAK_BYTE)] |= 0x03u << m_shift;

} /* antic_read_byte_mode_6_pf3 */

void antic_read_byte_mode_7_pf0 ( void ) {

        KBYTE temp_byte;

        /* Read current screen byte , 8 pixels               */
        temp_byte = rd_antic ( antic.current_ch_base_16_line | 
                              antic.screen_offset[antic.byte_count] );

        /* Go through first 4 bits                           */
        gtia.pf_byte[((temp_byte & 0x80) ? PF0_BYTE : BAK_BYTE)] |= (0xc0u << m_shift);
        gtia.pf_byte[((temp_byte & 0x40) ? PF0_BYTE : BAK_BYTE)] |= (0x30u << m_shift);
        gtia.pf_byte[((temp_byte & 0x20) ? PF0_BYTE : BAK_BYTE)] |= (0x0cu << m_shift);
        gtia.pf_byte[((temp_byte & 0x10) ? PF0_BYTE : BAK_BYTE)] |= (0x03u << m_shift);

        m_shift -= 8;

        /* Go through last 4 bits                            */
        gtia.pf_byte[((temp_byte & 0x08) ? PF0_BYTE : BAK_BYTE)] |= (0xc0u << m_shift);
        gtia.pf_byte[((temp_byte & 0x04) ? PF0_BYTE : BAK_BYTE)] |= (0x30u << m_shift);
        gtia.pf_byte[((temp_byte & 0x02) ? PF0_BYTE : BAK_BYTE)] |= (0x0cu << m_shift);
        gtia.pf_byte[((temp_byte & 0x01) ? PF0_BYTE : BAK_BYTE)] |= (0x03u << m_shift);

} /* antic_read_byte_mode_7_pf0 */

void antic_read_byte_mode_7_pf1 ( void ) {

        KBYTE temp_byte;

        /*
         * Read current screen byte , 8 pixels
         */
        temp_byte = rd_antic ( antic.current_ch_base_16_line | 
                              antic.screen_offset[antic.byte_count] );

        /*
         * Go through first 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x80) ? PF1_BYTE : BAK_BYTE)] |= (0xc0u << m_shift);
        gtia.pf_byte[((temp_byte & 0x40) ? PF1_BYTE : BAK_BYTE)] |= (0x30u << m_shift);
        gtia.pf_byte[((temp_byte & 0x20) ? PF1_BYTE : BAK_BYTE)] |= (0x0cu << m_shift);
        gtia.pf_byte[((temp_byte & 0x10) ? PF1_BYTE : BAK_BYTE)] |= (0x03u << m_shift);

        m_shift -= 8;

        /*
         * Go through last 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x08) ? PF1_BYTE : BAK_BYTE)] |= (0xc0u << m_shift);
        gtia.pf_byte[((temp_byte & 0x04) ? PF1_BYTE : BAK_BYTE)] |= (0x30u << m_shift);
        gtia.pf_byte[((temp_byte & 0x02) ? PF1_BYTE : BAK_BYTE)] |= (0x0cu << m_shift);
        gtia.pf_byte[((temp_byte & 0x01) ? PF1_BYTE : BAK_BYTE)] |= (0x03u << m_shift);

} /* antic_read_byte_mode_7_pf1 */

void antic_read_byte_mode_7_pf2 ( void ) {

        KBYTE temp_byte;

        /*
         * Read current screen byte , 8 pixels 
         */
        temp_byte = rd_antic ( antic.current_ch_base_16_line | 
                              antic.screen_offset[antic.byte_count] );

        /*
         * Go through first 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x80) ? PF2_BYTE : BAK_BYTE)] |= (0xc0u << m_shift);
        gtia.pf_byte[((temp_byte & 0x40) ? PF2_BYTE : BAK_BYTE)] |= (0x30u << m_shift);
        gtia.pf_byte[((temp_byte & 0x20) ? PF2_BYTE : BAK_BYTE)] |= (0x0cu << m_shift);
        gtia.pf_byte[((temp_byte & 0x10) ? PF2_BYTE : BAK_BYTE)] |= (0x03u << m_shift);

        m_shift -= 8;

        /*
         * Go through last 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x08) ? PF2_BYTE : BAK_BYTE)] |= (0xc0u << m_shift);
        gtia.pf_byte[((temp_byte & 0x04) ? PF2_BYTE : BAK_BYTE)] |= (0x30u << m_shift);
        gtia.pf_byte[((temp_byte & 0x02) ? PF2_BYTE : BAK_BYTE)] |= (0x0cu << m_shift);
        gtia.pf_byte[((temp_byte & 0x01) ? PF2_BYTE : BAK_BYTE)] |= (0x03u << m_shift);

} /* antic_read_byte_mode_7_pf2 */

void antic_read_byte_mode_7_pf3 ( void ) {

        KBYTE temp_byte;

        /*
         * Read current screen byte , 8 pixels
         */
        temp_byte = rd_antic ( antic.current_ch_base_16_line | 
                              antic.screen_offset[antic.byte_count] );

        /*
         * Go through first 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x80) ? PF3_BYTE : BAK_BYTE)] |= (0xc0u << m_shift);
        gtia.pf_byte[((temp_byte & 0x40) ? PF3_BYTE : BAK_BYTE)] |= (0x30u << m_shift);
        gtia.pf_byte[((temp_byte & 0x20) ? PF3_BYTE : BAK_BYTE)] |= (0x0cu << m_shift);
        gtia.pf_byte[((temp_byte & 0x10) ? PF3_BYTE : BAK_BYTE)] |= (0x03u << m_shift);

        m_shift -= 8;

        /*
         * Go through last 4 bits
         */
        gtia.pf_byte[((temp_byte & 0x08) ? PF3_BYTE : BAK_BYTE)] |= (0xc0u << m_shift);
        gtia.pf_byte[((temp_byte & 0x04) ? PF3_BYTE : BAK_BYTE)] |= (0x30u << m_shift);
        gtia.pf_byte[((temp_byte & 0x02) ? PF3_BYTE : BAK_BYTE)] |= (0x0cu << m_shift);
        gtia.pf_byte[((temp_byte & 0x01) ? PF3_BYTE : BAK_BYTE)] |= (0x03u << m_shift);

} /* antic_read_byte_mode_7_pf3 */

void antic_read_and_draw_mode_8 ( void ) {

        KWORD address;

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read number of bytes from RAM and store in cache
         *  Also, go ahead and figure out addresses
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            address = (antic.msc++ & 0x0fff) | antic.msc_fixed;
            antic.screen_cache[++antic.byte_count] = rd_antic ( address );
            /*
             * Transfer data to gtia
             */
            antic_send_byte_mode_8 ();
        }

        /*
         * Now write 32 bits to gtia 
         */
        gtia_set_byte_mode_4 ( );

} /* antic_read_and_draw_mode_8 */

void antic_draw_mode_8 ( void ) {

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read bytes from cache
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            ++antic.byte_count;
            antic_send_byte_mode_8 ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia_set_byte_mode_4 ( );

} /* antic_draw_mode_8 */

void antic_read_and_draw_mode_9 ( void ) {

        KWORD address;

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read number of bytes from RAM and store in cache
         *  Also, go ahead and figure out addresses
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            address = (antic.msc++ & 0x0fff) | antic.msc_fixed;
            antic.screen_cache[++antic.byte_count] = rd_antic ( address );

            antic_send_byte_mode_9 ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia_set_byte_mode_4 ( );

} /* antic_read_and_draw_mode_9 */

void antic_draw_mode_9 ( void ) {

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read bytes from cache
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            ++antic.byte_count;

            antic_send_byte_mode_9 ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia_set_byte_mode_4 ( );

} /* antic_draw_mode_9 */

void antic_read_and_draw_mode_a ( void ) {

        KWORD address;

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read number of bytes from RAM and store in cache
         *  Also, go ahead and figure out addresses 
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            address = (antic.msc++ & 0x0fff) | antic.msc_fixed;
            antic.screen_cache[++antic.byte_count] = rd_antic ( address );

            antic_send_byte_mode_a ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia_set_byte_mode_4 ( );

} /* antic_read_and_draw_mode_a */

void antic_draw_mode_a ( void ) {

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read bytes from cache
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            ++antic.byte_count;

            antic_send_byte_mode_a ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia_set_byte_mode_4 ( );

} /* antic_draw_mode_a */

void antic_read_and_draw_mode_b_c ( void ) {

        KWORD address;

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read number of bytes from RAM and store in cache
         *  Also, go ahead and figure out addresses 
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            address = (antic.msc++ & 0x0fff) | antic.msc_fixed;
            antic.screen_cache[++antic.byte_count] = rd_antic ( address );

            antic_send_byte_mode_b_c ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia_set_byte_mode_4 ( );

} /* antic_read_and_draw_mode_b_c */

void antic_draw_mode_b_c ( void ) {

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read bytes from cache
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            ++antic.byte_count;

            antic_send_byte_mode_b_c ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia_set_byte_mode_4 ( );

} /* antic_draw_mode_b_c */

void antic_read_and_draw_mode_d_e ( void ) {

        KWORD address;

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read number of bytes from RAM and store in cache
         *  Also, go ahead and figure out addresses 
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            address = (antic.msc++ & 0x0fff) | antic.msc_fixed;
            antic.screen_cache[++antic.byte_count] = rd_antic ( address );

            antic_send_byte_mode_d_e ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia_set_byte_mode_4 ( );

} /* antic_read_and_draw_mode_d_e */

void antic_draw_mode_d_e ( void ) {

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read bytes from cache
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            ++antic.byte_count;

            antic_send_byte_mode_d_e ();
        }

        /*
         * Now write 32 bits to gtia
         */
        gtia_set_byte_mode_4 ( );

} /* antic_draw_mode_d_e */

void antic_read_and_draw_mode_f ( void ) {

        KWORD address;

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read number of bytes from RAM and store in cache
         *  Also, go ahead and figure out addresses 
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            address = (antic.msc++ & 0x0fff) | antic.msc_fixed;
            antic.screen_cache[++antic.byte_count] = rd_antic ( address );

            antic_send_byte_mode_f ();
        }

        /*
         * Now write 32 bits to gtia
         */
        if ( gtia.gtia_mode == 0 )
            gtia_set_byte_mode_f ();
        else
            gtia.gtia_set_byte_mode_2_ptr ( );

} /* antic_read_and_draw_mode_f */

void antic_draw_mode_f ( void ) {

        /*
         * Reset gtia bytes
         */
        memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

        /*
         * Read bytes from cache
         */
        for ( m_shift = 24; m_shift >= 0; m_shift-=8 ) {

            ++antic.byte_count;

            /* Transfer data to gtia          */
            antic_send_byte_mode_f ();
        }

        /*
         * Now write 32 bits to gtia
         */
        if ( gtia.gtia_mode == 0 )
            gtia_set_byte_mode_f ();
        else
            gtia.gtia_set_byte_mode_2_ptr ( );

} /* antic_draw_mode_f */

void antic_send_byte_mode_8 ( void ) {

        KBYTE temp_byte = antic.screen_cache[antic.byte_count];

        /*
         * Write 4 bytes based on each set of 2 bits 
         */
        gtia.pf_byte[((temp_byte & 0xc0) >> 6)] |= 0xffu << m_shift;
        m_shift -= 8;

        gtia.pf_byte[((temp_byte & 0x30) >> 4)] |= 0xffu << m_shift;
        m_shift -= 8;

        gtia.pf_byte[((temp_byte & 0x0c) >> 2)] |= 0xffu << m_shift;
        m_shift -= 8;

        gtia.pf_byte[(temp_byte & 0x03)] |= 0xffu << m_shift;

} /* antic_send_byte_mode_8 */

void antic_send_byte_mode_9 ( void ) {

        KBYTE temp_byte = antic.screen_cache[antic.byte_count];

        /*
         * Every 2 bits is a byte to be sent
         */
        gtia.pf_byte[(temp_byte & 0x80) >> 7] |= 0xf0u << m_shift;
        gtia.pf_byte[(temp_byte & 0x40) >> 6] |= 0x0fu << m_shift;
        m_shift -= 8;

        gtia.pf_byte[(temp_byte & 0x20) >> 5] |= 0xf0u << m_shift;
        gtia.pf_byte[(temp_byte & 0x10) >> 4] |= 0x0fu << m_shift;
        m_shift -= 8;

        gtia.pf_byte[(temp_byte & 0x08) >> 3] |= 0xf0u << m_shift;
        gtia.pf_byte[(temp_byte & 0x04) >> 2] |= 0x0fu << m_shift;
        m_shift -= 8;

        gtia.pf_byte[(temp_byte & 0x02) >> 1] |= 0xf0u << m_shift;
        gtia.pf_byte[(temp_byte & 0x01) >> 0] |= 0x0fu << m_shift;

} /* antic_send_byte_mode_9 */

void antic_send_byte_mode_a ( void ) {

        KBYTE temp_byte = antic.screen_cache[antic.byte_count];

        /*
         * Write 2 bytes based on each set of 2 bits
         */
        gtia.pf_byte[((temp_byte & 0xc0) >> 6)] |= 0xf0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x30) >> 4)] |= 0x0fu << m_shift;
        m_shift -= 8;

        gtia.pf_byte[((temp_byte & 0x0c) >> 2)] |= 0xf0u << m_shift;
        gtia.pf_byte[(temp_byte & 0x03)] = 0x0fu << m_shift;

} /* antic_send_byte_mode_a */

void antic_send_byte_mode_b_c ( void ) {

        KBYTE temp_byte = antic.screen_cache[antic.byte_count];

        /*
         * Write 2 bytes based on each bit
         */
        gtia.pf_byte[((temp_byte & 0x80) >> 7)] |= 0xc0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x40) >> 6)] |= 0x30u << m_shift;
        gtia.pf_byte[((temp_byte & 0x20) >> 5)] |= 0x0cu << m_shift;
        gtia.pf_byte[((temp_byte & 0x10) >> 4)] |= 0x03u << m_shift;
        m_shift -= 8;

        gtia.pf_byte[((temp_byte & 0x08) >> 3)] |= 0xc0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x04) >> 2)] |= 0x30u << m_shift;
        gtia.pf_byte[((temp_byte & 0x02) >> 1)] |= 0x0cu << m_shift;
        gtia.pf_byte[((temp_byte & 0x01) >> 0)] |= 0x03u << m_shift;

} /* antic_send_byte_mode_b_c */

void antic_send_byte_mode_d_e ( void ) {

        KBYTE temp_byte = antic.screen_cache[antic.byte_count];

        /*
         * Write 1 byte based on each every 2 bits
         */
        gtia.pf_byte[((temp_byte & 0xc0) >> 6)] |= 0xc0u << m_shift;
        gtia.pf_byte[((temp_byte & 0x30) >> 4)] |= 0x30u << m_shift;
        gtia.pf_byte[((temp_byte & 0x0c) >> 2)] |= 0x0cu << m_shift;
        gtia.pf_byte[((temp_byte & 0x03) >> 0)] |= 0x03u << m_shift;

} /* antic_send_byte_mode_d_e */

void antic_send_byte_mode_f ( void ) {

        gtia.pf_byte[PF2_BYTE] |= (antic.screen_cache[antic.byte_count]) << m_shift;

} /* antic_send_byte_mode_f */

void antic_send_byte_mode_blank ( void ) {

        gtia_set_byte_blank ( );

} /* antic_send_byte_mode_blank */

/******************************************************************************
**  Function   :  antic_no_dma    
**                            
**  Objective  :  This function is when antic cannot do DMA, so set up 6502 for
**                everything
**
**  Parameters :  NONE
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void antic_no_dma ( void ) {

    /*
     * We are pretending no DMA is instruction 0x1
     */
    antic.ml_map[0] = antic.dl_map[antic.pl_width][1][0];
    antic.ml_map[1] = 0;

    antic.ml_cycles[0] = antic.dl_cycles[antic.pl_width][1][0];

    /*
     * With no DMA, the CPU keeps the cycle normally stolen by the DL fetch
     */
    cpu6502.i_cnt += 1;

    /*
     * FIXME: Tell GTIA to do background?
     */
} /* end antic_no_dma */

/********************************
 * ANITC op code functions      *
 ********************************/
void antic_blank_line ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Tell gtia we are not mode 2 for PRIOR
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    gtia.pf_x_start_ptr = &antic.normal_pixel_start;

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.pl_width][MODE_BLANK][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.pl_width][MODE_BLANK][ML_FIRST];
    antic.sl_map = antic.ml_map[0];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.pl_width][MODE_BLANK][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.pl_width][MODE_BLANK][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines == 0 ) {
            antic.ml_map[0] = antic.dl_map[antic.pl_width][MODE_BLANK][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.pl_width][MODE_BLANK][ML_FIRST_LAST];
            antic.sl_map = antic.ml_map[0];
        }
        else {
            antic.ml_map[antic.num_lines] = antic.dl_map[antic.pl_width][MODE_BLANK][ML_LAST];
            antic.ml_cycles[antic.num_lines] = antic.dl_cycles[antic.pl_width][MODE_BLANK][ML_LAST];
        }
    }

    /*
     * Last line if not DLI
     */
    else if ( antic.num_lines != 0 ) {
        antic.ml_map[antic.num_lines] = antic.dl_map[antic.pl_width][MODE_BLANK][ML_NORMAL];
        antic.ml_cycles[antic.num_lines] = antic.dl_cycles[antic.pl_width][MODE_BLANK][ML_NORMAL];
    }
    antic.ml_map[antic.num_lines+1] = 0;

} /* end antic_blank_line */

void antic_jump ( void ) {

    KWORD addr_lo = antic.pc_fixed | ((antic.pc + 1) & 0x03ff);
    KWORD addr_hi = antic.pc_fixed | ((antic.pc + 2) & 0x03ff);

    /*
     * Add to display list for debug
     */
    antic.dl[antic.dl_byte_number++] = rd_antic(addr_lo);
    antic.dl[antic.dl_byte_number++] = rd_antic(addr_hi);

    antic.pc = rd_antic(addr_lo) | (rd_antic(addr_hi) << 8);
    antic.pc_fixed = antic.pc & 0xfc00;

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    /*
     * Do a blank line
     */
    if ( antic.dl_current_byte & 0x80 ) {
        antic.ml_map[0] = antic.dl_map[antic.pl_width][MODE_BLANK][ML_FIRST_LAST];
        antic.ml_cycles[0] = antic.dl_cycles[antic.pl_width][MODE_BLANK][ML_FIRST_LAST];
    }
    else {
        antic.ml_map[0] = antic.dl_map[antic.pl_width][MODE_BLANK][ML_FIRST];
        antic.ml_cycles[0] = antic.dl_cycles[antic.pl_width][MODE_BLANK][ML_FIRST];
    }

    antic.ml_map[1] = 0;
    antic.sl_map = antic.ml_map[0];

    cpu6502.i_cnt -= 2;
    //antic.sl_cycle_count += 2;
    //antic.dli_count -= 2;

} /* end antic_jump */

void antic_jvb ( void ) {

    KWORD addr_lo = antic.pc_fixed | ((antic.pc + 1) & 0x03ff);
    KWORD addr_hi = antic.pc_fixed | ((antic.pc + 2) & 0x03ff);

    /*
     * Add to display list for debug
     */
    antic.dl[antic.dl_byte_number++] = rd_antic(addr_lo);
    antic.dl[antic.dl_byte_number++] = rd_antic(addr_hi);

    antic.pc = rd_antic(addr_lo) | (rd_antic(addr_hi) << 8);
    antic.pc_fixed = antic.pc & 0xfc00;

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    /*
     * Do all 6502 and let main proc find vertical blank
     */
    if ( antic.dl_current_byte & 0x80 ) {
        antic.ml_map[0] = antic.dl_map[0][1][ML_LAST];
        antic.ml_cycles[0] = antic.dl_cycles[0][1][ML_LAST];
    }
    else {
        antic.ml_map[0] = antic.dl_map[0][1][ML_NORMAL];
        antic.ml_cycles[0] = antic.dl_cycles[0][1][ML_NORMAL];
    }
    antic.sl_map = antic.ml_map[0];

    antic.ml_map[1] = 0;

    cpu6502.i_cnt -= 2;
    //antic.sl_cycle_count += 2;
    //antic.dli_count -= 2;

} /* end antic_jvb */

void antic_lms ( void ) {

    KWORD addr_lo = antic.pc_fixed | ((antic.pc + 1) & 0x03ff);
    KWORD addr_hi = antic.pc_fixed | ((antic.pc + 2) & 0x03ff);

    /*
     * Add to display list for debug
     */
    antic.dl[antic.dl_byte_number++] = rd_antic(addr_lo);
    antic.dl[antic.dl_byte_number++] = rd_antic(addr_hi);

    /*
     * This is called when LMS bit set
     * It then calls the instruction
     */
    antic.msc = rd_antic(addr_lo) | (rd_antic(addr_hi) << 8);
    antic.msc_fixed = antic.msc & 0xf000;

    antic.dl_current_byte = rd_antic(antic.pc);
    antic.pc = antic.pc_fixed | ((antic.pc + 2) & 0x03ff );

    antic.do_instruct [ antic.dl_current_byte & 0xbf ] ();

    /*
     * Lets take two cycles of 6502 count since
     * this is a 3 byte instr instead of 1
     */
    cpu6502.i_cnt -= 2;
    //antic.sl_cycle_count += 2;
    //antic.dli_count -= 2;

} /* end antic_lms */

void antic_none ( void ) {

    antic.pc++;

} /* end antic_none */

void antic_graphics_mode_2 ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * We only use one color, so just reset all here
     */
    memset (gtia.pf_byte, 0x0, 5*sizeof(KBYTE) );

    /*
     * Tell gtia we are mode 2 for PRIOR
     */
    if ( gtia.gtia_mode == 0 ) {
        gtia.prior_mask |= MODE2_MASK;
    }

    antic.ch_base_ptr = &antic.ch_base_40_mode;

    /*
     * Assign read char and data function ptrs
     */
    antic.antic_read_char_data_ptr = antic_read_char_data_mode_2;
    antic.antic_read_data_ptr = antic_read_data_mode_2;

    /*
     * Assign char ctrl function pointers
     */
    antic.antic_normal_char_ptr = antic_read_byte_mode_2;
    antic.antic_inv_video_ptr = antic_read_byte_inv_mode_2;
    antic.antic_blank_char_ptr = antic_read_byte_blank_mode_2;
    antic.antic_inv_blank_ptr = antic_read_byte_inv_blank_mode_2;

    /*
     * Recalculate ch base
     */
    antic.current_ch_base = antic_current_8row_ch_base ();

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_FIRST_LAST];
        }
    }

    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_2 */

void antic_graphics_mode_3 ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Tell gtia we are mode 2 for PRIOR
     */
    if ( gtia.gtia_mode == 0 ) {
        gtia.prior_mask |= MODE2_MASK;
    }

    antic.ch_base_ptr = &antic.ch_base_40_mode;

    /*
     * Assign read char and data function ptrs
     */
    antic.antic_read_char_data_ptr = antic_read_char_data_mode_3;
    antic.antic_read_data_ptr = antic_read_data_mode_3;

    /*
     * Assign char ctrl function pointers
     */
    antic.antic_normal_char_ptr = antic_read_byte_mode_2;
    antic.antic_inv_video_ptr = antic_read_byte_inv_mode_2;
    antic.antic_blank_char_ptr = antic_read_byte_blank_mode_2;
    antic.antic_inv_blank_ptr = antic_read_byte_inv_blank_mode_2;

    /*
     * Recalculate ch base
     */
    antic.current_ch_base = antic_current_8row_ch_base ();

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_FIRST_LAST];
        }
    }

    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_3 */

void antic_graphics_mode_4 ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    antic.ch_base_ptr = &antic.ch_base_40_mode;

    /*
     * Assign read char and data function ptrs
     */
    antic.antic_read_char_data_ptr = antic_read_char_data_mode_4;
    antic.antic_read_data_ptr = antic_read_data_mode_4;

    /*
     * Assign char ctrl function pointers
     */
    antic.antic_normal_char_ptr = antic_read_byte_mode_4_bit_0;
    antic.antic_bit1_char_ptr = antic_read_byte_mode_4_bit_1;

    /*
     * Recalculate ch base
     */
    antic.current_ch_base = antic_current_8row_ch_base ();

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_FIRST_LAST];
        }
    }

    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_4 */

void antic_graphics_mode_5 ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    antic.ch_base_ptr = &antic.ch_base_40_mode;

    /*
     * Assign read char and data function ptrs
     */
    antic.antic_read_char_data_ptr = antic_read_char_data_mode_4;
    antic.antic_read_data_ptr = antic_read_data_mode_4;

    /*
     * Assign char ctrl function pointers
     */
    antic.antic_normal_char_ptr = antic_read_byte_mode_5_bit_0;
    antic.antic_bit1_char_ptr = antic_read_byte_mode_5_bit_1;

    /*
     * Recalculate ch base
     */
    antic.current_ch_base_16_line = *antic.ch_base_ptr | 
                                         ((*antic.dl_mode_line_ptr>>1) & 0x7);

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_2_TO_5][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_2_TO_5][ML_FIRST_LAST];
        }
    }

    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_5 */

void antic_graphics_mode_6 ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    antic.ch_base_ptr = &antic.ch_base_20_mode;

    /*
     * Assign read char and data function ptrs
     */
    antic.antic_read_char_data_ptr = antic_read_char_data_mode_6;
    antic.antic_read_data_ptr = antic_read_data_mode_4;

    /*
     * Assign char ctrl function pointers
     */
    antic.antic_char_pf0_ptr = antic_read_byte_mode_6_pf0;
    antic.antic_char_pf1_ptr = antic_read_byte_mode_6_pf1;
    antic.antic_char_pf2_ptr = antic_read_byte_mode_6_pf2;
    antic.antic_char_pf3_ptr = antic_read_byte_mode_6_pf3;

    /*
     * Recalculate ch base
     */
    antic.current_ch_base = antic_current_8row_ch_base ();

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_6_7][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_6_7][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_6_7][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_6_7][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_6_7][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_6_7][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_6_7][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_6_7][ML_FIRST_LAST];
        }
    }

    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_6 */

void antic_graphics_mode_7 ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    antic.ch_base_ptr = &antic.ch_base_20_mode;

    /*
     * Assign read char and data function ptrs
     */
    antic.antic_read_char_data_ptr = antic_read_char_data_mode_6;
    antic.antic_read_data_ptr = antic_read_data_mode_4;

    /*
     * Assign char ctrl function pointers
     */
    antic.antic_char_pf0_ptr = antic_read_byte_mode_7_pf0;
    antic.antic_char_pf1_ptr = antic_read_byte_mode_7_pf1;
    antic.antic_char_pf2_ptr = antic_read_byte_mode_7_pf2;
    antic.antic_char_pf3_ptr = antic_read_byte_mode_7_pf3;

    /*
     * Recalculate ch base
     */
    antic.current_ch_base_16_line = *antic.ch_base_ptr | 
                                         ((*antic.dl_mode_line_ptr>>1) & 0x7);

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_6_7][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_6_7][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_6_7][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_6_7][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_6_7][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_6_7][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_6_7][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_6_7][ML_FIRST_LAST];
        }
    }

    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_7 */

void antic_graphics_mode_8 ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Check for number of lines <= 0
     */
    if ( antic.num_lines <= 0 ) {
        antic_do_display_list_instruction ();
        return;
    }

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    /*
     * Assign read data function ptrs
     */
    antic.antic_map_read_and_draw_ptr = antic_read_and_draw_mode_8;
    antic.antic_map_draw_ptr = antic_draw_mode_8;

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_8_9][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_8_9][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_8_9][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_8_9][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_8_9][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_8_9][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_8_9][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_8_9][ML_FIRST_LAST];
        }
    }


    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_8 */

void antic_graphics_mode_9 ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Check for number of lines <= 0 
     */
    if ( antic.num_lines <= 0 ) {
        antic_do_display_list_instruction ();
        return;
    }

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    /*
     * Assign read data function ptrs
     */
    antic.antic_map_read_and_draw_ptr = antic_read_and_draw_mode_9;
    antic.antic_map_draw_ptr = antic_draw_mode_9;

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_8_9][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_8_9][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_8_9][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_8_9][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_8_9][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_8_9][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_8_9][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_8_9][ML_FIRST_LAST];
        }
    }

    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_9 */

void antic_graphics_mode_a ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Check for number of lines <= 0
     */
    if ( antic.num_lines <= 0 ) {
        antic_do_display_list_instruction ();
        return;
    }

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    /*
     * Assign read data function ptrs
     */
    antic.antic_map_read_and_draw_ptr = antic_read_and_draw_mode_a;
    antic.antic_map_draw_ptr = antic_draw_mode_a;

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_FIRST_LAST];
        }
    }

    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode */

void antic_graphics_mode_b ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Check for number of lines <= 0 
     */
    if ( antic.num_lines <= 0 ) {
        antic_do_display_list_instruction ();
        return;
    }

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    /*
     * Assign read data function ptrs
     */
    antic.antic_map_read_and_draw_ptr = antic_read_and_draw_mode_b_c;
    antic.antic_map_draw_ptr = antic_draw_mode_b_c;

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_FIRST_LAST];
        }
    }

    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_b */

void antic_graphics_mode_c ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Check for number of lines <= 0
     */
    if ( antic.num_lines <= 0 ) {
        antic_do_display_list_instruction ();
        return;
    }

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    /*
     * Assign read data function ptrs
     */
    antic.antic_map_read_and_draw_ptr = antic_read_and_draw_mode_b_c;
    antic.antic_map_draw_ptr = antic_draw_mode_b_c;

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_A_B_C][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_A_B_C][ML_FIRST_LAST];
        }
    }

    antic.sl_map = antic.ml_map[0];
    antic.ml_map[antic.num_lines] = 0;

} /* end antic_graphics_mode_c */

void antic_graphics_mode_d ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Check for number of lines <= 0
     */
    if ( antic.num_lines <= 0 ) {
        antic_do_display_list_instruction ();
        return;
    }

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    /*
     * Assign read char and data function ptrs
     */
    antic.antic_map_read_and_draw_ptr = antic_read_and_draw_mode_d_e;
    antic.antic_map_draw_ptr = antic_draw_mode_d_e;

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_D_E][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_D_E][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_D_E][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_D_E][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_D_E][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_D_E][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_D_E][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_D_E][ML_FIRST_LAST];
        }
    }

    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_d */

void antic_graphics_mode_e ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Check for number of lines <= 0
     */
    if ( antic.num_lines <= 0 ) {
        antic_do_display_list_instruction ();
        return;
    }

    /*
     * Tell gtia we are not mode 2 for PRIOR 
     */
    gtia.prior_mask &= ~(MODE2_MASK);

    /*
     * Assign read data function ptrs
     */
    antic.antic_map_read_and_draw_ptr = antic_read_and_draw_mode_d_e;
    antic.antic_map_draw_ptr = antic_draw_mode_d_e;

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_D_E][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_D_E][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_D_E][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_D_E][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_D_E][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_D_E][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_D_E][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_D_E][ML_FIRST_LAST];
        }
    }

    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_e */

void antic_graphics_mode_f ( void ) {

    int i;

    antic.pc = antic.pc_fixed | ((antic.pc + 1) & 0x03ff );

    /*
     * Check for number of lines <= 0
     */
    if ( antic.num_lines <= 0 ) {
        antic_do_display_list_instruction ();
        return;
    }

    /*
     * Tell gtia we are mode 2 for PRIOR 
     */
    if ( gtia.gtia_mode == 0 ) {
        gtia.prior_mask |= MODE2_MASK;
    }

    /*
     * Assign read data function ptrs
     */
    antic.antic_map_read_and_draw_ptr = antic_read_and_draw_mode_f;
    antic.antic_map_draw_ptr = antic_draw_mode_f;

    /*
     * First line
     */
    antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_F][ML_FIRST];
    antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_F][ML_FIRST];

    /*
     * Middle lines
     */
    for ( i = 1; i < antic.num_lines; ++i ) {
        antic.ml_map[i] = antic.dl_map[antic.width_array][MODE_F][ML_NORMAL];
        antic.ml_cycles[i] = antic.dl_cycles[antic.width_array][MODE_F][ML_NORMAL];
    }

    /*
     * Last line if DLI
     */
    if ( antic.dl_current_byte & 0x80 ) {
        if ( antic.num_lines > 1 ) {
            antic.ml_map[antic.num_lines-1] = antic.dl_map[antic.width_array][MODE_F][ML_LAST];
            antic.ml_cycles[antic.num_lines-1] = antic.dl_cycles[antic.width_array][MODE_F][ML_LAST];
        }
        else {
            antic.ml_map[0] = antic.dl_map[antic.width_array][MODE_F][ML_FIRST_LAST];
            antic.ml_cycles[0] = antic.dl_cycles[antic.width_array][MODE_F][ML_FIRST_LAST];
        }
    }


    antic.ml_map[antic.num_lines] = 0;
    antic.sl_map = antic.ml_map[0];

} /* end antic_graphics_mode_f */

static void ( **antic_cycle_fn_ptr ( antic_cycle_fn fn ) ) ( void ) {

    switch ( fn ) {
        case AC_CPU: return &antic.run_6502_ptr;
        case AC_RM: return &antic.antic_read_missle_ptr;
        case AC_RP: return &antic.antic_read_player_ptr;
        case AC_DL: return &antic.antic_do_dl_instr_ptr;
        case AC_INIT: return &antic.antic_init_scanline_ptr;
        case AC_END: return &antic.antic_end_scanline_ptr;
        case AC_CH_FIRST: return &antic.antic_read_char_data_ptr;
        case AC_CH_DATA: return &antic.antic_read_data_ptr;
        case AC_MAP_RD: return &antic.antic_map_read_or_draw_ptr;
        case AC_MAP_DRAW: return &antic.antic_map_draw_ptr;
        case AC_DLI: return &antic.antic_set_dli_ptr;
        case AC_BLANK: return &antic.antic_blank_ptr;
        case AC_REFRESH: return &antic_refresh_ptr;
    }

    return 0;

} /* end antic_cycle_fn_ptr */

static const char *antic_cycle_fn_name ( void ( **func ) ( void ) ) {

    if ( func == &antic.run_6502_ptr ) return "CPU";
    if ( func == &antic.antic_read_missle_ptr ) return "RM";
    if ( func == &antic.antic_read_player_ptr ) return "RP";
    if ( func == &antic.antic_do_dl_instr_ptr ) return "DL";
    if ( func == &antic.antic_init_scanline_ptr ) return "INIT";
    if ( func == &antic.antic_end_scanline_ptr ) return "END";
    if ( func == &antic.antic_read_char_data_ptr ) return "CH_FIRST";
    if ( func == &antic.antic_read_data_ptr ) return "CH_DATA";
    if ( func == &antic.antic_map_read_or_draw_ptr ) return "MAP_RD";
    if ( func == &antic.antic_map_draw_ptr ) return "MAP_DRAW";
    if ( func == &antic.antic_set_dli_ptr ) return "DLI";
    if ( func == &antic.antic_blank_ptr ) return "BLANK";
    if ( func == &antic_refresh_ptr ) return "REF";

    return "UNKNOWN";

} /* end antic_cycle_fn_name */

static void antic_clear_cycle_maps ( void ) {

    memset ( antic.dl_map, 0, sizeof ( antic.dl_map ) );
    memset ( antic.dl_cycles, 0, sizeof ( antic.dl_cycles ) );

} /* end antic_clear_cycle_maps */

static void antic_append_cycle_slot ( int width, int mode, int line,
                                      int *index, int cycles,
                                      antic_cycle_fn fn ) {

    if ( *index >= MAX_CHANGES )
        return;

    antic.dl_cycles[width][mode][line][*index] = cycles;
    antic.dl_map[width][mode][line][*index] = antic_cycle_fn_ptr ( fn );
    ++*index;

} /* end antic_append_cycle_slot */

static int antic_install_cycle_row_at ( int width, int mode, int line,
                                        int index,
                                        const antic_cycle_row *row ) {

    int i;

    for ( i = 0; i < row->count; ++i )
        antic_append_cycle_slot ( width, mode, line, &index,
                                  row->cycles[i], row->funcs[i] );

    return index;

} /* end antic_install_cycle_row_at */

static void antic_install_cycle_rows ( int width, int mode, int line,
                                      const antic_cycle_row *start,
                                      const antic_cycle_row *body ) {

    int index = 0;

    index = antic_install_cycle_row_at ( width, mode, line, index, start );
    antic_install_cycle_row_at ( width, mode, line, index, body );

} /* end antic_install_cycle_rows */

static const int            start_first_w0_cycles[]   = { 9,     1,     1,     4,     18,    1,    0 }; // 34 cycles
static const antic_cycle_fn start_first_w0_funcs[]    = { CPU,   RM,    DL,    RP,    CPU,   REF,  INIT };
static const int            start_first_w1_cycles[]   = { 9,     1,     1,     4,     18,    1,    0 }; // 34 cycles
static const antic_cycle_fn start_first_w1_funcs[]    = { CPU,   RM,    DL,    RP,    CPU,   REF,  INIT };
static const int            start_first_w2_cycles[]   = { 9,     1,     1,     4,     11,    0 }; // 26 cycles
static const antic_cycle_fn start_first_w2_funcs[]    = { CPU,   RM,    DL,    RP,    CPU,   INIT };
static const int            start_first_w3_cycles[]   = { 9,     1,     1,     4,     3,     0 }; // 18 cycles
static const antic_cycle_fn start_first_w3_funcs[]    = { CPU,   RM,    DL,    RP,    CPU,   INIT };
static const int            start_first_w4_cycles[]   = { 9,     1,     1,     4,     3,     0 }; // 18 cycles
static const antic_cycle_fn start_first_w4_funcs[]    = { CPU,   RM,    DL,    RP,    CPU,   INIT };

static const int            start_normal_w0_cycles[]  = { 10,     1,     4,     22,    1,     0 }; // 38 cycles
static const antic_cycle_fn start_normal_w0_funcs[]   = { CPU,   RM,    RP,    CPU,   REF,   INIT };
static const int            start_normal_w1_cycles[]  = { 10,     1,     4,     22,    1,     0 }; // 38 cycles
static const antic_cycle_fn start_normal_w1_funcs[]   = { CPU,   RM,    RP,    CPU,   REF,   INIT };
static const int            start_normal_w2_cycles[]  = { 10,     1,     4,     15,    0 }; // 30 cycles
static const antic_cycle_fn start_normal_w2_funcs[]   = { CPU,   RM,    RP,    CPU,   INIT };
static const int            start_normal_w3_cycles[]  = { 10,     1,     4,     7,     0 }; // 22 cycles
static const antic_cycle_fn start_normal_w3_funcs[]   = { CPU,   RM,    RP,    CPU,   INIT };
static const int            start_normal_w4_cycles[]  = { 10,     1,     4,     7,     0 }; // 22 cycles
static const antic_cycle_fn start_normal_w4_funcs[]   = { CPU,   RM,    RP,    CPU,   INIT };

static const int            start_last_w0_cycles[]    = { 10,    1,     4,     0,     22,    1,     0 }; // 38 cycles
static const antic_cycle_fn start_last_w0_funcs[]     = { CPU,   RM,    RP,    DLI,   CPU,   REF,   INIT };
static const int            start_last_w1_cycles[]    = { 10,    1,     4,     0,     22,    1,     0 }; // 38 cycles
static const antic_cycle_fn start_last_w1_funcs[]     = { CPU,   RM,    RP,    DLI,   CPU,   REF,   INIT };
static const int            start_last_w2_cycles[]    = { 10,    1,     4,     0,     15,    0 }; // 30 cycles
static const antic_cycle_fn start_last_w2_funcs[]     = { CPU,   RM,    RP,    DLI,   CPU,   INIT };
static const int            start_last_w3_cycles[]    = { 10,    1,     4,     0,     7,     0 }; // 22 cycles
static const antic_cycle_fn start_last_w3_funcs[]     = { CPU,   RM,    RP,    DLI,   CPU,   INIT };
static const int            start_last_w4_cycles[]    = { 10,    1,     4,     0,     7,     0 }; // 22 cycles
static const antic_cycle_fn start_last_w4_funcs[]     = { CPU,   RM,    RP,    DLI,   CPU,   INIT };

static const int            start_normal_mrd_w0_cycles[] = { 10,     1,     4,     18,    1,     0 }; // 34 cycles
static const antic_cycle_fn start_normal_mrd_w0_funcs[]  = { CPU,   RM,    RP,    CPU,   REF,   INIT };
static const int            start_normal_mrd_w1_cycles[] = { 10,     1,     4,     18,    1,     0 }; // 34 cycles
static const antic_cycle_fn start_normal_mrd_w1_funcs[]  = { CPU,   RM,    RP,    CPU,   REF,   INIT };
static const int            start_normal_mrd_w2_cycles[] = { 10,     1,     4,     11,    0 }; // 26 cycles
static const antic_cycle_fn start_normal_mrd_w2_funcs[]  = { CPU,   RM,    RP,    CPU,   INIT };
static const int            start_normal_mrd_w3_cycles[] = { 10,     1,     4,     3,     0 }; // 18 cycles
static const antic_cycle_fn start_normal_mrd_w3_funcs[]  = { CPU,   RM,    RP,    CPU,   INIT };
static const int            start_normal_mrd_w4_cycles[] = { 10,     1,     4,     3,     0 }; // 18 cycles
static const antic_cycle_fn start_normal_mrd_w4_funcs[]  = { CPU,   RM,    RP,    CPU,   INIT };

static const int            start_last_mrd_w0_cycles[]   = { 10,    1,     4,     0,     18,    1,     0 }; // 34 cycles
static const antic_cycle_fn start_last_mrd_w0_funcs[]    = { CPU,   RM,    RP,    DLI,   CPU,   REF,   INIT };
static const int            start_last_mrd_w1_cycles[]   = { 10,    1,     4,     0,     18,    1,     0 }; // 34 cycles
static const antic_cycle_fn start_last_mrd_w1_funcs[]    = { CPU,   RM,    RP,    DLI,   CPU,   REF,   INIT };
static const int            start_last_mrd_w2_cycles[]   = { 10,    1,     4,     0,     11,    0 }; // 26 cycles
static const antic_cycle_fn start_last_mrd_w2_funcs[]    = { CPU,   RM,    RP,    DLI,   CPU,   INIT };
static const int            start_last_mrd_w3_cycles[]   = { 10,    1,     4,     0,     3,     0 }; // 18 cycles
static const antic_cycle_fn start_last_mrd_w3_funcs[]    = { CPU,   RM,    RP,    DLI,   CPU,   INIT };
static const int            start_last_mrd_w4_cycles[]   = { 10,    1,     4,     0,     3,     0 }; // 18 cycles
static const antic_cycle_fn start_last_mrd_w4_funcs[]    = { CPU,   RM,    RP,    DLI,   CPU,   INIT };

static const int            start_first_last_w0_cycles[] = { 9,     1,     1,     4,     0,     18,    1,    0 }; // 34 cycles
static const antic_cycle_fn start_first_last_w0_funcs[]  = { CPU,   RM,    DL,    RP,    DLI,   CPU,   REF,  INIT };
static const int            start_first_last_w1_cycles[] = { 9,     1,     1,     4,     0,     18,    1,    0 }; // 34 cycles
static const antic_cycle_fn start_first_last_w1_funcs[]  = { CPU,   RM,    DL,    RP,    DLI,   CPU,   REF,  INIT };
static const int            start_first_last_w2_cycles[] = { 9,     1,     1,     4,     0,     11,    0 }; // 26 cycles
static const antic_cycle_fn start_first_last_w2_funcs[]  = { CPU,   RM,    DL,    RP,    DLI,   CPU,   INIT };
static const int            start_first_last_w3_cycles[] = { 9,     1,     1,     4,     0,     3,     0 }; // 18 cycles
static const antic_cycle_fn start_first_last_w3_funcs[]  = { CPU,   RM,    DL,    RP,    DLI,   CPU,   INIT };
static const int            start_first_last_w4_cycles[] = { 9,     1,     1,     4,     0,     3,     0 }; // 18 cycles
static const antic_cycle_fn start_first_last_w4_funcs[]  = { CPU,   RM,    DL,    RP,    DLI,   CPU,   INIT };

static const int            start_mode25_first_w0_cycles[] = { 9,     1,     1,     4,     20,    0 }; // 35 cycles
static const antic_cycle_fn start_mode25_first_w0_funcs[]  = { CPU,   RM,    DL,    RP,    CPU,   INIT };
static const int            start_mode25_first_w1_cycles[] = { 9,     1,     1,     4,     20,    0 }; // 35 cycles
static const antic_cycle_fn start_mode25_first_w1_funcs[]  = { CPU,   RM,    DL,    RP,    CPU,   INIT };
static const int            start_mode25_first_w2_cycles[] = { 9,     1,     1,     4,     13,    0 }; // 28 cycles
static const antic_cycle_fn start_mode25_first_w2_funcs[]  = { CPU,   RM,    DL,    RP,    CPU,   INIT };
static const int            start_mode25_first_w3_cycles[] = { 9,     1,     1,     4,     5,     0 }; // 20 cycles
static const antic_cycle_fn start_mode25_first_w3_funcs[]  = { CPU,   RM,    DL,    RP,    CPU,   INIT };
static const int            start_mode25_first_w4_cycles[] = { 9,     1,     1,     4,     5,     0 }; // 20 cycles
static const antic_cycle_fn start_mode25_first_w4_funcs[]  = { CPU,   RM,    DL,    RP,    CPU,   INIT };

static const int            start_mode25_first_last_w0_cycles[] = { 9,     1,     1,     4,     0,     20,    0 }; // 35 cycles
static const antic_cycle_fn start_mode25_first_last_w0_funcs[]  = { CPU,   RM,    DL,    RP,    DLI,   CPU,   INIT };
static const int            start_mode25_first_last_w1_cycles[] = { 9,     1,     1,     4,     0,     20,    0 }; // 35 cycles
static const antic_cycle_fn start_mode25_first_last_w1_funcs[]  = { CPU,   RM,    DL,    RP,    DLI,   CPU,   INIT };
static const int            start_mode25_first_last_w2_cycles[] = { 9,     1,     1,     4,     0,     13,    0 }; // 28 cycles
static const antic_cycle_fn start_mode25_first_last_w2_funcs[]  = { CPU,   RM,    DL,    RP,    DLI,   CPU,   INIT };
static const int            start_mode25_first_last_w3_cycles[] = { 9,     1,     1,     4,     0,     5,     0 }; // 20 cycles
static const antic_cycle_fn start_mode25_first_last_w3_funcs[]  = { CPU,   RM,    DL,    RP,    DLI,   CPU,   INIT };
static const int            start_mode25_first_last_w4_cycles[] = { 9,     1,     1,     4,     0,     5,     0 }; // 20 cycles
static const antic_cycle_fn start_mode25_first_last_w4_funcs[]  = { CPU,   RM,    DL,    RP,    DLI,   CPU,   INIT };

static const antic_cycle_row start_rows[4][5] = {
    { ANTIC_ROW ( start_first_w0_cycles, start_first_w0_funcs ), ANTIC_ROW ( start_first_w1_cycles, start_first_w1_funcs ), ANTIC_ROW ( start_first_w2_cycles, start_first_w2_funcs ), ANTIC_ROW ( start_first_w3_cycles, start_first_w3_funcs ), ANTIC_ROW ( start_first_w4_cycles, start_first_w4_funcs ) },
    { ANTIC_ROW ( start_normal_w0_cycles, start_normal_w0_funcs ), ANTIC_ROW ( start_normal_w1_cycles, start_normal_w1_funcs ), ANTIC_ROW ( start_normal_w2_cycles, start_normal_w2_funcs ), ANTIC_ROW ( start_normal_w3_cycles, start_normal_w3_funcs ), ANTIC_ROW ( start_normal_w4_cycles, start_normal_w4_funcs ) },
    { ANTIC_ROW ( start_last_w0_cycles, start_last_w0_funcs ), ANTIC_ROW ( start_last_w1_cycles, start_last_w1_funcs ), ANTIC_ROW ( start_last_w2_cycles, start_last_w2_funcs ), ANTIC_ROW ( start_last_w3_cycles, start_last_w3_funcs ), ANTIC_ROW ( start_last_w4_cycles, start_last_w4_funcs ) },
    { ANTIC_ROW ( start_first_last_w0_cycles, start_first_last_w0_funcs ), ANTIC_ROW ( start_first_last_w1_cycles, start_first_last_w1_funcs ), ANTIC_ROW ( start_first_last_w2_cycles, start_first_last_w2_funcs ), ANTIC_ROW ( start_first_last_w3_cycles, start_first_last_w3_funcs ), ANTIC_ROW ( start_first_last_w4_cycles, start_first_last_w4_funcs ) }
};

static const antic_cycle_row start_normal_mrd_rows[5] = {
    ANTIC_ROW ( start_normal_mrd_w0_cycles, start_normal_mrd_w0_funcs ),
    ANTIC_ROW ( start_normal_mrd_w1_cycles, start_normal_mrd_w1_funcs ),
    ANTIC_ROW ( start_normal_mrd_w2_cycles, start_normal_mrd_w2_funcs ),
    ANTIC_ROW ( start_normal_mrd_w3_cycles, start_normal_mrd_w3_funcs ),
    ANTIC_ROW ( start_normal_mrd_w4_cycles, start_normal_mrd_w4_funcs )
};

static const antic_cycle_row start_last_mrd_rows[5] = {
    ANTIC_ROW ( start_last_mrd_w0_cycles, start_last_mrd_w0_funcs ),
    ANTIC_ROW ( start_last_mrd_w1_cycles, start_last_mrd_w1_funcs ),
    ANTIC_ROW ( start_last_mrd_w2_cycles, start_last_mrd_w2_funcs ),
    ANTIC_ROW ( start_last_mrd_w3_cycles, start_last_mrd_w3_funcs ),
    ANTIC_ROW ( start_last_mrd_w4_cycles, start_last_mrd_w4_funcs )
};

static const antic_cycle_row mode25_first_rows[5] = {
    ANTIC_ROW ( start_mode25_first_w0_cycles, start_mode25_first_w0_funcs ),
    ANTIC_ROW ( start_mode25_first_w1_cycles, start_mode25_first_w1_funcs ),
    ANTIC_ROW ( start_mode25_first_w2_cycles, start_mode25_first_w2_funcs ),
    ANTIC_ROW ( start_mode25_first_w3_cycles, start_mode25_first_w3_funcs ),
    ANTIC_ROW ( start_mode25_first_w4_cycles, start_mode25_first_w4_funcs )
};

static const antic_cycle_row mode25_first_last_rows[5] = {
    ANTIC_ROW ( start_mode25_first_last_w0_cycles, start_mode25_first_last_w0_funcs ),
    ANTIC_ROW ( start_mode25_first_last_w1_cycles, start_mode25_first_last_w1_funcs ),
    ANTIC_ROW ( start_mode25_first_last_w2_cycles, start_mode25_first_last_w2_funcs ),
    ANTIC_ROW ( start_mode25_first_last_w3_cycles, start_mode25_first_last_w3_funcs ),
    ANTIC_ROW ( start_mode25_first_last_w4_cycles, start_mode25_first_last_w4_funcs )
};

/*
 * Body rows are intentionally spelled out as cycle/function pairs. Keep CPU
 * entries at four or more cycles unless the CPU slot is immediately before END;
 * the start-row CPU before INIT and this final tail CPU are the HSCROL/width
 * adjustment points.
 *
 * BLANK rows use zero-cycle draw markers. The elapsed time is CPU time unless
 * a REF slot explicitly marks a memory-refresh steal.
 *
 * REF rows are no-op elapsed cycles for memory refresh. They keep
 * sl_cycle_count honest while withholding those cycles from the CPU.
 * Cached MAP_DRAW rows keep the draw markers but donate their elapsed time to
 * CPU slots; the previous timing is commented above each replacement.
 */
static const int            body_blank_w01_cycles[]       = { 0,   6,   2,   0,   6,   2,   0,   6,   2,   0,   6,   2,   0,   8,   0,   8,   0,   8,   0,   24,  0 }; // 80 cycles
static const antic_cycle_fn body_blank_w01_funcs[]        = { BLK, CPU, REF, BLK, CPU, REF, BLK, CPU, REF, BLK, CPU, REF, BLK, CPU, BLK, CPU, BLK, CPU, BLK, CPU, END };
static const int            body_blank_w2_cycles[]        = { 0,   7,   1,   0,   6,   2,   0,   6,   2,   0,   6,   2,   0,   6,   2,   0,   8,   0,   8,   0,   8,   0,   8,   0,   16,  0 }; // 88 cycles
static const antic_cycle_fn body_blank_w2_funcs[]         = { BLK, CPU, REF, BLK, CPU, REF, BLK, CPU, REF, BLK, CPU, REF, BLK, CPU, REF, BLK, CPU, BLK, CPU, BLK, CPU, BLK, CPU, BLK, CPU, END };
static const int            body_blank_w34_cycles[]       = { 0,   8,   0,   7,   1,   0,   6,   2,   0,   6,   2,   0,   6,   2,   0,   6,   2,   0,   8,   0,   8,   0,   8,   0,   8,   0,   8,   0,   8,   0 }; // 96 cycles
static const antic_cycle_fn body_blank_w34_funcs[]        = { BLK, CPU, BLK, CPU, REF, BLK, CPU, REF, BLK, CPU, REF, BLK, CPU, REF, BLK, CPU, REF, BLK, CPU, BLK, CPU, BLK, CPU, BLK, CPU, BLK, CPU, BLK, CPU, END };

static const int            body_m25_first_w01_cycles[]   = { 64,  13,  0 }; // 77 cycles
static const antic_cycle_fn body_m25_first_w01_funcs[]    = { CHF, CPU, END };
static const int            body_m25_first_w2_cycles[]    = { 80,  5,   0 }; // 85 cycles
static const antic_cycle_fn body_m25_first_w2_funcs[]     = { CHF, CPU, END };
static const int            body_m25_first_w34_cycles[]   = { 96,  0,   -2,  0 }; // 94 cycles
static const antic_cycle_fn body_m25_first_w34_funcs[]    = { CHF, CPU, CPU, END };

static const int            body_chd4_w01_cycles[]        = { 4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   4,   4,   4,   4,   4,   4,   4+12,  0 }; // 76 cycles
static const antic_cycle_fn body_chd4_w01_funcs[]         = { CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, END };
static const int            body_chd4_w2_cycles[]         = { 4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   1,   3,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4+4,  0 }; // 84 cycles
static const antic_cycle_fn body_chd4_w2_funcs[]          = { CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, END };
static const int            body_chd4_w34_cycles[]        = { 4,   4,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   1,   3,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   -1,   0 }; // 91 cycles
static const antic_cycle_fn body_chd4_w34_funcs[]         = { CHD, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, END };

static const int            body_chf2_w01_cycles[]        = { 4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   4,   4,   4,   4,   4,   4,   4+16,  0 }; // 80 cycles
static const antic_cycle_fn body_chf2_w01_funcs[]         = { CHF, REF, CPU, CHF, REF, CPU, CHF, REF, CPU, CHF, REF, CPU, CHF, CPU, CHF, CPU, CHF, CPU, CHF, CPU, END };
static const int            body_chf2_w2_cycles[]         = { 4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   1,   3,   4,   4,   4,   4,   4,   4,   4,   4,   4,   12,  0 }; // 88 cycles
static const antic_cycle_fn body_chf2_w2_funcs[]          = { CHF, REF, CPU, CHF, REF, CPU, CHF, REF, CPU, CHF, REF, CPU, CHF, REF, CPU, CHF, CPU, CHF, CPU, CHF, CPU, CHF, CPU, CHF, CPU, END };
static const int            body_chf2_w34_cycles[]        = { 4,   4,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   1,   3,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4-1,   0 }; // 95 cycles
static const antic_cycle_fn body_chf2_w34_funcs[]         = { CHF, CPU, CHF, REF, CPU, CHF, REF, CPU, CHF, REF, CPU, CHF, REF, CPU, CHF, REF, CPU, CHF, CPU, CHF, CPU, CHF, CPU, CHF, CPU, CHF, CPU, CHF, CPU, END };

static const int            body_chd2_w01_cycles[]        = { 2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   6,   2,   6,   2,   6,   2,   18,  0 }; // 76 cycles
static const antic_cycle_fn body_chd2_w01_funcs[]         = { CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, END };
static const int            body_chd2_w2_cycles[]         = { 2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   1,   5,   2,   6,   2,   6,   2,   6,   2,   6,   2,   10,  0 }; // 84 cycles
static const antic_cycle_fn body_chd2_w2_funcs[]          = { CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, END };
static const int            body_chd2_w34_cycles[]        = { 2,   6,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   1,   5,   2,   6,   2,   6,   2,   6,   2,   6,   2,   6,   2,   2,   0 }; // 91 cycles
static const antic_cycle_fn body_chd2_w34_funcs[]         = { CHD, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, REF, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, CHD, CPU, END };

static const int            body_mrd1_w01_cycles[]        = { 1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   7,   1,   7,   1,   7,   1,   23,  0 }; // 80 cycles
static const antic_cycle_fn body_mrd1_w01_funcs[]         = { MRD, CPU, REF, CPU, MRD, CPU, REF, CPU, MRD, CPU, REF, CPU, MRD, CPU, REF, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, END };
static const int            body_mrd1_w2_cycles[]         = { 1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   1,   3,   1,   7,   1,   7,   1,   7,   1,   7,   1,   15,  0 }; // 88 cycles
static const antic_cycle_fn body_mrd1_w2_funcs[]          = { MRD, CPU, REF, CPU, MRD, CPU, REF, CPU, MRD, CPU, REF, CPU, MRD, CPU, REF, CPU, MRD, CPU, REF, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, END };
static const int            body_mrd1_w34_cycles[]        = { 1,   7,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   1,   3,   1,   7,   1,   7,   1,   7,   1,   7,   1,   7,   1,   7,   0 }; // 96 cycles
static const antic_cycle_fn body_mrd1_w34_funcs[]         = { MRD, CPU, MRD, CPU, REF, CPU, MRD, CPU, REF, CPU, MRD, CPU, REF, CPU, MRD, CPU, REF, CPU, MRD, CPU, REF, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, END };

//static const int            body_mdr1_w01_cycles[]        = { 1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   7,   1,   7,   1,   7,   1,   23,  0 }; // 80 cycles
static const int            body_mdr1_w01_cycles[]        = { 0,   4,   2,   2,   0,   4,   2,   2,   0,   4,   2,   2,   0,   4,   2,   2,   0,   8,   0,   8,   0,   8,   0,   24,  0 }; // 80 cycles
static const antic_cycle_fn body_mdr1_w01_funcs[]         = { MDR, CPU, REF, CPU, MDR, CPU, REF, CPU, MDR, CPU, REF, CPU, MDR, CPU, REF, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, END };
//static const int            body_mdr1_w2_cycles[]         = { 1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   1,   3,   1,   7,   1,   7,   1,   7,   1,   7,   1,   15,  0 }; // 88 cycles
static const int            body_mdr1_w2_cycles[]         = { 0,   4,   2,   2,   0,   4,   2,   2,   0,   4,   2,   2,   0,   4,   2,   2,   0,   4,   1,   3,   0,   8,   0,   8,   0,   8,   0,   8,   0,   16,  0 }; // 88 cycles
static const antic_cycle_fn body_mdr1_w2_funcs[]          = { MDR, CPU, REF, CPU, MDR, CPU, REF, CPU, MDR, CPU, REF, CPU, MDR, CPU, REF, CPU, MDR, CPU, REF, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, END };
//static const int            body_mdr1_w34_cycles[]        = { 1,   7,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   2,   2,   1,   3,   1,   3,   1,   7,   1,   7,   1,   7,   1,   7,   1,   7,   1,   7,   0 }; // 96 cycles
static const int            body_mdr1_w34_cycles[]        = { 0,   8,   0,   4,   2,   2,   0,   4,   2,   2,   0,   4,   2,   2,   0,   4,   2,   2,   0,   4,   1,   3,   0,   8,   0,   8,   0,   8,   0,   8,   0,   8,   0,   8,   0 }; // 96 cycles
static const antic_cycle_fn body_mdr1_w34_funcs[]         = { MDR, CPU, MDR, CPU, REF, CPU, MDR, CPU, REF, CPU, MDR, CPU, REF, CPU, MDR, CPU, REF, CPU, MDR, CPU, REF, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, END };

static const int            body_mrd2_w01_cycles[]        = { 2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   6,   2,   6,   2,   6,   2,   22,  0 }; // 80 cycles
static const antic_cycle_fn body_mrd2_w01_funcs[]         = { MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, END };
static const int            body_mrd2_w2_cycles[]         = { 2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   1,   5,   2,   6,   2,   6,   2,   6,   2,   6,   2,   14,  0 }; // 88 cycles
static const antic_cycle_fn body_mrd2_w2_funcs[]          = { MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, END };
static const int            body_mrd2_w34_cycles[]        = { 2,   6,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   1,   5,   2,   6,   2,   6,   2,   6,   2,   6,   2,   6,   2,   6,   0 }; // 96 cycles
static const antic_cycle_fn body_mrd2_w34_funcs[]         = { MRD, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, END };

//static const int            body_mdr2_w01_cycles[]        = { 2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   6,   2,   6,   2,   6,   2,   22,  0 }; // 80 cycles
static const int            body_mdr2_w01_cycles[]        = { 0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   8,   0,   8,   0,   8,   0,   24,  0 }; // 80 cycles
static const antic_cycle_fn body_mdr2_w01_funcs[]         = { MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, END };
//static const int            body_mdr2_w2_cycles[]         = { 2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   1,   5,   2,   6,   2,   6,   2,   6,   2,   6,   2,   14,  0 }; // 88 cycles
static const int            body_mdr2_w2_cycles[]         = { 0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   1,   7,   0,   8,   0,   8,   0,   8,   0,   8,   0,   16,  0 }; // 88 cycles
static const antic_cycle_fn body_mdr2_w2_funcs[]          = { MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, END };
//static const int            body_mdr2_w34_cycles[]        = { 2,   6,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   1,   5,   2,   6,   2,   6,   2,   6,   2,   6,   2,   6,   2,   6,   0 }; // 96 cycles
static const int            body_mdr2_w34_cycles[]        = { 0,   8,   0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   1,   7,   0,   8,   0,   8,   0,   8,   0,   8,   0,   8,   0,   8,   0 }; // 96 cycles
static const antic_cycle_fn body_mdr2_w34_funcs[]         = { MDR, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, END };

static const int            body_mrd4_w01_cycles[]        = { 4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   4,   4,   4,   4,   4,   4,   20,  0 }; // 80 cycles
static const antic_cycle_fn body_mrd4_w01_funcs[]         = { MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, END };
static const int            body_mrd4_w2_cycles[]         = { 4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   1,   6,   4,   1,   4,   4,   4,   4,   4,   4,   4,   12,  0 }; // 88 cycles edit three cycle after last ref Atariblast
static const antic_cycle_fn body_mrd4_w2_funcs[]          = { MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, END };
static const int            body_mrd4_w34_cycles[]        = { 4,   4,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   1,   3,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   0 }; // 96 cycles
static const antic_cycle_fn body_mrd4_w34_funcs[]         = { MRD, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, REF, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, MRD, CPU, END };

//static const int            body_mdr4_w01_cycles[]        = { 4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   4,   4,   4,   4,   4,   4,   20,  0 }; // 80 cycles
static const int            body_mdr4_w01_cycles[]        = { 0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   8,   0,   8,   0,   8,   0,   24,  0 }; // 80 cycles
static const antic_cycle_fn body_mdr4_w01_funcs[]         = { MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, END };
//static const int            body_mdr4_w2_cycles[]         = { 4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   1,   3,   4,   4,   4,   4,   4,   4,   4,   4,   4,   12,  0 }; // 88 cycles
static const int            body_mdr4_w2_cycles[]         = { 0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   1,   7,   0,   8,   0,   8,   0,   8,   0,   8,   0,   16,  0 }; // 88 cycles
static const antic_cycle_fn body_mdr4_w2_funcs[]          = { MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, END };
//static const int            body_mdr4_w34_cycles[]        = { 4,   4,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   2,   2,   4,   1,   3,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   4,   0 }; // 96 cycles
static const int            body_mdr4_w34_cycles[]        = { 0,   8,   0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   2,   6,   0,   1,   7,   0,   8,   0,   8,   0,   8,   0,   8,   0,   8,   0,   8,   0 }; // 96 cycles
static const antic_cycle_fn body_mdr4_w34_funcs[]         = { MDR, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, REF, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, MDR, CPU, END };

static const antic_cycle_row body_blank_rows[5] = {
    ANTIC_ROW ( body_blank_w01_cycles, body_blank_w01_funcs ), ANTIC_ROW ( body_blank_w01_cycles, body_blank_w01_funcs ), ANTIC_ROW ( body_blank_w2_cycles, body_blank_w2_funcs ), ANTIC_ROW ( body_blank_w34_cycles, body_blank_w34_funcs ), ANTIC_ROW ( body_blank_w34_cycles, body_blank_w34_funcs )
};
static const antic_cycle_row body_m25_first_rows[5] = {
    ANTIC_ROW ( body_m25_first_w01_cycles, body_m25_first_w01_funcs ), ANTIC_ROW ( body_m25_first_w01_cycles, body_m25_first_w01_funcs ), ANTIC_ROW ( body_m25_first_w2_cycles, body_m25_first_w2_funcs ), ANTIC_ROW ( body_m25_first_w34_cycles, body_m25_first_w34_funcs ), ANTIC_ROW ( body_m25_first_w34_cycles, body_m25_first_w34_funcs )
};
static const antic_cycle_row body_chd4_rows[5] = {
    ANTIC_ROW ( body_chd4_w01_cycles, body_chd4_w01_funcs ), ANTIC_ROW ( body_chd4_w01_cycles, body_chd4_w01_funcs ), ANTIC_ROW ( body_chd4_w2_cycles, body_chd4_w2_funcs ), ANTIC_ROW ( body_chd4_w34_cycles, body_chd4_w34_funcs ), ANTIC_ROW ( body_chd4_w34_cycles, body_chd4_w34_funcs )
};
static const antic_cycle_row body_chf2_rows[5] = {
    ANTIC_ROW ( body_chf2_w01_cycles, body_chf2_w01_funcs ), ANTIC_ROW ( body_chf2_w01_cycles, body_chf2_w01_funcs ), ANTIC_ROW ( body_chf2_w2_cycles, body_chf2_w2_funcs ), ANTIC_ROW ( body_chf2_w34_cycles, body_chf2_w34_funcs ), ANTIC_ROW ( body_chf2_w34_cycles, body_chf2_w34_funcs )
};
static const antic_cycle_row body_chd2_rows[5] = {
    ANTIC_ROW ( body_chd2_w01_cycles, body_chd2_w01_funcs ), ANTIC_ROW ( body_chd2_w01_cycles, body_chd2_w01_funcs ), ANTIC_ROW ( body_chd2_w2_cycles, body_chd2_w2_funcs ), ANTIC_ROW ( body_chd2_w34_cycles, body_chd2_w34_funcs ), ANTIC_ROW ( body_chd2_w34_cycles, body_chd2_w34_funcs )
};
static const antic_cycle_row body_mrd1_rows[5] = {
    ANTIC_ROW ( body_mrd1_w01_cycles, body_mrd1_w01_funcs ), ANTIC_ROW ( body_mrd1_w01_cycles, body_mrd1_w01_funcs ), ANTIC_ROW ( body_mrd1_w2_cycles, body_mrd1_w2_funcs ), ANTIC_ROW ( body_mrd1_w34_cycles, body_mrd1_w34_funcs ), ANTIC_ROW ( body_mrd1_w34_cycles, body_mrd1_w34_funcs )
};
static const antic_cycle_row body_mdr1_rows[5] = {
    ANTIC_ROW ( body_mdr1_w01_cycles, body_mdr1_w01_funcs ), ANTIC_ROW ( body_mdr1_w01_cycles, body_mdr1_w01_funcs ), ANTIC_ROW ( body_mdr1_w2_cycles, body_mdr1_w2_funcs ), ANTIC_ROW ( body_mdr1_w34_cycles, body_mdr1_w34_funcs ), ANTIC_ROW ( body_mdr1_w34_cycles, body_mdr1_w34_funcs )
};
static const antic_cycle_row body_mrd2_rows[5] = {
    ANTIC_ROW ( body_mrd2_w01_cycles, body_mrd2_w01_funcs ), ANTIC_ROW ( body_mrd2_w01_cycles, body_mrd2_w01_funcs ), ANTIC_ROW ( body_mrd2_w2_cycles, body_mrd2_w2_funcs ), ANTIC_ROW ( body_mrd2_w34_cycles, body_mrd2_w34_funcs ), ANTIC_ROW ( body_mrd2_w34_cycles, body_mrd2_w34_funcs )
};
static const antic_cycle_row body_mdr2_rows[5] = {
    ANTIC_ROW ( body_mdr2_w01_cycles, body_mdr2_w01_funcs ), ANTIC_ROW ( body_mdr2_w01_cycles, body_mdr2_w01_funcs ), ANTIC_ROW ( body_mdr2_w2_cycles, body_mdr2_w2_funcs ), ANTIC_ROW ( body_mdr2_w34_cycles, body_mdr2_w34_funcs ), ANTIC_ROW ( body_mdr2_w34_cycles, body_mdr2_w34_funcs )
};
static const antic_cycle_row body_mrd4_rows[5] = {
    ANTIC_ROW ( body_mrd4_w01_cycles, body_mrd4_w01_funcs ), ANTIC_ROW ( body_mrd4_w01_cycles, body_mrd4_w01_funcs ), ANTIC_ROW ( body_mrd4_w2_cycles, body_mrd4_w2_funcs ), ANTIC_ROW ( body_mrd4_w34_cycles, body_mrd4_w34_funcs ), ANTIC_ROW ( body_mrd4_w34_cycles, body_mrd4_w34_funcs )
};
static const antic_cycle_row body_mdr4_rows[5] = {
    ANTIC_ROW ( body_mdr4_w01_cycles, body_mdr4_w01_funcs ), ANTIC_ROW ( body_mdr4_w01_cycles, body_mdr4_w01_funcs ), ANTIC_ROW ( body_mdr4_w2_cycles, body_mdr4_w2_funcs ), ANTIC_ROW ( body_mdr4_w34_cycles, body_mdr4_w34_funcs ), ANTIC_ROW ( body_mdr4_w34_cycles, body_mdr4_w34_funcs )
};

static void antic_install_mode_rows ( int mode, const antic_cycle_row *first,
                                      const antic_cycle_row *normal,
                                      const antic_cycle_row *last,
                                      const antic_cycle_row *first_last ) {

    int width;

    for ( width = 0; width < 5; ++width ) {
        antic_install_cycle_rows ( width, mode, ML_FIRST,
                                   &start_rows[ML_FIRST][width], &first[width] );
        antic_install_cycle_rows ( width, mode, ML_NORMAL,
                                   &start_rows[ML_NORMAL][width], &normal[width] );
        antic_install_cycle_rows ( width, mode, ML_LAST,
                                   &start_rows[ML_LAST][width], &last[width] );
        antic_install_cycle_rows ( width, mode, ML_FIRST_LAST,
                                   &start_rows[ML_FIRST_LAST][width], &first_last[width] );
    }

} /* end antic_install_mode_rows */

static void antic_install_blank_mode_rows ( int mode ) {

    int width;

    for ( width = 0; width < 5; ++width ) {
        antic_install_cycle_rows ( width, mode, ML_FIRST,
                                   &start_rows[ML_FIRST][width],
                                   &body_blank_rows[width] );
        antic_install_cycle_rows ( width, mode, ML_NORMAL,
                                   &start_normal_mrd_rows[width],
                                   &body_blank_rows[width] );
        antic_install_cycle_rows ( width, mode, ML_LAST,
                                   &start_last_mrd_rows[width],
                                   &body_blank_rows[width] );
        antic_install_cycle_rows ( width, mode, ML_FIRST_LAST,
                                   &start_rows[ML_FIRST_LAST][width],
                                   &body_blank_rows[width] );
    }

} /* end antic_install_blank_mode_rows */

void antic_create_cycle_maps ( void ) {

    int width;

    antic_clear_cycle_maps ();

    /*
     * The cycle rows keep the current callback grouping intact. 
     */
    antic_install_blank_mode_rows ( MODE_BLANK );
    antic_install_blank_mode_rows ( 1 );

    for ( width = 0; width < 5; ++width ) {
        antic_install_cycle_rows ( width, MODE_2_TO_5, ML_FIRST,
                                   &mode25_first_rows[width],
                                   &body_m25_first_rows[width] );
        antic_install_cycle_rows ( width, MODE_2_TO_5, ML_NORMAL,
                                   &start_rows[ML_NORMAL][width],
                                   &body_chd4_rows[width] );
        antic_install_cycle_rows ( width, MODE_2_TO_5, ML_LAST,
                                   &start_rows[ML_LAST][width],
                                   &body_chd4_rows[width] );
        antic_install_cycle_rows ( width, MODE_2_TO_5, ML_FIRST_LAST,
                                   &mode25_first_last_rows[width],
                                   &body_m25_first_rows[width] );
    }

    antic_install_mode_rows ( MODE_6_7, body_chf2_rows, body_chd2_rows,
                              body_chd2_rows, body_chf2_rows );
    for ( width = 0; width < 5; ++width ) {
        antic_install_cycle_rows ( width, MODE_8_9, ML_FIRST,
                                   &start_rows[ML_FIRST][width],
                                   &body_mrd1_rows[width] );
        antic_install_cycle_rows ( width, MODE_8_9, ML_NORMAL,
                                   &start_normal_mrd_rows[width],
                                   &body_mdr1_rows[width] );
        antic_install_cycle_rows ( width, MODE_8_9, ML_LAST,
                                   &start_last_mrd_rows[width],
                                   &body_mdr1_rows[width] );
        antic_install_cycle_rows ( width, MODE_8_9, ML_FIRST_LAST,
                                   &start_rows[ML_FIRST_LAST][width],
                                   &body_mrd1_rows[width] );
    }
    for ( width = 0; width < 5; ++width ) {
        antic_install_cycle_rows ( width, MODE_A_B_C, ML_FIRST,
                                   &start_rows[ML_FIRST][width],
                                   &body_mrd2_rows[width] );
        antic_install_cycle_rows ( width, MODE_A_B_C, ML_NORMAL,
                                   &start_normal_mrd_rows[width],
                                   &body_mdr2_rows[width] );
        antic_install_cycle_rows ( width, MODE_A_B_C, ML_LAST,
                                   &start_last_mrd_rows[width],
                                   &body_mdr2_rows[width] );
        antic_install_cycle_rows ( width, MODE_A_B_C, ML_FIRST_LAST,
                                   &start_rows[ML_FIRST_LAST][width],
                                   &body_mrd2_rows[width] );
    }
    for ( width = 0; width < 5; ++width ) {
        antic_install_cycle_rows ( width, MODE_D_E, ML_FIRST,
                                   &start_rows[ML_FIRST][width],
                                   &body_mrd4_rows[width] );
        antic_install_cycle_rows ( width, MODE_D_E, ML_NORMAL,
                                   &start_normal_mrd_rows[width],
                                   &body_mdr4_rows[width] );
        antic_install_cycle_rows ( width, MODE_D_E, ML_LAST,
                                   &start_last_mrd_rows[width],
                                   &body_mdr4_rows[width] );
        antic_install_cycle_rows ( width, MODE_D_E, ML_FIRST_LAST,
                                   &start_rows[ML_FIRST_LAST][width],
                                   &body_mrd4_rows[width] );
    }
    for ( width = 0; width < 5; ++width ) {
        antic_install_cycle_rows ( width, MODE_F, ML_FIRST,
                                   &start_rows[ML_FIRST][width],
                                   &body_mrd4_rows[width] );
        antic_install_cycle_rows ( width, MODE_F, ML_NORMAL,
                                   &start_normal_mrd_rows[width],
                                   &body_mdr4_rows[width] );
        antic_install_cycle_rows ( width, MODE_F, ML_LAST,
                                   &start_last_mrd_rows[width],
                                   &body_mdr4_rows[width] );
        antic_install_cycle_rows ( width, MODE_F, ML_FIRST_LAST,
                                   &start_rows[ML_FIRST_LAST][width],
                                   &body_mrd4_rows[width] );
    }

    antic_init_hscroll_tables ();
    antic_dump_cycle_maps ( getenv ( "KAT5200_CYCLE_MAP_DUMP" ) );

} /* end antic_create_cycle_maps */

static void antic_dump_cycle_maps ( const char *path ) {

    FILE *fp;
    int width;
    int mode;
    int line;
    int i;

    if ( !path || !*path )
        return;

    fp = fopen ( path, "w" );
    if ( !fp )
        return;

    for ( width = 0; width < 5; ++width ) {
        for ( mode = 0; mode < MAX_INSTR; ++mode ) {
            for ( line = 0; line < MAX_MODE_LINES; ++line ) {
                if ( !antic.dl_map[width][mode][line][0] )
                    continue;

                fprintf ( fp, "width=%d mode=%d line=%d cycles=", width, mode, line );
                for ( i = 0; i < MAX_CHANGES && antic.dl_map[width][mode][line][i]; ++i )
                    fprintf ( fp, "%s%d", i ? "," : "", antic.dl_cycles[width][mode][line][i] );

                fprintf ( fp, " funcs=" );
                for ( i = 0; i < MAX_CHANGES && antic.dl_map[width][mode][line][i]; ++i )
                    fprintf ( fp, "%s%s", i ? "," : "", antic_cycle_fn_name ( antic.dl_map[width][mode][line][i] ) );
                fprintf ( fp, "\n" );
            }
        }
    }

    antic_dump_hscroll_cycle_values ( fp );

    fclose ( fp );

} /* end antic_dump_cycle_maps */

static int *antic_find_previous_cpu_cycle_ptr ( int width, int mode,
                                                int line, int before_index ) {

    int i;

    for ( i = before_index - 1; i >= 0; --i ) {
        if ( antic.dl_map[width][mode][line][i] == &antic.run_6502_ptr )
            return &antic.dl_cycles[width][mode][line][i];
    }

    return 0;

} /* end antic_find_previous_cpu_cycle_ptr */

static int antic_hscroll_ml_type ( void ) {

    if ( antic.mode_line <= 0 ) {
        if ( (antic.dl_current_byte & 0x80) && antic.num_lines <= 1 )
            return ML_FIRST_LAST;
        return ML_FIRST;
    }

    if ( (antic.dl_current_byte & 0x80) &&
         antic.mode_line == antic.num_lines - 1 )
        return ML_LAST;

    return ML_NORMAL;

} /* end antic_hscroll_ml_type */

static void antic_init_hscroll_tables ( void ) {

    int width;
    int mode;
    int line;
    int i;

    memset ( antic_hscroll_cycle_ptr, 0, sizeof ( antic_hscroll_cycle_ptr ) );
    memset ( antic_hscroll_active_ptr, 0, sizeof ( antic_hscroll_active_ptr ) );
    antic_hscroll_active_values = 0;

    for ( width = 0; width < 5; ++width ) {
        for ( mode = MODE_2_TO_5; mode < MAX_INSTR; ++mode ) {
            for ( line = 0; line < 4; ++line ) {
                if ( !antic.dl_map[width][mode][line][0] )
                    continue;

                for ( i = 1; i < MAX_CHANGES &&
                            antic.dl_map[width][mode][line][i]; ++i ) {
                    if ( antic.dl_map[width][mode][line][i] ==
                         &antic.antic_init_scanline_ptr ) {
                        antic_hscroll_cycle_ptr[width][mode][line][HSCROLL_BEGIN] =
                            antic_find_previous_cpu_cycle_ptr ( width, mode, line, i );
                    }
                    else if ( antic.dl_map[width][mode][line][i] ==
                              &antic.antic_end_scanline_ptr ) {
                        antic_hscroll_cycle_ptr[width][mode][line][HSCROLL_END] =
                            antic_find_previous_cpu_cycle_ptr ( width, mode, line, i );
                    }
                }

            }
        }
    }

} /* end antic_init_hscroll_tables */

static void antic_dump_hscroll_cycle_values ( FILE *fp ) {

    int width;
    int mode;
    int line;
    int hscroll;

    fprintf ( fp, "\n[hscroll_cycle_values]\n" );
    for ( width = 0; width < 5; ++width ) {
        for ( mode = MODE_2_TO_5; mode < MAX_INSTR; ++mode ) {
            for ( line = 0; line < 4; ++line ) {
                int *begin_ptr = antic_hscroll_cycle_ptr[width][mode][line][HSCROLL_BEGIN];
                int *end_ptr = antic_hscroll_cycle_ptr[width][mode][line][HSCROLL_END];

                if ( !begin_ptr || !end_ptr )
                    continue;

                fprintf ( fp,
                          "width=%d mode=%d line=%d begin_index=%ld end_index=%ld values=",
                          width, mode, line,
                          (long)(begin_ptr - antic.dl_cycles[width][mode][line]),
                          (long)(end_ptr - antic.dl_cycles[width][mode][line]) );

                for ( hscroll = 0; hscroll < HSCROLL_STEPS; ++hscroll ) {
                    fprintf ( fp, "%s%d:%d/%d", hscroll ? "," : "",
                              hscroll,
                              antic_hscroll_cycle_values[width][mode][line][hscroll][HSCROLL_BEGIN],
                              antic_hscroll_cycle_values[width][mode][line][hscroll][HSCROLL_END] );
                }
                fprintf ( fp, "\n" );
            }
        }
    }

} /* end antic_dump_hscroll_cycle_values */

void antic_apply_hscroll ( void ) {

    int mode;
    int mode_type;
    int ml_type;
    int width;
    int hscroll_index;
    int *begin_ptr;
    int *end_ptr;
    const int ( *values )[2];

    mode = antic.dl_current_byte & 0x0f;
    if ( mode <= 1 )
        return;

    if ( antic_hscroll_active_ptr[HSCROLL_BEGIN] )
        return;

    if ( !(antic.dl_current_byte & 0x10) || !antic.pl_width )
        return;

    hscroll_index = ( antic.hscroll_reg_value >> 2 ) & 0x7;
    if ( !hscroll_index )
        return;

    width = antic.width_array;
    if ( width >= 5 )
        return;

    mode_type = antic_mode_to_type[mode];
    ml_type = antic_hscroll_ml_type ();

    begin_ptr = antic_hscroll_cycle_ptr[width][mode_type][ml_type][HSCROLL_BEGIN];
    end_ptr = antic_hscroll_cycle_ptr[width][mode_type][ml_type][HSCROLL_END];
    //if ( !begin_ptr || !end_ptr )
    //    return;

    values = antic_hscroll_cycle_values[width][mode_type][ml_type];
    *begin_ptr = values[hscroll_index][HSCROLL_BEGIN];
    *end_ptr = values[hscroll_index][HSCROLL_END];

    antic_hscroll_active_ptr[HSCROLL_BEGIN] = begin_ptr;
    antic_hscroll_active_ptr[HSCROLL_END] = end_ptr;
    antic_hscroll_active_values = values;

} /* end antic_apply_hscroll */

void antic_restore_hscroll ( void ) {

    if ( !antic_hscroll_active_ptr[HSCROLL_BEGIN] ||
         !antic_hscroll_active_values )
        return;

    *antic_hscroll_active_ptr[HSCROLL_BEGIN] =
        antic_hscroll_active_values[0][HSCROLL_BEGIN];
    *antic_hscroll_active_ptr[HSCROLL_END] =
        antic_hscroll_active_values[0][HSCROLL_END];

    antic_hscroll_active_ptr[HSCROLL_BEGIN] = 0;
    antic_hscroll_active_ptr[HSCROLL_END] = 0;
    antic_hscroll_active_values = 0;

} /* end antic_restore_hscroll */
