/*      $NetBSD: grfabs_cc.c,v 1.39 2023/07/12 05:16:42 mlelstv Exp $ */

/*
* Copyright (c) 1994 Christian E. Hopps
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*      This product includes software developed by Christian E. Hopps.
* 4. The name of the author may not be used to endorse or promote products
*    derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
*  abstract interface for custom chips to the amiga abstract graphics driver.
*
*/

#include "opt_amigaccgrf.h"

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: grfabs_cc.c,v 1.39 2023/07/12 05:16:42 mlelstv Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/queue.h>
#include <sys/intr.h>

#include <amiga/amiga/custom.h>
#include <amiga/amiga/cc.h>

#include <amiga/dev/grfabs_reg.h>
#include <amiga/dev/grfabs_ccreg.h>

monitor_t *m_this;
mdata_t *m_this_data;
const char *monitor_name = "CCMONITOR";
monitor_t monitor;
mdata_t monitor_data;
cop_t  *null_mode_copper_list;

#if defined (GRF_PAL)
#  if defined (GRF_A2024)
dmode_t pal_a2024_mode;
dmdata_t pal_a2024_mode_data;
cop_t  *pal_a2024_frames[F_QD_TOTAL];
u_char *hedley_init;            /* init bitplane. */
dmode_t *p24_this;
dmdata_t *p24_this_data;

dmode_t pal_hires_dlace_mode;
dmdata_t pal_hires_dlace_mode_data;
cop_t  *pal_hires_dlace_frames[F_LACE_TOTAL];
dmode_t *phdl_this;
dmdata_t *phdl_this_data;
#  endif /* GRF_A2024 */

#  if defined (GRF_AGA)
dmode_t paga_mode;
dmdata_t paga_mode_data;
cop_t *paga_frames[F_TOTAL];
dmode_t *paga_this;
dmdata_t *paga_this_data;

#  endif /* GRF_AGA */

dmode_t pal_hires_lace_mode;
dmdata_t pal_hires_lace_mode_data;
cop_t  *pal_hires_lace_frames[F_LACE_TOTAL];
dmode_t *phl_this;
dmdata_t *phl_this_data;

dmode_t pal_hires_mode;
dmdata_t pal_hires_mode_data;
cop_t  *pal_hires_frames[F_TOTAL];
dmode_t *ph_this;
dmdata_t *ph_this_data;
#endif /* PAL */

#if defined (GRF_NTSC)
#  if defined (GRF_A2024)
dmode_t a2024_mode;
dmdata_t a2024_mode_data;
cop_t  *a2024_frames[F_QD_TOTAL];
u_char *hedley_init;            /* init bitplane. */
dmode_t *a24_this;
dmdata_t *a24_this_data;

dmode_t hires_dlace_mode;
dmdata_t hires_dlace_mode_data;
cop_t  *hires_dlace_frames[F_LACE_TOTAL];
dmode_t *hdl_this;
dmdata_t *hdl_this_data;
#  endif /* GRF_A2024 */

#  if defined (GRF_AGA)
dmode_t aga_mode;
dmdata_t aga_mode_data;
cop_t *aga_frames[F_TOTAL];
dmode_t *aga_this;
dmdata_t *aga_this_data;

#if defined (GRF_SUPER72)
dmode_t super72_mode;
dmdata_t super72_mode_data;
cop_t *super72_frames[F_LACE_TOTAL];
dmode_t *super72_this;
dmdata_t *super72_this_data;
#endif /* GRF_SUPER72 */

#  endif /* GRF_AGA */

dmode_t hires_lace_mode;
dmdata_t hires_lace_mode_data;
cop_t  *hires_lace_frames[F_LACE_TOTAL];
dmode_t *hl_this;
dmdata_t *hl_this_data;

void    display_hires_view(view_t * v);
dmode_t hires_mode;
dmdata_t hires_mode_data;
cop_t  *hires_frames[F_TOTAL];
dmode_t *h_this;
dmdata_t *h_this_data;
#endif /* GRF_NTSC */

#ifdef GRF_AGA
#define AGA_ENABLE      0x0001
#define AGA_ENABLE2     0x0002
#define AGA_TRACE       0x0004
#define AGA_TRACE2      0x0008
#define AGA_VGAONLY     0x0010
#define AGA_VGA31KHZ    0x0020

int aga_enable = 0;     /* set by start_c(), or can be patched */
colormap_t *cc_alloc_aga_colormap(int);
int cc_use_aga_colormap(view_t *, colormap_t *);
#endif

/* monitor functions. */
monitor_t *
cc_init_monitor(void)
{
       cop_t  *cp;

       if (m_this)
               return(m_this);

       cc_monitor = m_this = &monitor;
       /* turn sprite DMA off. we don't support them yet. */
       custom.dmacon = DMAF_SPRITE;

       /* make sure sprite data registers are clear as well */
       custom.spr[0].data = 0;
       custom.spr[0].datb = 0;

       m_this->name = monitor_name;
       m_this_data = m_this->data = &monitor_data;

       m_this->get_current_mode = get_current_mode;
       m_this->vbl_handler = (vbl_handler_func *) monitor_vbl_handler;
       m_this->get_next_mode = get_next_mode;
       m_this->get_best_mode = get_best_mode;

       m_this->alloc_bitmap = alloc_bitmap;
       m_this->free_bitmap = free_bitmap;

       m_this_data->current_mode = NULL;
       LIST_INIT(&m_this_data->modes);

       cp = null_mode_copper_list = alloc_chipmem(sizeof(cop_t) * 4);
       if (!cp)
               panic("no chipmem for grf.");

       CMOVE(cp, R_COLOR00, 0x0000);   /* background is black */
       CMOVE(cp, R_BPLCON0, 0x0000);   /* no planes to fetch from */
       CWAIT(cp, 255, 255);    /* COPEND */
       CWAIT(cp, 255, 255);    /* COPEND really */

       /* install this list and turn DMA on */
       custom.cop1lc = PREP_DMA_MEM(null_mode_copper_list);
       custom.copjmp1 = 0;
       custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER \
           |DMAF_COPPER;

       cc_init_modes();
       LIST_INSERT_HEAD(monitors, m_this, link);
       return (m_this);
}

void
monitor_vbl_handler(monitor_t *m)
{
       dmdata_t *dmd;

       if (m_this_data->current_mode == NULL)
               return;

       dmd = DMDATA(m_this_data->current_mode);
       if (dmd)
               dmd->vbl_handler(m_this_data->current_mode);
}

dmode_t *
get_current_mode(void)
{
       if (m_this_data->current_mode)
               return(m_this_data->current_mode);
       else
               return(NULL);
}

dmode_t *
get_next_mode(dmode_t *d)
{
       if (d)
               return(d->link.le_next);
       return(m_this_data->modes.lh_first);
}

/* XXX needs to have more control attributes */
dmode_t *
get_best_mode(dimen_t *size, u_char depth)
{
       dmode_t *save;
       dmode_t *dm;
       long    dt = 0, dx, dy, ct;
       dmdata_t *dmd;

       save = NULL;
       dm = m_this_data->modes.lh_first;
       while (dm != NULL) {
               dmd = dm->data;
               if (depth > dmd->max_depth || depth < dmd->min_depth) {
                       dm = dm->link.le_next;
                       continue;
               } else if (size->width > dmd->max_size.width ||
                   size->height > dmd->max_size.height) {
                       dm = dm->link.le_next;
                       continue;
               } else if (size->width < dmd->min_size.width ||
                   size->height < dmd->min_size.height) {
                       dm = dm->link.le_next;
                       continue;
               }
               dx = abs(dm->nominal_size.width - size->width);
               dy = abs(dm->nominal_size.height - size->height);
               ct = dx + dy;

               if (ct < dt || save == NULL) {
                       save = dm;
                       dt = ct;
               }
               dm = dm->link.le_next;
       }
       return (save);
}
/* bitmap functions */
bmap_t *
alloc_bitmap(u_short width, u_short height, u_short depth, u_short flags)
{
       int     i;
       u_long  total_size;
#ifdef GRF_AGA
       u_short lwpr = (flags & BMF_ALIGN64) ? ((width + 63) / 64) * 2 :
           (width + 31) / 32;                  /* AGA needs 64 bit align */
#else
       u_short lwpr = (width + 31) / 32;
#endif
       u_short wpr = lwpr << 1;
       u_short bpr = wpr << 1;
       u_short array_size = sizeof(u_char *) * depth;
       u_long  plane_size = bpr * height;
       u_short temp_size = bpr + sizeof(u_long);
       bmap_t *bm;

       /* note the next allocation will give everything, also note that all
        * the stuff we want (including bitmaps) will be long short aligned.
        * This is a function of the data being allocated and the fact that
        * alloc_chipmem() returns long short aligned data. note also that
        * each row of the bitmap is long word aligned and made of exactly n
        * longwords. -ch */

       /* Sigh, it seems for mapping to work we need the bitplane data to 1:
        * be aligned on a page boundary. 2: be n pages large.
        *
        * why? because the user gets a page aligned address, if this is before
        * your allocation, too bad.  Also it seems that the mapping routines
        * do not watch to closely to the allowable length. so if you go over
        * n pages by less than another page, the user gets to write all over
        * the entire page.  Since you did not allocate up to a page boundary
        * (or more) the user writes into someone elses memory. -ch */
#ifdef __powerpc__
#define m68k_round_page(x)      ((((unsigned)(x)) + PGOFSET) & ~PGOFSET)
#endif
       total_size = m68k_round_page(plane_size * depth) +      /* for length */
           (temp_size) + (array_size) + sizeof(bmap_t) +
           PAGE_SIZE;          /* for alignment */
       bm = alloc_chipmem(total_size);
       if (bm) {
               if (flags & BMF_CLEAR) {
                       memset(bm, 0, total_size);
               }
               bm->bytes_per_row = bpr;
               bm->rows = height;
               bm->depth = depth;
               bm->flags = flags;
               bm->plane = (u_char **) & bm[1];
               bm->blit_temp = ((u_char *) bm->plane) + array_size;
               bm->plane[0] = (u_char *) m68k_round_page((u_long)
                                               (bm->blit_temp + temp_size));
               if (flags & BMF_INTERLEAVED) {
                       bm->row_mod = bm->bytes_per_row * (depth - 1);
                       for (i = 1; i < depth; i++) {
                               bm->plane[i] = bm->plane[i - 1] + bpr;
                       }
               } else {
                       bm->row_mod = 0;
                       for (i = 1; i < depth; i++) {
                               bm->plane[i] = bm->plane[i - 1] + plane_size;
                       }
               }
               bm->hardware_address = PREP_DMA_MEM(bm->plane[0]);
               return (bm);
       }
       return (NULL);
}


void
free_bitmap(bmap_t *bm)
{
       if (bm)
               free_chipmem(bm);
}
/* load a new mode into the current display, if NULL shut display off. */
void
cc_load_mode(dmode_t *d)
{
       if (d) {
               m_this_data->current_mode = d;
#ifdef __powerpc__      /* XXX ???? */
               custom.cop1lc = PREP_DMA_MEM(DMDATA(d)->frames[F_LONG]);
               custom.copjmp1 = 0;
#endif
               return;
       }
       /* turn off display */
       m_this_data->current_mode = NULL;
       wait_tof();
       wait_tof();
       custom.cop1lc = PREP_DMA_MEM(null_mode_copper_list);
       custom.copjmp1 = 0;
}
/*
* CC Mode Stuff.
*/

dmode_t *(*mode_init_funcs[]) (void) = {
#if defined (GRF_NTSC)
#if defined (GRF_A2024)
       cc_init_ntsc_a2024,
       cc_init_ntsc_hires_dlace,
#endif /* GRF_A2024 */
       cc_init_ntsc_hires_lace,
       cc_init_ntsc_hires,
#if defined (GRF_AGA)
       cc_init_ntsc_aga,
#if defined (GRF_SUPER72)
       cc_init_super72,
#endif /* GRF_SUPER72 */
#endif /* GRF_AGA */
#endif /* GRF_NTSC */
#if defined (GRF_PAL)
#if defined (GRF_A2024)
       cc_init_pal_a2024,
       cc_init_pal_hires_dlace,
#endif /* GRF_A2024 */
       cc_init_pal_hires_lace,
       cc_init_pal_hires,
#if defined (GRF_AGA)
       cc_init_pal_aga,
#endif /* GRF_AGA */
#endif /* GRF_PAL */
       NULL
};

int
cc_init_modes(void)
{
       int     i = 0;
       int     error = 0;
       while (mode_init_funcs[i]) {
               mode_init_funcs[i] ();
               i++;
       }
       return (error);
}

monitor_t *
cc_get_monitor(dmode_t *d)
{
       return (DMDATA(d)->monitor);
}

view_t *
cc_get_current_view(dmode_t *d)
{
       return (DMDATA(d)->current_view);
}


view_t *
cc_alloc_view(dmode_t *mode, dimen_t *dim, u_char depth)
{
       view_t *v = alloc_chipmem(sizeof(*v) + sizeof(vdata_t));
       if (v) {
               bmap_t *bm = cc_monitor->alloc_bitmap(dim->width, dim->height,
                   depth, BMF_CLEAR | (DMDATA(mode)->max_depth == 8 ? BMF_ALIGN64 : 0));
               if (bm) {
                       box_t   box;

                       v->data = &v[1];        /* at the end of view */
                       VDATA(v)->colormap = DMDATA(mode)->alloc_colormap(depth);
                       if (VDATA(v)->colormap) {
                               INIT_BOX(&box, 0, 0, dim->width, dim->height);
                               cc_init_view(v, bm, mode, &box);
                               return (v);
                       }
                       cc_monitor->free_bitmap(bm);
               }
               free_chipmem(v);
       }
       return (NULL);
}

colormap_t *
cc_alloc_colormap(int depth)
{
       u_long  size = 1U << depth, i;
       colormap_t *cm = alloc_chipmem(sizeof(u_long) * size + sizeof(*cm));

       if (cm) {
               cm->type = CM_COLOR;
               cm->red_mask = 0x0F;
               cm->green_mask = 0x0F;
               cm->blue_mask = 0x0F;
               cm->first = 0;
               cm->size = size;
               cm->entry = (u_long *) & cm[1]; /* table directly after. */
               for (i = 0; i < size; i++) {
                       cm->entry[i] = CM_WTOL(cc_default_colors[i&31]);
               }
               return (cm);
       }
       return (NULL);
}

#ifdef GRF_AGA
colormap_t *
cc_alloc_aga_colormap(int depth)
{
       u_long  size = 1U << depth, i;
       colormap_t *cm = alloc_chipmem(sizeof(u_long) * size + sizeof(*cm));

       if (cm) {
               cm->type = CM_COLOR;
               cm->red_mask = 0x0FF;
               cm->green_mask = 0x0FF;
               cm->blue_mask = 0x0FF;
               cm->first = 0;
               cm->size = size;
               cm->entry = (u_long *) & cm[1]; /* table directly after. */
               for (i = 0; i < size; i++) {
                       cm->entry[i] = CM_WTOL(cc_default_colors[i&31]) |
                           (CM_WTOL(cc_default_colors[i&31]) << 4);
               }
               return (cm);
       }
       return (NULL);
}
#endif

int
cc_colormap_checkvals(colormap_t *vcm, colormap_t *cm, int use)
{
       if (use) {
               /* check to see if its the view's colormap, if so just do
                * update. */
               if (vcm != cm) {
                       if (cm->first >= vcm->size ||
                          (cm->first + cm->size) > (cm->first + vcm->size) ||
                           cm->type != vcm->type) {
                               return (0);
                       }
                       switch (vcm->type) {
                       case CM_COLOR:
                               if (cm->red_mask != vcm->red_mask ||
                                   cm->green_mask != vcm->green_mask ||
                                   cm->blue_mask != vcm->blue_mask) {
                                       return (0);
                               }
                               break;
                       case CM_GREYSCALE:
                               if (cm->grey_mask != vcm->grey_mask) {
                                       return (0);
                               }
                               break;
                       }
               }
       } else {
               if (cm->first >= vcm->size ||
                  (cm->first + cm->size) > (cm->first + vcm->size)) {
                       return (0);
               }
       }
       return (1);
}

/* does sanity check on values */
int
cc_get_colormap(view_t *v, colormap_t *cm)
{
       colormap_t *vcm = VDATA(v)->colormap;
       int     i;

       if (!cc_colormap_checkvals(vcm, cm, 0)) {
               return (EINVAL);
       }
       cm->type = vcm->type;

       switch (vcm->type) {
       case CM_COLOR:
               cm->red_mask = vcm->red_mask;
               cm->green_mask = vcm->green_mask;
               cm->blue_mask = vcm->blue_mask;
               break;
       case CM_GREYSCALE:
               cm->grey_mask = vcm->grey_mask;
               break;
       }

       /* copy entries into colormap. */
       for (i = cm->first; i < (cm->first + cm->size); i++) {
               cm->entry[i] = vcm->entry[i];
       }
       return (0);
}

/* does sanity check on values */
int
cc_use_colormap(view_t *v, colormap_t *cm)
{
       colormap_t *vcm = VDATA(v)->colormap;
       int     s, i;

       if (!cc_colormap_checkvals(vcm, cm, 1)) {
               return (EINVAL);
       }
       /* check to see if its the view's colormap, if so just do update. */
       if (vcm != cm) {
               /* copy entries into colormap. */
               for (i = cm->first; i < (cm->first + cm->size); i++) {
                       vcm->entry[i] = cm->entry[i];
               }
       }
       s = spltty();

       /* is view currently being displayed? */
       if (VDATA(v)->flags & VF_DISPLAY) {
               /* yes, update the copper lists */
               cop_t  *tmp, *cp;
               int     nframes = 1, j;

               if (DMDATA(VDATA(v)->mode)->flags & DMF_INTERLACE) {
                       nframes = 2;
               }
               for (i = 0; i < nframes; i++) {
                       cp = DMDATA(VDATA(v)->mode)->frames[i];

                       tmp = find_copper_inst(cp, CI_MOVE(R_COLOR07));
                       tmp -= 7;

                       for (j = 0; j < 32; j++) {
                               CMOVE(tmp, (R_COLOR00 + (j << 1)),
                                       CM_LTOW(vcm->entry[j]));
                       }
               }
       }
       splx(s);
       return (0);
}

