home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 6
/
AACD06.ISO
/
AACD
/
Emulation
/
Atari800
/
antic.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-03-09
|
39KB
|
1,670 lines
/*
*****************************************************************
* *
* Section : Antic Display Modes *
* Original Author : David Firth *
* : Thomas Richter (thor) *
* Date Written : 28th May 1995 *
* : 17th February 1988 *
* Version : 1.3 *
* *
* *
* Description *
* ----------- *
* *
* Section that handles Antic display modes. Not required *
* for BASIC version. *
* *
*****************************************************************
*/
#include <stdio.h>
#include <string.h>
#ifndef AMIGA
#include "config.h"
#endif
#include "atari.h"
#include "rt-config.h"
#include "mem.h"
#include "cpu.h"
#include "gtia.h"
#include "antic.h"
#define FALSE 0
#define TRUE 1
int xmin;
int xmax;
int dmactl_xmin_noscroll;
int dmactl_xmax_noscroll;
static int dmactl_xmin_scroll;
static int dmactl_xmax_scroll;
static int memory_basis; /* refresh cycles needed for memory */
static int pm_dma; /* DMA cycles needed by P/M graphics */
static int char_delta;
static int char_offset;
static int invert_mask;
static int blank_mask;
static int screenaddr;
#ifdef DEBUG
static int hpos; /* identifier for horizontal position.
used for debugging only. */
#define H_BEFORE_DMA 1
#define H_FIRST_HALF 2
#define H_SECOND_HALF 3
#define H_AFTER_WSYNC 4
static int dlipos;
static int dline;
#endif
/* colour lookup tables */
static int lookup_f[256];
static int lookup_4[256];
static int lookup24[256];
static int lookup_6[256];
static int lookup_9[256];
/* the scan line buffer of antic */
static int scanbuf[64];
/* A function that is used to build the graphics for a given line of
the mode line.
fillin is the pointer where to put the screen data in. Due to CPU
limitations, THIS BUFFER MUST BE LONGWORD ALIGNED. To allow HSCROLLING,
all this magic is done in the GTIA module, not here.
width is the width of the scan line, in half color clocks.
scanline is the scanline to be displayed, counts from zero up. */
typedef void ModeFunc(UBYTE *fillin,int width,int scanline);
static char *rcsid = "$Id: antic.c,v 1.30 1998/02/17 thor,david Exp $";
UBYTE CHACTL;
UBYTE CHBASE;
UWORD DLIST,DLISTINIT;
UBYTE DMACTL;
UBYTE HSCROL;
UBYTE NMIEN;
UBYTE NMIST;
UBYTE PMBASE;
UBYTE VSCROL;
int DMAwidth;
extern UWORD regPC;
/*
* These are defined for Word (2 Byte) memory accesses. I have not
* defined Longword (4 Byte) values since the Sparc architecture
* requires that Longword are on a longword boundry.
*
* Words accesses don't appear to be a problem because the first
* pixel plotted on a line will always be at an even offset, and
* hence on a word boundry.
*
* Note: HSCROL is in colour clocks whereas the pixels are emulated
* down to a half colour clock - the first pixel plotted is
* moved across by 2*HSCROL
*/
#define PF2_COLPF0 0x0404
#define PF2_COLPF1 0x0505
#define PF2_COLPF2 0x0606
#define PF2_COLPF3 0x0707
#define PF2_COLBK 0x0808
#define PF2_COLPF1_FID 0x1515
#define PF4_COLPF0 0x04040404
#define PF4_COLPF1 0x05050505
#define PF4_COLPF2 0x06060606
#define PF4_COLPF3 0x07070707
#define PF4_COLBK 0x08080808
#define PF4_COLPF1_FID 0x15151515
/* The middle of the display. All color/display/whatever changes BEFORE that
cycle are seen on the same row.
All changes after this color clock are visible ON THE NEXT row */
#define CC_MIDDLE 50
/* The propagation delay needed by the 6502 to react on the NMI interrupt */
#define DLI_DELAY 8
/* The number of cycles available on the same row to proceed after WSYNC and
before the horizontal blank */
#define AFTER_WSYNC 20
/* The number of cycles available after the horizontal blank but before the
DMA of antic actually starts */
#define BEFORE_DMA 0
/* The line where the VSYNC is generated. */
#define VSYNC_POS 250
int cc_middle=CC_MIDDLE;
int dli_delay=DLI_DELAY;
int after_wsync=AFTER_WSYNC;
int before_dma=BEFORE_DMA;
int vsync_pos=VSYNC_POS;
int ypos;
/*
* Pre-computed values for improved performance
*/
static int chbase_40; /* CHBASE for 40 character mode */
static int chbase_20; /* CHBASE for 20 character mode */
static int maddr_s; /* Address of Missiles - Single Line Resolution */
static int p0addr_s; /* Address of Player0 - Single Line Resolution */
static int p1addr_s; /* Address of Player1 - Single Line Resolution */
static int p2addr_s; /* Address of Player2 - Single Line Resolution */
static int p3addr_s; /* Address of Player3 - Single Line Resolution */
static int maddr_d; /* Address of Missiles - Double Line Resolution */
static int p0addr_d; /* Address of Player0 - Double Line Resolution */
static int p1addr_d; /* Address of Player1 - Double Line Resolution */
static int p2addr_d; /* Address of Player2 - Double Line Resolution */
static int p3addr_d; /* Address of Player3 - Double Line Resolution */
int wsync_halt = 0;
static int carry=0; /* carry over of CPU cycles */
/*
=============================================================
Define screen as ULONG to ensure that it is Longword aligned.
This allows special optimisations under certain conditions.
-------------------------------------------------------------
The extra 16 scanlines is used as an overflow buffer and has
enough room for any extra mode line. It is needed on the
occasions that a valid JVB instruction is not found in the
display list - An automatic break out will occur when ypos
is greater than the ATARI_HEIGHT, if its one less than this
there must be enough space for another mode line.
=============================================================
*/
ULONG *atari_screen = NULL;
UBYTE *scrn_ptr;
/* I/O register read */
mtype ANTIC_CHBASE_GET(void)
{
return CHBASE;
}
mtype ANTIC_CHACTL_GET(void)
{
return CHACTL;
}
mtype ANTIC_DLISTL_GET(void)
{
return DLIST & 0xff;
}
mtype ANTIC_DLISTH_GET(void)
{
return DLIST >> 8;
}
mtype ANTIC_DMACTL_GET(void)
{
return DMACTL;
}
mtype ANTIC_VCOUNT_GET(void)
{
return ypos >> 1;
}
mtype ANTIC_NMIEN_GET(void)
{
return NMIEN | 0x1f;
}
mtype ANTIC_NMIST_GET(void)
{
return NMIST;
}
mtype ANTIC_WSYNC_GET(void)
{
if (wsync_halt)
printf("Double wsync!\n");
wsync_halt++;
return 0xff;
}
/* I/O put routines */
int ANTIC_CHBASE_PUT(mtype byte)
{
CHBASE = byte;
chbase_40 = (byte << 8) & 0xfc00;
chbase_20 = (byte << 8) & 0xfe00;
#ifdef DEBUG
printf("CHBASE = %x, ypos %d, hpos state %d, dlipos %d dline %d\n",byte,ypos,hpos,dlipos,dline);
#endif
return FALSE;
}
int ANTIC_CHACTL_PUT(mtype byte)
{
CHACTL = byte;
/*
=================================================================
Check for vertical reflect, video invert and character blank bits
=================================================================
*/
switch (CHACTL & 0x07)
{
case 0x00 :
char_offset = 0;
char_delta = 1;
invert_mask = 0x00;
blank_mask = 0x00;
break;
case 0x01 :
char_offset = 0;
char_delta = 1;
invert_mask = 0x00;
blank_mask = 0x80;
break;
case 0x02 :
char_offset = 0;
char_delta = 1;
invert_mask = 0x80;
blank_mask = 0x00;
break;
case 0x03 :
char_offset = 0;
char_delta = 1;
invert_mask = 0x80;
blank_mask = 0x80;
break;
case 0x04 :
char_offset = 7;
char_delta = -1;
invert_mask = 0x00;
blank_mask = 0x00;
break;
case 0x05 :
char_offset = 7;
char_delta = -1;
invert_mask = 0x00;
blank_mask = 0x80;
break;
case 0x06 :
char_offset = 7;
char_delta = -1;
invert_mask = 0x80;
blank_mask = 0x00;
break;
case 0x07 :
char_offset = 7;
char_delta = -1;
invert_mask = 0x80;
blank_mask = 0x80;
break;
}
return FALSE;
}
int ANTIC_DLISTL_PUT(mtype byte)
{
DLIST = (DLIST & 0xff00) | byte;
DLISTINIT = DLIST;
return FALSE;
}
int ANTIC_DLISTH_PUT(mtype byte)
{
DLIST = (DLIST & 0x00ff) | (byte<<8);
DLISTINIT = DLIST;
return FALSE;
}
int ANTIC_DMACTL_PUT(mtype byte)
{
/* printf("DMACTL set to %2x at %4x\n",byte,regPC); */
DMACTL = byte;
switch (DMACTL & 0x03)
{
case 0x00 :
dmactl_xmin_noscroll = dmactl_xmax_noscroll = 0;
dmactl_xmin_scroll = dmactl_xmax_scroll = 0;
DMAwidth = 0;
memory_basis = 9; /* nine cycles for refresh */
break;
case 0x01 :
dmactl_xmin_noscroll = 64;
dmactl_xmax_noscroll = ATARI_WIDTH - 64;
dmactl_xmin_scroll = 32;
dmactl_xmax_scroll = ATARI_WIDTH - 32;
DMAwidth = 4;
memory_basis = 2; /* nine cycles for refresh */
break;
case 0x02 :
dmactl_xmin_noscroll = 32;
dmactl_xmax_noscroll = ATARI_WIDTH - 32;
dmactl_xmin_scroll = 0;
dmactl_xmax_scroll = ATARI_WIDTH;
memory_basis = 1;
DMAwidth = 5;
break;
case 0x03 :
dmactl_xmin_noscroll = dmactl_xmin_scroll = 0;
dmactl_xmax_noscroll = dmactl_xmax_scroll = ATARI_WIDTH;
memory_basis = 0;
DMAwidth = 6;
break;
}
pm_dma = 0; /* cycles needed for PM graphics */
if (DMACTL & 0x0C) /* Player DMA enables missile DMA */
pm_dma += 1;
if (DMACTL & 0x08) /* Player DMA ? */
pm_dma += 4;
/* SingleLine DMACTL & 0x10 not covered here */
return FALSE;
}
int ANTIC_HSCROL_PUT(mtype byte)
{
HSCROL = byte & 0x0f;
return FALSE;
}
int ANTIC_NMIEN_PUT(mtype byte)
{
NMIEN = byte | 0x1f;
/* printf("Wrote %d into NMIEN.\n",byte); */
return FALSE;
}
int ANTIC_NMIRES_PUT(mtype byte)
{
NMIST = 0x1f;
return FALSE;
}
int ANTIC_PMBASE_PUT(mtype byte)
{
UWORD pmbase_s;
UWORD pmbase_d;
PMBASE = byte;
pmbase_s = (PMBASE & 0xf8) << 8;
pmbase_d = (PMBASE & 0xfc) << 8;
maddr_s = pmbase_s + 768;
p0addr_s = pmbase_s + 1024;
p1addr_s = pmbase_s + 1280;
p2addr_s = pmbase_s + 1536;
p3addr_s = pmbase_s + 1792;
maddr_d = pmbase_d + 384;
p0addr_d = pmbase_d + 512;
p1addr_d = pmbase_d + 640;
p2addr_d = pmbase_d + 768;
p3addr_d = pmbase_d + 896;
return FALSE;
}
int ANTIC_VSCROL_PUT(mtype byte)
{
VSCROL = byte & 0x0f;
return FALSE;
}
int ANTIC_WSYNC_PUT(mtype byte)
{
wsync_halt ++;
return TRUE;
}
void Init_Antic (int *argc, char *argv[],int base)
{
int i;
int j;
if (argc) {
for (i=j=1;i<*argc;i++)
{
if (strcmp(argv[i],"-xcolpf1") == 0)
enable_xcolpf1 = TRUE;
else
argv[j++] = argv[i];
}
*argc = j;
}
NMIEN = 0x1f;
NMIST = 0x00;
DMACTL = 0x00;
VSCROL = 0x00;
HSCROL = 0x00;
/* setup lookup tables */
memset(lookup_f,0,256*sizeof(int));
memset(lookup_4,0,256*sizeof(int));
memset(lookup24,0,256*sizeof(int));
memset(lookup_9,0,256*sizeof(int));
lookup_f[0x00]=PF_COLPF2;
lookup_f[0x80]=lookup_f[0x40]=lookup_f[0x20]=
lookup_f[0x10]=lookup_f[0x08]=lookup_f[0x04]=
lookup_f[0x02]=lookup_f[0x01]=PF_COLPF1_FID;
lookup_4[0x00]=PF4_COLBK;
lookup_4[0x40]=lookup_4[0x10]=lookup_4[0x04]=lookup_4[0x01]=PF4_COLPF0;
lookup_4[0x80]=lookup_4[0x20]=lookup_4[0x08]=lookup_4[0x02]=PF4_COLPF1;
lookup_4[0xc0]=lookup_4[0x30]=lookup_4[0x0c]=lookup_4[0x03]=PF4_COLPF2;
lookup24[0x00]=PF2_COLBK;
lookup24[0x40]=lookup24[0x10]=lookup24[0x04]=lookup24[0x01]=PF2_COLPF0;
lookup24[0x80]=lookup24[0x20]=lookup24[0x08]=lookup24[0x02]=PF2_COLPF1;
lookup24[0xc0]=lookup24[0x30]=lookup24[0x0c]=lookup24[0x03]=PF2_COLPF3;
lookup_9[0x00]=PF4_COLBK;
lookup_9[0x80]=lookup_9[0x40]=lookup_9[0x20]=lookup_9[0x10]=
lookup_9[0x08]=lookup_9[0x04]=lookup_9[0x02]=lookup_9[0x01]=PF4_COLPF0;
memset(lookup_6+0x00,PF2_COLPF0,0x40*sizeof(int));
memset(lookup_6+0x40,PF2_COLPF1,0x40*sizeof(int));
memset(lookup_6+0x80,PF2_COLPF2,0x40*sizeof(int));
memset(lookup_6+0xc0,PF2_COLPF3,0x40*sizeof(int));
SetHW(base+_DMACTL,0xff0f,&ANTIC_DMACTL_GET,&ANTIC_DMACTL_PUT);
SetHW(base+_CHACTL,0xff0f,&ANTIC_CHACTL_GET,&ANTIC_CHACTL_PUT);
SetHW(base+_DLISTL,0xff0f,&ANTIC_DLISTL_GET,&ANTIC_DLISTL_PUT);
SetHW(base+_DLISTH,0xff0f,&ANTIC_DLISTH_GET,&ANTIC_DLISTH_PUT);
SetHW(base+_HSCROL,0xff0f,NULL,&ANTIC_HSCROL_PUT);
SetHW(base+_VSCROL,0xff0f,NULL,&ANTIC_VSCROL_PUT);
SetHW(base+_PMBASE,0xff0f,NULL,&ANTIC_PMBASE_PUT);
SetHW(base+_CHBASE,0xff0f,&ANTIC_CHBASE_GET,&ANTIC_CHBASE_PUT);
SetHW(base+_VCOUNT,0xff0f,&ANTIC_VCOUNT_GET,NULL);
SetHW(base+_NMIEN,0xff0f,&ANTIC_NMIEN_GET,&ANTIC_NMIEN_PUT);
SetHW(base+_NMIRES,0xff0f,&ANTIC_NMIST_GET,&ANTIC_NMIRES_PUT);
SetHW(base+_WSYNC,0xff0f,&ANTIC_WSYNC_GET,&ANTIC_WSYNC_PUT);
}
/********************************************************************
** Antic Mode line generators **
** **
** These functions come in pairs. One is used to fill the antic **
** scan line buffer scanbuf[] and is called once for each mode **
** line. It returns a function pointer for the second function **
** of the pair, used to build the actual scan lines. They take an **
** integer as argument that defines which scan line of the mode **
** line should be build - as needed by vertical scrolling. **
** Horizontal scrolling, however, is done elsewhere, in the GTIA **
** buffer. That looks rather wierd, but allows optimized **
** long accesses here. **
********************************************************************/
/*
* Builder pair for blank lines
*/
void Build_Blank(UBYTE *fillin,int width,int scanline)
{
memset(fillin,PF_COLBK,width);
}
ModeFunc *Antic_Blank(void)
{
return &Build_Blank;
}
/*
* Builder pair for Antic_2
*/
void Build_Antic_2(UBYTE *ptr,int width,int scanline)
{
int chaddr;
int i;
int nchars = width >> 3;
int *scan=scanbuf;
int screendata;
int chbase;
int chdata;
chbase = chbase_40 + char_offset + scanline*char_delta;
for (i=0;i<nchars;i++,scan++) {
/* get character data */
screendata = *scan;
/* get character base address */
chaddr = chbase + ((screendata & 0x7f) << 3);
/* get character data */
chdata = APeek(chaddr);
if (screendata & invert_mask)
chdata ^= 0xff;
if (screendata & blank_mask)
chdata = 0;
if (chdata) {
*ptr++ = lookup_f[chdata & 0x80];
*ptr++ = lookup_f[chdata & 0x40];
*ptr++ = lookup_f[chdata & 0x20];
*ptr++ = lookup_f[chdata & 0x10];
*ptr++ = lookup_f[chdata & 0x08];
*ptr++ = lookup_f[chdata & 0x04];
*ptr++ = lookup_f[chdata & 0x02];
*ptr++ = lookup_f[chdata & 0x01];
} else {
/* Since HSCROLL is always done in the GTIA module, this is aligned ! */
ULONG *l_ptr = (ULONG*)ptr;
*l_ptr++ = PF4_COLPF2;
*l_ptr++ = PF4_COLPF2;
ptr = (UBYTE*)l_ptr;
}
}
}
ModeFunc *Antic_2(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 3;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_2;
}
/*
* Builder pair for Antic 3
*/
void Build_Antic_3(UBYTE *ptr,int width,int scanline)
{
int chaddr;
int i;
int nchars = width >> 3;
int *scan=scanbuf;
int screendata;
int chdata=0;
for (i=0;i<nchars;i++,scan++) {
/* get character data */
screendata = *scan;
if ((screendata & 0x60) == 0x60) {
/* This is a lowercase character. This means that the first two
scan lines are blank and get mirrored as the last two scan lines */
switch(scanline) {
case 0:
case 1:
chdata = 0;
break;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
chaddr = chbase_40 + char_offset + scanline*char_delta;
chdata = APeek(chaddr);
break;
case 8:
chaddr = chbase_40 + char_offset;
chdata = APeek(chaddr);
break;
case 9:
chaddr = chbase_40 + char_offset + char_delta;
chdata = APeek(chaddr);
break;
}
} else {
/* Uppercase character. We use the standard orientation and keep the
last two scan lines blank */
if (scanline<8) {
chaddr = chbase_40 + char_offset + char_delta * scanline;
chdata = APeek(chaddr);
} else {
chdata = 0;
}
}
if (screendata & invert_mask)
chdata ^= 0xff;
if (screendata & blank_mask)
chdata = 0;
if (chdata) {
*ptr++ = lookup_f[chdata & 0x80];
*ptr++ = lookup_f[chdata & 0x40];
*ptr++ = lookup_f[chdata & 0x20];
*ptr++ = lookup_f[chdata & 0x10];
*ptr++ = lookup_f[chdata & 0x08];
*ptr++ = lookup_f[chdata & 0x04];
*ptr++ = lookup_f[chdata & 0x02];
*ptr++ = lookup_f[chdata & 0x01];
} else {
/* Since HSCROLL is always done in the GTIA module, this is aligned ! */
ULONG *l_ptr = (ULONG*)ptr;
*l_ptr++ = PF4_COLPF2;
*l_ptr++ = PF4_COLPF2;
ptr = (UBYTE*)l_ptr;
}
}
}
ModeFunc *Antic_3(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 3;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_3;
}
/*
* Display Builders for Antic Mode 4
*/
void Build_Antic_4(UBYTE *b_ptr,int width,int scanline)
{
int chaddr;
int i;
int nchars = width >> 3;
int *scan=scanbuf;
int screendata;
int chbase;
int chdata;
int *lookup;
UWORD *ptr=(UWORD *)b_ptr;
chbase = chbase_40 + char_offset + scanline*char_delta;
for (i=0;i<nchars;i++,scan++) {
/* get character data */
screendata = *scan;
/* get character base address */
chaddr = chbase + ((screendata & 0x7f) << 3);
/* get character data */
chdata = APeek(chaddr);
if (screendata & 0x80)
lookup = lookup24;
else
lookup = lookup_4;
if (chdata) {
*ptr++ = lookup[chdata & 0xc0];
*ptr++ = lookup[chdata & 0x30];
*ptr++ = lookup[chdata & 0x0c];
*ptr++ = lookup[chdata & 0x03];
} else {
*ptr++ = PF2_COLBK;
*ptr++ = PF2_COLBK;
*ptr++ = PF2_COLBK;
*ptr++ = PF2_COLBK;
}
}
}
ModeFunc *Antic_4(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 3;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_4;
}
/*
* Builder Pair for Antic Mode 5
*/
void Build_Antic_5(UBYTE *b_ptr,int width,int scanline)
{
int chaddr;
int i;
int nchars = width >> 3;
int *scan=scanbuf;
int screendata;
int chbase;
int chdata;
int *lookup;
UWORD *ptr=(UWORD *)b_ptr;
chbase = chbase_40 + char_offset + (scanline>>1)*char_delta;
for (i=0;i<nchars;i++,scan++) {
/* get character data */
screendata = *scan;
/* get character base address */
chaddr = chbase + ((screendata & 0x7f) << 3);
/* get character data */
chdata = APeek(chaddr);
if (screendata & 0x80)
lookup = lookup24;
else
lookup = lookup_4;
if (chdata) {
*ptr++ = lookup[chdata & 0xc0];
*ptr++ = lookup[chdata & 0x30];
*ptr++ = lookup[chdata & 0x0c];
*ptr++ = lookup[chdata & 0x03];
} else {
*ptr++ = PF2_COLBK;
*ptr++ = PF2_COLBK;
*ptr++ = PF2_COLBK;
*ptr++ = PF2_COLBK;
}
}
}
ModeFunc *Antic_5(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 3;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_5;
}
/*
* Display Pair for Antic Mode 6
*/
void Build_Antic_6(UBYTE *b_ptr,int width,int scanline)
{
int chaddr;
int i;
int nchars = width >> 4;
int *scan=scanbuf;
int screendata;
int chbase;
int chdata;
int color;
UWORD *ptr=(UWORD *)b_ptr;
chbase = chbase_20 + char_offset + scanline*char_delta;
for (i=0;i<nchars;i++,scan++) {
/* get character data */
screendata = *scan;
/* get character base address */
chaddr = chbase + ((screendata & 0x3f) << 3);
/* get character cell color */
color = lookup_6[screendata];
/* get character data */
chdata = APeek(chaddr);
if (chdata) {
*ptr++ = (chdata & 0x80)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x40)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x20)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x10)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x08)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x04)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x02)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x01)?(color):(PF2_COLBK);
} else {
/* Since HSCROLL is always done in the GTIA module, this is aligned ! */
ULONG *l_ptr = (ULONG*)ptr;
*l_ptr++ = PF4_COLBK;
*l_ptr++ = PF4_COLBK;
*l_ptr++ = PF4_COLBK;
*l_ptr++ = PF4_COLBK;
ptr = (UWORD*)l_ptr;
}
}
}
ModeFunc *Antic_6(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 4;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_6;
}
/*
* Display Pair for Antic Mode 7
*/
void Build_Antic_7(UBYTE *b_ptr,int width,int scanline)
{
int chaddr;
int i;
int nchars = width >> 4;
int *scan=scanbuf;
int screendata;
int chbase;
int chdata;
int color;
UWORD *ptr=(UWORD *)b_ptr;
chbase = chbase_20 + char_offset + (scanline>>1)*char_delta;
for (i=0;i<nchars;i++,scan++) {
/* get character data */
screendata = *scan;
/* get character base address */
chaddr = chbase + ((screendata & 0x3f) << 3);
/* get character cell color */
color = lookup_6[screendata];
/* get character data */
chdata = APeek(chaddr);
if (chdata) {
*ptr++ = (chdata & 0x80)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x40)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x20)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x10)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x08)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x04)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x02)?(color):(PF2_COLBK);
*ptr++ = (chdata & 0x01)?(color):(PF2_COLBK);
} else {
/* Since HSCROLL is always done in the GTIA module, this is aligned ! */
ULONG *l_ptr = (ULONG*)ptr;
*l_ptr++ = PF4_COLBK;
*l_ptr++ = PF4_COLBK;
*l_ptr++ = PF4_COLBK;
*l_ptr++ = PF4_COLBK;
ptr = (UWORD*)l_ptr;
}
}
}
ModeFunc *Antic_7(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 4;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_7;
}
/*
* Function to Display Antic Mode 8
*/
void Build_Antic_8(UBYTE *ptr,int width,int scanline)
{
int i;
int nchars = width >> 5;
int *scan = scanbuf;
int screendata;
for(i=0;i<nchars;i++,scan++) {
screendata = *scan;
memset(ptr,lookup_4[screendata & 0xc0],8);
ptr += 8;
memset(ptr,lookup_4[screendata & 0x30],8);
ptr += 8;
memset(ptr,lookup_4[screendata & 0x0c],8);
ptr += 8;
memset(ptr,lookup_4[screendata & 0x03],8);
ptr += 8;
}
}
ModeFunc *Antic_8(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 5;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_8;
}
/*
* Display pair for Antic Mode 9
*/
void Build_Antic_9(UBYTE *b_ptr,int width,int scanline)
{
int i;
int nchars = width >> 5;
int *scan = scanbuf;
int screendata;
ULONG *ptr = (ULONG *)(b_ptr);
for(i=0;i<nchars;i++,scan++) {
screendata = *scan;
*ptr++=lookup_9[screendata & 0x80];
*ptr++=lookup_9[screendata & 0x40];
*ptr++=lookup_9[screendata & 0x20];
*ptr++=lookup_9[screendata & 0x10];
*ptr++=lookup_9[screendata & 0x08];
*ptr++=lookup_9[screendata & 0x04];
*ptr++=lookup_9[screendata & 0x02];
*ptr++=lookup_9[screendata & 0x01];
}
}
ModeFunc *Antic_9(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 5;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_9;
}
/*
* Function to Display Antic Mode a
*/
void Build_Antic_A(UBYTE *b_ptr,int width,int scanline)
{
int i;
int nchars = width >> 4;
int *scan = scanbuf;
int screendata;
ULONG *ptr=(ULONG *)b_ptr;
for(i=0;i<nchars;i++,scan++) {
screendata = *scan;
*ptr++=lookup_4[screendata & 0xc0];
*ptr++=lookup_4[screendata & 0x30];
*ptr++=lookup_4[screendata & 0x0c];
*ptr++=lookup_4[screendata & 0x03];
}
}
ModeFunc *Antic_A(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 4;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_A;
}
/*
* Function to Display Antic Mode b
*/
void Build_Antic_B(UBYTE *b_ptr,int width,int scanline)
{
int i;
int nchars = width >> 4;
int *scan = scanbuf;
int screendata;
UWORD *ptr = (UWORD *)(b_ptr);
for(i=0;i<nchars;i++,scan++) {
screendata = *scan;
*ptr++=lookup_9[screendata & 0x80];
*ptr++=lookup_9[screendata & 0x40];
*ptr++=lookup_9[screendata & 0x20];
*ptr++=lookup_9[screendata & 0x10];
*ptr++=lookup_9[screendata & 0x08];
*ptr++=lookup_9[screendata & 0x04];
*ptr++=lookup_9[screendata & 0x02];
*ptr++=lookup_9[screendata & 0x01];
}
}
ModeFunc *Antic_B(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 4;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_B;
}
/*
* Function to Display Antic Mode c
*/
ModeFunc *Antic_C(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 4;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_B;
/* The scan lines of modes C & B look identically */
}
/*
* Function to Display Antic Mode d
*/
void Build_Antic_D(UBYTE *b_ptr,int width,int scanline)
{
int i;
int nchars = width >> 3;
int *scan = scanbuf;
int screendata;
UWORD *ptr=(UWORD *)b_ptr;
for(i=0;i<nchars;i++,scan++) {
screendata = *scan;
*ptr++=lookup_4[screendata & 0xc0];
*ptr++=lookup_4[screendata & 0x30];
*ptr++=lookup_4[screendata & 0x0c];
*ptr++=lookup_4[screendata & 0x03];
}
}
ModeFunc *Antic_D(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 3;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_D;
}
/*
* Function to display Antic Mode e
*/
ModeFunc *Antic_E(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 3;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_D;
/* The mode lines of modes E & D look alike */
}
/*
* Function to display Antic Mode f
*/
void Build_Antic_F(UBYTE *ptr,int width,int scanline)
{
int i;
int nchars = width >> 3;
int *scan = scanbuf;
int screendata;
for(i=0;i<nchars;i++,scan++) {
screendata = *scan;
*ptr++=lookup_f[screendata & 0x80];
*ptr++=lookup_f[screendata & 0x40];
*ptr++=lookup_f[screendata & 0x20];
*ptr++=lookup_f[screendata & 0x10];
*ptr++=lookup_f[screendata & 0x08];
*ptr++=lookup_f[screendata & 0x04];
*ptr++=lookup_f[screendata & 0x02];
*ptr++=lookup_f[screendata & 0x01];
}
}
ModeFunc *Antic_F(int width)
{
int i;
int *scan=scanbuf;
int nchars = width >> 3;
for(i=0;i<nchars;i++,scan++,screenaddr++)
*scan=APeek(screenaddr);
return &Build_Antic_F;
}
/*
*****************************************************************
* *
* Section : Display List *
* Original Author : David Firth *
* Date Written : 28th May 1995 *
* Version : 1.0 *
* *
* Description *
* ----------- *
* *
* Section that handles Antic Display List. Not required for *
* BASIC version. *
* *
*****************************************************************
*/
void pmg_dma (void)
{
int yhalf = ypos >> 1;
/* single line shift not yet implemented.... */
if (DMACTL & 0x08)
{
if (DMACTL & 0x10)
{
GRAFP0 = memory[p0addr_s + ypos];
GRAFP1 = memory[p1addr_s + ypos];
GRAFP2 = memory[p2addr_s + ypos];
GRAFP3 = memory[p3addr_s + ypos];
}
else
{
GRAFP0 = memory[p0addr_d + yhalf - delayp0];
GRAFP1 = memory[p1addr_d + yhalf - delayp1];
GRAFP2 = memory[p2addr_d + yhalf - delayp2];
GRAFP3 = memory[p3addr_d + yhalf - delayp3];
}
}
if (DMACTL & 0x0C) /* Player DMA enables missile DMA as well */
{
if (DMACTL & 0x10)
GRAFM = memory[maddr_s + ypos];
else {
int mis0,mis1,mis2,mis3;
mis0 = memory[maddr_d + yhalf - delaym0];
mis1 = memory[maddr_d + yhalf - delaym1];
mis2 = memory[maddr_d + yhalf - delaym2];
mis3 = memory[maddr_d + yhalf - delaym3];
GRAFM = (mis0 & 0x03) | (mis1 & 0x0c) | (mis2 & 0x30) | (mis3 & 0xc0);
}
}
}
static void Clear_Border(int hscrol)
{
int scrol=HSCROL+HSCROL;
int shift=FILLIN_OFFSET;
int left=FILLIN_OFFSET+dmactl_xmin_noscroll;
if (hscrol) {
shift -= scrol;
if ((DMACTL & 0x03)!=0x03)
left -= scrol;
}
memset(scrn_ptr,PF_COLBK,left);
memset(scrn_ptr+dmactl_xmax_noscroll+shift,PF_COLBK,
ATARI_MODULO-dmactl_xmax_noscroll-shift);
}
static void ANTIC_Scanline(int dmacycles,int nmi,int hscrol,ModeFunc *gen,UBYTE *fillin,int width,int displayline)
{
int before;
int after;
int add;
#ifdef DEBUG
hpos=H_BEFORE_DMA;
#endif
before=cc_middle-before_dma-dmacycles;
after=114-cc_middle-after_wsync;
if (before<0) {
after += before;
before = 0;
}
add = carry;
Clear_Border(hscrol);
if (!wsync_halt) {
if (before_dma>0)
add = GO(before_dma+add);
#ifdef DEBUG
hpos=H_FIRST_HALF;
#endif
if (nmi) {
before += add;
before -= dli_delay;
if (before>0) {
NMI();
nmi = FALSE;
add = GO(before);
}
} else {
before += add;
if (before>0)
add = GO(before);
}
}
/* generate the display */
(*gen)(fillin,width,displayline);
pmg_dma ();
Atari_ScanLine (hscrol);
#ifdef DEBUG
hpos=H_SECOND_HALF;
if (nmi) {
dlipos=ypos;
dline=displayline;
}
#endif
if (!wsync_halt) {
if (nmi) {
after += add;
after -= dli_delay;
if (after>0) {
NMI();
nmi = FALSE;
add = GO(after);
}
} else {
after += add;
if (after>0)
add = GO(after);
}
}
#ifdef DEBUG
hpos=H_AFTER_WSYNC;
#endif
wsync_halt=0;
if (nmi) {
NMI();
add = GO(after_wsync-dli_delay+add);
} else add = GO(after_wsync+add);
carry = add;
scrn_ptr += ATARI_MODULO;
ypos++;
}
/* Generate one mode line of the ANTIC display.
IR is the instruction code and only needed for horizontal/vertical scrolling
and NMI generation. No jump codes are generated here.
first is the first scan line of the mode line to be generated. It may be
negative for artefacts. The first scan line is then generated over again
until the counter gets zero.
nlines is the number of scan lines in this mode line.
last is the number of the last scan line to be generated. It may be larger
than nlines. In this case, the last scan line is repeated over again to
generate VSCROLL artefacts.
acnt is the # of stealed DMA cycles for each scan line of the mode line
acntn is the # of additional DMA cycles for the first scan line.
ModeFunc * is the scan line generator function. It's called with the
*fillin pointer, so to know where to place the graphics, the width
of the scan line in half color clocks and the scan line of the mode line
to be generated. */
static void Antic_Modeline(int IR,int first,int last,int nlines,int dmashift,int dmaadd,ModeFunc *gen)
{
int width;
int scanline;
int displayline;
int dmawidth;
UBYTE *fillin;
int dma;
int nmi=FALSE;
nlines--; /* for simpler calculations */
for (scanline=first;scanline<=last;scanline++) {
/* get the line to be displayed. */
displayline=scanline;
if (displayline<0)
displayline = 0;
if (displayline>nlines)
displayline=nlines;
/* Get the width of the line. Must be taken from DMACTL right now because
the CPU may change it within the mode line */
dmawidth = DMAwidth; /* DMA base cycle counter */
width = dmawidth<<6; /* # of color clocks */
fillin = scrn_ptr+dmactl_xmin_noscroll+FILLIN_OFFSET; /* graphics fill-in position */
/* All that changes a lot if HSCROL is turned on. Get the next wider display */
if (IR & 0x10) {
fillin = scrn_ptr+dmactl_xmin_scroll+FILLIN_OFFSET;
if (dmawidth<6) {
dmawidth++;
width += 64;
dmaadd--; /* one memory refresh cycle is dropped */
}
}
/* get the number of DMA cycles needed to display that mode */
/* base cycles for DISPLAY DMA, used for character based DMA */
if (dmashift)
dma = dmawidth << dmashift;
else dma = 0;
/* add the memory refresh cycles */
dma += 9;
if ((DMACTL & 0x10) || (ypos & 0x01)==0)
dma += pm_dma; /* turn on player DMA? */
if (scanline==first)
dma += dmaadd; /* add the DMA cycles to get this mode line IR */
/* keep track of the DLI if turned on */
if ((scanline == last) && (IR & 0x80)) {
if (NMIEN & 0x80) {
NMIST = 0x80;
nmi = TRUE;
}
}
/* run the scancode */
ANTIC_Scanline(dma,nmi,IR & 0x10,gen,fillin,width,displayline);
}
}
void ANTIC_RunDisplayList (void)
{
int JVB=FALSE;
int nlines=0;
int width;
int IR;
int dmabase;
int dmawidth;
int dmashift;
int vertthis,vertlast;
ModeFunc *gen; /* scanline generator. Requires fill-in position,
width in half color clocks and scan line within
the mode line to be build */
wsync_halt = 0;
vertthis=FALSE;
vertlast=FALSE;
gen = NULL;
/*
* VCOUNT must equal zero for some games but the first line starts
* when VCOUNT=4. This portion processes when VCOUNT=0, 1, 2 and 3
*/
scrn_ptr = (UBYTE*)atari_screen;
DLIST=DLISTINIT;
for (ypos = 0; ypos <8 ;ypos++) {
carry=GO (carry+105); /* 114 minus 9 memory cycles */
}
NMIST = 0x00;
for (ypos = 8, JVB=FALSE ; ypos < (ATARI_HEIGHT + 8);) {
/* Counter needed for the DMA cycles to fetch display instructions */
dmabase = 0;
/* vertical scroll flags. */
vertlast=vertthis;
vertthis=FALSE;
/* setup base DMA width. Changed for HSCROL */
dmawidth = DMAwidth;
/* display width */
width = dmawidth<<6;
gen = NULL;
/* scan line generator. Needs to be called for each scan line
to be generated. */
/* dmawidth must be shifted by this to get the DMA display cycles */
dmashift = 0;
if (JVB || (DMACTL & 0x20)==0) {
ANTIC_Scanline(9,FALSE,FALSE,&Build_Blank,scrn_ptr,ATARI_MODULO,0);
} else {
IR = APeek(DLIST);
DLIST++;
dmabase++;
switch (IR & 0x0f)
{
case 0x00 :
nlines = ((IR >> 4) & 0x07) + 1;
gen = &Build_Blank;
IR &= 0x80; /* avoid confusion with scrolling flags */
break;
case 0x01 :
if (IR & 0x40)
JVB = TRUE;
DLIST = DAPeek(DLIST);
dmabase += 2;
nlines = 1;
gen = &Build_Blank; /* Jump aparently uses 1 scan line */
IR &= 0x80;
break;
default :
if (IR & 0x40) {
screenaddr = DAPeek(DLIST);
DLIST += 2;
dmabase += 2;
}
/* Keep track of vertical scrolling */
if (IR & 0x20) {
vertthis = TRUE;
}
if (IR & 0x10) {
if (dmawidth<6) {
dmawidth++;
width += 64;
}
}
switch (IR & 0x0f) {
case 0x02 :
nlines = 8;
dmashift = 3; /* dmawith * 8 */
dmabase += (dmawidth<<3)+memory_basis-9; /* reduce memory DMA */
gen = Antic_2(width);
break;
case 0x03 :
nlines = 10;
dmashift = 3;
dmabase += (dmawidth<<3)+memory_basis-9;
gen = Antic_3(width);
break;
case 0x04 :
nlines = 8;
dmashift = 3;
dmabase += (dmawidth<<3)+memory_basis-9;
gen = Antic_4(width);
break;
case 0x05 :
nlines = 16;
dmashift = 3;
dmabase += (dmawidth<<3)+memory_basis-9;
gen = Antic_5(width);
break;
case 0x06 :
nlines = 8;
dmashift = 2;
dmabase += (dmawidth<<2);
gen = Antic_6(width);
break;
case 0x07 :
nlines = 16;
dmashift = 2;
dmabase += (dmawidth<<2);
gen = Antic_7(width);
break;
case 0x08 :
nlines = 8;
dmabase += (dmawidth<<1);
gen = Antic_8(width);
break;
case 0x09 :
nlines = 4;
dmabase += (dmawidth<<1);
gen = Antic_9(width);
break;
case 0x0a :
nlines = 4;
dmabase += (dmawidth<<2);
gen = Antic_A(width);
break;
case 0x0b :
nlines = 2;
dmabase += (dmawidth<<2);
gen = Antic_B(width);
break;
case 0x0c :
nlines = 1;
dmabase += (dmawidth<<2);
gen = Antic_C(width);
break;
case 0x0d :
nlines = 2;
dmabase += (dmawidth<<3);
gen = Antic_D(width);
break;
case 0x0e :
nlines = 1;
dmabase += (dmawidth<<3);
gen = Antic_E(width);
break;
case 0x0f :
nlines = 1;
dmabase += (dmawidth<<3);
gen = Antic_F(width);
break;
default :
printf("Antic.c: IR %x caused problems.\n",IR);
nlines = 0;
break;
}
break;
}
if (nlines > 0) {
int first,last;
if (gen) {
/* Calculate the first & last line to display */
first = 0;
last = nlines-1;
/* If this is a VScrol-Line, delay the first line. */
if (vertthis && !vertlast) {
first = VSCROL;
if (first>last)
first -= 16;
}
if (!vertthis && vertlast) {
last = VSCROL+1;
}
Antic_Modeline(IR,first,last,nlines,dmashift,dmabase,gen);
} else {
printf("Antic.c: Found unknown mode generator.\n");
}
}
}
}
for(ypos=248; ypos<vsync_pos;ypos++)
carry = GO(carry+105);
NMIST = 0x40; /* Set VBLANK */
if (NMIEN & 0x40) {
carry=GO (carry+7);
/* Needed for programs that monitor NMIST (Spy's Demise, GORF) */
NMI ();
carry -= dli_delay+7; /* Needed by 6502 to react */
}
if (tv_mode == PAL)
for (ypos=vsync_pos;ypos<312;ypos++)
carry=GO (carry+105);
else
for (ypos=vsync_pos;ypos<262;ypos++)
carry=GO (carry+105);
}