/*	$NetBSD: grfabs_cc.c,v 1.37.4.1 2023/08/09 17:42:03 martin 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.37.4.1 2023/08/09 17:42:03 martin 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;

	/* makre 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 */