#ifdef GRF_AGA
/* does sanity check on values */
int
cc_use_aga_colormap(view_t *v, colormap_t *cm)
{
       colormap_t *vcm = VDATA(v)->colormap;
       int     s, i;

       if (!cc_colormap_checkvals(vcm, cm, 1)) {
               return (EINVAL);
       }
       /* check to see if its the view's colormap, if so just do update. */
       if (vcm != cm) {
               /* copy entries into colormap. */
               for (i = cm->first; i < (cm->first + cm->size); i++) {
                       vcm->entry[i] = cm->entry[i];
               }
       }
       s = spltty();

       /* is view currently being displayed? */
       if (VDATA(v)->flags & VF_DISPLAY) {
               /* yes, update the copper lists */
               cop_t  *tmp, *cp;
               int     nframes = 1, j;

               if (DMDATA(VDATA(v)->mode)->flags & DMF_INTERLACE) {
                       nframes = 2;
               }
               for (i = 0; i < nframes; i++) {
                       cp = DMDATA(VDATA(v)->mode)->frames[i];

                       tmp = find_copper_inst(cp, CI_MOVE(R_COLOR00));
                       for (j = 0; j < vcm->size; j += 32) {
                               int k;

                               for (k = 0; k < 32; k++) {
                                       int ce = vcm->entry[j + k] >> 4;
                                       CMOVE(tmp, (R_COLOR00 + (k << 1)),
                                               CM_LTOW(ce));
                               }
                               tmp++;
                               for (k = 0; k < 32; k++) {
                                       int ce =vcm->entry[j + k];
                                       CMOVE(tmp, (R_COLOR00 + (k << 1)),
                                               CM_LTOW(ce));
                               }
                               tmp++;
                       }
               }
       }
       splx(s);
       return (0);
}
#endif

#if defined (GRF_A2024)
colormap_t *
cc_a2024_alloc_colormap(int depth)
{
       u_long  size = 1U << depth, i;
       colormap_t *cm = alloc_chipmem(sizeof(u_long) * size + sizeof(*cm));

       if (cm) {
               cm->type = CM_GREYSCALE;
               cm->grey_mask = 0x03;
               cm->first = 0;
               cm->size = size;
               cm->entry = (u_long *) & cm[1]; /* table directly after. */
               for (i = 0; i < size; i++) {
                       cm->entry[i] = CM_WTOL(cc_a2024_default_colors[i]);
               }
               return (cm);
       }
       return (NULL);
}

int
cc_a2024_get_colormap(view_t *v, colormap_t *cm)
{
       /* there are no differences (yet) in the way the cm's are stored */
       return (cc_get_colormap(v, cm));
}

int
cc_a2024_use_colormap(view_t *v, colormap_t *cm)
{
       colormap_t *vcm = VDATA(v)->colormap;
       int     s, i;

       if (!cc_colormap_checkvals(vcm, cm, 1)) {
               return (EINVAL);
       }
       /* check to see if its the view's colormap, if so just do update. */
       if (vcm != cm) {
               /* copy entries into colormap. */
               for (i = cm->first; i < (cm->first + cm->size); i++) {
                       vcm->entry[i] = cm->entry[i];
               }
       }
       s = spltty();

       /* is view currently being displayed? */
       if (VDATA(v)->flags & VF_DISPLAY) {
               /* yes, update the copper lists */
               cop_t  *tmp, *cp;
               int     nframes = 2, nregs = cm->size == 4 ? 16 : 8, j;

               if (DMDATA(VDATA(v)->mode)->flags & DMF_HEDLEY_EXP) {
                       nframes = 4;
               }
               for (i = 0; i < nframes; i++) {
                       cp = DMDATA(VDATA(v)->mode)->frames[i];

                       tmp = find_copper_inst(cp, CI_MOVE(R_COLOR07));
                       tmp -= 7;

                       for (j = 0; j < nregs; j++) {
                               CMOVE(tmp, (R_COLOR00 + (j << 1)),
                                       A2024_CM_TO_CR(vcm, j));
                       }
               }
       }
       splx(s);
       return (0);
}
#endif /* GRF_A2024 */


/*
* CC View stuff.
*/

void
cc_init_view(view_t *v, bmap_t *bm, dmode_t *mode, box_t *dbox)
{
       vdata_t *vd = VDATA(v);
       v->bitmap = bm;
       vd->mode = mode;
       memcpy(&v->display, dbox, sizeof(box_t));

       v->display_view = DMDATA(vd->mode)->display_view;
       v->use_colormap = DMDATA(vd->mode)->use_colormap;
       v->get_colormap = DMDATA(vd->mode)->get_colormap;
       v->free_view = cc_free_view;
       v->get_display_mode = cc_get_display_mode;
       v->remove_view = cc_remove_view;
}

void
cc_free_view(view_t *v)
{
       if (v) {
               v->remove_view(v);
               free_chipmem(VDATA(v)->colormap);
               cc_monitor->free_bitmap(v->bitmap);
               free_chipmem(v);
       }
}

void
cc_remove_view(view_t *v)
{
       dmode_t *mode = VDATA(v)->mode;

       if (MDATA(cc_monitor)->current_mode == mode) {
               if (DMDATA(mode)->current_view == v) {
                       cc_load_mode(NULL);
               }
       }
       if (DMDATA(mode)->current_view == v) {
               DMDATA(mode)->current_view = NULL;
       }
       VDATA(v)->flags &= ~VF_DISPLAY;
}

dmode_t *
cc_get_display_mode(view_t *v)
{
       return (VDATA(v)->mode);
}

void
cc_mode_vbl_handler(dmode_t *d)
{
       u_short vp = ((custom.vposr & 0x0007) << 8) | ((custom.vhposr) >> 8);

       if (vp < 12) {
               custom.cop1lc = PREP_DMA_MEM(DMDATA(d)->frames[F_LONG]);
               custom.copjmp1 = 0;
       }
}

void
cc_lace_mode_vbl_handler(dmode_t *d)
{
       u_short vp = ((custom.vposr & 0x0007) << 8) | ((custom.vhposr) >> 8);

       if (vp < 12) {
               if (custom.vposr & 0x8000) {
                       custom.cop1lc = PREP_DMA_MEM(DMDATA(d)->frames[F_LACE_LONG]);
               } else {
                       custom.cop1lc = PREP_DMA_MEM(DMDATA(d)->frames[F_LACE_SHORT]);
               }
               custom.copjmp1 = 0;
       }
}

/*
* Modes. (ick)
*/

/*
* NTSC Modes
*/

#if defined (GRF_NTSC)

dmode_t *
cc_init_ntsc_hires(void)
{
       /* this function should only be called once. */
       if (!h_this) {
               u_short len = std_copper_list_len;

               h_this = &hires_mode;
               h_this_data = &hires_mode_data;
               memset(h_this, 0, sizeof(dmode_t));
               memset(h_this_data, 0, sizeof(dmdata_t));

               h_this->name = "ntsc: hires";
               h_this->nominal_size.width = 640;
               h_this->nominal_size.height = 200;
               h_this_data->max_size.width = 724;
               h_this_data->max_size.height = 242;
               h_this_data->min_size.width = 320;
               h_this_data->min_size.height = 100;
               h_this_data->min_depth = 1;
               h_this_data->max_depth = 4;
               h_this->data = h_this_data;

               h_this->get_monitor = cc_get_monitor;
               h_this->alloc_view = cc_alloc_view;
               h_this->get_current_view = cc_get_current_view;

               h_this_data->use_colormap = cc_use_colormap;
               h_this_data->get_colormap = cc_get_colormap;
               h_this_data->alloc_colormap = cc_alloc_colormap;
               h_this_data->display_view = display_hires_view;
               h_this_data->monitor = cc_monitor;

               h_this_data->frames = hires_frames;
               h_this_data->frames[F_LONG] =
                       alloc_chipmem(std_copper_list_size * F_TOTAL);
               if (!h_this_data->frames[F_LONG]) {
                       panic("couldn't get chipmem for copper list");
               }
               h_this_data->frames[F_STORE_LONG] =
                       &h_this_data->frames[F_LONG][len];

               memcpy(h_this_data->frames[F_STORE_LONG], std_copper_list,
                       std_copper_list_size);
               memcpy(h_this_data->frames[F_LONG], std_copper_list,
                       std_copper_list_size);

               h_this_data->bplcon0 = 0x8200 | USE_CON3;       /* hires, color
                                                                * composite enable */
               h_this_data->std_start_x = STANDARD_VIEW_X;
               h_this_data->std_start_y = STANDARD_VIEW_Y;
               h_this_data->vbl_handler =
                       (vbl_handler_func *) cc_mode_vbl_handler;
#if defined (GRF_ECS) || defined (GRF_AGA)
               h_this_data->beamcon0 = STANDARD_NTSC_BEAMCON;
#endif

               LIST_INSERT_HEAD(&MDATA(cc_monitor)->modes, h_this, link);
       }
       return (h_this);
}

void
display_hires_view(view_t *v)
{
       if (h_this_data->current_view != v) {
               vdata_t *vd = VDATA(v);
               cop_t  *cp = h_this_data->frames[F_STORE_LONG], *tmp;
               int     depth = v->bitmap->depth, i;
               int     hstart, hstop, vstart, vstop, j;
               int     x, y, w = v->display.width, h = v->display.height;
               u_short ddfstart, ddfwidth, con1;

               /* round down to nearest even width */
               /* w &= 0xfffe; */
               /* calculate datafetch width. */

               ddfwidth = ((v->bitmap->bytes_per_row >> 1) - 2) << 2;

               /* This will center the any overscanned display */
               /* and allow user to modify. */
               x = v->display.x + h_this_data->std_start_x - ((w - 640) >> 2);
               y = v->display.y + h_this_data->std_start_y - ((h - 200) >> 1);

               if (y & 1)
                       y--;

               if (!(x & 1))
                       x--;

               hstart = x;
               hstop = x + (w >> 1);
               vstart = y;
               vstop = y + h;
               ddfstart = (hstart - 9) >> 1;

               /* check for hardware limits, AGA may allow more..? */
               /* anyone got a 4000 I can borrow :^) -ch */
               if ((ddfstart & 0xfffc) + ddfwidth > 0xd8) {
                       int     d = 0;

                       /* XXX anyone know the equality properties of
                        * intermixed logical AND's */
                       /* XXX and arithmetic operators? */
                       while (((ddfstart & 0xfffc) + ddfwidth - d) > 0xd8) {
                               d++;
                       }

                       ddfstart -= d;
                       hstart -= d << 1;
                       hstop -= d << 1;
               }
               /* correct the datafetch to proper limits. */
               /* delay the actual display of the data until we need it. */
               ddfstart &= 0xfffc;
               con1 = ((hstart - 9) - (ddfstart << 1)) |
                       (((hstart - 9) - (ddfstart << 1)) << 4);

               if (h_this_data->current_view) {
                       VDATA(h_this_data->current_view)->flags &=
                               ~VF_DISPLAY;    /* mark as no longer displayed. */
               }
               h_this_data->current_view = v;

               cp = h_this_data->frames[F_STORE_LONG];
#if defined (GRF_ECS) || defined (GRF_AGA)
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON3));
               tmp->cp.inst.operand = 0x0020;
#if defined (GRF_AGA)
               tmp = find_copper_inst(cp, CI_MOVE(R_FMODE));
               tmp->cp.inst.operand = 0;
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_BEAMCON0));
               tmp->cp.inst.operand = h_this_data->beamcon0;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWHIGH));
               tmp->cp.inst.operand = CALC_DIWHIGH(hstart, vstart, hstop, vstop);
#endif /* ECS */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON0));
               tmp->cp.inst.operand = h_this_data->bplcon0 | ((depth & 0x7) << 12);
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON1));
               tmp->cp.inst.operand = con1;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTART));
               tmp->cp.inst.operand = ((vstart & 0xff) << 8) | (hstart & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTOP));
               tmp->cp.inst.operand = ((vstop & 0xff) << 8) | (hstop & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTART));
               tmp->cp.inst.operand = ddfstart;
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTOP));
               tmp->cp.inst.operand = ddfstart + ddfwidth;

               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               for (i = 0, j = 0; i < depth; j += 2, i++) {
                       /* update the plane pointers */
                       tmp[j].cp.inst.operand =
                               HIADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
                       tmp[j + 1].cp.inst.operand =
                               LOADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
               }

               /* set mods correctly. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL1MOD));
               tmp[0].cp.inst.operand = v->bitmap->row_mod;
               tmp[1].cp.inst.operand = v->bitmap->row_mod;

               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand =
                               HIADDR(PREP_DMA_MEM(h_this_data->frames[F_STORE_LONG]));
               tmp[1].cp.inst.operand =
                               LOADDR(PREP_DMA_MEM(h_this_data->frames[F_STORE_LONG]));

               cp = h_this_data->frames[F_LONG];
               h_this_data->frames[F_LONG] = h_this_data->frames[F_STORE_LONG];
               h_this_data->frames[F_STORE_LONG] = cp;

               vd->flags |= VF_DISPLAY;

               cc_use_colormap(v, vd->colormap);
       }
       cc_load_mode(h_this);
}

dmode_t *
cc_init_ntsc_hires_lace(void)
{
       /* this function should only be called once. */
       if (!hl_this) {
               u_short len = std_copper_list_len;

               hl_this = &hires_lace_mode;
               hl_this_data = &hires_lace_mode_data;
               memset(hl_this, 0, sizeof(dmode_t));
               memset(hl_this_data, 0, sizeof(dmdata_t));

               hl_this->name = "ntsc: hires interlace";
               hl_this->nominal_size.width = 640;
               hl_this->nominal_size.height = 400;
               hl_this_data->max_size.width = 724;
               hl_this_data->max_size.height = 482;
               hl_this_data->min_size.width = 320;
               hl_this_data->min_size.height = 200;
               hl_this_data->min_depth = 1;
               hl_this_data->max_depth = 4;
               hl_this->data = hl_this_data;

               hl_this->get_monitor = cc_get_monitor;
               hl_this->alloc_view = cc_alloc_view;
               hl_this->get_current_view = cc_get_current_view;

               hl_this_data->use_colormap = cc_use_colormap;
               hl_this_data->get_colormap = cc_get_colormap;
               hl_this_data->alloc_colormap = cc_alloc_colormap;
               hl_this_data->display_view = display_hires_lace_view;
               hl_this_data->monitor = cc_monitor;

               hl_this_data->flags |= DMF_INTERLACE;

               hl_this_data->frames = hires_lace_frames;
               hl_this_data->frames[F_LACE_LONG] =
                               alloc_chipmem(std_copper_list_size * F_LACE_TOTAL);
               if (!hl_this_data->frames[F_LACE_LONG]) {
                       panic("couldn't get chipmem for copper list");
               }
               hl_this_data->frames[F_LACE_SHORT] =
                               &hl_this_data->frames[F_LACE_LONG][len];
               hl_this_data->frames[F_LACE_STORE_LONG] =
                               &hl_this_data->frames[F_LACE_SHORT][len];
               hl_this_data->frames[F_LACE_STORE_SHORT] =
                               &hl_this_data->frames[F_LACE_STORE_LONG][len];

               memcpy(hl_this_data->frames[F_LACE_STORE_LONG], std_copper_list,
                       std_copper_list_size);
               memcpy(hl_this_data->frames[F_LACE_STORE_SHORT], std_copper_list,
                       std_copper_list_size);
               memcpy(hl_this_data->frames[F_LACE_LONG], std_copper_list,
                       std_copper_list_size);
               memcpy(hl_this_data->frames[F_LACE_SHORT], std_copper_list,
                       std_copper_list_size);

               hl_this_data->bplcon0 = 0x8204 | USE_CON3;      /* hires, color
                                                                * composite enable,
                                                                * lace. */
               hl_this_data->std_start_x = STANDARD_VIEW_X;
               hl_this_data->std_start_y = STANDARD_VIEW_Y;
               hl_this_data->vbl_handler =
                       (vbl_handler_func *) cc_lace_mode_vbl_handler;
#if defined (GRF_ECS) || defined (GRF_AGA)
               hl_this_data->beamcon0 = STANDARD_NTSC_BEAMCON;
#endif

               LIST_INSERT_HEAD(&MDATA(cc_monitor)->modes, hl_this, link);
       }
       return (hl_this);
}

void
display_hires_lace_view(view_t *v)
{
       if (hl_this_data->current_view != v) {
               vdata_t *vd = VDATA(v);
               cop_t  *cp = hl_this_data->frames[F_LACE_STORE_LONG], *tmp;
               int     depth = v->bitmap->depth, i;
               int     hstart, hstop, vstart, vstop, j;
               int     x, y, w = v->display.width, h = v->display.height;
               u_short ddfstart, ddfwidth, con1;

               /* round down to nearest even width */
               /* w &= 0xfffe; */


               /* calculate datafetch width. */

               ddfwidth = ((v->bitmap->bytes_per_row >> 1) - 2) << 2;

               /* This will center the any overscanned display */
               /* and allow user to modify. */
               x = v->display.x + hl_this_data->std_start_x - ((w - 640) >> 2);
               y = v->display.y + hl_this_data->std_start_y - ((h - 400) >> 2);

               if (y & 1)
                       y--;

               if (!(x & 1))
                       x--;

               hstart = x;
               hstop = x + (w >> 1);
               vstart = y;
               vstop = y + (h >> 1);
               ddfstart = (hstart - 9) >> 1;

               /* check for hardware limits, AGA may allow more..? */
               /* anyone got a 4000 I can borrow :^) -ch */
               if ((ddfstart & 0xfffc) + ddfwidth > 0xd8) {
                       int     d = 0;

                       /* XXX anyone know the equality properties of
                        * intermixed logial AND's */
                       /* XXX and arithmetic operators? */
                       while (((ddfstart & 0xfffc) + ddfwidth - d) > 0xd8) {
                               d++;
                       }

                       ddfstart -= d;
                       hstart -= d << 1;
                       hstop -= d << 1;
               }
               /* correct the datafetch to proper limits. */
               /* delay the actual display of the data until we need it. */
               ddfstart &= 0xfffc;
               con1 = ((hstart - 9) - (ddfstart << 1)) |
                               (((hstart - 9) - (ddfstart << 1)) << 4);

               if (hl_this_data->current_view) {
                       VDATA(hl_this_data->current_view)->flags &=
                               ~VF_DISPLAY;    /* mark as no longer displayed. */
               }
               hl_this_data->current_view = v;

               cp = hl_this_data->frames[F_LACE_STORE_LONG];
#if defined (GRF_ECS) || defined (GRF_AGA)
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON3));
               tmp->cp.inst.operand = 0x0020;
#if defined (GRF_AGA)
               tmp = find_copper_inst(cp, CI_MOVE(R_FMODE));
               tmp->cp.inst.operand = 0;
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_BEAMCON0));
               tmp->cp.inst.operand = hl_this_data->beamcon0;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWHIGH));
               tmp->cp.inst.operand = CALC_DIWHIGH(hstart, vstart, hstop, vstop);
#endif /* ECS */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON0));
               tmp->cp.inst.operand = hl_this_data->bplcon0 | ((depth & 0x7) << 12);
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON1));
               tmp->cp.inst.operand = con1;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTART));
               tmp->cp.inst.operand = ((vstart & 0xff) << 8) | (hstart & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTOP));
               tmp->cp.inst.operand = ((vstop & 0xff) << 8) | (hstop & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTART));
               tmp->cp.inst.operand = ddfstart;
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTOP));
               tmp->cp.inst.operand = ddfstart + ddfwidth;

               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               for (i = 0, j = 0; i < depth; j += 2, i++) {
                       /* update the plane pointers */
                       tmp[j].cp.inst.operand =
                               HIADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
                       tmp[j + 1].cp.inst.operand =
                               LOADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
               }

               /* set mods correctly. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL1MOD));
               tmp[0].cp.inst.operand = v->bitmap->bytes_per_row + v->bitmap->row_mod;
               tmp[1].cp.inst.operand = v->bitmap->bytes_per_row + v->bitmap->row_mod;

               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand =
                       HIADDR(PREP_DMA_MEM(hl_this_data->frames[F_LACE_STORE_SHORT]));
               tmp[1].cp.inst.operand =
                       LOADDR(PREP_DMA_MEM(hl_this_data->frames[F_LACE_STORE_SHORT]));


               bcopy(hl_this_data->frames[F_LACE_STORE_LONG],
                       hl_this_data->frames[F_LACE_STORE_SHORT], std_copper_list_size);

               /* these are the only ones that are different from long frame. */
               cp = hl_this_data->frames[F_LACE_STORE_SHORT];
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               for (i = 0, j = 0; i < depth; j += 2, i++) {
                       u_short mod = v->bitmap->bytes_per_row + v->bitmap->row_mod;
                       /* update plane pointers. high and low. */
                       tmp[j].cp.inst.operand =
                               HIADDR(PREP_DMA_MEM(&v->bitmap->plane[i][mod]));
                       tmp[j + 1].cp.inst.operand =
                               LOADDR(PREP_DMA_MEM(&v->bitmap->plane[i][mod]));
               }

               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand =
                       HIADDR(PREP_DMA_MEM(hl_this_data->frames[F_LACE_STORE_LONG]));
               tmp[1].cp.inst.operand =
                       LOADDR(PREP_DMA_MEM(hl_this_data->frames[F_LACE_STORE_LONG]));


               cp = hl_this_data->frames[F_LACE_LONG];
               hl_this_data->frames[F_LACE_LONG] =
                       hl_this_data->frames[F_LACE_STORE_LONG];
               hl_this_data->frames[F_LACE_STORE_LONG] = cp;

               cp = hl_this_data->frames[F_LACE_SHORT];
               hl_this_data->frames[F_LACE_SHORT] =
                       hl_this_data->frames[F_LACE_STORE_SHORT];
               hl_this_data->frames[F_LACE_STORE_SHORT] = cp;

               vd->flags |= VF_DISPLAY;

               cc_use_colormap(v, vd->colormap);
       }
       cc_load_mode(hl_this);
}
#if defined (GRF_A2024)

dmode_t *
cc_init_ntsc_hires_dlace(void)
{
       /* this function should only be called once. */
       if (!hdl_this) {
               u_short len = std_dlace_copper_list_len;

               hdl_this = &hires_dlace_mode;
               hdl_this_data = &hires_dlace_mode_data;
               memset(hdl_this, 0, sizeof(dmode_t));
               memset(hdl_this_data, 0, sizeof(dmdata_t));

               hdl_this->name = "ntsc: hires double interlace";
               hdl_this->nominal_size.width = 640;
               hdl_this->nominal_size.height = 800;
               hdl_this_data->max_size.width = 724;
               hdl_this_data->max_size.height = 800;
               hdl_this_data->min_size.width = 320;
               hdl_this_data->min_size.height = 400;
               hdl_this_data->min_depth = 1;
               hdl_this_data->max_depth = 2;
               hdl_this->data = hdl_this_data;

               hdl_this->get_monitor = cc_get_monitor;
               hdl_this->alloc_view = cc_alloc_view;
               hdl_this->get_current_view = cc_get_current_view;

               hdl_this_data->use_colormap = cc_a2024_use_colormap;
               hdl_this_data->get_colormap = cc_a2024_get_colormap;
               hdl_this_data->alloc_colormap = cc_a2024_alloc_colormap;
               hdl_this_data->display_view = display_hires_dlace_view;
               hdl_this_data->monitor = cc_monitor;

               hdl_this_data->flags |= DMF_INTERLACE;

               hdl_this_data->frames = hires_dlace_frames;
               hdl_this_data->frames[F_LACE_LONG] =
                       alloc_chipmem(std_dlace_copper_list_size * F_LACE_TOTAL);
               if (!hdl_this_data->frames[F_LACE_LONG]) {
                       panic("couldn't get chipmem for copper list");
               }
               hdl_this_data->frames[F_LACE_SHORT] =
                       &hdl_this_data->frames[F_LACE_LONG][len];
               hdl_this_data->frames[F_LACE_STORE_LONG] =
                       &hdl_this_data->frames[F_LACE_SHORT][len];
               hdl_this_data->frames[F_LACE_STORE_SHORT] =
                       &hdl_this_data->frames[F_LACE_STORE_LONG][len];

               bcopy(std_dlace_copper_list,
                       hdl_this_data->frames[F_LACE_STORE_LONG],
                       std_dlace_copper_list_size);
               bcopy(std_dlace_copper_list,
                       hdl_this_data->frames[F_LACE_STORE_SHORT],
                       std_dlace_copper_list_size);
               bcopy(std_dlace_copper_list,
                       hdl_this_data->frames[F_LACE_LONG],
                       std_dlace_copper_list_size);
               bcopy(std_dlace_copper_list,
                       hdl_this_data->frames[F_LACE_SHORT],
                       std_dlace_copper_list_size);

               hdl_this_data->bplcon0 = 0x8204 | USE_CON3;     /* hires, color
                                                                * composite enable,
                                                                * dlace. */
               hdl_this_data->std_start_x = STANDARD_VIEW_X;
               hdl_this_data->std_start_y = STANDARD_VIEW_Y;
               hdl_this_data->vbl_handler =
                       (vbl_handler_func *) cc_lace_mode_vbl_handler;
#if defined (GRF_ECS) || defined (GRF_AGA)
               hdl_this_data->beamcon0 = STANDARD_NTSC_BEAMCON;
#endif
               LIST_INSERT_HEAD(&MDATA(cc_monitor)->modes, hdl_this, link);
       }
       return (hdl_this);
}

void
display_hires_dlace_view(view_t *v)
{
       if (hdl_this_data->current_view != v) {
               vdata_t *vd = VDATA(v);
               cop_t  *cp = hdl_this_data->frames[F_LACE_STORE_LONG], *tmp;
               int     depth = v->bitmap->depth;
               int     hstart, hstop, vstart, vstop;
               int     x, y, w = v->display.width, h = v->display.height;
               u_short ddfstart, ddfwidth, con1;
               u_short mod1l, mod2l;

               /* round down to nearest even width */
               /* w &= 0xfffe; */

               /* calculate datafetch width. */

               ddfwidth = ((v->bitmap->bytes_per_row >> 1) - 2) << 2;

               /* This will center the any overscanned display */
               /* and allow user to modify. */
               x = v->display.x + hdl_this_data->std_start_x - ((w - 640) >> 2);
               y = v->display.y + hdl_this_data->std_start_y - ((h - 800) >> 3);

               if (y & 1)
                       y--;

               if (!(x & 1))
                       x--;

               hstart = x;
               hstop = x + (w >> 1);
               vstart = y;
               vstop = y + (h >> 2);

               ddfstart = (hstart - 9) >> 1;

               /* check for hardware limits, AGA may allow more..? */
               /* anyone got a 4000 I can borrow :^) -ch */
               if ((ddfstart & 0xfffc) + ddfwidth > 0xd8) {
                       int     d = 0;

                       /* XXX anyone know the equality properties of
                        * intermixed logial AND's */
                       /* XXX and arithmetic operators? */
                       while (((ddfstart & 0xfffc) + ddfwidth - d) > 0xd8) {
                               d++;
                       }

                       ddfstart -= d;
                       hstart -= d << 1;
                       hstop -= d << 1;
               }
               /* correct the datafetch to proper limits. */
               /* delay the actual display of the data until we need it. */
               ddfstart &= 0xfffc;
               con1 = ((hstart - 9) - (ddfstart << 1)) |
                       (((hstart - 9) - (ddfstart << 1)) << 4);

               if (hdl_this_data->current_view) {
                       VDATA(hdl_this_data->current_view)->flags &=
                               ~VF_DISPLAY;    /* mark as no longer displayed. */
               }
               hdl_this_data->current_view = v;

               cp = hdl_this_data->frames[F_LACE_STORE_LONG];
#if defined (GRF_ECS) || defined (GRF_AGA)
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON3));
               tmp->cp.inst.operand = 0x0020;
#if defined (GRF_AGA)
               tmp = find_copper_inst(cp, CI_MOVE(R_FMODE));
               tmp->cp.inst.operand = 0;
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_BEAMCON0));
               tmp->cp.inst.operand = hdl_this_data->beamcon0;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWHIGH));
               tmp->cp.inst.operand = CALC_DIWHIGH(hstart, vstart, hstop, vstop);
#endif /* ECS */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON0));
               tmp->cp.inst.operand =
                       hdl_this_data->bplcon0 | ((depth & 0x7) << 13); /* times two. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON1));
               tmp->cp.inst.operand = con1;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTART));
               tmp->cp.inst.operand = ((vstart & 0xff) << 8) | (hstart & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTOP));
               tmp->cp.inst.operand = ((vstop & 0xff) << 8) | (hstop & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTART));
               tmp->cp.inst.operand = ddfstart;
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTOP));
               tmp->cp.inst.operand = ddfstart + ddfwidth;

               mod1l = v->bitmap->bytes_per_row + v->bitmap->row_mod;
               mod2l = mod1l << 1;

               /* update plane pointers. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               tmp[0].cp.inst.operand =
                       HIADDR(PREP_DMA_MEM(&v->bitmap->plane[0][0]));
               tmp[1].cp.inst.operand =
                       LOADDR(PREP_DMA_MEM(&v->bitmap->plane[0][0]));
               tmp[2].cp.inst.operand =
                       HIADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod1l]));
               tmp[3].cp.inst.operand =
                       LOADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod1l]));
               if (depth == 2) {
                       tmp[4].cp.inst.operand =
                               HIADDR(PREP_DMA_MEM(&v->bitmap->plane[1][0]));
                       tmp[5].cp.inst.operand =
                               LOADDR(PREP_DMA_MEM(&v->bitmap->plane[1][0]));
                       tmp[6].cp.inst.operand =
                               HIADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod1l]));
                       tmp[7].cp.inst.operand =
                               LOADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod1l]));
               }
               /* set modulos. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL1MOD));
               tmp[0].cp.inst.operand = mod2l + mod1l;
               tmp[1].cp.inst.operand = mod2l + mod1l;


               /* set next coper list pointers */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand =
                       HIADDR(PREP_DMA_MEM(hdl_this_data->frames[F_LACE_STORE_SHORT]));
               tmp[1].cp.inst.operand =
                       LOADDR(PREP_DMA_MEM(hdl_this_data->frames[F_LACE_STORE_SHORT]));

               bcopy(hdl_this_data->frames[F_LACE_STORE_LONG],
                       hdl_this_data->frames[F_LACE_STORE_SHORT],
                       std_dlace_copper_list_size);

               /* these are the only ones that are different from long frame. */
               cp = hdl_this_data->frames[F_LACE_STORE_SHORT];
               /* update plane pointers. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               tmp[0].cp.inst.operand =
                       HIADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod2l]));
               tmp[1].cp.inst.operand =
                       LOADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod2l]));
               tmp[2].cp.inst.operand =
                       HIADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod2l + mod1l]));
               tmp[3].cp.inst.operand =
                       LOADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod2l + mod1l]));
               if (depth == 2) {
                       tmp[4].cp.inst.operand =
                               HIADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod2l]));
                       tmp[5].cp.inst.operand =
                               LOADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod2l]));
                       tmp[6].cp.inst.operand =
                               HIADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod2l + mod1l]));
                       tmp[7].cp.inst.operand =
                               LOADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod2l + mod1l]));
               }
               /* set next copper list pointers */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand =
                       HIADDR(PREP_DMA_MEM(hdl_this_data->frames[F_LACE_STORE_LONG]));
               tmp[1].cp.inst.operand =
                       LOADDR(PREP_DMA_MEM(hdl_this_data->frames[F_LACE_STORE_LONG]));

               cp = hdl_this_data->frames[F_LACE_LONG];
               hdl_this_data->frames[F_LACE_LONG] =
                       hdl_this_data->frames[F_LACE_STORE_LONG];
               hdl_this_data->frames[F_LACE_STORE_LONG] = cp;

               cp = hdl_this_data->frames[F_LACE_SHORT];
               hdl_this_data->frames[F_LACE_SHORT] =
                       hdl_this_data->frames[F_LACE_STORE_SHORT];
               hdl_this_data->frames[F_LACE_STORE_SHORT] = cp;

               vd->flags |= VF_DISPLAY;
               cc_a2024_use_colormap(v, vd->colormap);
       }
       cc_load_mode(hdl_this);
}


dmode_t *
cc_init_ntsc_a2024(void)
{
       /* this function should only be called once. */
       if (!a24_this) {
               int     i;
               u_short len = std_a2024_copper_list_len;
               cop_t  *cp;

               a24_this = &a2024_mode;
               a24_this_data = &a2024_mode_data;
               memset(a24_this, 0, sizeof(dmode_t));
               memset(a24_this_data, 0, sizeof(dmdata_t));

               a24_this->name = "ntsc: A2024 15 kHz";
               a24_this->nominal_size.width = 1024;
               a24_this->nominal_size.height = 800;
               a24_this_data->max_size.width = 1024;
               a24_this_data->max_size.height = 800;
               a24_this_data->min_size.width = 1024;
               a24_this_data->min_size.height = 800;
               a24_this_data->min_depth = 1;
               a24_this_data->max_depth = 2;
               a24_this->data = a24_this_data;

               a24_this->get_monitor = cc_get_monitor;
               a24_this->alloc_view = cc_alloc_view;
               a24_this->get_current_view = cc_get_current_view;

               a24_this_data->use_colormap = cc_a2024_use_colormap;
               a24_this_data->get_colormap = cc_a2024_get_colormap;
               a24_this_data->display_view = display_a2024_view;
               a24_this_data->alloc_colormap = cc_a2024_alloc_colormap;
               a24_this_data->monitor = cc_monitor;

               a24_this_data->flags |= DMF_HEDLEY_EXP;

               a24_this_data->frames = a2024_frames;
               a24_this_data->frames[F_QD_QUAD0] =
                       alloc_chipmem(std_a2024_copper_list_size * F_QD_TOTAL);
               if (!a24_this_data->frames[F_QD_QUAD0]) {
                       panic("couldn't get chipmem for copper list");
               }
               /* setup the hedley init bitplane. */
               hedley_init = alloc_chipmem(128);
               if (!hedley_init) {
                       panic("couldn't get chipmem for hedley init bitplane");
               }
               for (i = 1; i < 128; i++)
                       hedley_init[i] = 0xff;
               hedley_init[0] = 0x03;

               /* copy image of standard copper list. */
               memcpy(a24_this_data->frames[0], std_a2024_copper_list,
                       std_a2024_copper_list_size);

               /* set the init plane pointer. */
               cp = find_copper_inst(a24_this_data->frames[F_QD_QUAD0],
                                       CI_MOVE(R_BPL0PTH));
               cp[0].cp.inst.operand = HIADDR(PREP_DMA_MEM(hedley_init));
               cp[1].cp.inst.operand = LOADDR(PREP_DMA_MEM(hedley_init));

               for (i = 1; i < F_QD_TOTAL; i++) {
                       a24_this_data->frames[i] = &a24_this_data->frames[i - 1][len];
                       bcopy(a24_this_data->frames[0],
                               a24_this_data->frames[i],
                               std_a2024_copper_list_size);
               }

               a24_this_data->bplcon0 = 0x8200;        /* hires */
               a24_this_data->vbl_handler =
                       (vbl_handler_func *) a2024_mode_vbl_handler;


               LIST_INSERT_HEAD(&MDATA(cc_monitor)->modes, a24_this, link);
       }
       return (a24_this);
}

void
display_a2024_view(view_t *v)
{
       if (a24_this_data->current_view != v) {
               vdata_t *vd = VDATA(v);
               cop_t  *cp, *tmp;
               u_char *inst_plane[2] = { NULL, NULL };
               u_char **plane = inst_plane;
               u_long  full_line = v->bitmap->bytes_per_row + v->bitmap->row_mod;
               u_long  half_plane = full_line * v->bitmap->rows / 2;

               int     depth = v->bitmap->depth, i, j;

               plane[0] = v->bitmap->plane[0];
               if (depth == 2) {
                       plane[1] = v->bitmap->plane[1];
               }
               if (a24_this_data->current_view) {
                       VDATA(a24_this_data->current_view)->flags &=
                               ~VF_DISPLAY;    /* mark as no longer displayed. */
               }
               cp = a24_this_data->frames[F_QD_STORE_QUAD0];
               tmp = find_copper_inst(cp, CI_MOVE(R_COLOR1F));
               tmp = find_copper_inst(tmp, CI_MOVE(R_BPLCON0)); /* grab third one. */
               tmp->cp.inst.operand = a24_this_data->bplcon0 |
                                       ((depth & 0x7) << 13);  /* times 2 */

               bcopy(a24_this_data->frames[F_QD_STORE_QUAD0],
                       a24_this_data->frames[F_QD_STORE_QUAD1],
                       std_a2024_copper_list_size);
               bcopy(a24_this_data->frames[F_QD_STORE_QUAD0],
                       a24_this_data->frames[F_QD_STORE_QUAD2],
                       std_a2024_copper_list_size);
               bcopy(a24_this_data->frames[F_QD_STORE_QUAD0],
                       a24_this_data->frames[F_QD_STORE_QUAD3],
                       std_a2024_copper_list_size);

               /*
                * Mark Id's
                */
               tmp = find_copper_inst(a24_this_data->frames[F_QD_STORE_QUAD1],
                       CI_WAIT(126, 21));
               CBUMP(tmp);
               CMOVE(tmp, R_COLOR01, QUAD1_ID);
               tmp = find_copper_inst(a24_this_data->frames[F_QD_STORE_QUAD2],
                       CI_WAIT(126, 21));
               CBUMP(tmp);
               CMOVE(tmp, R_COLOR01, QUAD2_ID);
               tmp = find_copper_inst(a24_this_data->frames[F_QD_STORE_QUAD3],
                       CI_WAIT(126, 21));
               CBUMP(tmp);
               CMOVE(tmp, R_COLOR01, QUAD3_ID);

               plane[0]--;
               plane[0]--;
               if (depth == 2) {
                       plane[1]--;
                       plane[1]--;
               }
               /*
                * Set bitplane pointers.
                */
               tmp = find_copper_inst(a24_this_data->frames[F_QD_STORE_QUAD0],
                       CI_MOVE(R_BPLMOD2));
               CBUMP(tmp);
               CMOVE(tmp, R_BPL0PTH, HIADDR(PREP_DMA_MEM(&plane[0][0])));
               CMOVE(tmp, R_BPL0PTL, LOADDR(PREP_DMA_MEM(&plane[0][0])));
               CMOVE(tmp, R_BPL1PTH, HIADDR(PREP_DMA_MEM(&plane[0][full_line])));
               CMOVE(tmp, R_BPL1PTL, LOADDR(PREP_DMA_MEM(&plane[0][full_line])));
               if (depth == 2) {
                       CMOVE(tmp, R_BPL2PTH, HIADDR(PREP_DMA_MEM(&plane[1][0])));
                       CMOVE(tmp, R_BPL2PTL, LOADDR(PREP_DMA_MEM(&plane[1][0])));
                       CMOVE(tmp, R_BPL3PTH, HIADDR(PREP_DMA_MEM(&plane[1][full_line])));
                       CMOVE(tmp, R_BPL3PTL, LOADDR(PREP_DMA_MEM(&plane[1][full_line])));
               }
#if defined (GRF_ECS) || defined (GRF_AGA)
               CMOVE(tmp, R_DIWHIGH, 0x2000);
#endif
               CMOVE(tmp, R_COP1LCH,
                       HIADDR(PREP_DMA_MEM(a24_this_data->frames[F_QD_STORE_QUAD1])));
               CMOVE(tmp, R_COP1LCL,
                       LOADDR(PREP_DMA_MEM(a24_this_data->frames[F_QD_STORE_QUAD1])));
               CEND(tmp);
               CEND(tmp);

               tmp = find_copper_inst(a24_this_data->frames[F_QD_STORE_QUAD1],
                                       CI_MOVE(R_BPLMOD2));
               CBUMP(tmp);
               CMOVE(tmp, R_BPL0PTH,
                       HIADDR(PREP_DMA_MEM(&plane[0][HALF_2024_LINE])));
               CMOVE(tmp, R_BPL0PTL,
                       LOADDR(PREP_DMA_MEM(&plane[0][HALF_2024_LINE])));
               CMOVE(tmp, R_BPL1PTH,
                       HIADDR(PREP_DMA_MEM(&plane[0][full_line + HALF_2024_LINE])));
               CMOVE(tmp, R_BPL1PTL,
                       LOADDR(PREP_DMA_MEM(&plane[0][full_line + HALF_2024_LINE])));
               if (depth == 2) {
                       CMOVE(tmp, R_BPL2PTH,
                               HIADDR(PREP_DMA_MEM(&plane[1][HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL2PTL,
                               LOADDR(PREP_DMA_MEM(&plane[1][HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL3PTH,
                               HIADDR(PREP_DMA_MEM(&plane[1][full_line + HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL3PTL,
                               LOADDR(PREP_DMA_MEM(&plane[1][full_line + HALF_2024_LINE])));
               }
#if defined (GRF_ECS) || defined (GRF_AGA)
               CMOVE(tmp, R_DIWHIGH, 0x2000);
#endif
               CMOVE(tmp, R_COP1LCH,
                       HIADDR(PREP_DMA_MEM(a24_this_data->frames[F_QD_STORE_QUAD2])));
               CMOVE(tmp, R_COP1LCL,
                       LOADDR(PREP_DMA_MEM(a24_this_data->frames[F_QD_STORE_QUAD2])));
               CEND(tmp);
               CEND(tmp);

               tmp = find_copper_inst(a24_this_data->frames[F_QD_STORE_QUAD2],
                                       CI_MOVE(R_BPLMOD2));
               CBUMP(tmp);
               CMOVE(tmp, R_BPL0PTH,
                       HIADDR(PREP_DMA_MEM(&plane[0][half_plane])));
               CMOVE(tmp, R_BPL0PTL,
                       LOADDR(PREP_DMA_MEM(&plane[0][half_plane])));
               CMOVE(tmp, R_BPL1PTH,
                       HIADDR(PREP_DMA_MEM(&plane[0][half_plane + full_line])));
               CMOVE(tmp, R_BPL1PTL,
                       LOADDR(PREP_DMA_MEM(&plane[0][half_plane + full_line])));
               if (depth == 2) {
                       CMOVE(tmp, R_BPL2PTH,
                               HIADDR(PREP_DMA_MEM(&plane[1][half_plane])));
                       CMOVE(tmp, R_BPL2PTL,
                               LOADDR(PREP_DMA_MEM(&plane[1][half_plane])));
                       CMOVE(tmp, R_BPL3PTH,
                               HIADDR(PREP_DMA_MEM(&plane[1][half_plane + full_line])));
                       CMOVE(tmp, R_BPL3PTL,
                               LOADDR(PREP_DMA_MEM(&plane[1][half_plane + full_line])));
               }
#if defined (GRF_ECS) || defined (GRF_AGA)
               CMOVE(tmp, R_DIWHIGH, 0x2000);
#endif
               CMOVE(tmp, R_COP1LCH,
                       HIADDR(PREP_DMA_MEM(a24_this_data->frames[F_QD_STORE_QUAD3])));
               CMOVE(tmp, R_COP1LCL,
                       LOADDR(PREP_DMA_MEM(a24_this_data->frames[F_QD_STORE_QUAD3])));
               CEND(tmp);
               CEND(tmp);

               tmp = find_copper_inst(a24_this_data->frames[F_QD_STORE_QUAD3],
                                       CI_MOVE(R_BPLMOD2));
               CBUMP(tmp);
               CMOVE(tmp, R_BPL0PTH, HIADDR(PREP_DMA_MEM(
                       &plane[0][half_plane + HALF_2024_LINE])));
               CMOVE(tmp, R_BPL0PTL, LOADDR(PREP_DMA_MEM(
                       &plane[0][half_plane + HALF_2024_LINE])));
               CMOVE(tmp, R_BPL1PTH, HIADDR(PREP_DMA_MEM(
                       &plane[0][half_plane + full_line + HALF_2024_LINE])));
               CMOVE(tmp, R_BPL1PTL, LOADDR(PREP_DMA_MEM(
                       &plane[0][half_plane + full_line + HALF_2024_LINE])));
               if (depth == 2) {
                       CMOVE(tmp, R_BPL2PTH, HIADDR(PREP_DMA_MEM(
                               &plane[1][half_plane + HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL2PTL, LOADDR(PREP_DMA_MEM(
                               &plane[1][half_plane + HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL3PTH, HIADDR(PREP_DMA_MEM(
                               &plane[1][half_plane + full_line + HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL3PTL, LOADDR(PREP_DMA_MEM(
                               &plane[1][half_plane + full_line + HALF_2024_LINE])));
               }
#if defined (GRF_ECS) || defined (GRF_AGA)
               CMOVE(tmp, R_DIWHIGH, 0x2000);
#endif
               CMOVE(tmp, R_COP1LCH, HIADDR(PREP_DMA_MEM(
                               a24_this_data->frames[F_QD_STORE_QUAD0])));
               CMOVE(tmp, R_COP1LCL, LOADDR(PREP_DMA_MEM(
                               a24_this_data->frames[F_QD_STORE_QUAD0])));
               CEND(tmp);
               CEND(tmp);

               /* swap new pointers in. */
               for (i = F_QD_STORE_QUAD0, j = F_QD_QUAD0;
                   i <= F_QD_STORE_QUAD3; i++, j++) {
                       cp = a24_this_data->frames[j];
                       a24_this_data->frames[j] = a24_this_data->frames[i];
                       a24_this_data->frames[i] = cp;
               }

               a24_this_data->current_view = v;
               vd->flags |= VF_DISPLAY;

               cc_a2024_use_colormap(v, vd->colormap);
       }
       cc_load_mode(a24_this);
}

void
a2024_mode_vbl_handler(dmode_t *d)
{
       u_short vp = ((custom.vposr & 0x0007) << 8) | ((custom.vhposr) >> 8);

       if (vp < 12) {
               custom.cop1lc =
                 PREP_DMA_MEM(a24_this_data->frames[a24_this_data->hedley_current]);
               custom.copjmp1 = 0;
       }
       a24_this_data->hedley_current++;
       a24_this_data->hedley_current &= 0x3;   /* if 4 then 0. */
}
#endif /* GRF_A2024 */

#if defined (GRF_AGA)

dmode_t *
cc_init_ntsc_aga(void)
{
       /* this function should only be called once. */
       if (!aga_this && (custom.deniseid & 0xff) == 0xf8 &&
           aga_enable & AGA_ENABLE) {
               u_short len = aga_copper_list_len;

               aga_this = &aga_mode;
               aga_this_data = &aga_mode_data;
               memset(aga_this, 0, sizeof(dmode_t));
               memset(aga_this_data, 0, sizeof(dmdata_t));

               aga_this->name = "ntsc: AGA dbl";
               aga_this->nominal_size.width = 640;
               aga_this->nominal_size.height = 400;
               aga_this_data->max_size.width = 724;
               aga_this_data->max_size.height = 482;
               aga_this_data->min_size.width = 320;
               aga_this_data->min_size.height = 200;
               aga_this_data->min_depth = 1;
               aga_this_data->max_depth = 8;
               aga_this->data = aga_this_data;

               aga_this->get_monitor = cc_get_monitor;
               aga_this->alloc_view = cc_alloc_view;
               aga_this->get_current_view = cc_get_current_view;

               aga_this_data->use_colormap = cc_use_aga_colormap;
               aga_this_data->get_colormap = cc_get_colormap;
               aga_this_data->alloc_colormap = cc_alloc_aga_colormap;
               aga_this_data->display_view = display_aga_view;
               aga_this_data->monitor = cc_monitor;

               aga_this_data->frames = aga_frames;
               aga_this_data->frames[F_LONG] = alloc_chipmem(aga_copper_list_size * F_TOTAL);
               if (!aga_this_data->frames[F_LONG]) {
                       panic("couldn't get chipmem for copper list");
               }
               aga_this_data->frames[F_STORE_LONG] = &aga_this_data->frames[F_LONG][len];

               memcpy(aga_this_data->frames[F_STORE_LONG], aga_copper_list, aga_copper_list_size);
               memcpy(aga_this_data->frames[F_LONG], aga_copper_list, aga_copper_list_size);

               aga_this_data->bplcon0 = 0x0240 | USE_CON3;     /* color composite
                                                                * enable,
                                                                * shres. */
#ifdef GRF_AGA_VGA
               aga_this_data->std_start_x = 0x40 /*STANDARD_VIEW_X*/;
#else
               aga_this_data->std_start_x = 0x4f /*STANDARD_VIEW_X*/;
#endif
               aga_this_data->std_start_y = 0x2b /*STANDARD_VIEW_Y*/;
               aga_this_data->vbl_handler = (vbl_handler_func *) cc_mode_vbl_handler;
               aga_this_data->beamcon0 = SPECIAL_BEAMCON ^ VSYNCTRUE;

               LIST_INSERT_HEAD(&MDATA(cc_monitor)->modes,
                   aga_this, link);
       }
       return (aga_this);
}

/* static, so I can patch and play */

#ifdef GRF_AGA_VGA
int     AGA_htotal = 0x71;
int     AGA_hsstrt = 0xc;
int     AGA_hsstop = 0x16;
int     AGA_hbstrt = 0x5;
int     AGA_vtotal = 0x1c1;
#else
int     AGA_htotal = 0x79;
int     AGA_hsstrt = 0xe;
int     AGA_hsstop = 0x1c;
int     AGA_hbstrt = 0x8;
int     AGA_vtotal = 0x1ec;
#endif
int     AGA_hbstop = 0x1e;
int     AGA_vsstrt = 0x3;
int     AGA_vsstop = 0x6;
int     AGA_vbstrt = 0x0;
int     AGA_vbstop = 0x19;
int     AGA_hcenter = 0x4a;

void
display_aga_view(view_t *v)
{
       if (aga_this_data->current_view != v) {
               vdata_t *vd = VDATA(v);
               cop_t  *cp = aga_this_data->frames[F_STORE_LONG], *tmp;
               int     depth = v->bitmap->depth, i;
               int     hstart, hstop, vstart, vstop, j;
               int     x, y, w = v->display.width, h = v->display.height;
               u_short ddfstart, ddfwidth, con1;

#ifdef DEBUG
               if (aga_enable & AGA_TRACE)
                       printf("display_aga_view(%dx%dx%d) %p\n", w, h,
                           depth, v);
#endif
               /* round down to nearest even width */
               /* w &= 0xfffe; */
               /* calculate datafetch width. */

               ddfwidth = ((v->bitmap->bytes_per_row >> 1) - 4) << 1;

               /* this will center the any overscanned display */
               /* and allow user to modify. */
               x = v->display.x + aga_this_data->std_start_x - ((w - 640) >> 3);
               y = v->display.y + aga_this_data->std_start_y - ((h - 400) >> 1);

               if (y & 1)
                       y--;

               if (!(x & 1))
                       x--;

               hstart = x;
               hstop = x + (w >> 2);
               vstart = y;
               vstop = y + (h >> 0);
               ddfstart = (hstart >> 1) - 8;

#ifdef DEBUG
               if (aga_enable & AGA_TRACE2) {
                       printf ("  ddfwidth %04x x %04x y %04x", ddfwidth,
                           x, y);
                       printf (" hstart %04x hstop %04x vstart %04x vstop %04x ddfstart %04x\n",
                           hstart, hstop, vstart, vstop, ddfstart);
               }
#endif
               /* check for hardware limits, AGA may allow more..? */
               /* anyone got a 4000 I can borrow :^) -ch */
               if ((ddfstart & 0xfffc) + ddfwidth > 0xd8) {
                       int     d = 0;

                       /* XXX anyone know the equality properties of
                        * intermixed logial AND's */
                       /* XXX and arithmetic operators? */
                       while (((ddfstart & 0xfffc) + ddfwidth - d) > 0xd8) {
                               d++;
                       }

                       ddfstart -= d;
                       hstart -= d << 1;
                       hstop -= d << 1;
               }
               /* correct the datafetch to proper limits. */
               /* delay the actual display of the data until we need it. */
               ddfstart &= 0xfffc;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2) {
                       printf ("  ddfwidth %04x x %04x y %04x", ddfwidth,
                           x, y);
                       printf (" hstart %04x hstop %04x vstart %04x vstop %04x ddfstart %04x\n",
                           hstart, hstop, vstart, vstop, ddfstart);
               }
#endif
               con1 = ((hstart - 9) - (ddfstart << 1)) | (((hstart - 9) - (ddfstart << 1)) << 4);

               if (aga_this_data->current_view) {
                       VDATA(aga_this_data->current_view)->flags &= ~VF_DISPLAY;       /* mark as no longer */
                       /* displayed. */
               }
               aga_this_data->current_view = v;

               cp = aga_this_data->frames[F_STORE_LONG];
               tmp = cp;
               for (i = 0; i < 8; ++i) {
                       if (tmp == NULL)
                               break;
                       tmp = find_copper_inst(tmp + 1, CI_MOVE(R_BPLCON3));
                       if (tmp == NULL)
                               break;
                       tmp->cp.inst.operand = 0x0ca1 | (i << 13);
                       tmp = find_copper_inst(tmp + 1, CI_MOVE(R_BPLCON3));
                       if (tmp == NULL)
                               break;
                       tmp->cp.inst.operand = 0x0ea1 | (i << 13);
               }
               if (tmp)
                       tmp = find_copper_inst(tmp + 1, CI_MOVE(R_BPLCON3));
               if (tmp)
                       tmp->cp.inst.operand = 0x0ca1;
               tmp = find_copper_inst(cp, CI_MOVE(R_FMODE));
               tmp->cp.inst.operand = 0x8003;
               tmp = find_copper_inst(cp, CI_MOVE(R_HTOTAL));
               tmp->cp.inst.operand = AGA_htotal; /* 81/71/73/79? */
               tmp = find_copper_inst(cp, CI_MOVE(R_HBSTRT));
               tmp->cp.inst.operand = AGA_hbstrt; /* 0x0008 */
               tmp = find_copper_inst(cp, CI_MOVE(R_HSSTRT));
               tmp->cp.inst.operand = AGA_hsstrt; /* 0x000e */
               tmp = find_copper_inst(cp, CI_MOVE(R_HSSTOP));
               tmp->cp.inst.operand = AGA_hsstop; /* 0x001c */
               tmp = find_copper_inst(cp, CI_MOVE(R_HBSTOP));
               tmp->cp.inst.operand = AGA_hsstop; /* 0x001e */
               tmp = find_copper_inst(cp, CI_MOVE(R_HCENTER));
               tmp->cp.inst.operand = AGA_hcenter; /*AGA_htotal / 2 + AGA_hsstrt */
               tmp = find_copper_inst(cp, CI_MOVE(R_VBSTRT));
               tmp->cp.inst.operand = AGA_vbstrt; /* 0x0000 */
               tmp = find_copper_inst(cp, CI_MOVE(R_VSSTRT));
               tmp->cp.inst.operand = AGA_vsstrt; /* 0x016b / AGA_htotal */
               tmp = find_copper_inst(cp, CI_MOVE(R_VSSTOP));
               tmp->cp.inst.operand = AGA_vsstop; /* 0x02d6 / AGA_htotal */
               tmp = find_copper_inst(cp, CI_MOVE(R_VBSTOP));
               tmp->cp.inst.operand = AGA_vbstop; /* 0x0bd1 / AGA_htotal */
               tmp = find_copper_inst(cp, CI_MOVE(R_VTOTAL));
               tmp->cp.inst.operand = AGA_vtotal;
               tmp = find_copper_inst(cp, CI_MOVE(R_BEAMCON0));
               tmp->cp.inst.operand = aga_this_data->beamcon0;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf("  beamcon0 %04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWHIGH));
               tmp->cp.inst.operand = CALC_DIWHIGH(hstart, vstart, hstop, vstop);
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" diwhigh %04x>", tmp->cp.inst.operand);
#endif
#if 0
               tmp->cp.inst.operand = (vstop & 0x0700) | ((hstop & 0x0100) << 5);
#endif
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf("%04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON0));
               tmp->cp.inst.operand = aga_this_data->bplcon0 |
                   ((depth & 0x7) << 12) | ((depth & 0x8) << 1);
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" bplcon0 %04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON1));
               tmp->cp.inst.operand = con1;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" bplcon1 %04x>0000\n", con1);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTART));
               tmp->cp.inst.operand = ((vstart & 0xff) << 8) | (hstart & 0xff);
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf("  diwstart %04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTOP));
               tmp->cp.inst.operand = ((vstop & 0xff) << 8) | (hstop & 0xff);
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" diwstop %04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTART));
               tmp->cp.inst.operand = ddfstart;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" ddfstart %04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTOP));
               tmp->cp.inst.operand = ddfstart + ddfwidth;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" ddfstop %04x", tmp->cp.inst.operand);
#endif

               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               for (i = 0, j = 0; i < depth; j += 2, i++) {
                       /* update the plane pointers */
                       tmp[j].cp.inst.operand = HIADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
                       tmp[j + 1].cp.inst.operand = LOADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf (" bpl%dpth %p", i, v->bitmap->plane[i]);
#endif
               }

               /* set mods correctly. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL1MOD));
               tmp[0].cp.inst.operand = v->bitmap->row_mod;
               tmp[1].cp.inst.operand = v->bitmap->row_mod;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" bplxmod %04x\n", v->bitmap->row_mod);
#endif

               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand = HIADDR(PREP_DMA_MEM(aga_this_data->frames[F_STORE_LONG]));
               tmp[1].cp.inst.operand = LOADDR(PREP_DMA_MEM(aga_this_data->frames[F_STORE_LONG]));

               cp = aga_this_data->frames[F_LONG];
               aga_this_data->frames[F_LONG] = aga_this_data->frames[F_STORE_LONG];
               aga_this_data->frames[F_STORE_LONG] = cp;

               vd->flags |= VF_DISPLAY;

               cc_use_aga_colormap(v, vd->colormap);
       }
       cc_load_mode(aga_this);
#ifdef DEBUG
       if (aga_enable & AGA_TRACE)
               aga_enable |= AGA_TRACE2;       /* XXXX */
#endif
}

/*
* SUPER72 Mode
*/

#if defined (GRF_SUPER72)
dmode_t *
cc_init_super72(void)
{
       /* this function should only be called once. */
       if (!super72_this && (custom.deniseid & 0xff) == 0xf8) {
               u_short len = aga_copper_list_len;

               super72_this = &super72_mode;
               super72_this_data = &super72_mode_data;
               memset(super72_this, 0, sizeof(dmode_t));
               memset(super72_this_data, 0, sizeof(dmdata_t));

               super72_this->name = "super72: superhires interlace";
               super72_this->nominal_size.width = 800;
               super72_this->nominal_size.height = 600;
               super72_this_data->max_size.width = 848;
               super72_this_data->max_size.height = 614;
               super72_this_data->min_size.width = 320;
               super72_this_data->min_size.height = 484;
               super72_this_data->min_depth = 1;
               super72_this_data->max_depth = 8;
               super72_this->data = super72_this_data;

               super72_this->get_monitor = cc_get_monitor;
               super72_this->alloc_view = cc_alloc_view;
               super72_this->get_current_view = cc_get_current_view;

               super72_this_data->use_colormap = cc_use_aga_colormap;
               super72_this_data->get_colormap = cc_get_colormap;
               super72_this_data->alloc_colormap = cc_alloc_aga_colormap;
               super72_this_data->display_view = display_super72_view;
               super72_this_data->monitor = cc_monitor;

               super72_this_data->flags |= DMF_INTERLACE;

               super72_this_data->frames = super72_frames;     /* MAY NEED TO CHANGE COPLIST */
               super72_this_data->frames[F_LACE_LONG] =
                   alloc_chipmem(aga_copper_list_size * F_LACE_TOTAL);
               if (!super72_this_data->frames[F_LACE_LONG]) {
                       panic("couldn't get chipmem for copper list");
               }
               super72_this_data->frames[F_LACE_SHORT] =
                   &super72_this_data->frames[F_LACE_LONG][len];
               super72_this_data->frames[F_LACE_STORE_LONG] =
                   &super72_this_data->frames[F_LACE_SHORT][len];
               super72_this_data->frames[F_LACE_STORE_SHORT] =
                   &super72_this_data->frames[F_LACE_STORE_LONG][len];

               bcopy(aga_copper_list,
                   super72_this_data->frames[F_LACE_STORE_LONG],
                   aga_copper_list_size);
               bcopy(aga_copper_list,
                   super72_this_data->frames[F_LACE_STORE_SHORT],
                   aga_copper_list_size);
               bcopy(aga_copper_list,
                   super72_this_data->frames[F_LACE_LONG],
                   aga_copper_list_size);
               bcopy(aga_copper_list,
                   super72_this_data->frames[F_LACE_SHORT],
                   aga_copper_list_size);

               super72_this_data->bplcon0 = 0x0244 | USE_CON3; /* color
                                                                * composite enable,
                                                                * shres
                                                                * lace. */
#if 0   /* patchable variables for testing */
               super72_this_data->std_start_x = 0x6c;
               super72_this_data->std_start_y = 0x1b;
#endif
               super72_this_data->vbl_handler =
                   (vbl_handler_func *) cc_lace_mode_vbl_handler;
               super72_this_data->beamcon0 = (SPECIAL_BEAMCON ^ VSYNCTRUE) |
                   DISPLAYPAL | 0x4000;
               super72_this_data->beamcon0 = 0x5bb0;

               LIST_INSERT_HEAD(&MDATA(cc_monitor)->modes, super72_this, link);
       }
       return (super72_this);
}

/* Super72 83Hz hack monitor values */
/*int   super72_htotal = 0x083;
int     super72_hsstrt = 0x00d;
int     super72_hsstop = 0x01b;
int     super72_hbstrt = 0x001;
int     super72_hbstop = 0x021;
int     super72_vtotal = 0x148;
int     super72_vsstrt = 0x2d5;
int     super72_vsstop = 0x3ca;
int     super72_vbstrt = 0x000;
int     super72_vbstop = 0xfdc;
int     super72_hcenter = 0x04e;
*/

/* Super72 standard monitor values */
int     super72_htotal = 154;   /* 0x099*/
int     super72_hsstrt = 17;    /* 0x01c*/
int     super72_hsstop = 27;    /* 0x038*/
int     super72_hbstrt = 154;   /* 0x008*/
int     super72_hbstop = 55;    /* 0x01e*/
int     super72_vtotal = 328;   /* 0x147*/
int     super72_vsstrt = 11;    /* 0x030*/
int     super72_vsstop = 18;    /* 0x033*/
int     super72_vbstrt = 327;   /* 0x000*/
int     super72_vbstop = 27;    /* 0x019*/
int     super72_hcenter = 94;   /* 0x057*/
int     super72_startx = 100;
int     super72_starty = 27;

void
display_super72_view(view_t *v)
{
       if (super72_this_data->current_view != v) {
               vdata_t *vd = VDATA(v);
               cop_t  *cp = super72_this_data->frames[F_LACE_STORE_LONG], *tmp;
               int     depth = v->bitmap->depth, i;
               int     hstart, hstop, vstart, vstop, j;
               int     x, y, w = v->display.width, h = v->display.height;
               u_short ddfstart, ddfwidth, con1;

               /* round down to nearest even width */
               /* w &= 0xfffe; */

               /* calculate datafetch width. */
               ddfwidth = ((v->bitmap->bytes_per_row >> 1) - 4) << 1;

               /* This will center any overscanned display */
               /* and allow user to modify. */
               x = (v->display.x >> 1) + super72_startx - ((w - 800) >> 3);
               y = v->display.y + super72_starty - ((h - 600) >> 2);

               hstart = x;
               hstop = x + (w >> 2);
               vstart = y;
               vstop = y + (h >> 1);
               ddfstart = (hstart >> 1) - 16;

               ddfstart = (hstart << 2) - 4;
               con1 = ddfstart & 63;
               ddfstart = (ddfstart & -64) - 64;
               ddfwidth = ((w + 64 - 1) & -64) - 64;
               ddfwidth = ddfwidth >> 3;
               ddfstart = ddfstart >> 3;
               super72_hbstrt = ((x << 2) + w + 4) >> 3;
               super72_hbstop = (hstart + 1) >> 1;
               super72_vbstrt = vstop;
               super72_vbstop = vstart - 2;

               if ((hstop >> 1) > super72_htotal) {
                       int     d;

                       d = (hstop >> 1) - super72_htotal;
                       ddfstart -= d;
                       hstart -= d << 1;
                       hstop -= d << 1;
               }
               if (vstop >= super72_vtotal) {
                       int     d;
                       d = (vstop - super72_vtotal + 1);
                       vstart -= d;
                       vstop -= d;
               }
               con1 = ((con1 >> 2) & 0x000f) |         /* PF1H2-PF1H5 */
                      ((con1 << 8) & 0x0300) |         /* PF1H0-PF1H2 */
                      ((con1 << 4) & 0x0c00);          /* PF1H6-PF1H7 */
               con1 |= con1 << 4;                      /* PF2H2-PF2H7 */

               if (super72_this_data->current_view) {
                       VDATA(super72_this_data->current_view)->flags &=
                           ~VF_DISPLAY;        /* mark as no longer */
                                               /* displayed. */
               }
               super72_this_data->current_view = v;

               cp = super72_this_data->frames[F_LACE_STORE_LONG];
               tmp = find_copper_inst(cp, CI_MOVE(R_FMODE));
               tmp->cp.inst.operand = 0x8003;
               tmp = find_copper_inst(cp, CI_MOVE(R_HTOTAL));
               tmp->cp.inst.operand = super72_htotal;
               tmp = find_copper_inst(cp, CI_MOVE(R_HBSTRT));
               tmp->cp.inst.operand = super72_hbstrt;
               tmp = find_copper_inst(cp, CI_MOVE(R_HSSTRT));
               tmp->cp.inst.operand = super72_hsstrt;
               tmp = find_copper_inst(cp, CI_MOVE(R_HSSTOP));
               tmp->cp.inst.operand = super72_hsstop;
               tmp = find_copper_inst(cp, CI_MOVE(R_HBSTOP));
               tmp->cp.inst.operand = super72_hbstop;
               tmp = find_copper_inst(cp, CI_MOVE(R_HCENTER));
               tmp->cp.inst.operand = super72_hcenter;
               tmp = find_copper_inst(cp, CI_MOVE(R_VBSTRT));
               tmp->cp.inst.operand = super72_vbstrt;
               tmp = find_copper_inst(cp, CI_MOVE(R_VSSTRT));
               tmp->cp.inst.operand = super72_vsstrt;
               tmp = find_copper_inst(cp, CI_MOVE(R_VSSTOP));
               tmp->cp.inst.operand = super72_vsstop;
               tmp = find_copper_inst(cp, CI_MOVE(R_VBSTOP));
               tmp->cp.inst.operand = super72_vbstop;
               tmp = find_copper_inst(cp, CI_MOVE(R_VTOTAL));
               tmp->cp.inst.operand = super72_vtotal;

               tmp = find_copper_inst(cp, CI_MOVE(R_BEAMCON0));
               tmp->cp.inst.operand = super72_this_data->beamcon0;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWHIGH));
               tmp->cp.inst.operand =
                   CALC_DIWHIGH(hstart, vstart, hstop, vstop);
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON0));
               tmp->cp.inst.operand = super72_this_data->bplcon0 |
                   ((depth & 0x7) << 12) | ((depth & 0x8) << 1);
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON1));
               tmp->cp.inst.operand = con1;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTART));
               tmp->cp.inst.operand = ((vstart & 0xff) << 8) | (hstart & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTOP));
               tmp->cp.inst.operand = ((vstop & 0xff) << 8) | (hstop & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTART));
               tmp->cp.inst.operand = ddfstart;
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTOP));
               tmp->cp.inst.operand = ddfstart + ddfwidth;

               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               for (i = 0, j = 0; i < depth; j += 2, i++) {
                       /* update the plane pointers */
                       tmp[j].cp.inst.operand =
                           HIADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
                       tmp[j + 1].cp.inst.operand =
                           LOADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
               }

               /* set mods correctly. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL1MOD));
               tmp[0].cp.inst.operand = v->bitmap->bytes_per_row +
                   v->bitmap->row_mod;
               tmp[1].cp.inst.operand = v->bitmap->bytes_per_row +
                   v->bitmap->row_mod;

               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand =
                   HIADDR(PREP_DMA_MEM(super72_this_data->frames[F_LACE_STORE_SHORT]));
               tmp[1].cp.inst.operand =
                   LOADDR(PREP_DMA_MEM(super72_this_data->frames[F_LACE_STORE_SHORT]));

               bcopy(super72_this_data->frames[F_LACE_STORE_LONG],
                   super72_this_data->frames[F_LACE_STORE_SHORT],
                   aga_copper_list_size);

               /* these are the only ones that are different from long frame. */
               cp = super72_this_data->frames[F_LACE_STORE_SHORT];
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               for (i = 0, j = 0; i < depth; j += 2, i++) {
                       u_short mod = v->bitmap->bytes_per_row +
                           v->bitmap->row_mod;
                       /* update plane pointers. high and low. */
                       tmp[j].cp.inst.operand =
                           HIADDR(PREP_DMA_MEM(&v->bitmap->plane[i][mod]));
                       tmp[j + 1].cp.inst.operand =
                           LOADDR(PREP_DMA_MEM(&v->bitmap->plane[i][mod]));
               }

               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand =
                   HIADDR(PREP_DMA_MEM(super72_this_data->frames[F_LACE_STORE_LONG]));
               tmp[1].cp.inst.operand =
                    LOADDR(PREP_DMA_MEM(super72_this_data->frames[F_LACE_STORE_LONG]));

               cp = super72_this_data->frames[F_LACE_LONG];
               super72_this_data->frames[F_LACE_LONG] =
                   super72_this_data->frames[F_LACE_STORE_LONG];
               super72_this_data->frames[F_LACE_STORE_LONG] = cp;

               cp = super72_this_data->frames[F_LACE_SHORT];
               super72_this_data->frames[F_LACE_SHORT] =
                   super72_this_data->frames[F_LACE_STORE_SHORT];
               super72_this_data->frames[F_LACE_STORE_SHORT] = cp;

               vd->flags |= VF_DISPLAY;
               cc_use_aga_colormap(v, vd->colormap);
       }
       cc_load_mode(super72_this);
}
#endif /* GRF_SUPER72 */

#endif /* GRF_AGA */
#endif /* GRF_NTSC */

/*
* PAL modes.
*/

#if defined (GRF_PAL)

dmode_t *
cc_init_pal_hires(void)
{
       /* this function should only be called once. */
       if (!ph_this) {
               u_short len = std_copper_list_len;

               ph_this = &pal_hires_mode;
               ph_this_data = &pal_hires_mode_data;
               memset(ph_this, 0, sizeof(dmode_t));
               memset(ph_this_data, 0, sizeof(dmdata_t));

               ph_this->name = "pal: hires";
               ph_this->nominal_size.width = 640;
               ph_this->nominal_size.height = 256;
               ph_this_data->max_size.width = 724;
               ph_this_data->max_size.height = 289;
               ph_this_data->min_size.width = 320;
               ph_this_data->min_size.height = 244;
               ph_this_data->min_depth = 1;
               ph_this_data->max_depth = 4;
               ph_this->data = ph_this_data;

               ph_this->get_monitor = cc_get_monitor;
               ph_this->alloc_view = cc_alloc_view;
               ph_this->get_current_view = cc_get_current_view;

               ph_this_data->use_colormap = cc_use_colormap;
               ph_this_data->get_colormap = cc_get_colormap;
               ph_this_data->alloc_colormap = cc_alloc_colormap;
               ph_this_data->display_view = display_pal_hires_view;
               ph_this_data->monitor = cc_monitor;

               ph_this_data->frames = pal_hires_frames;
               ph_this_data->frames[F_LONG] = alloc_chipmem(std_copper_list_size * F_TOTAL);
               if (!ph_this_data->frames[F_LONG]) {
                       panic("couldn't get chipmem for copper list");
               }
               ph_this_data->frames[F_STORE_LONG] = &ph_this_data->frames[F_LONG][len];

               memcpy(ph_this_data->frames[F_STORE_LONG], std_copper_list, std_copper_list_size);
               memcpy(ph_this_data->frames[F_LONG], std_copper_list, std_copper_list_size);

               ph_this_data->bplcon0 = 0x8200 | USE_CON3;      /* pal_hires, color
                                                                * composite enable,
                                                                * lace. */
               ph_this_data->std_start_x = STANDARD_VIEW_X;
               ph_this_data->std_start_y = STANDARD_VIEW_Y;
               ph_this_data->vbl_handler = (vbl_handler_func *) cc_mode_vbl_handler;
#if defined (GRF_ECS) || defined (GRF_AGA)
               ph_this_data->beamcon0 = STANDARD_PAL_BEAMCON;
#endif

               LIST_INSERT_HEAD(&MDATA(cc_monitor)->modes, ph_this, link);
       }
       return (ph_this);
}

void
display_pal_hires_view(view_t *v)
{
       if (ph_this_data->current_view != v) {
               vdata_t *vd = VDATA(v);
               cop_t  *cp = ph_this_data->frames[F_STORE_LONG], *tmp;
               int     depth = v->bitmap->depth, i;
               int     hstart, hstop, vstart, vstop, j;
               int     x, y, w = v->display.width, h = v->display.height;
               u_short ddfstart, ddfwidth, con1;

               /* round down to nearest even width */
               /* w &= 0xfffe; */

               /* calculate datafetch width. */
               ddfwidth = ((v->bitmap->bytes_per_row >> 1) - 2) << 2;

               /* This will center the any overscanned display */
               /* and allow user to modify. */
               x = v->display.x + ph_this_data->std_start_x - ((w - 640) >> 2);
               y = v->display.y + ph_this_data->std_start_y - ((h - 256) >> 1);

               if (y & 1)
                       y--;

               if (!(x & 1))
                       x--;

               hstart = x;
               hstop = x + (w >> 1);
               vstart = y;
               vstop = y + h;
               ddfstart = (hstart - 9) >> 1;
               /* check for hardware limits, AGA may allow more..? */
               /* anyone got a 4000 I can borrow :^) -ch */
               if ((ddfstart & 0xfffc) + ddfwidth > 0xd8) {
                       int     d = 0;

                       /* XXX anyone know the equality properties of
                        * intermixed logial AND's */
                       /* XXX and arithmetic operators? */
                       while (((ddfstart & 0xfffc) + ddfwidth - d) > 0xd8) {
                               d++;
                       }

                       ddfstart -= d;
                       hstart -= d << 1;
                       hstop -= d << 1;
               }
               /* correct the datafetch to proper limits. */
               /* delay the actual display of the data until we need it. */
               ddfstart &= 0xfffc;
               con1 = ((hstart - 9) - (ddfstart << 1)) | (((hstart - 9) - (ddfstart << 1)) << 4);

               if (ph_this_data->current_view) {
                       VDATA(ph_this_data->current_view)->flags &= ~VF_DISPLAY;        /* mark as no longer */
                       /* displayed. */
               }
               ph_this_data->current_view = v;

               cp = ph_this_data->frames[F_STORE_LONG];
#if defined (GRF_ECS) || defined (GRF_AGA)
#if defined (GRF_AGA)
               tmp = find_copper_inst(cp, CI_MOVE(R_FMODE));
               tmp->cp.inst.operand = 0;
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_BEAMCON0));
               tmp->cp.inst.operand = ph_this_data->beamcon0;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWHIGH));
               tmp->cp.inst.operand = CALC_DIWHIGH(hstart, vstart, hstop, vstop);
#endif /* ECS */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON0));
               tmp->cp.inst.operand = ph_this_data->bplcon0 | ((depth & 0x7) << 12);
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON1));
               tmp->cp.inst.operand = con1;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTART));
               tmp->cp.inst.operand = ((vstart & 0xff) << 8) | (hstart & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTOP));
               tmp->cp.inst.operand = ((vstop & 0xff) << 8) | (hstop & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTART));
               tmp->cp.inst.operand = ddfstart;
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTOP));
               tmp->cp.inst.operand = ddfstart + ddfwidth;

               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               for (i = 0, j = 0; i < depth; j += 2, i++) {
                       /* update the plane pointers */
                       tmp[j].cp.inst.operand = HIADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
                       tmp[j + 1].cp.inst.operand = LOADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
               }

               /* set mods correctly. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL1MOD));
               tmp[0].cp.inst.operand = v->bitmap->row_mod;
               tmp[1].cp.inst.operand = v->bitmap->row_mod;

               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand = HIADDR(PREP_DMA_MEM(ph_this_data->frames[F_STORE_LONG]));
               tmp[1].cp.inst.operand = LOADDR(PREP_DMA_MEM(ph_this_data->frames[F_STORE_LONG]));

               cp = ph_this_data->frames[F_LONG];
               ph_this_data->frames[F_LONG] = ph_this_data->frames[F_STORE_LONG];
               ph_this_data->frames[F_STORE_LONG] = cp;

               vd->flags |= VF_DISPLAY;
               cc_use_colormap(v, vd->colormap);
       }
       cc_load_mode(ph_this);
}

dmode_t *
cc_init_pal_hires_lace(void)
{
       /* this function should only be called once. */
       if (!phl_this) {
               u_short len = std_copper_list_len;

               phl_this = &pal_hires_lace_mode;
               phl_this_data = &pal_hires_lace_mode_data;
               memset(phl_this, 0, sizeof(dmode_t));
               memset(phl_this_data, 0, sizeof(dmdata_t));

               phl_this->name = "pal: hires interlace";
               phl_this->nominal_size.width = 640;
               phl_this->nominal_size.height = 512;
               phl_this_data->max_size.width = 724;
               phl_this_data->max_size.height = 578;
               phl_this_data->min_size.width = 320;
               phl_this_data->min_size.height = 484;
               phl_this_data->min_depth = 1;
               phl_this_data->max_depth = 4;
               phl_this->data = phl_this_data;

               phl_this->get_monitor = cc_get_monitor;
               phl_this->alloc_view = cc_alloc_view;
               phl_this->get_current_view = cc_get_current_view;

               phl_this_data->use_colormap = cc_use_colormap;
               phl_this_data->get_colormap = cc_get_colormap;
               phl_this_data->alloc_colormap = cc_alloc_colormap;
               phl_this_data->display_view = display_pal_hires_lace_view;
               phl_this_data->monitor = cc_monitor;

               phl_this_data->flags |= DMF_INTERLACE;

               phl_this_data->frames = pal_hires_lace_frames;
               phl_this_data->frames[F_LACE_LONG] = alloc_chipmem(std_copper_list_size * F_LACE_TOTAL);
               if (!phl_this_data->frames[F_LACE_LONG]) {
                       panic("couldn't get chipmem for copper list");
               }
               phl_this_data->frames[F_LACE_SHORT] = &phl_this_data->frames[F_LACE_LONG][len];
               phl_this_data->frames[F_LACE_STORE_LONG] = &phl_this_data->frames[F_LACE_SHORT][len];
               phl_this_data->frames[F_LACE_STORE_SHORT] = &phl_this_data->frames[F_LACE_STORE_LONG][len];

               memcpy(phl_this_data->frames[F_LACE_STORE_LONG], std_copper_list, std_copper_list_size);
               memcpy(phl_this_data->frames[F_LACE_STORE_SHORT], std_copper_list, std_copper_list_size);
               memcpy(phl_this_data->frames[F_LACE_LONG], std_copper_list, std_copper_list_size);
               memcpy(phl_this_data->frames[F_LACE_SHORT], std_copper_list, std_copper_list_size);

               phl_this_data->bplcon0 = 0x8204 | USE_CON3;     /* hires, color
                                                                * composite enable,
                                                                * lace. */
               phl_this_data->std_start_x = STANDARD_VIEW_X;
               phl_this_data->std_start_y = STANDARD_VIEW_Y;
               phl_this_data->vbl_handler = (vbl_handler_func *) cc_lace_mode_vbl_handler;
#if defined (GRF_ECS) || defined (GRF_AGA)
               phl_this_data->beamcon0 = STANDARD_PAL_BEAMCON;
#endif

               LIST_INSERT_HEAD(&MDATA(cc_monitor)->modes, phl_this, link);
       }
       return (phl_this);
}

void
display_pal_hires_lace_view(view_t *v)
{
       if (phl_this_data->current_view != v) {
               vdata_t *vd = VDATA(v);
               cop_t  *cp = phl_this_data->frames[F_LACE_STORE_LONG], *tmp;
               int     depth = v->bitmap->depth, i;
               int     hstart, hstop, vstart, vstop, j;
               int     x, y, w = v->display.width, h = v->display.height;
               u_short ddfstart, ddfwidth, con1;

               /* round down to nearest even width */
               /* w &= 0xfffe; */

               /* calculate datafetch width. */
               ddfwidth = ((v->bitmap->bytes_per_row >> 1) - 2) << 2;

               /* This will center the any overscanned display */
               /* and allow user to modify. */
               x = v->display.x + phl_this_data->std_start_x - ((w - 640) >> 2);
               y = v->display.y + phl_this_data->std_start_y - ((h - 512) >> 2);

               if (y & 1)
                       y--;

               if (!(x & 1))
                       x--;

               hstart = x;
               hstop = x + (w >> 1);
               vstart = y;
               vstop = y + (h >> 1);
               ddfstart = (hstart - 9) >> 1;

               /* check for hardware limits, AGA may allow more..? */
               /* anyone got a 4000 I can borrow :^) -ch */
               if ((ddfstart & 0xfffc) + ddfwidth > 0xd8) {
                       int     d = 0;

                       /* XXX anyone know the equality properties of
                        * intermixed logial AND's */
                       /* XXX and arithmetic operators? */
                       while (((ddfstart & 0xfffc) + ddfwidth - d) > 0xd8) {
                               d++;
                       }

                       ddfstart -= d;
                       hstart -= d << 1;
                       hstop -= d << 1;
               }
               /* correct the datafetch to proper limits. */
               /* delay the actual display of the data until we need it. */
               ddfstart &= 0xfffc;
               con1 = ((hstart - 9) - (ddfstart << 1)) | (((hstart - 9) - (ddfstart << 1)) << 4);

               if (phl_this_data->current_view) {
                       VDATA(phl_this_data->current_view)->flags &= ~VF_DISPLAY;       /* mark as no longer */
                       /* displayed. */
               }
               phl_this_data->current_view = v;

               cp = phl_this_data->frames[F_LACE_STORE_LONG];
#if defined (GRF_ECS) || defined (GRF_AGA)
#if defined (GRF_AGA)
               tmp = find_copper_inst(cp, CI_MOVE(R_FMODE));
               tmp->cp.inst.operand = 0;
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_BEAMCON0));
               tmp->cp.inst.operand = phl_this_data->beamcon0;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWHIGH));
               tmp->cp.inst.operand = CALC_DIWHIGH(hstart, vstart, hstop, vstop);
#endif /* ECS */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON0));
               tmp->cp.inst.operand = phl_this_data->bplcon0 | ((depth & 0x7) << 12);
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON1));
               tmp->cp.inst.operand = con1;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTART));
               tmp->cp.inst.operand = ((vstart & 0xff) << 8) | (hstart & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTOP));
               tmp->cp.inst.operand = ((vstop & 0xff) << 8) | (hstop & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTART));
               tmp->cp.inst.operand = ddfstart;
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTOP));
               tmp->cp.inst.operand = ddfstart + ddfwidth;

               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               for (i = 0, j = 0; i < depth; j += 2, i++) {
                       /* update the plane pointers */
                       tmp[j].cp.inst.operand = HIADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
                       tmp[j + 1].cp.inst.operand = LOADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
               }

               /* set mods correctly. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL1MOD));
               tmp[0].cp.inst.operand = v->bitmap->bytes_per_row + v->bitmap->row_mod;
               tmp[1].cp.inst.operand = v->bitmap->bytes_per_row + v->bitmap->row_mod;

               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand = HIADDR(PREP_DMA_MEM(phl_this_data->frames[F_LACE_STORE_SHORT]));
               tmp[1].cp.inst.operand = LOADDR(PREP_DMA_MEM(phl_this_data->frames[F_LACE_STORE_SHORT]));


               memcpy(phl_this_data->frames[F_LACE_STORE_SHORT], phl_this_data->frames[F_LACE_STORE_LONG], std_copper_list_size);

               /* these are the only ones that are different from long frame. */
               cp = phl_this_data->frames[F_LACE_STORE_SHORT];
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               for (i = 0, j = 0; i < depth; j += 2, i++) {
                       u_short mod = v->bitmap->bytes_per_row + v->bitmap->row_mod;
                       /* update plane pointers. high and low. */
                       tmp[j].cp.inst.operand = HIADDR(PREP_DMA_MEM(&v->bitmap->plane[i][mod]));
                       tmp[j + 1].cp.inst.operand = LOADDR(PREP_DMA_MEM(&v->bitmap->plane[i][mod]));
               }

               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand = HIADDR(PREP_DMA_MEM(phl_this_data->frames[F_LACE_STORE_LONG]));
               tmp[1].cp.inst.operand = LOADDR(PREP_DMA_MEM(phl_this_data->frames[F_LACE_STORE_LONG]));


               cp = phl_this_data->frames[F_LACE_LONG];
               phl_this_data->frames[F_LACE_LONG] = phl_this_data->frames[F_LACE_STORE_LONG];
               phl_this_data->frames[F_LACE_STORE_LONG] = cp;

               cp = phl_this_data->frames[F_LACE_SHORT];
               phl_this_data->frames[F_LACE_SHORT] = phl_this_data->frames[F_LACE_STORE_SHORT];
               phl_this_data->frames[F_LACE_STORE_SHORT] = cp;

               vd->flags |= VF_DISPLAY;
               cc_use_colormap(v, vd->colormap);
       }
       cc_load_mode(phl_this);
}
#if defined (GRF_A2024)

dmode_t *
cc_init_pal_hires_dlace(void)
{
       /* this function should only be called once. */
       if (!phdl_this) {
               u_short len = std_dlace_copper_list_len;

               phdl_this = &pal_hires_dlace_mode;
               phdl_this_data = &pal_hires_dlace_mode_data;
               memset(phdl_this, 0, sizeof(dmode_t));
               memset(phdl_this_data, 0, sizeof(dmdata_t));

               phdl_this->name = "pal: hires double interlace";
               phdl_this->nominal_size.width = 640;
               phdl_this->nominal_size.height = 1024;
               phdl_this_data->max_size.width = 724;
               phdl_this_data->max_size.height = 1024;
               phdl_this_data->min_size.width = 320;
               phdl_this_data->min_size.height = 512;
               phdl_this_data->min_depth = 1;
               phdl_this_data->max_depth = 2;
               phdl_this->data = phdl_this_data;

               phdl_this->get_monitor = cc_get_monitor;
               phdl_this->alloc_view = cc_alloc_view;
               phdl_this->get_current_view = cc_get_current_view;

               phdl_this_data->use_colormap = cc_a2024_use_colormap;
               phdl_this_data->get_colormap = cc_a2024_get_colormap;
               phdl_this_data->alloc_colormap = cc_a2024_alloc_colormap;
               phdl_this_data->display_view = display_pal_hires_dlace_view;
               phdl_this_data->monitor = cc_monitor;

               phdl_this_data->flags |= DMF_INTERLACE;

               phdl_this_data->frames = pal_hires_dlace_frames;
               phdl_this_data->frames[F_LACE_LONG] = alloc_chipmem(std_dlace_copper_list_size * F_LACE_TOTAL);
               if (!phdl_this_data->frames[F_LACE_LONG]) {
                       panic("couldn't get chipmem for copper list");
               }
               phdl_this_data->frames[F_LACE_SHORT] = &phdl_this_data->frames[F_LACE_LONG][len];
               phdl_this_data->frames[F_LACE_STORE_LONG] = &phdl_this_data->frames[F_LACE_SHORT][len];
               phdl_this_data->frames[F_LACE_STORE_SHORT] = &phdl_this_data->frames[F_LACE_STORE_LONG][len];

               memcpy(phdl_this_data->frames[F_LACE_STORE_LONG], std_dlace_copper_list, std_dlace_copper_list_size);
               memcpy(phdl_this_data->frames[F_LACE_STORE_SHORT], std_dlace_copper_list, std_dlace_copper_list_size);
               memcpy(phdl_this_data->frames[F_LACE_LONG], std_dlace_copper_list, std_dlace_copper_list_size);
               memcpy(phdl_this_data->frames[F_LACE_SHORT], std_dlace_copper_list, std_dlace_copper_list_size);

               phdl_this_data->bplcon0 = 0x8204 | USE_CON3;    /* hires, color
                                                                * composite enable,
                                                                * dlace. */
               phdl_this_data->std_start_x = STANDARD_VIEW_X;
               phdl_this_data->std_start_y = STANDARD_VIEW_Y;
               phdl_this_data->vbl_handler = (vbl_handler_func *) cc_lace_mode_vbl_handler;
#if defined (GRF_ECS) || defined (GRF_AGA)
               phdl_this_data->beamcon0 = STANDARD_PAL_BEAMCON;
#endif

               LIST_INSERT_HEAD(&MDATA(cc_monitor)->modes, phdl_this, link);
       }
       return (phdl_this);
}

void
display_pal_hires_dlace_view(view_t *v)
{
       if (phdl_this_data->current_view != v) {
               vdata_t *vd = VDATA(v);
               cop_t  *cp = phdl_this_data->frames[F_LACE_STORE_LONG], *tmp;
               int     depth = v->bitmap->depth;
               int     hstart, hstop, vstart, vstop;
               int     x, y, w = v->display.width, h = v->display.height;
               u_short ddfstart, ddfwidth, con1;
               u_short mod1l, mod2l;

               /* round down to nearest even width */
               /* w &= 0xfffe; */

               /* calculate datafetch width. */
               ddfwidth = ((v->bitmap->bytes_per_row >> 1) - 2) << 2;

               /* This will center the any overscanned display */
               /* and allow user to modify. */
               x = v->display.x + phdl_this_data->std_start_x - ((w - 640) >> 2);
               y = v->display.y + phdl_this_data->std_start_y - ((h - 1024) >> 3);

               if (y & 1)
                       y--;

               if (!(x & 1))
                       x--;

               hstart = x;
               hstop = x + (w >> 1);
               vstart = y;
               vstop = y + (h >> 2);
               ddfstart = (hstart - 9) >> 1;

               /* check for hardware limits, AGA may allow more..? */
               /* anyone got a 4000 I can borrow :^) -ch */
               if ((ddfstart & 0xfffc) + ddfwidth > 0xd8) {
                       int     d = 0;

                       /* XXX anyone know the equality properties of
                        * intermixed logial AND's */
                       /* XXX and arithmetic operators? */
                       while (((ddfstart & 0xfffc) + ddfwidth - d) > 0xd8) {
                               d++;
                       }

                       ddfstart -= d;
                       hstart -= d << 1;
                       hstop -= d << 1;
               }
               /* correct the datafetch to proper limits. */
               /* delay the actual display of the data until we need it. */
               ddfstart &= 0xfffc;
               con1 = ((hstart - 9) - (ddfstart << 1)) | (((hstart - 9) - (ddfstart << 1)) << 4);

               if (phdl_this_data->current_view) {
                       VDATA(phdl_this_data->current_view)->flags &= ~VF_DISPLAY;      /* mark as no longer */
                       /* displayed. */
               }
               phdl_this_data->current_view = v;

               cp = phdl_this_data->frames[F_LACE_STORE_LONG];
#if defined (GRF_ECS) || defined (GRF_AGA)
#if defined (GRF_AGA)
               tmp = find_copper_inst(cp, CI_MOVE(R_FMODE));
               tmp->cp.inst.operand = 0;
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_BEAMCON0));
               tmp->cp.inst.operand = phdl_this_data->beamcon0;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWHIGH));
               tmp->cp.inst.operand = CALC_DIWHIGH(hstart, vstart, hstop, vstop);
#endif /* ECS */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON0));
               tmp->cp.inst.operand = phdl_this_data->bplcon0 | ((depth & 0x7) << 13); /* times two. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON1));
               tmp->cp.inst.operand = con1;
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTART));
               tmp->cp.inst.operand = ((vstart & 0xff) << 8) | (hstart & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTOP));
               tmp->cp.inst.operand = ((vstop & 0xff) << 8) | (hstop & 0xff);
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTART));
               tmp->cp.inst.operand = ddfstart;
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTOP));
               tmp->cp.inst.operand = ddfstart + ddfwidth;

               mod1l = v->bitmap->bytes_per_row + v->bitmap->row_mod;
               mod2l = mod1l << 1;

               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               tmp[0].cp.inst.operand = HIADDR(PREP_DMA_MEM(&v->bitmap->plane[0][0])); /* update plane
                                                                                        * pointers. */
               tmp[1].cp.inst.operand = LOADDR(PREP_DMA_MEM(&v->bitmap->plane[0][0])); /* high and low. */
               tmp[2].cp.inst.operand = HIADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod1l]));     /* update plane
                                                                                                * pointers. */
               tmp[3].cp.inst.operand = LOADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod1l]));     /* high and low. */
               if (depth == 2) {
                       tmp[4].cp.inst.operand = HIADDR(PREP_DMA_MEM(&v->bitmap->plane[1][0])); /* update plane
                                                                                                * pointers. */
                       tmp[5].cp.inst.operand = LOADDR(PREP_DMA_MEM(&v->bitmap->plane[1][0])); /* high and low. */
                       tmp[6].cp.inst.operand = HIADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod1l]));     /* update plane
                                                                                                        * pointers. */
                       tmp[7].cp.inst.operand = LOADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod1l]));     /* high and low. */
               }
               /* set mods correctly. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL1MOD));
               tmp[0].cp.inst.operand = mod2l + mod1l;
               tmp[1].cp.inst.operand = mod2l + mod1l;

               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand = HIADDR(PREP_DMA_MEM(phdl_this_data->frames[F_LACE_STORE_SHORT]));
               tmp[1].cp.inst.operand = LOADDR(PREP_DMA_MEM(phdl_this_data->frames[F_LACE_STORE_SHORT]));

               memcpy(phdl_this_data->frames[F_LACE_STORE_SHORT], phdl_this_data->frames[F_LACE_STORE_LONG], std_dlace_copper_list_size);

               /* these are the only ones that are different from long frame. */
               cp = phdl_this_data->frames[F_LACE_STORE_SHORT];
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               tmp[0].cp.inst.operand = HIADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod2l]));     /* update plane
                                                                                                * pointers. */
               tmp[1].cp.inst.operand = LOADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod2l]));     /* high and low. */
               tmp[2].cp.inst.operand = HIADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod2l + mod1l]));     /* update plane
                                                                                                        * pointers. */
               tmp[3].cp.inst.operand = LOADDR(PREP_DMA_MEM(&v->bitmap->plane[0][mod2l + mod1l]));     /* high and low. */
               if (depth == 2) {
                       tmp[4].cp.inst.operand = HIADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod2l]));     /* update plane
                                                                                                        * pointers. */
                       tmp[5].cp.inst.operand = LOADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod2l]));     /* high and low. */
                       tmp[6].cp.inst.operand = HIADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod2l + mod1l]));     /* update plane
                                                                                                                * pointers. */
                       tmp[7].cp.inst.operand = LOADDR(PREP_DMA_MEM(&v->bitmap->plane[1][mod2l + mod1l]));     /* high and low. */
               }
               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand = HIADDR(PREP_DMA_MEM(phdl_this_data->frames[F_LACE_STORE_LONG]));
               tmp[1].cp.inst.operand = LOADDR(PREP_DMA_MEM(phdl_this_data->frames[F_LACE_STORE_LONG]));

               cp = phdl_this_data->frames[F_LACE_LONG];
               phdl_this_data->frames[F_LACE_LONG] = phdl_this_data->frames[F_LACE_STORE_LONG];
               phdl_this_data->frames[F_LACE_STORE_LONG] = cp;

               cp = phdl_this_data->frames[F_LACE_SHORT];
               phdl_this_data->frames[F_LACE_SHORT] = phdl_this_data->frames[F_LACE_STORE_SHORT];
               phdl_this_data->frames[F_LACE_STORE_SHORT] = cp;

               vd->flags |= VF_DISPLAY;

               cc_a2024_use_colormap(v, vd->colormap);
       }
       cc_load_mode(phdl_this);
}

dmode_t *
cc_init_pal_a2024(void)
{
       /* this function should only be called once. */
       if (!p24_this) {
               int     i;
               u_short len = std_pal_a2024_copper_list_len;
               cop_t  *cp;

               p24_this = &pal_a2024_mode;
               p24_this_data = &pal_a2024_mode_data;
               memset(p24_this, 0, sizeof(dmode_t));
               memset(p24_this_data, 0, sizeof(dmdata_t));

               p24_this->name = "pal: A2024 15 kHz";
               p24_this->nominal_size.width = 1024;
               p24_this->nominal_size.height = 1024;
               p24_this_data->max_size.width = 1024;
               p24_this_data->max_size.height = 1024;
               p24_this_data->min_size.width = 1024;
               p24_this_data->min_size.height = 1024;
               p24_this_data->min_depth = 1;
               p24_this_data->max_depth = 2;
               p24_this->data = p24_this_data;

               p24_this->get_monitor = cc_get_monitor;
               p24_this->alloc_view = cc_alloc_view;
               p24_this->get_current_view = cc_get_current_view;

               p24_this_data->use_colormap = cc_a2024_use_colormap;
               p24_this_data->get_colormap = cc_a2024_get_colormap;
               p24_this_data->display_view = display_pal_a2024_view;
               p24_this_data->alloc_colormap = cc_a2024_alloc_colormap;
               p24_this_data->monitor = cc_monitor;

               p24_this_data->flags |= DMF_HEDLEY_EXP;

               p24_this_data->frames = pal_a2024_frames;
               p24_this_data->frames[F_QD_QUAD0] = alloc_chipmem(std_pal_a2024_copper_list_size * F_QD_TOTAL);
               if (!p24_this_data->frames[F_QD_QUAD0]) {
                       panic("couldn't get chipmem for copper list");
               }
               /* setup the hedley init bitplane. */
               hedley_init = alloc_chipmem(128);
               if (!hedley_init) {
                       panic("couldn't get chipmem for hedley init bitplane");
               }
               for (i = 1; i < 128; i++)
                       hedley_init[i] = 0xff;
               hedley_init[0] = 0x03;

               /* copy image of standard copper list. */
               memcpy(p24_this_data->frames[0], std_pal_a2024_copper_list, std_pal_a2024_copper_list_size);

               /* set the init plane pointer. */
               cp = find_copper_inst(p24_this_data->frames[F_QD_QUAD0], CI_MOVE(R_BPL0PTH));
               cp[0].cp.inst.operand = HIADDR(PREP_DMA_MEM(hedley_init));
               cp[1].cp.inst.operand = LOADDR(PREP_DMA_MEM(hedley_init));

               for (i = 1; i < F_QD_TOTAL; i++) {
                       p24_this_data->frames[i] = &p24_this_data->frames[i - 1][len];
                       memcpy(p24_this_data->frames[i], p24_this_data->frames[0], std_pal_a2024_copper_list_size);
               }

               p24_this_data->bplcon0 = 0x8200;        /* hires */
               p24_this_data->vbl_handler = (vbl_handler_func *) pal_a2024_mode_vbl_handler;


               LIST_INSERT_HEAD(&MDATA(cc_monitor)->modes, p24_this, link);
       }
       return (p24_this);
}

void
display_pal_a2024_view(view_t *v)
{
       if (p24_this_data->current_view != v) {
               vdata_t *vd = VDATA(v);
               cop_t  *cp, *tmp;
               u_char *inst_plane[2] = { NULL, NULL };
               u_char **plane = inst_plane;
               u_long  full_line = v->bitmap->bytes_per_row + v->bitmap->row_mod;
               u_long  half_plane = full_line * v->bitmap->rows / 2;

               int     depth = v->bitmap->depth, i, j;

               plane[0] = v->bitmap->plane[0];
               if (depth == 2) {
                       plane[1] = v->bitmap->plane[1];
               }
               if (p24_this_data->current_view) {
                       VDATA(p24_this_data->current_view)->flags &= ~VF_DISPLAY;       /* mark as no longer
                                                                                        * displayed. */
               }
               cp = p24_this_data->frames[F_QD_STORE_QUAD0];
               tmp = find_copper_inst(cp, CI_MOVE(R_COLOR1F));
               tmp = find_copper_inst(tmp, CI_MOVE(R_BPLCON0));        /* grab third one. */
               tmp->cp.inst.operand = p24_this_data->bplcon0 | ((depth & 0x7) << 13);  /* times 2 */

               memcpy(p24_this_data->frames[F_QD_STORE_QUAD1], p24_this_data->frames[F_QD_STORE_QUAD0], std_pal_a2024_copper_list_size);
               memcpy(p24_this_data->frames[F_QD_STORE_QUAD2], p24_this_data->frames[F_QD_STORE_QUAD0], std_pal_a2024_copper_list_size);
               memcpy(p24_this_data->frames[F_QD_STORE_QUAD3], p24_this_data->frames[F_QD_STORE_QUAD0], std_pal_a2024_copper_list_size);

               /*
                * Mark Id's
                */
               tmp = find_copper_inst(p24_this_data->frames[F_QD_STORE_QUAD1], CI_WAIT(126, 29));
               CBUMP(tmp);
               CMOVE(tmp, R_COLOR01, QUAD1_ID);
               tmp = find_copper_inst(p24_this_data->frames[F_QD_STORE_QUAD2], CI_WAIT(126, 29));
               CBUMP(tmp);
               CMOVE(tmp, R_COLOR01, QUAD2_ID);
               tmp = find_copper_inst(p24_this_data->frames[F_QD_STORE_QUAD3], CI_WAIT(126, 29));
               CBUMP(tmp);
               CMOVE(tmp, R_COLOR01, QUAD3_ID);

               plane[0]--;
               plane[0]--;
               if (depth == 2) {
                       plane[1]--;
                       plane[1]--;
               }
               /*
                * Set bitplane pointers.
                */
               tmp = find_copper_inst(p24_this_data->frames[F_QD_STORE_QUAD0], CI_MOVE(R_BPLMOD2));
               CBUMP(tmp);
               CMOVE(tmp, R_BPL0PTH, HIADDR(PREP_DMA_MEM(&plane[0][0])));
               CMOVE(tmp, R_BPL0PTL, LOADDR(PREP_DMA_MEM(&plane[0][0])));
               CMOVE(tmp, R_BPL1PTH, HIADDR(PREP_DMA_MEM(&plane[0][full_line])));
               CMOVE(tmp, R_BPL1PTL, LOADDR(PREP_DMA_MEM(&plane[0][full_line])));
               if (depth == 2) {
                       CMOVE(tmp, R_BPL2PTH, HIADDR(PREP_DMA_MEM(&plane[1][0])));
                       CMOVE(tmp, R_BPL2PTL, LOADDR(PREP_DMA_MEM(&plane[1][0])));
                       CMOVE(tmp, R_BPL3PTH, HIADDR(PREP_DMA_MEM(&plane[1][full_line])));
                       CMOVE(tmp, R_BPL3PTL, LOADDR(PREP_DMA_MEM(&plane[1][full_line])));
               }
#if defined (GRF_ECS) || defined (GRF_AGA)
               CMOVE(tmp, R_DIWHIGH, 0x2100);
#endif
               CMOVE(tmp, R_COP1LCH, HIADDR(PREP_DMA_MEM(p24_this_data->frames[F_QD_STORE_QUAD1])));
               CMOVE(tmp, R_COP1LCL, LOADDR(PREP_DMA_MEM(p24_this_data->frames[F_QD_STORE_QUAD1])));
               CEND(tmp);
               CEND(tmp);

               tmp = find_copper_inst(p24_this_data->frames[F_QD_STORE_QUAD1], CI_MOVE(R_BPLMOD2));
               CBUMP(tmp);
               CMOVE(tmp, R_BPL0PTH, HIADDR(PREP_DMA_MEM(&plane[0][HALF_2024_LINE])));
               CMOVE(tmp, R_BPL0PTL, LOADDR(PREP_DMA_MEM(&plane[0][HALF_2024_LINE])));
               CMOVE(tmp, R_BPL1PTH, HIADDR(PREP_DMA_MEM(&plane[0][full_line + HALF_2024_LINE])));
               CMOVE(tmp, R_BPL1PTL, LOADDR(PREP_DMA_MEM(&plane[0][full_line + HALF_2024_LINE])));
               if (depth == 2) {
                       CMOVE(tmp, R_BPL2PTH, HIADDR(PREP_DMA_MEM(&plane[1][HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL2PTL, LOADDR(PREP_DMA_MEM(&plane[1][HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL3PTH, HIADDR(PREP_DMA_MEM(&plane[1][full_line + HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL3PTL, LOADDR(PREP_DMA_MEM(&plane[1][full_line + HALF_2024_LINE])));
               }
#if defined (GRF_ECS) || defined (GRF_AGA)
               CMOVE(tmp, R_DIWHIGH, 0x2100);
#endif
               CMOVE(tmp, R_COP1LCH, HIADDR(PREP_DMA_MEM(p24_this_data->frames[F_QD_STORE_QUAD2])));
               CMOVE(tmp, R_COP1LCL, LOADDR(PREP_DMA_MEM(p24_this_data->frames[F_QD_STORE_QUAD2])));
               CEND(tmp);
               CEND(tmp);

               tmp = find_copper_inst(p24_this_data->frames[F_QD_STORE_QUAD2], CI_MOVE(R_BPLMOD2));
               CBUMP(tmp);
               CMOVE(tmp, R_BPL0PTH, HIADDR(PREP_DMA_MEM(&plane[0][half_plane])));
               CMOVE(tmp, R_BPL0PTL, LOADDR(PREP_DMA_MEM(&plane[0][half_plane])));
               CMOVE(tmp, R_BPL1PTH, HIADDR(PREP_DMA_MEM(&plane[0][half_plane + full_line])));
               CMOVE(tmp, R_BPL1PTL, LOADDR(PREP_DMA_MEM(&plane[0][half_plane + full_line])));
               if (depth == 2) {
                       CMOVE(tmp, R_BPL2PTH, HIADDR(PREP_DMA_MEM(&plane[1][half_plane])));
                       CMOVE(tmp, R_BPL2PTL, LOADDR(PREP_DMA_MEM(&plane[1][half_plane])));
                       CMOVE(tmp, R_BPL3PTH, HIADDR(PREP_DMA_MEM(&plane[1][half_plane + full_line])));
                       CMOVE(tmp, R_BPL3PTL, LOADDR(PREP_DMA_MEM(&plane[1][half_plane + full_line])));
               }
#if defined (GRF_ECS) || defined (GRF_AGA)
               CMOVE(tmp, R_DIWHIGH, 0x2100);
#endif
               CMOVE(tmp, R_COP1LCH, HIADDR(PREP_DMA_MEM(p24_this_data->frames[F_QD_STORE_QUAD3])));
               CMOVE(tmp, R_COP1LCL, LOADDR(PREP_DMA_MEM(p24_this_data->frames[F_QD_STORE_QUAD3])));
               CEND(tmp);
               CEND(tmp);

               tmp = find_copper_inst(p24_this_data->frames[F_QD_STORE_QUAD3], CI_MOVE(R_BPLMOD2));
               CBUMP(tmp);
               CMOVE(tmp, R_BPL0PTH, HIADDR(PREP_DMA_MEM(&plane[0][half_plane + HALF_2024_LINE])));
               CMOVE(tmp, R_BPL0PTL, LOADDR(PREP_DMA_MEM(&plane[0][half_plane + HALF_2024_LINE])));
               CMOVE(tmp, R_BPL1PTH, HIADDR(PREP_DMA_MEM(&plane[0][half_plane + full_line + HALF_2024_LINE])));
               CMOVE(tmp, R_BPL1PTL, LOADDR(PREP_DMA_MEM(&plane[0][half_plane + full_line + HALF_2024_LINE])));
               if (depth == 2) {
                       CMOVE(tmp, R_BPL2PTH, HIADDR(PREP_DMA_MEM(&plane[1][half_plane + HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL2PTL, LOADDR(PREP_DMA_MEM(&plane[1][half_plane + HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL3PTH, HIADDR(PREP_DMA_MEM(&plane[1][half_plane + full_line + HALF_2024_LINE])));
                       CMOVE(tmp, R_BPL3PTL, LOADDR(PREP_DMA_MEM(&plane[1][half_plane + full_line + HALF_2024_LINE])));
               }
#if defined (GRF_ECS) || defined (GRF_AGA)
               CMOVE(tmp, R_DIWHIGH, 0x2100);
#endif
               CMOVE(tmp, R_COP1LCH, HIADDR(PREP_DMA_MEM(p24_this_data->frames[F_QD_STORE_QUAD0])));
               CMOVE(tmp, R_COP1LCL, LOADDR(PREP_DMA_MEM(p24_this_data->frames[F_QD_STORE_QUAD0])));
               CEND(tmp);
               CEND(tmp);

               /* swap new pointers in. */
               for (i = F_QD_STORE_QUAD0, j = F_QD_QUAD0;
                   i <= F_QD_STORE_QUAD3; i++, j++) {
                       cp = p24_this_data->frames[j];
                       p24_this_data->frames[j] = p24_this_data->frames[i];
                       p24_this_data->frames[i] = cp;
               }

               p24_this_data->current_view = v;
               vd->flags |= VF_DISPLAY;

               cc_a2024_use_colormap(v, vd->colormap);
       }
       cc_load_mode(p24_this);
}

void
pal_a2024_mode_vbl_handler(dmode_t *d)
{
       u_short vp = ((custom.vposr & 0x0007) << 8) | ((custom.vhposr) >> 8);

       if (vp < 20) {
               custom.cop1lc = PREP_DMA_MEM(p24_this_data->frames[p24_this_data->hedley_current]);
               custom.copjmp1 = 0;
       }
       p24_this_data->hedley_current++;
       p24_this_data->hedley_current &= 0x3;   /* if 4 then 0. */
}
#endif /* GRF_A2024 */

#if defined (GRF_AGA)

dmode_t *
cc_init_pal_aga(void)
{
       /* this function should only be called once. */
       if (!paga_this && (custom.deniseid & 0xff) == 0xf8 &&
           aga_enable & AGA_ENABLE) {
               u_short len = aga_copper_list_len;

               paga_this = &paga_mode;
               paga_this_data = &paga_mode_data;
               memset(paga_this, 0, sizeof(dmode_t));
               memset(paga_this_data, 0, sizeof(dmdata_t));

               paga_this->name = "pal: AGA dbl";
               paga_this->nominal_size.width = 640;
               paga_this->nominal_size.height = 512;
               paga_this_data->max_size.width = 720;
               paga_this_data->max_size.height = 564;
               paga_this_data->min_size.width = 320;
               paga_this_data->min_size.height = 200;
               paga_this_data->min_depth = 1;
               paga_this_data->max_depth = 8;
               paga_this->data = paga_this_data;

               paga_this->get_monitor = cc_get_monitor;
               paga_this->alloc_view = cc_alloc_view;
               paga_this->get_current_view = cc_get_current_view;

               paga_this_data->use_colormap = cc_use_aga_colormap;
               paga_this_data->get_colormap = cc_get_colormap;
               paga_this_data->alloc_colormap = cc_alloc_aga_colormap;
               paga_this_data->display_view = display_pal_aga_view;
               paga_this_data->monitor = cc_monitor;

               paga_this_data->frames = paga_frames;
               paga_this_data->frames[F_LONG] = alloc_chipmem(aga_copper_list_size * F_TOTAL);
               if (!paga_this_data->frames[F_LONG]) {
                       panic("couldn't get chipmem for copper list");
               }
               paga_this_data->frames[F_STORE_LONG] = &paga_this_data->frames[F_LONG][len];

               memcpy(paga_this_data->frames[F_STORE_LONG], aga_copper_list, aga_copper_list_size);
               memcpy(paga_this_data->frames[F_LONG], aga_copper_list, aga_copper_list_size);

               paga_this_data->bplcon0 = 0x0240 | USE_CON3;    /* color composite
                                                                * enable,
                                                                * shres. */
               paga_this_data->std_start_x = 0x4f /*STANDARD_VIEW_X*/;
               paga_this_data->std_start_y = 0x2b /*STANDARD_VIEW_Y*/;
               paga_this_data->vbl_handler = (vbl_handler_func *) cc_mode_vbl_handler;
               paga_this_data->beamcon0 = STANDARD_PAL_BEAMCON | (SPECIAL_BEAMCON ^ VSYNCTRUE);

               LIST_INSERT_HEAD(&MDATA(cc_monitor)->modes,
                   paga_this, link);
       }
       return (paga_this);
}

/* static, so I can patch and play */

#ifdef GRF_AGA_VGA
int     pAGA_htotal  = 0x079;
int     pAGA_vtotal  = 0x24d;
int     pAGA_vbstop  = 0x019;
int     pAGA_hcenter = 0x04b;
#else
int     pAGA_htotal  = 0x081;
int     pAGA_vtotal  = 0x23d;
int     pAGA_vbstop  = 0x017;
int     pAGA_hcenter = 0x04f;
#endif
int     pAGA_hsstrt  = 0x00f;
int     pAGA_hsstop  = 0x019;
int     pAGA_hbstrt  = 0x001;
int     pAGA_hbstop  = 0x021;
int     pAGA_vsstrt  = 0x001;
int     pAGA_vsstop  = 0x008;
int     pAGA_vbstrt  = 0x000;

void
display_pal_aga_view(view_t *v)
{
       if (paga_this_data->current_view != v) {
               vdata_t *vd = VDATA(v);
               cop_t  *cp = paga_this_data->frames[F_STORE_LONG], *tmp;
               int     depth = v->bitmap->depth, i;
               int     hstart, hstop, vstart, vstop, j;
               int     x, y, w = v->display.width, h = v->display.height;
               u_short ddfstart, ddfwidth, con1;

#ifdef DEBUG
               if (aga_enable & AGA_TRACE)
                       printf("display_aga_view(%dx%dx%d) %p\n", w, h,
                           depth, v);
#endif
               /* round down to nearest even width */
               /* w &= 0xfffe; */
               /* calculate datafetch width. */

               ddfwidth = ((v->bitmap->bytes_per_row >> 1) - 4) << 1;

               /* this will center the any overscanned display */
               /* and allow user to modify. */
               x = v->display.x + paga_this_data->std_start_x - ((w - 640) >> 3);
               y = v->display.y + paga_this_data->std_start_y - ((h - 512) >> 1);

               if (y & 1)
                       y--;

               if (!(x & 1))
                       x--;

               hstart = x;
               hstop = x + (w >> 2);
               vstart = y;
               vstop = y + (h >> 0);
               ddfstart = (hstart >> 1) - 8;

#ifdef DEBUG
               if (aga_enable & AGA_TRACE2) {
                       printf ("  ddfwidth %04x x %04x y %04x", ddfwidth,
                           x, y);
                       printf (" hstart %04x hstop %04x vstart %04x vstop %04x ddfstart %04x\n",
                           hstart, hstop, vstart, vstop, ddfstart);
               }
#endif
               /* check for hardware limits, AGA may allow more..? */
               /* anyone got a 4000 I can borrow :^) -ch */
               if ((ddfstart & 0xfffc) + ddfwidth > 0xd8) {
                       int     d = 0;

                       /* XXX anyone know the equality properties of
                        * intermixed logial AND's */
                       /* XXX and arithmetic operators? */
                       while (((ddfstart & 0xfffc) + ddfwidth - d) > 0xd8) {
                               d++;
                       }

                       ddfstart -= d;
                       hstart -= d << 1;
                       hstop -= d << 1;
               }
               /* correct the datafetch to proper limits. */
               /* delay the actual display of the data until we need it. */
               ddfstart &= 0xfffc;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2) {
                       printf ("  ddfwidth %04x x %04x y %04x", ddfwidth,
                           x, y);
                       printf (" hstart %04x hstop %04x vstart %04x vstop %04x ddfstart %04x\n",
                           hstart, hstop, vstart, vstop, ddfstart);
               }
#endif
               con1 = ((hstart - 9) - (ddfstart << 1)) | (((hstart - 9) - (ddfstart << 1)) << 4);

               if (paga_this_data->current_view) {
                       VDATA(paga_this_data->current_view)->flags &= ~VF_DISPLAY;      /* mark as no longer */
                       /* displayed. */
               }
               paga_this_data->current_view = v;

               cp = paga_this_data->frames[F_STORE_LONG];
               tmp = cp;
               for (i = 0; i < 8; ++i) {
                       if (tmp == NULL)
                               break;
                       tmp = find_copper_inst(tmp + 1, CI_MOVE(R_BPLCON3));
                       if (tmp == NULL)
                               break;
                       tmp->cp.inst.operand = 0x0ca1 | (i << 13);
                       tmp = find_copper_inst(tmp + 1, CI_MOVE(R_BPLCON3));
                       if (tmp == NULL)
                               break;
                       tmp->cp.inst.operand = 0x0ea1 | (i << 13);
               }
               if (tmp)
                       tmp = find_copper_inst(tmp + 1, CI_MOVE(R_BPLCON3));
               if (tmp)
                       tmp->cp.inst.operand = 0x0ca1;
               tmp = find_copper_inst(cp, CI_MOVE(R_FMODE));
               tmp->cp.inst.operand = 0x8003;
               tmp = find_copper_inst(cp, CI_MOVE(R_HTOTAL));
               tmp->cp.inst.operand = pAGA_htotal; /* 81/71/73/79? */
               tmp = find_copper_inst(cp, CI_MOVE(R_HBSTRT));
               tmp->cp.inst.operand = pAGA_hbstrt; /* 0x0008 */
               tmp = find_copper_inst(cp, CI_MOVE(R_HSSTRT));
               tmp->cp.inst.operand = pAGA_hsstrt; /* 0x000e */
               tmp = find_copper_inst(cp, CI_MOVE(R_HSSTOP));
               tmp->cp.inst.operand = pAGA_hsstop; /* 0x001c */
               tmp = find_copper_inst(cp, CI_MOVE(R_HBSTOP));
               tmp->cp.inst.operand = pAGA_hsstop; /* 0x001e */
               tmp = find_copper_inst(cp, CI_MOVE(R_HCENTER));
               tmp->cp.inst.operand = pAGA_hcenter; /*AGA_htotal / 2 + AGA_hsstrt */
               tmp = find_copper_inst(cp, CI_MOVE(R_VBSTRT));
               tmp->cp.inst.operand = pAGA_vbstrt; /* 0x0000 */
               tmp = find_copper_inst(cp, CI_MOVE(R_VSSTRT));
               tmp->cp.inst.operand = pAGA_vsstrt; /* 0x016b / AGA_htotal */
               tmp = find_copper_inst(cp, CI_MOVE(R_VSSTOP));
               tmp->cp.inst.operand = pAGA_vsstop; /* 0x02d6 / AGA_htotal */
               tmp = find_copper_inst(cp, CI_MOVE(R_VBSTOP));
               tmp->cp.inst.operand = pAGA_vbstop; /* 0x0bd1 / AGA_htotal */
               tmp = find_copper_inst(cp, CI_MOVE(R_VTOTAL));
               tmp->cp.inst.operand = pAGA_vtotal;
               tmp = find_copper_inst(cp, CI_MOVE(R_BEAMCON0));
               tmp->cp.inst.operand = paga_this_data->beamcon0;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf("  beamcon0 %04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWHIGH));
               tmp->cp.inst.operand = CALC_DIWHIGH(hstart, vstart, hstop, vstop);
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" diwhigh %04x>", tmp->cp.inst.operand);
#endif
#if 0
               tmp->cp.inst.operand = (vstop & 0x0700) | ((hstop & 0x0100) << 5);
#endif
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf("%04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON0));
               tmp->cp.inst.operand = paga_this_data->bplcon0 |
                   ((depth & 0x7) << 12) | ((depth & 0x8) << 1);
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" bplcon0 %04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_BPLCON1));
               tmp->cp.inst.operand = con1;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" bplcon1 %04x>0000\n", con1);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTART));
               tmp->cp.inst.operand = ((vstart & 0xff) << 8) | (hstart & 0xff);
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf("  diwstart %04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_DIWSTOP));
               tmp->cp.inst.operand = ((vstop & 0xff) << 8) | (hstop & 0xff);
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" diwstop %04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTART));
               tmp->cp.inst.operand = ddfstart;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" ddfstart %04x", tmp->cp.inst.operand);
#endif
               tmp = find_copper_inst(cp, CI_MOVE(R_DDFSTOP));
               tmp->cp.inst.operand = ddfstart + ddfwidth;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" ddfstop %04x", tmp->cp.inst.operand);
#endif

               tmp = find_copper_inst(cp, CI_MOVE(R_BPL0PTH));
               for (i = 0, j = 0; i < depth; j += 2, i++) {
                       /* update the plane pointers */
                       tmp[j].cp.inst.operand = HIADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
                       tmp[j + 1].cp.inst.operand = LOADDR(PREP_DMA_MEM(v->bitmap->plane[i]));
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf (" bpl%dpth %p", i, v->bitmap->plane[i]);
#endif
               }

               /* set mods correctly. */
               tmp = find_copper_inst(cp, CI_MOVE(R_BPL1MOD));
               tmp[0].cp.inst.operand = v->bitmap->row_mod;
               tmp[1].cp.inst.operand = v->bitmap->row_mod;
#ifdef DEBUG
               if (aga_enable & AGA_TRACE2)
                       printf(" bplxmod %04x\n", v->bitmap->row_mod);
#endif

               /* set next pointers correctly */
               tmp = find_copper_inst(cp, CI_MOVE(R_COP1LCH));
               tmp[0].cp.inst.operand = HIADDR(PREP_DMA_MEM(paga_this_data->frames[F_STORE_LONG]));
               tmp[1].cp.inst.operand = LOADDR(PREP_DMA_MEM(paga_this_data->frames[F_STORE_LONG]));

               cp = paga_this_data->frames[F_LONG];
               paga_this_data->frames[F_LONG] = paga_this_data->frames[F_STORE_LONG];
               paga_this_data->frames[F_STORE_LONG] = cp;

               vd->flags |= VF_DISPLAY;

               cc_use_aga_colormap(v, vd->colormap);
       }
       cc_load_mode(paga_this);
#ifdef DEBUG
       if (aga_enable & AGA_TRACE)
               aga_enable |= AGA_TRACE2;       /* XXXX */
#endif
}

#endif /* GRF_AGA */
#endif /* GRF_PAL */