mirror of
https://github.com/wavemotion-dave/A5200DS.git
synced 2025-04-02 10:52:40 -04:00
2609 lines
95 KiB
C
2609 lines
95 KiB
C
/*
|
|
* antic.c - ANTIC chip emulation
|
|
*
|
|
* Copyright (C) 1995-1998 David Firth
|
|
* Copyright (C) 1998-2005 Atari800 development team (see DOC/CREDITS)
|
|
*
|
|
* This file is part of the Atari800 emulator project which emulates
|
|
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
|
*
|
|
* Atari800 is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Atari800 is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Atari800; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
#include <nds.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "a5200utils.h"
|
|
#include "config.h"
|
|
#include "cartridge.h"
|
|
#include "antic.h"
|
|
#include "atari.h"
|
|
#include "cpu.h"
|
|
#include "gtia.h"
|
|
#include "memory.h"
|
|
#include "pokeysnd.h"
|
|
#include "input.h"
|
|
|
|
#define LCHOP 3 /* do not build lefmost 0..3 characters in wide mode */
|
|
#define RCHOP 3 /* do not build rightmost 0..3 characters in wide mode */
|
|
|
|
#define WRITE_VIDEO(ptr, val) (*(ptr) = val)
|
|
#define WRITE_VIDEO_LONG(ptr, val) (*(ptr) = val)
|
|
#define WRITE_VIDEO_BYTE(ptr, val) (*(ptr) = val)
|
|
#define FILL_VIDEO(ptr, val, size) memset(ptr, val, size)
|
|
#define READ_VIDEO_LONG(ptr) (*(ptr))
|
|
|
|
|
|
/* Memory access helpers----------------------------------------------------- */
|
|
/* Some optimizations result in unaligned 32-bit accesses. These macros have
|
|
been introduced for machines that don't allow unaligned memory accesses. */
|
|
|
|
#define WRITE_VIDEO_LONG_UNALIGNED(ptr, val) UNALIGNED_PUT_LONG((ptr), (val))
|
|
|
|
#define IS_ZERO_ULONG(x) (((ULONG)x & 0x03) ? (!((const UBYTE *)(x))[0] && !((const UBYTE *)(x))[1] && !((const UBYTE *)(x))[2] && !((const UBYTE *)(x))[3]) : (! UNALIGNED_GET_LONG(x)))
|
|
|
|
#define DO_GTIA_BYTE(p, l, x) { \
|
|
if (((ULONG)p & 0x03) == 0) { \
|
|
UNALIGNED_PUT_LONG((ULONG *) (p), (l)[(x) >> 4]); \
|
|
UNALIGNED_PUT_LONG((ULONG *) (p) + 1, (l)[(x) & 0xf]); \
|
|
} else { \
|
|
WRITE_VIDEO((UWORD *) (p), (UWORD) ((l)[(x) >> 4])); \
|
|
WRITE_VIDEO((UWORD *) (p) + 1, (UWORD) ((l)[(x) >> 4])); \
|
|
WRITE_VIDEO((UWORD *) (p) + 2, (UWORD) ((l)[(x) & 0xf])); \
|
|
WRITE_VIDEO((UWORD *) (p) + 3, (UWORD) ((l)[(x) & 0xf])); \
|
|
} \
|
|
}
|
|
|
|
|
|
/* ANTIC Memory ------------------------------------------------------------ */
|
|
|
|
UBYTE ANTIC_memory[52] __attribute__((section(".dtcm")));
|
|
#define ANTIC_margin 4
|
|
/* It's number of bytes in ANTIC_memory, which are never loaded, but may be
|
|
read in wide playfield mode. These bytes are uninitialized, because on
|
|
real computer there's some kind of 'garbage'. Possibly 1 is enough, but
|
|
4 bytes surely won't cause negative indexes. :) */
|
|
|
|
/* ANTIC Registers --------------------------------------------------------- */
|
|
|
|
UBYTE DMACTL __attribute__((section(".dtcm")));
|
|
UBYTE CHACTL __attribute__((section(".dtcm")));
|
|
UWORD dlist __attribute__((section(".dtcm")));
|
|
UBYTE HSCROL __attribute__((section(".dtcm")));
|
|
UBYTE VSCROL __attribute__((section(".dtcm")));
|
|
UBYTE PMBASE __attribute__((section(".dtcm")));
|
|
UBYTE CHBASE __attribute__((section(".dtcm")));
|
|
UBYTE NMIEN __attribute__((section(".dtcm")));
|
|
UBYTE NMIST __attribute__((section(".dtcm")));
|
|
|
|
/* Screen -----------------------------------------------------------------
|
|
Define screen as ULONG to ensure that it is Longword aligned.
|
|
This allows special optimisations under certain conditions.
|
|
------------------------------------------------------------------------ */
|
|
|
|
UWORD *scrn_ptr __attribute__((section(".dtcm")));
|
|
|
|
|
|
/* ANTIC Timing --------------------------------------------------------------
|
|
|
|
NOTE: this information was written before NEW_CYCLE_EXACT was introduced!
|
|
|
|
I've introduced global variable xpos, which contains current number of cycle
|
|
in a line. This simplifies ANTIC/CPU timing much. The GO() function which
|
|
emulates CPU is now void and is called with xpos limit, below which CPU can go.
|
|
|
|
All strange variables holding 'unused cycles', 'DMA cycles', 'allocated cycles'
|
|
etc. are removed. Simply whenever ANTIC fetches a byte, it takes single cycle,
|
|
which can be done now with xpos++. There's only one exception: in text modes
|
|
2-5 ANTIC takes more bytes than cycles, because it does less than DMAR refresh
|
|
cycles.
|
|
|
|
Now emulation is really screenline-oriented. We do ypos++ after a line,
|
|
not inside it.
|
|
|
|
This simplified diagram shows when what is done in a line:
|
|
|
|
MDPPPPDD..............(------R/S/F------)..........
|
|
^ ^ ^ ^ ^ ^ ^ ^ ---> time/xpos
|
|
0 | NMIST_C NMI_C SCR_C WSYNC_C|LINE_C
|
|
VSCON_C VSCOF_C
|
|
|
|
M - fetch Missiles
|
|
D - fetch DL
|
|
P - fetch Players
|
|
S - fetch Screen
|
|
F - fetch Font (in text modes)
|
|
R - refresh Memory (DMAR cycles)
|
|
|
|
Only Memory Refresh happens in every line, other tasks are optional.
|
|
|
|
Below are exact diagrams for some non-scrolled modes:
|
|
11111111111111
|
|
11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111
|
|
012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123
|
|
/--------------------------narrow------------------------------\
|
|
/----------------------------------normal--------------------------------------\
|
|
/-------------------------------------------wide--------------------------------------------\
|
|
|
|
blank line:
|
|
MDPPPPDD.................R...R...R...R...R...R...R...R...R........................................................
|
|
|
|
mode 8,9:
|
|
MDPPPPDD....S.......S....R..SR...R..SR...R..SR...R..SR...R..S.......S.......S.......S.......S.......S.............
|
|
|
|
mode a,b,c:
|
|
MDPPPPDD....S...S...S...SR..SR..SR..SR..SR..SR..SR..SR..SR..S...S...S...S...S...S...S...S...S...S...S...S.........
|
|
|
|
mode d,e,f:
|
|
MDPPPPDD....S.S.S.S.S.S.SRS.SRS.SRS.SRS.SRS.SRS.SRS.SRS.SRS.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.........
|
|
|
|
Notes:
|
|
* At the beginning of a line fetched are:
|
|
- a byte of Missiles
|
|
- a byte of DL (instruction)
|
|
- four bytes of Players
|
|
- two bytes of DL argument (jump or screen address)
|
|
The emulator, however, fetches them all continuously.
|
|
|
|
* Refresh cycles and Screen/Font fetches have been tested for some modes (see above).
|
|
This is for making the emulator more accurate, able to change colour registers,
|
|
sprite positions or GTIA modes during scanline. These modes are the most commonly used
|
|
with those effects.
|
|
Currently this isn't implemented, and all R/S/F cycles are fetched continuously in *all* modes
|
|
(however, right number of cycles is taken in every mode, basing on screen width and HSCROL).
|
|
|
|
There are a few constants representing following events:
|
|
|
|
* VSCON_C - in first VSC line dctr is loaded with VSCROL
|
|
|
|
* NMIST_C - NMIST is updated (set to 0x9f on DLI, set to 0x5f on VBLKI)
|
|
|
|
* NMI_C - If NMIEN permits, NMI interrupt is generated
|
|
|
|
* SCR_C - We draw whole line of screen. On a real computer you can change
|
|
ANTIC/GTIA registers while displaying screen, however this emulator
|
|
isn't that accurate.
|
|
|
|
* WSYNC_C - ANTIC holds CPU until this moment, when WSYNC is written
|
|
|
|
* VSCOF_C - in last VSC line dctr is compared with VSCROL
|
|
|
|
* LINE_C - simply end of line (this used to be called CPUL)
|
|
|
|
All constants are determined by tests on real Atari computer. It is assumed,
|
|
that ANTIC registers are read with LDA, LDX, LDY and written with STA, STX,
|
|
STY, all in absolute addressing mode. All these instructions last 4 cycles
|
|
and perform read/write operation in last cycle. The CPU emulation should
|
|
correctly emulate WSYNC and add cycles for current instruction BEFORE
|
|
executing it. That's why VSCOF_C > LINE_C is correct.
|
|
|
|
How WSYNC is now implemented:
|
|
|
|
* On writing WSYNC:
|
|
- if xpos <= WSYNC_C && xpos_limit >= WSYNC_C,
|
|
we only change xpos to WSYNC_C - that's all
|
|
- otherwise we set wsync_halt and change xpos to xpos_limit causing GO()
|
|
to return
|
|
|
|
* At the beginning of GO() (CPU emulation), when wsync_halt is set:
|
|
- if xpos_limit < WSYNC_C we return
|
|
- else we set xpos to WSYNC_C, reset wsync_halt and emulate some cycles
|
|
|
|
We don't emulate NMIST_C, NMI_C and SCR_C if it is unnecessary.
|
|
These are all cases:
|
|
|
|
* Common overscreen line
|
|
Nothing happens except that ANTIC gets DMAR cycles:
|
|
xpos += DMAR; GOEOL;
|
|
|
|
* First overscreen line - start of vertical blank
|
|
- CPU goes until NMIST_C
|
|
- ANTIC sets NMIST to 0x5f
|
|
if (NMIEN & 0x40) {
|
|
- CPU goes until NMI_C
|
|
- ANTIC forces NMI
|
|
}
|
|
- ANTIC gets DMAR cycles
|
|
- CPU goes until LINE_C
|
|
|
|
* Screen line without DLI
|
|
- ANTIC fetches DL and P/MG
|
|
- CPU goes until SCR_C
|
|
- ANTIC draws whole line fetching Screen/Font and refreshing memory
|
|
- CPU goes until LINE_C
|
|
|
|
* Screen line with DLI
|
|
- ANTIC fetches DL and P/MG
|
|
- CPU goes until NMIST_C
|
|
- ANTIC sets NMIST to 0x9f
|
|
if (NMIEN & 0x80) {
|
|
- CPU goes until NMI_C
|
|
- ANTIC forces NMI
|
|
}
|
|
- CPU goes until SCR_C
|
|
- ANTIC draws line with DMAR
|
|
- CPU goes until LINE_C
|
|
|
|
-------------------------------------------------------------------------- */
|
|
|
|
#define VSCON_C 1
|
|
#define SCR_C 28
|
|
#define VSCOF_C 112
|
|
|
|
#define GOEOL GO(LINE_C); xpos -= LINE_C; ypos++
|
|
#define OVERSCREEN_LINE xpos += DMAR; GOEOL
|
|
|
|
int xpos __attribute__((section(".dtcm"))) = 0;
|
|
int xpos_limit __attribute__((section(".dtcm")));
|
|
UBYTE wsync_halt __attribute__((section(".dtcm"))) = FALSE;
|
|
int ypos __attribute__((section(".dtcm"))) = 0; /* Line number - lines 8..247 are on screen */
|
|
|
|
|
|
/* Timing in first line of modes 2-5
|
|
In these modes ANTIC takes more bytes than cycles. Despite this, it would be
|
|
possible that SCR_C + cycles_taken > WSYNC_C. To avoid this we must take some
|
|
cycles before SCR_C. before_cycles contains number of them, while extra_cycles
|
|
contains difference between bytes taken and cycles taken plus before_cycles. */
|
|
|
|
#define BEFORE_CYCLES (SCR_C - 28)
|
|
/* It's number of cycles taken before SCR_C for not scrolled, narrow playfield.
|
|
It wasn't tested, but should be ok. ;) */
|
|
|
|
/* Light pen support ------------------------------------------------------- */
|
|
|
|
static UBYTE PENH;
|
|
static UBYTE PENV;
|
|
|
|
/* Internal ANTIC registers ------------------------------------------------ */
|
|
|
|
UWORD screenaddr __attribute__((section(".dtcm"))); /* Screen Pointer */
|
|
UBYTE IR __attribute__((section(".dtcm"))); /* Instruction Register */
|
|
UBYTE anticmode __attribute__((section(".dtcm"))); /* Antic mode */
|
|
UBYTE dctr __attribute__((section(".dtcm"))); /* Delta Counter */
|
|
UBYTE lastline __attribute__((section(".dtcm"))); /* dctr limit */
|
|
UBYTE need_dl __attribute__((section(".dtcm"))); /* boolean: fetch DL next line */
|
|
UBYTE vscrol_off __attribute__((section(".dtcm"))); /* boolean: displaying line ending VSC */
|
|
|
|
/* Pre-computed values for improved performance ---------------------------- */
|
|
|
|
#define NORMAL0 0 /* modes 2,3,4,5,0xd,0xe,0xf */
|
|
#define NORMAL1 1 /* modes 6,7,0xa,0xb,0xc */
|
|
#define NORMAL2 2 /* modes 8,9 */
|
|
#define SCROLL0 3 /* modes 2,3,4,5,0xd,0xe,0xf with HSC */
|
|
#define SCROLL1 4 /* modes 6,7,0xa,0xb,0xc with HSC */
|
|
#define SCROLL2 5 /* modes 8,9 with HSC */
|
|
static int md __attribute__((section(".dtcm"))); /* current mode NORMAL0..SCROLL2 */
|
|
/* tables for modes NORMAL0..SCROLL2 */
|
|
static short int chars_read[6] __attribute__((section(".dtcm")));
|
|
static short int chars_displayed[6] __attribute__((section(".dtcm")));
|
|
static short int x_min[6] __attribute__((section(".dtcm")));
|
|
static short int ch_offset[6] __attribute__((section(".dtcm")));
|
|
static short int load_cycles[6] __attribute__((section(".dtcm")));
|
|
static short int font_cycles[6] __attribute__((section(".dtcm")));
|
|
static short int before_cycles[6] __attribute__((section(".dtcm")));
|
|
static short int extra_cycles[6] __attribute__((section(".dtcm")));
|
|
|
|
/* border parameters for current display width */
|
|
static short int left_border_chars __attribute__((section(".dtcm")));
|
|
static short int right_border_start __attribute__((section(".dtcm")));
|
|
|
|
#define LBORDER_START (LCHOP * 4)
|
|
#define RBORDER_END ((48 - RCHOP) * 4)
|
|
|
|
/* set with CHBASE *and* CHACTL - bits 0..2 set if flip on */
|
|
static UWORD chbase_20 __attribute__((section(".dtcm"))); /* CHBASE for 20 character mode */
|
|
|
|
/* set with CHACTL */
|
|
static UBYTE invert_mask __attribute__((section(".dtcm")));
|
|
static UBYTE blank_mask __attribute__((section(".dtcm")));
|
|
|
|
/* A scanline of AN0 and AN1 signals as transmitted from ANTIC to GTIA.
|
|
In every byte, bit 0 is AN0 and bit 1 is AN1 */
|
|
static UBYTE an_scanline[ATARI_WIDTH / 2 + 8] __attribute__((section(".dtcm")));
|
|
|
|
/* lookup tables */
|
|
static UBYTE blank_lookup[256] __attribute__((section(".dtcm")));
|
|
static UWORD lookup2[256] __attribute__((section(".dtcm")));
|
|
ULONG lookup_gtia9[16] __attribute__((section(".dtcm")));
|
|
ULONG lookup_gtia11[16];
|
|
static UBYTE playfield_lookup[257];
|
|
static UBYTE mode_e_an_lookup[256];
|
|
|
|
/* Colour lookup table
|
|
This single table replaces 4 previously used: cl_word, cur_prior,
|
|
prior_table and pf_colls. It should be treated as a two-dimensional table,
|
|
with playfield colours in rows and PMG colours in columns:
|
|
no_PMG PM0 PM1 PM01 PM2 PM3 PM23 PM023 PM123 PM0123 PM25 PM35 PM235 colls ... ...
|
|
BAK
|
|
...
|
|
HI2
|
|
HI3
|
|
PF0
|
|
PF1
|
|
PF2
|
|
PF3
|
|
The table contains word value (lsb = msb) of colour to be drawn.
|
|
The table is being updated taking current PRIOR setting into consideration.
|
|
'...' represent two unused columns and single unused row.
|
|
HI2 and HI3 are used only if colour_translation_table is being used.
|
|
They're colours of hi-res pixels on PF2 and PF3 respectively (PF2 is
|
|
default background for hi-res, PF3 is PM5).
|
|
Columns PM023, PM123 and PM0123 are used when PRIOR & 0xf equals any
|
|
of 5,7,0xc,0xd,0xe,0xf. The columns represent PM0, PM1 and PM01 respectively
|
|
covered by PM2 and/or PM3. This is to handle black colour on PF2 and PF3.
|
|
Columns PM25, PM35 and PM235 are used when PRIOR & 0x1f equals any
|
|
of 0x10,0x1a,0x1c,0x1e. The columns represent PM2, PM3 and PM23
|
|
respectively covered by PM5. This to handle colour on PF0 and PF1:
|
|
PF3 if (PRIOR & 0x1f) == 0x10, PF0 or PF1 otherwise.
|
|
Additional column 'colls' holds collisions of playfields with PMG. */
|
|
|
|
UWORD cl_lookup[128] __attribute__((section(".dtcm")));
|
|
|
|
#define C_PM0 0x01
|
|
#define C_PM1 0x02
|
|
#define C_PM01 0x03
|
|
#define C_PM2 0x04
|
|
#define C_PM3 0x05
|
|
#define C_PM23 0x06
|
|
#define C_PM023 0x07
|
|
#define C_PM123 0x08
|
|
#define C_PM0123 0x09
|
|
#define C_PM25 0x0a
|
|
#define C_PM35 0x0b
|
|
#define C_PM235 0x0c
|
|
#define C_COLLS 0x0d
|
|
#define C_BAK 0x00
|
|
#define C_HI2 0x20
|
|
#define C_HI3 0x30
|
|
#define C_PF0 0x40
|
|
#define C_PF1 0x50
|
|
#define C_PF2 0x60
|
|
#define C_PF3 0x70
|
|
#define C_BLACK (C_PF3 | C_PM25)
|
|
|
|
/* these are byte-offsets in the table, so left shift for indexing word table
|
|
has been avoided */
|
|
#define COLOUR(x) (*(UWORD *) ((UBYTE *) cl_lookup + (x) ))
|
|
#define L_PM0 (2 * C_PM0)
|
|
#define L_PM1 (2 * C_PM1)
|
|
#define L_PM01 (2 * C_PM01)
|
|
#define L_PM2 (2 * C_PM2)
|
|
#define L_PM3 (2 * C_PM3)
|
|
#define L_PM23 (2 * C_PM23)
|
|
#define L_PM023 (2 * C_PM023)
|
|
#define L_PM123 (2 * C_PM123)
|
|
#define L_PM0123 (2 * C_PM0123)
|
|
#define L_PM25 (2 * C_PM25)
|
|
#define L_PM35 (2 * C_PM35)
|
|
#define L_PM235 (2 * C_PM235)
|
|
#define L_COLLS (2 * C_COLLS)
|
|
#define L_BAK (2 * C_BAK)
|
|
#define L_HI2 (2 * C_HI2)
|
|
#define L_HI3 (2 * C_HI3)
|
|
#define L_PF0 (2 * C_PF0)
|
|
#define L_PF1 (2 * C_PF1)
|
|
#define L_PF2 (2 * C_PF2)
|
|
#define L_PF3 (2 * C_PF3)
|
|
#define L_BLACK (2 * C_BLACK)
|
|
|
|
/* Blank areas optimizations
|
|
Routines for most graphics modes take advantage of fact, that often
|
|
large areas of screen are background colour. If it is possible, 8 pixels
|
|
of background are drawn at once - with two longs or four words, if
|
|
the platform doesn't allow unaligned long access.
|
|
Artifacting also uses unaligned long access if it's supported. */
|
|
|
|
#define INIT_BACKGROUND_6 ULONG background = cl_lookup[C_PF2] | (((ULONG) cl_lookup[C_PF2]) << 16);
|
|
#define INIT_BACKGROUND_8 ULONG background = lookup_gtia9[0];
|
|
|
|
#define DRAW_BACKGROUND(colreg) {\
|
|
if (((ULONG)ptr & 0x03) == 0) { \
|
|
WRITE_VIDEO_LONG_UNALIGNED(((ULONG *) ptr), background); \
|
|
WRITE_VIDEO_LONG_UNALIGNED(((ULONG *) ptr)+1, background); \
|
|
ptr += 4; \
|
|
} else \
|
|
{ \
|
|
WRITE_VIDEO(ptr++, cl_lookup[colreg]); \
|
|
WRITE_VIDEO(ptr++, cl_lookup[colreg]); \
|
|
WRITE_VIDEO(ptr++, cl_lookup[colreg]); \
|
|
WRITE_VIDEO(ptr++, cl_lookup[colreg]); \
|
|
} \
|
|
}
|
|
|
|
#define DRAW_ARTIF {\
|
|
WRITE_VIDEO(ptr++, ((UWORD *) art_curtable)[(screendata_tally & 0x03fc00) >> 9]); \
|
|
WRITE_VIDEO(ptr++, ((UWORD *) art_curtable)[((screendata_tally & 0x03fc00) >> 9) + 1]); \
|
|
WRITE_VIDEO(ptr++, ((UWORD *) art_curtable)[(screendata_tally & 0x003fc0) >> 5]); \
|
|
WRITE_VIDEO(ptr++, ((UWORD *) art_curtable)[((screendata_tally & 0x003fc0) >> 5) + 1]); \
|
|
}
|
|
|
|
|
|
/* Hi-res modes optimizations
|
|
Now hi-res modes are drawn with words, not bytes. Endianess defaults
|
|
to little-endian. */
|
|
|
|
#define BYTE0_MASK 0x00ff
|
|
#define BYTE1_MASK 0xff00
|
|
#define HIRES_MASK_01 0xf0ff
|
|
#define HIRES_MASK_10 0xfff0
|
|
#define HIRES_LUM_01 0x0f00
|
|
#define HIRES_LUM_10 0x000f
|
|
|
|
#define hires_norm(x) hires_lookup_n[(x) >> 1]
|
|
#define hires_mask(x) hires_lookup_m[(x) >> 1]
|
|
|
|
UWORD hires_lookup_n[128] __attribute__((section(".dtcm")));
|
|
UWORD hires_lookup_m[128] __attribute__((section(".dtcm")));
|
|
UWORD hires_lookup_l[128] __attribute__((section(".dtcm"))); /* accessed in gtia.c */
|
|
#define hires_lum(x) hires_lookup_l[(x) >> 1]
|
|
|
|
/* Player/Missile Graphics ------------------------------------------------- */
|
|
|
|
#define PF0PM (*(UBYTE *) &cl_lookup[C_PF0 | C_COLLS])
|
|
#define PF1PM (*(UBYTE *) &cl_lookup[C_PF1 | C_COLLS])
|
|
#define PF2PM (*(UBYTE *) &cl_lookup[C_PF2 | C_COLLS])
|
|
#define PF3PM (*(UBYTE *) &cl_lookup[C_PF3 | C_COLLS])
|
|
#define PF_COLLS(x) (((UBYTE *) &cl_lookup)[(x) + L_COLLS])
|
|
|
|
UBYTE singleline __attribute__((section(".dtcm")));
|
|
UBYTE player_dma_enabled __attribute__((section(".dtcm")));
|
|
UBYTE player_gra_enabled __attribute__((section(".dtcm")));
|
|
UBYTE missile_dma_enabled __attribute__((section(".dtcm")));
|
|
UBYTE missile_gra_enabled __attribute__((section(".dtcm")));
|
|
UBYTE player_flickering __attribute__((section(".dtcm")));
|
|
UBYTE missile_flickering __attribute__((section(".dtcm")));
|
|
UBYTE missile_or_player_dma_enabled __attribute__((section(".dtcm")));
|
|
|
|
UWORD pmbase_s __attribute__((section(".dtcm")));
|
|
UWORD pmbase_d __attribute__((section(".dtcm")));
|
|
|
|
extern UBYTE pm_scanline[ATARI_WIDTH / 2 + 8] __attribute__((section(".dtcm")));
|
|
extern UBYTE pm_dirty __attribute__((section(".dtcm")));
|
|
|
|
/* PMG lookup tables */
|
|
UBYTE pm_lookup_table[20][256] __attribute__((section(".dtcm")));
|
|
/* current PMG lookup table */
|
|
const UBYTE *pm_lookup_ptr __attribute__((section(".dtcm")));
|
|
|
|
#define PL_00 0 /* 0x00,0x01,0x02,0x03,0x04,0x06,0x08,0x09,0x0a,0x0b */
|
|
#define PL_05 1 /* 0x05,0x07,0x0c,0x0d,0x0e,0x0f */
|
|
#define PL_10 2 /* 0x10,0x1a */
|
|
#define PL_11 3 /* 0x11,0x18,0x19 */
|
|
#define PL_12 4 /* 0x12 */
|
|
#define PL_13 5 /* 0x13,0x1b */
|
|
#define PL_14 6 /* 0x14,0x16 */
|
|
#define PL_15 7 /* 0x15,0x17,0x1d,0x1f */
|
|
#define PL_1c 8 /* 0x1c */
|
|
#define PL_1e 9 /* 0x1e */
|
|
#define PL_20 10 /* 0x20,0x21,0x22,0x23,0x24,0x26,0x28,0x29,0x2a,0x2b */
|
|
#define PL_25 11 /* 0x25,0x27,0x2c,0x2d,0x2e,0x2f */
|
|
#define PL_30 12 /* 0x30,0x3a */
|
|
#define PL_31 13 /* 0x31,0x38,0x39 */
|
|
#define PL_32 14 /* 0x32 */
|
|
#define PL_33 15 /* 0x33,0x3b */
|
|
#define PL_34 16 /* 0x34,0x36 */
|
|
#define PL_35 17 /* 0x35,0x37,0x3d,0x3f */
|
|
#define PL_3c 18 /* 0x3c */
|
|
#define PL_3e 19 /* 0x3e */
|
|
|
|
static const UBYTE prior_to_pm_lookup[64] = {
|
|
PL_00, PL_00, PL_00, PL_00, PL_00, PL_05, PL_00, PL_05,
|
|
PL_00, PL_00, PL_00, PL_00, PL_05, PL_05, PL_05, PL_05,
|
|
PL_10, PL_11, PL_12, PL_13, PL_14, PL_15, PL_14, PL_15,
|
|
PL_11, PL_11, PL_10, PL_13, PL_1c, PL_15, PL_1e, PL_15,
|
|
PL_20, PL_20, PL_20, PL_20, PL_20, PL_25, PL_20, PL_25,
|
|
PL_20, PL_20, PL_20, PL_20, PL_25, PL_25, PL_25, PL_25,
|
|
PL_30, PL_31, PL_32, PL_33, PL_34, PL_35, PL_34, PL_35,
|
|
PL_31, PL_31, PL_30, PL_33, PL_3c, PL_35, PL_3e, PL_35
|
|
};
|
|
|
|
static void init_pm_lookup(void) {
|
|
static const UBYTE pm_lookup_template[10][16] = {
|
|
/* PL_20 */
|
|
{ L_BAK, L_PM0, L_PM1, L_PM01, L_PM2, L_PM0, L_PM1, L_PM01,
|
|
L_PM3, L_PM0, L_PM1, L_PM01, L_PM23, L_PM0, L_PM1, L_PM01 },
|
|
/* PL_25 */
|
|
{ L_BAK, L_PM0, L_PM1, L_PM01, L_PM2, L_PM023, L_PM123, L_PM0123,
|
|
L_PM3, L_PM023, L_PM123, L_PM0123, L_PM23, L_PM023, L_PM123, L_PM0123 },
|
|
/* PL_30 */
|
|
{ L_PF3, L_PM0, L_PM1, L_PM01, L_PM25, L_PM0, L_PM1, L_PM01,
|
|
L_PM35, L_PM0, L_PM1, L_PM01, L_PM235, L_PM0, L_PM1, L_PM01 },
|
|
/* PL_31 */
|
|
{ L_PF3, L_PM0, L_PM1, L_PM01, L_PM2, L_PM0, L_PM1, L_PM01,
|
|
L_PM3, L_PM0, L_PM1, L_PM01, L_PM23, L_PM0, L_PM1, L_PM01 },
|
|
/* PL_32 */
|
|
{ L_PF3, L_PM0, L_PM1, L_PM01, L_PF3, L_PM0, L_PM1, L_PM01,
|
|
L_PF3, L_PM0, L_PM1, L_PM01, L_PF3, L_PM0, L_PM1, L_PM01 },
|
|
/* PL_33 */
|
|
{ L_PF3, L_PM0, L_PM1, L_PM01, L_BLACK, L_PM0, L_PM1, L_PM01,
|
|
L_BLACK, L_PM0, L_PM1, L_PM01, L_BLACK, L_PM0, L_PM1, L_PM01 },
|
|
/* PL_34 */
|
|
{ L_PF3, L_PF3, L_PF3, L_PF3, L_PF3, L_PF3, L_PF3, L_PF3,
|
|
L_PF3, L_PF3, L_PF3, L_PF3, L_PF3, L_PF3, L_PF3, L_PF3 },
|
|
/* PL_35 */
|
|
{ L_PF3, L_PF3, L_PF3, L_PF3, L_BLACK, L_BLACK, L_BLACK, L_BLACK,
|
|
L_BLACK, L_BLACK, L_BLACK, L_BLACK, L_BLACK, L_BLACK, L_BLACK, L_BLACK },
|
|
/* PL_3c */
|
|
{ L_PF3, L_PF3, L_PF3, L_PF3, L_PM25, L_PM25, L_PM25, L_PM25,
|
|
L_PM25, L_PM25, L_PM25, L_PM25, L_PM25, L_PM25, L_PM25, L_PM25 },
|
|
/* PL_3e */
|
|
{ L_PF3, L_PF3, L_PF3, L_PF3, L_PM25, L_BLACK, L_BLACK, L_BLACK,
|
|
L_PM25, L_BLACK, L_BLACK, L_BLACK, L_PM25, L_BLACK, L_BLACK, L_BLACK }
|
|
};
|
|
|
|
static UBYTE multi_to_normal[] = {
|
|
L_BAK,
|
|
L_PM0, L_PM1, L_PM0,
|
|
L_PM2, L_PM3, L_PM2,
|
|
L_PM023, L_PM123, L_PM023,
|
|
L_PM25, L_PM35, L_PM25
|
|
};
|
|
|
|
int i;
|
|
int j;
|
|
UBYTE temp;
|
|
|
|
for (i = 0; i <= 1; i++)
|
|
for (j = 0; j <= 255; j++) {
|
|
pm_lookup_table[i + 10][j] = temp = pm_lookup_template[i][(j & 0xf) | (j >> 4)];
|
|
pm_lookup_table[i][j] = temp <= L_PM235 ? multi_to_normal[temp >> 1] : temp;
|
|
}
|
|
for (; i <= 9; i++) {
|
|
for (j = 0; j <= 15; j++) {
|
|
pm_lookup_table[i + 10][j] = temp = pm_lookup_template[i < 7 ? 0 : 1][j];
|
|
pm_lookup_table[i][j] = temp <= L_PM235 ? multi_to_normal[temp >> 1] : temp;
|
|
}
|
|
for (; j <= 255; j++) {
|
|
pm_lookup_table[i + 10][j] = temp = pm_lookup_template[i][j & 0xf];
|
|
pm_lookup_table[i][j] = temp <= L_PM235 ? multi_to_normal[temp >> 1] : temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
static UBYTE hold_missiles_tab[16] __attribute__((section(".dtcm"))) = {
|
|
0x00,0x03,0x0c,0x0f,0x30,0x33,0x3c,0x3f,
|
|
0xc0,0xc3,0xcc,0xcf,0xf0,0xf3,0xfc,0xff};
|
|
|
|
static void pmg_dma(void) {
|
|
/* VDELAY bit set == GTIA ignores PMG DMA in even lines */
|
|
|
|
if (player_dma_enabled) {
|
|
if (player_gra_enabled) {
|
|
const UBYTE *base;
|
|
if (singleline) {
|
|
base = AnticMainMemLookup(pmbase_s + ypos);
|
|
if (ypos & 1) {
|
|
GRAFP0 = base[0x400];
|
|
GRAFP1 = base[0x500];
|
|
GRAFP2 = base[0x600];
|
|
GRAFP3 = base[0x700];
|
|
}
|
|
else {
|
|
if ((VDELAY & 0x10) == 0)
|
|
GRAFP0 = base[0x400];
|
|
if ((VDELAY & 0x20) == 0)
|
|
GRAFP1 = base[0x500];
|
|
if ((VDELAY & 0x40) == 0)
|
|
GRAFP2 = base[0x600];
|
|
if ((VDELAY & 0x80) == 0)
|
|
GRAFP3 = base[0x700];
|
|
}
|
|
}
|
|
else {
|
|
base = AnticMainMemLookup(pmbase_d + (ypos >> 1));
|
|
if (ypos & 1) {
|
|
GRAFP0 = base[0x200];
|
|
GRAFP1 = base[0x280];
|
|
GRAFP2 = base[0x300];
|
|
GRAFP3 = base[0x380];
|
|
}
|
|
else {
|
|
if ((VDELAY & 0x10) == 0)
|
|
GRAFP0 = base[0x200];
|
|
if ((VDELAY & 0x20) == 0)
|
|
GRAFP1 = base[0x280];
|
|
if ((VDELAY & 0x40) == 0)
|
|
GRAFP2 = base[0x300];
|
|
if ((VDELAY & 0x80) == 0)
|
|
GRAFP3 = base[0x380];
|
|
}
|
|
}
|
|
}
|
|
xpos += 4;
|
|
}
|
|
if (missile_dma_enabled) {
|
|
if (missile_gra_enabled) {
|
|
UBYTE data;
|
|
data = dGetByte(singleline ? pmbase_s + ypos + 0x300 : pmbase_d + (ypos >> 1) + 0x180);
|
|
/* in odd lines load all missiles, in even only those, for which VDELAY bit is zero */
|
|
GRAFM = ypos & 1 ? data : ((GRAFM ^ data) & hold_missiles_tab[VDELAY & 0xf]) ^ data;
|
|
}
|
|
xpos++;
|
|
}
|
|
}
|
|
|
|
/* Artifacting ------------------------------------------------------------ */
|
|
|
|
static ULONG art_lookup_normal[256];
|
|
static ULONG art_lookup_reverse[256];
|
|
static ULONG art_bkmask_normal[256];
|
|
static ULONG art_lummask_normal[256];
|
|
static ULONG art_bkmask_reverse[256];
|
|
static ULONG art_lummask_reverse[256];
|
|
|
|
static ULONG *art_curtable = art_lookup_normal;
|
|
static ULONG *art_curbkmask = art_bkmask_normal;
|
|
static ULONG *art_curlummask = art_lummask_normal;
|
|
|
|
static UWORD art_normal_colpf1_save;
|
|
static UWORD art_normal_colpf2_save;
|
|
static UWORD art_reverse_colpf1_save;
|
|
static UWORD art_reverse_colpf2_save;
|
|
|
|
static void setup_art_colours(void)
|
|
{
|
|
static UWORD *art_colpf1_save = &art_normal_colpf1_save;
|
|
static UWORD *art_colpf2_save = &art_normal_colpf2_save;
|
|
UWORD curlum = cl_lookup[C_PF1] & 0x0f0f;
|
|
|
|
if (curlum != *art_colpf1_save || cl_lookup[C_PF2] != *art_colpf2_save) {
|
|
if (curlum < (cl_lookup[C_PF2] & 0x0f0f)) {
|
|
art_colpf1_save = &art_reverse_colpf1_save;
|
|
art_colpf2_save = &art_reverse_colpf2_save;
|
|
art_curtable = art_lookup_reverse;
|
|
art_curlummask = art_lummask_reverse;
|
|
art_curbkmask = art_bkmask_reverse;
|
|
}
|
|
else {
|
|
art_colpf1_save = &art_normal_colpf1_save;
|
|
art_colpf2_save = &art_normal_colpf2_save;
|
|
art_curtable = art_lookup_normal;
|
|
art_curlummask = art_lummask_normal;
|
|
art_curbkmask = art_bkmask_normal;
|
|
}
|
|
if (curlum ^ *art_colpf1_save) {
|
|
int i;
|
|
ULONG new_colour = curlum ^ *art_colpf1_save;
|
|
new_colour |= new_colour << 16;
|
|
*art_colpf1_save = curlum;
|
|
for (i = 0; i <= 255; i++)
|
|
art_curtable[i] ^= art_curlummask[i] & new_colour;
|
|
}
|
|
if (cl_lookup[C_PF2] ^ *art_colpf2_save) {
|
|
int i;
|
|
ULONG new_colour = cl_lookup[C_PF2] ^ *art_colpf2_save;
|
|
new_colour |= new_colour << 16;
|
|
*art_colpf2_save = cl_lookup[C_PF2];
|
|
for (i = 0; i <= 255; i++)
|
|
art_curtable[i] ^= art_curbkmask[i] & new_colour;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/* Initialization ---------------------------------------------------------- */
|
|
|
|
void ANTIC_Initialise(void) {
|
|
ANTIC_UpdateArtifacting();
|
|
|
|
playfield_lookup[0x00] = L_BAK;
|
|
playfield_lookup[0x40] = L_PF0;
|
|
playfield_lookup[0x80] = L_PF1;
|
|
playfield_lookup[0xc0] = L_PF2;
|
|
playfield_lookup[0x100] = L_PF3;
|
|
blank_lookup[0x80] = blank_lookup[0xa0] = blank_lookup[0xc0] = blank_lookup[0xe0] = 0x00;
|
|
hires_mask(0x00) = 0xffff;
|
|
hires_mask(0x40) = HIRES_MASK_01;
|
|
hires_mask(0x80) = HIRES_MASK_10;
|
|
hires_mask(0xc0) = 0xf0f0;
|
|
hires_lum(0x00) = hires_lum(0x40) = hires_lum(0x80) = hires_lum(0xc0) = 0;
|
|
init_pm_lookup();
|
|
mode_e_an_lookup[0] = 0;
|
|
mode_e_an_lookup[1] = mode_e_an_lookup[4] = mode_e_an_lookup[0x10] = mode_e_an_lookup[0x40] = 0;
|
|
mode_e_an_lookup[2] = mode_e_an_lookup[8] = mode_e_an_lookup[0x20] = mode_e_an_lookup[0x80] = 1;
|
|
mode_e_an_lookup[3] = mode_e_an_lookup[12] = mode_e_an_lookup[0x30] = mode_e_an_lookup[0xc0] = 2;
|
|
}
|
|
|
|
void ANTIC_Reset(void) {
|
|
NMIEN = 0x00;
|
|
NMIST = 0x1f;
|
|
ANTIC_PutByte(_DMACTL, 0);
|
|
}
|
|
|
|
/* Border ------------------------------------------------------------------ */
|
|
|
|
#define DO_BORDER_1 {\
|
|
if (IS_ZERO_ULONG(pm_scanline_ptr)) {\
|
|
ULONG *l_ptr = (ULONG *) ptr;\
|
|
WRITE_VIDEO_LONG(l_ptr++, background); \
|
|
WRITE_VIDEO_LONG(l_ptr++, background); \
|
|
ptr = (UWORD *) l_ptr;\
|
|
pm_scanline_ptr += 4;\
|
|
}\
|
|
else {\
|
|
int k = 4;\
|
|
do
|
|
|
|
#define DO_BORDER DO_BORDER_1\
|
|
WRITE_VIDEO(ptr++, COLOUR(pm_lookup_ptr[*pm_scanline_ptr++]));\
|
|
while (--k);\
|
|
}\
|
|
}
|
|
|
|
#define DO_GTIA10_BORDER DO_BORDER_1\
|
|
WRITE_VIDEO(ptr++, COLOUR(pm_lookup_ptr[*pm_scanline_ptr++ | 1]));\
|
|
while (--k);\
|
|
}\
|
|
}
|
|
|
|
void do_border(void)
|
|
{
|
|
int kk;
|
|
UWORD *ptr = &scrn_ptr[LBORDER_START];
|
|
const UBYTE *pm_scanline_ptr = &pm_scanline[LBORDER_START];
|
|
ULONG background = lookup_gtia9[0];
|
|
/* left border */
|
|
for (kk = left_border_chars; kk; kk--)
|
|
DO_BORDER
|
|
/* right border */
|
|
ptr = &scrn_ptr[right_border_start];
|
|
pm_scanline_ptr = &pm_scanline[right_border_start];
|
|
while (pm_scanline_ptr < &pm_scanline[RBORDER_END])
|
|
DO_BORDER
|
|
}
|
|
|
|
static void do_border_gtia10(void)
|
|
{
|
|
int kk;
|
|
UWORD *ptr = &scrn_ptr[LBORDER_START];
|
|
const UBYTE *pm_scanline_ptr = &pm_scanline[LBORDER_START];
|
|
ULONG background = cl_lookup[C_PM0] | (cl_lookup[C_PM0] << 16);
|
|
/* left border */
|
|
for (kk = left_border_chars; kk; kk--)
|
|
DO_GTIA10_BORDER
|
|
WRITE_VIDEO(ptr, COLOUR(pm_lookup_ptr[*pm_scanline_ptr | 1]));
|
|
/* right border */
|
|
pm_scanline_ptr = &pm_scanline[right_border_start];
|
|
if (pm_scanline_ptr < &pm_scanline[RBORDER_END]) {
|
|
ptr = &scrn_ptr[right_border_start + 1];
|
|
WRITE_VIDEO(ptr++, COLOUR(pm_lookup_ptr[pm_scanline_ptr[1] | 1]));
|
|
WRITE_VIDEO(ptr++, COLOUR(pm_lookup_ptr[pm_scanline_ptr[2] | 1]));
|
|
WRITE_VIDEO(ptr++, COLOUR(pm_lookup_ptr[pm_scanline_ptr[3] | 1]));
|
|
pm_scanline_ptr += 4;
|
|
while (pm_scanline_ptr < &pm_scanline[RBORDER_END])
|
|
DO_GTIA10_BORDER
|
|
}
|
|
}
|
|
|
|
static void do_border_gtia11(void)
|
|
{
|
|
int kk;
|
|
UWORD *ptr = &scrn_ptr[LBORDER_START];
|
|
const UBYTE *pm_scanline_ptr = &pm_scanline[LBORDER_START];
|
|
ULONG background = lookup_gtia11[0];
|
|
cl_lookup[C_PF3] &= 0xf0f0;
|
|
cl_lookup[C_BAK] = (UWORD) background;
|
|
/* left border */
|
|
for (kk = left_border_chars; kk; kk--)
|
|
DO_BORDER
|
|
/* right border */
|
|
ptr = &scrn_ptr[right_border_start];
|
|
pm_scanline_ptr = &pm_scanline[right_border_start];
|
|
while (pm_scanline_ptr < &pm_scanline[RBORDER_END])
|
|
DO_BORDER
|
|
COLOUR_TO_WORD(cl_lookup[C_PF3],COLPF3)
|
|
COLOUR_TO_WORD(cl_lookup[C_BAK],COLBK)
|
|
}
|
|
|
|
static void draw_antic_0(void)
|
|
{
|
|
UWORD *ptr = scrn_ptr + LBORDER_START;
|
|
if (pm_dirty) {
|
|
const UBYTE *pm_scanline_ptr = &pm_scanline[LBORDER_START];
|
|
ULONG background = lookup_gtia9[0];
|
|
do
|
|
DO_BORDER
|
|
while (pm_scanline_ptr < &pm_scanline[RBORDER_END]);
|
|
}
|
|
else
|
|
FILL_VIDEO(ptr, cl_lookup[C_BAK], (RBORDER_END - LBORDER_START) * 2);
|
|
}
|
|
|
|
static void draw_antic_0_gtia10(void)
|
|
{
|
|
UWORD *ptr = scrn_ptr + LBORDER_START;
|
|
if (pm_dirty) {
|
|
const UBYTE *pm_scanline_ptr = &pm_scanline[LBORDER_START];
|
|
ULONG background = cl_lookup[C_PM0] | (cl_lookup[C_PM0] << 16);
|
|
do
|
|
DO_GTIA10_BORDER
|
|
while (pm_scanline_ptr < &pm_scanline[RBORDER_END]);
|
|
}
|
|
else
|
|
FILL_VIDEO(ptr, cl_lookup[C_PM0], (RBORDER_END - LBORDER_START) * 2);
|
|
}
|
|
|
|
static void draw_antic_0_gtia11(void)
|
|
{
|
|
UWORD *ptr = scrn_ptr + LBORDER_START;
|
|
if (pm_dirty) {
|
|
const UBYTE *pm_scanline_ptr = &pm_scanline[LBORDER_START];
|
|
ULONG background = lookup_gtia11[0];
|
|
cl_lookup[C_PF3] &= 0xf0f0;
|
|
cl_lookup[C_BAK] = (UWORD) background;
|
|
do
|
|
DO_BORDER
|
|
while (pm_scanline_ptr < &pm_scanline[RBORDER_END]);
|
|
COLOUR_TO_WORD(cl_lookup[C_PF3],COLPF3)
|
|
COLOUR_TO_WORD(cl_lookup[C_BAK],COLBK)
|
|
}
|
|
else
|
|
FILL_VIDEO(ptr, lookup_gtia11[0], (RBORDER_END - LBORDER_START) * 2);
|
|
}
|
|
|
|
/* ANTIC modes ------------------------------------------------------------- */
|
|
|
|
static UBYTE gtia_10_lookup[] __attribute__((section(".dtcm"))) =
|
|
{L_BAK, L_BAK, L_BAK, L_BAK, L_PF0, L_PF1, L_PF2, L_PF3,
|
|
L_BAK, L_BAK, L_BAK, L_BAK, L_PF0, L_PF1, L_PF2, L_PF3};
|
|
static UBYTE gtia_10_pm[] __attribute__((section(".dtcm"))) =
|
|
{1, 2, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
|
static void draw_an_gtia9(const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
int i = ((const UBYTE *) t_pm_scanline_ptr - pm_scanline) & ~1;
|
|
while (i < right_border_start) {
|
|
UWORD *ptr = scrn_ptr + i;
|
|
int pixel = (an_scanline[i] << 2) + an_scanline[i + 1];
|
|
UBYTE pm_reg;
|
|
WRITE_VIDEO_LONG((ULONG *) ptr, lookup_gtia9[pixel]);
|
|
pm_reg = pm_scanline[i];
|
|
if (pm_reg) {
|
|
if (pm_reg == L_PF3) {
|
|
WRITE_VIDEO(ptr, pixel | (pixel << 8) | cl_lookup[C_PF3]);
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr, COLOUR(pm_reg));
|
|
}
|
|
}
|
|
i++;
|
|
pm_reg = pm_scanline[i];
|
|
if (pm_reg) {
|
|
if (pm_reg == L_PF3) {
|
|
WRITE_VIDEO(ptr + 1, pixel | (pixel << 8) | cl_lookup[C_PF3]);
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr + 1, COLOUR(pm_reg));
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
do_border();
|
|
}
|
|
|
|
static void draw_an_gtia10(const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
int i = ((const UBYTE *) t_pm_scanline_ptr - pm_scanline) | 1;
|
|
UWORD lookup_gtia10[16];
|
|
lookup_gtia10[0] = cl_lookup[C_PM0];
|
|
lookup_gtia10[1] = cl_lookup[C_PM1];
|
|
lookup_gtia10[2] = cl_lookup[C_PM2];
|
|
lookup_gtia10[3] = cl_lookup[C_PM3];
|
|
lookup_gtia10[12] = lookup_gtia10[4] = cl_lookup[C_PF0];
|
|
lookup_gtia10[13] = lookup_gtia10[5] = cl_lookup[C_PF1];
|
|
lookup_gtia10[14] = lookup_gtia10[6] = cl_lookup[C_PF2];
|
|
lookup_gtia10[15] = lookup_gtia10[7] = cl_lookup[C_PF3];
|
|
lookup_gtia10[8] = lookup_gtia10[9] = lookup_gtia10[10] = lookup_gtia10[11] = cl_lookup[C_BAK];
|
|
while (i < right_border_start) {
|
|
UWORD *ptr = scrn_ptr + i;
|
|
int pixel = (an_scanline[i - 1] << 2) + an_scanline[i];
|
|
UBYTE pm_reg;
|
|
int colreg;
|
|
pm_reg = pm_scanline[i];
|
|
if (pm_reg) {
|
|
colreg = gtia_10_lookup[pixel];
|
|
PF_COLLS(colreg) |= pm_reg;
|
|
pm_reg |= gtia_10_pm[pixel];
|
|
WRITE_VIDEO(ptr, COLOUR(pm_lookup_ptr[pm_reg] | colreg));
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr, lookup_gtia10[pixel]);
|
|
}
|
|
i++;
|
|
pm_reg = pm_scanline[i];
|
|
if (pm_reg) {
|
|
colreg = gtia_10_lookup[pixel];
|
|
PF_COLLS(colreg) |= pm_reg;
|
|
pm_reg |= gtia_10_pm[pixel];
|
|
WRITE_VIDEO(ptr + 1, COLOUR(pm_lookup_ptr[pm_reg] | colreg));
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr + 1, lookup_gtia10[pixel]);
|
|
}
|
|
i++;
|
|
}
|
|
do_border_gtia10();
|
|
}
|
|
|
|
static void draw_an_gtia11(const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
int i = ((const UBYTE *) t_pm_scanline_ptr - pm_scanline) & ~1;
|
|
while (i < right_border_start) {
|
|
UWORD *ptr = scrn_ptr + i;
|
|
int pixel = (an_scanline[i] << 2) + an_scanline[i + 1];
|
|
UBYTE pm_reg;
|
|
WRITE_VIDEO_LONG((ULONG *) ptr, lookup_gtia11[pixel]);
|
|
pm_reg = pm_scanline[i];
|
|
if (pm_reg) {
|
|
if (pm_reg == L_PF3) {
|
|
WRITE_VIDEO(ptr, pixel ? pixel | (pixel << 8) | cl_lookup[C_PF3] : cl_lookup[C_PF3] & 0xf0f0);
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr, COLOUR(pm_reg));
|
|
}
|
|
}
|
|
i++;
|
|
pm_reg = pm_scanline[i];
|
|
if (pm_reg) {
|
|
if (pm_reg == L_PF3) {
|
|
WRITE_VIDEO(ptr + 1, pixel ? pixel | (pixel << 8) | cl_lookup[C_PF3] : cl_lookup[C_PF3] & 0xf0f0);
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr + 1, COLOUR(pm_reg));
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
do_border_gtia11();
|
|
}
|
|
|
|
#define DEFINE_DRAW_AN(anticmode) \
|
|
static void draw_antic_ ## anticmode ## _gtia9 (int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)\
|
|
{\
|
|
prepare_an_antic_ ## anticmode (nchars, ANTIC_memptr, t_pm_scanline_ptr);\
|
|
draw_an_gtia9(t_pm_scanline_ptr);\
|
|
}\
|
|
static void draw_antic_ ## anticmode ## _gtia10 (int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)\
|
|
{\
|
|
prepare_an_antic_ ## anticmode (nchars, ANTIC_memptr, t_pm_scanline_ptr);\
|
|
draw_an_gtia10(t_pm_scanline_ptr);\
|
|
}\
|
|
static void draw_antic_ ## anticmode ## _gtia11 (int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)\
|
|
{\
|
|
prepare_an_antic_ ## anticmode (nchars, ANTIC_memptr, t_pm_scanline_ptr);\
|
|
draw_an_gtia11(t_pm_scanline_ptr);\
|
|
}
|
|
|
|
#define CHAR_LOOP_BEGIN do {
|
|
#define CHAR_LOOP_END } while (--nchars);
|
|
|
|
#define DO_PMG_LORES PF_COLLS(colreg) |= pm_pixel = *c_pm_scanline_ptr++;\
|
|
WRITE_VIDEO(ptr++, COLOUR(pm_lookup_ptr[pm_pixel] | colreg));
|
|
|
|
#define FOUR_LOOP_BEGIN(data) int k = 4; do {
|
|
#define FOUR_LOOP_END(data) } while (--k);
|
|
|
|
#define INIT_HIRES hires_norm(0x00) = cl_lookup[C_PF2];\
|
|
hires_norm(0x40) = hires_norm(0x10) = hires_norm(0x04) = (cl_lookup[C_PF2] & HIRES_MASK_01) | hires_lum(0x40);\
|
|
hires_norm(0x80) = hires_norm(0x20) = hires_norm(0x08) = (cl_lookup[C_PF2] & HIRES_MASK_10) | hires_lum(0x80);\
|
|
hires_norm(0xc0) = hires_norm(0x30) = hires_norm(0x0c) = (cl_lookup[C_PF2] & 0xf0f0) | hires_lum(0xc0);
|
|
|
|
#define DO_PMG_HIRES(data) {\
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;\
|
|
int pm_pixel;\
|
|
FOUR_LOOP_BEGIN(data)\
|
|
pm_pixel = *c_pm_scanline_ptr++;\
|
|
if (data & 0xc0)\
|
|
PF2PM |= pm_pixel;\
|
|
WRITE_VIDEO(ptr++, (COLOUR(pm_lookup_ptr[pm_pixel] | L_PF2) & hires_mask(data & 0xc0)) | hires_lum(data & 0xc0));\
|
|
data <<= 2;\
|
|
FOUR_LOOP_END(data)\
|
|
}
|
|
|
|
#define ADD_FONT_CYCLES xpos += font_cycles[md]
|
|
|
|
#define INIT_ANTIC_2 const UBYTE *chptr;\
|
|
chptr = AnticMainMemLookup(((dctr ^ chbase_20) & 0xfc07));\
|
|
ADD_FONT_CYCLES;\
|
|
blank_lookup[0x60] = (anticmode == 2 || dctr & 0xe) ? 0xff : 0;\
|
|
blank_lookup[0x00] = blank_lookup[0x20] = blank_lookup[0x40] = (dctr & 0xe) == 8 ? 0 : 0xff;
|
|
|
|
#define GET_CHDATA_ANTIC_2 chdata = (screendata & invert_mask) ? 0xff : 0;\
|
|
if (blank_lookup[screendata & blank_mask])\
|
|
chdata ^= chptr[(screendata & 0x7f) << 3];
|
|
|
|
|
|
ITCM_CODE static void draw_antic_2(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
INIT_BACKGROUND_6
|
|
INIT_ANTIC_2
|
|
INIT_HIRES
|
|
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
int chdata;
|
|
|
|
GET_CHDATA_ANTIC_2
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
if (chdata) {
|
|
WRITE_VIDEO(ptr++, hires_norm(chdata & 0xc0));
|
|
WRITE_VIDEO(ptr++, hires_norm(chdata & 0x30));
|
|
WRITE_VIDEO(ptr++, hires_norm(chdata & 0x0c));
|
|
WRITE_VIDEO(ptr++, hires_norm((chdata & 0x03) << 2));
|
|
}
|
|
else
|
|
DRAW_BACKGROUND(C_PF2)
|
|
}
|
|
else
|
|
{
|
|
DO_PMG_HIRES(chdata)
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
|
|
static void draw_antic_2_artif(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
ULONG screendata_tally;
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
UBYTE chdata;
|
|
INIT_ANTIC_2
|
|
GET_CHDATA_ANTIC_2
|
|
screendata_tally = chdata;
|
|
setup_art_colours();
|
|
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
ULONG chdata;
|
|
|
|
GET_CHDATA_ANTIC_2
|
|
screendata_tally <<= 8;
|
|
screendata_tally |= chdata;
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr))
|
|
DRAW_ARTIF
|
|
else {
|
|
chdata = screendata_tally >> 8;
|
|
DO_PMG_HIRES(chdata)
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
|
|
ITCM_CODE static void prepare_an_antic_2(int nchars, const UBYTE *ANTIC_memptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
UBYTE *an_ptr = (UBYTE *) t_pm_scanline_ptr + (an_scanline - pm_scanline);
|
|
const UBYTE *chptr;
|
|
chptr = AnticMainMemLookup(((dctr ^ chbase_20) & 0xfc07));
|
|
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
int chdata;
|
|
GET_CHDATA_ANTIC_2
|
|
*an_ptr++ = chdata >> 6;
|
|
*an_ptr++ = (chdata >> 4) & 3;
|
|
*an_ptr++ = (chdata >> 2) & 3;
|
|
*an_ptr++ = chdata & 3;
|
|
CHAR_LOOP_END
|
|
}
|
|
|
|
static void draw_antic_2_gtia9(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
INIT_ANTIC_2
|
|
if ((unsigned long) ptr & 2) { /* HSCROL & 1 */
|
|
prepare_an_antic_2(nchars, ANTIC_memptr, t_pm_scanline_ptr);
|
|
draw_an_gtia9(t_pm_scanline_ptr);
|
|
return;
|
|
}
|
|
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
int chdata;
|
|
|
|
GET_CHDATA_ANTIC_2
|
|
WRITE_VIDEO_LONG((ULONG *) ptr, lookup_gtia9[chdata >> 4]);
|
|
WRITE_VIDEO_LONG((ULONG *) ptr + 1, lookup_gtia9[chdata & 0xf]);
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr))
|
|
ptr += 4;
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int k = 4;
|
|
UBYTE pm_reg;
|
|
do {
|
|
pm_reg = pm_lookup_ptr[*c_pm_scanline_ptr++];
|
|
if (pm_reg) {
|
|
if (pm_reg == L_PF3) {
|
|
UBYTE tmp = k > 2 ? chdata >> 4 : chdata & 0xf;
|
|
WRITE_VIDEO(ptr, tmp | ((UWORD)tmp << 8) | cl_lookup[C_PF3]);
|
|
}
|
|
else
|
|
{
|
|
WRITE_VIDEO(ptr, COLOUR(pm_reg));
|
|
}
|
|
}
|
|
ptr++;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
static void draw_antic_2_gtia10(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
UWORD lookup_gtia10[16];
|
|
INIT_ANTIC_2
|
|
if ((unsigned long) ptr & 2) { /* HSCROL & 1 */
|
|
prepare_an_antic_2(nchars, ANTIC_memptr, t_pm_scanline_ptr);
|
|
draw_an_gtia10(t_pm_scanline_ptr);
|
|
return;
|
|
}
|
|
|
|
lookup_gtia10[0] = cl_lookup[C_PM0];
|
|
lookup_gtia10[1] = cl_lookup[C_PM1];
|
|
lookup_gtia10[2] = cl_lookup[C_PM2];
|
|
lookup_gtia10[3] = cl_lookup[C_PM3];
|
|
lookup_gtia10[12] = lookup_gtia10[4] = cl_lookup[C_PF0];
|
|
lookup_gtia10[13] = lookup_gtia10[5] = cl_lookup[C_PF1];
|
|
lookup_gtia10[14] = lookup_gtia10[6] = cl_lookup[C_PF2];
|
|
lookup_gtia10[15] = lookup_gtia10[7] = cl_lookup[C_PF3];
|
|
lookup_gtia10[8] = lookup_gtia10[9] = lookup_gtia10[10] = lookup_gtia10[11] = cl_lookup[C_BAK];
|
|
|
|
ptr++;
|
|
t_pm_scanline_ptr = (const ULONG *) (((const UBYTE *) t_pm_scanline_ptr) + 1);
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
int chdata;
|
|
|
|
GET_CHDATA_ANTIC_2
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
DO_GTIA_BYTE(ptr, lookup_gtia10, chdata)
|
|
ptr += 4;
|
|
}
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int pm_pixel;
|
|
int colreg;
|
|
int k = 4;
|
|
UBYTE t_screendata = chdata >> 4;
|
|
do {
|
|
colreg = gtia_10_lookup[t_screendata];
|
|
PF_COLLS(colreg) |= pm_pixel = *c_pm_scanline_ptr++;
|
|
pm_pixel |= gtia_10_pm[t_screendata];
|
|
WRITE_VIDEO(ptr++, COLOUR(pm_lookup_ptr[pm_pixel] | colreg));
|
|
if (k == 3)
|
|
t_screendata = chdata & 0x0f;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border_gtia10();
|
|
}
|
|
|
|
static void draw_antic_2_gtia11(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
INIT_ANTIC_2
|
|
if ((unsigned long) ptr & 2) { /* HSCROL & 1 */
|
|
prepare_an_antic_2(nchars, ANTIC_memptr, t_pm_scanline_ptr);
|
|
draw_an_gtia11(t_pm_scanline_ptr);
|
|
return;
|
|
}
|
|
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
int chdata;
|
|
|
|
GET_CHDATA_ANTIC_2
|
|
WRITE_VIDEO_LONG((ULONG *) ptr, lookup_gtia11[chdata >> 4]);
|
|
WRITE_VIDEO_LONG((ULONG *) ptr + 1, lookup_gtia11[chdata & 0xf]);
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr))
|
|
ptr += 4;
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int k = 4;
|
|
UBYTE pm_reg;
|
|
do {
|
|
pm_reg = pm_lookup_ptr[*c_pm_scanline_ptr++];
|
|
if (pm_reg) {
|
|
if (pm_reg == L_PF3) {
|
|
UBYTE tmp = k > 2 ? chdata & 0xf0 : chdata << 4;
|
|
WRITE_VIDEO(ptr, tmp ? tmp | ((UWORD)tmp << 8) | cl_lookup[C_PF3] : cl_lookup[C_PF3] & 0xf0f0);
|
|
}
|
|
else
|
|
{
|
|
WRITE_VIDEO(ptr, COLOUR(pm_reg));
|
|
}
|
|
}
|
|
ptr++;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border_gtia11();
|
|
}
|
|
|
|
ITCM_CODE static void draw_antic_4(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
INIT_BACKGROUND_8
|
|
const UBYTE *chptr;
|
|
chptr = AnticMainMemLookup((((anticmode == 4 ? dctr : dctr >> 1) ^ chbase_20) & 0xfc07));
|
|
|
|
ADD_FONT_CYCLES;
|
|
lookup2[0x0f] = lookup2[0x00] = cl_lookup[C_BAK];
|
|
lookup2[0x4f] = lookup2[0x1f] = lookup2[0x13] =
|
|
lookup2[0x40] = lookup2[0x10] = lookup2[0x04] = lookup2[0x01] = cl_lookup[C_PF0];
|
|
lookup2[0x8f] = lookup2[0x2f] = lookup2[0x17] = lookup2[0x11] =
|
|
lookup2[0x80] = lookup2[0x20] = lookup2[0x08] = lookup2[0x02] = cl_lookup[C_PF1];
|
|
lookup2[0xc0] = lookup2[0x30] = lookup2[0x0c] = lookup2[0x03] = cl_lookup[C_PF2];
|
|
lookup2[0xcf] = lookup2[0x3f] = lookup2[0x1b] = lookup2[0x12] = cl_lookup[C_PF3];
|
|
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
const UWORD *lookup;
|
|
UBYTE chdata;
|
|
if (screendata & 0x80)
|
|
lookup = lookup2 + 0xf;
|
|
else
|
|
lookup = lookup2;
|
|
chdata = chptr[(screendata & 0x7f) << 3];
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
if (chdata) {
|
|
WRITE_VIDEO(ptr++, lookup[chdata & 0xc0]);
|
|
WRITE_VIDEO(ptr++, lookup[chdata & 0x30]);
|
|
WRITE_VIDEO(ptr++, lookup[chdata & 0x0c]);
|
|
WRITE_VIDEO(ptr++, lookup[chdata & 0x03]);
|
|
}
|
|
else
|
|
DRAW_BACKGROUND(C_BAK)
|
|
}
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int pm_pixel;
|
|
int colreg;
|
|
int k = 4;
|
|
playfield_lookup[0xc0] = screendata & 0x80 ? L_PF3 : L_PF2;
|
|
do {
|
|
colreg = playfield_lookup[chdata & 0xc0];
|
|
DO_PMG_LORES
|
|
chdata <<= 2;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
playfield_lookup[0xc0] = L_PF2;
|
|
do_border();
|
|
}
|
|
|
|
ITCM_CODE static void prepare_an_antic_4(int nchars, const UBYTE *ANTIC_memptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
UBYTE *an_ptr = (UBYTE *) t_pm_scanline_ptr + (an_scanline - pm_scanline);
|
|
const UBYTE *chptr;
|
|
chptr = AnticMainMemLookup((((anticmode == 4 ? dctr : dctr >> 1) ^ chbase_20) & 0xfc07));
|
|
|
|
ADD_FONT_CYCLES;
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
UBYTE an;
|
|
UBYTE chdata;
|
|
chdata = chptr[(screendata & 0x3f) << 3];
|
|
an = mode_e_an_lookup[chdata & 0xc0];
|
|
*an_ptr++ = (an == 2 && screendata & 0x80) ? 3 : an;
|
|
an = mode_e_an_lookup[chdata & 0x30];
|
|
*an_ptr++ = (an == 2 && screendata & 0x80) ? 3 : an;
|
|
an = mode_e_an_lookup[chdata & 0x0c];
|
|
*an_ptr++ = (an == 2 && screendata & 0x80) ? 3 : an;
|
|
an = mode_e_an_lookup[chdata & 0x03];
|
|
*an_ptr++ = (an == 2 && screendata & 0x80) ? 3 : an;
|
|
CHAR_LOOP_END
|
|
}
|
|
|
|
DEFINE_DRAW_AN(4)
|
|
|
|
ITCM_CODE static void draw_antic_6(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
const UBYTE *chptr;
|
|
chptr = AnticMainMemLookup(((anticmode == 6 ? dctr & 7 : dctr >> 1) ^ chbase_20));
|
|
|
|
ADD_FONT_CYCLES;
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
UBYTE chdata;
|
|
UWORD colour;
|
|
int kk = 2;
|
|
colour = COLOUR((playfield_lookup + 0x40)[screendata & 0xc0]);
|
|
chdata = chptr[(screendata & 0x3f) << 3];
|
|
do {
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
if (chdata & 0xf0) {
|
|
if (chdata & 0x80) {
|
|
WRITE_VIDEO(ptr++, colour);
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr++, cl_lookup[C_BAK]);
|
|
}
|
|
if (chdata & 0x40) {
|
|
WRITE_VIDEO(ptr++, colour);
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr++, cl_lookup[C_BAK]);
|
|
}
|
|
if (chdata & 0x20) {
|
|
WRITE_VIDEO(ptr++, colour);
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr++, cl_lookup[C_BAK]);
|
|
}
|
|
if (chdata & 0x10) {
|
|
WRITE_VIDEO(ptr++, colour);
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr++, cl_lookup[C_BAK]);
|
|
}
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr++, cl_lookup[C_BAK]);
|
|
WRITE_VIDEO(ptr++, cl_lookup[C_BAK]);
|
|
WRITE_VIDEO(ptr++, cl_lookup[C_BAK]);
|
|
WRITE_VIDEO(ptr++, cl_lookup[C_BAK]);
|
|
}
|
|
chdata <<= 4;
|
|
}
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int pm_pixel;
|
|
UBYTE setcol = (playfield_lookup + 0x40)[screendata & 0xc0];
|
|
int colreg;
|
|
int k = 4;
|
|
do {
|
|
colreg = chdata & 0x80 ? setcol : L_BAK;
|
|
DO_PMG_LORES
|
|
chdata <<= 1;
|
|
} while (--k);
|
|
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
} while (--kk);
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
ITCM_CODE static void prepare_an_antic_6(int nchars, const UBYTE *ANTIC_memptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
UBYTE *an_ptr = (UBYTE *) t_pm_scanline_ptr + (an_scanline - pm_scanline);
|
|
const UBYTE *chptr;
|
|
chptr = AnticMainMemLookup(((anticmode == 6 ? dctr & 7 : dctr >> 1) ^ chbase_20));
|
|
|
|
ADD_FONT_CYCLES;
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
UBYTE an = screendata >> 6;
|
|
UBYTE chdata;
|
|
chdata = chptr[(screendata & 0x3f) << 3];
|
|
*an_ptr++ = chdata & 0x80 ? an : 0;
|
|
*an_ptr++ = chdata & 0x40 ? an : 0;
|
|
*an_ptr++ = chdata & 0x20 ? an : 0;
|
|
*an_ptr++ = chdata & 0x10 ? an : 0;
|
|
*an_ptr++ = chdata & 0x08 ? an : 0;
|
|
*an_ptr++ = chdata & 0x04 ? an : 0;
|
|
*an_ptr++ = chdata & 0x02 ? an : 0;
|
|
*an_ptr++ = chdata & 0x01 ? an : 0;
|
|
CHAR_LOOP_END
|
|
}
|
|
|
|
DEFINE_DRAW_AN(6)
|
|
|
|
ITCM_CODE static void draw_antic_8(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
lookup2[0x00] = cl_lookup[C_BAK];
|
|
lookup2[0x40] = cl_lookup[C_PF0];
|
|
lookup2[0x80] = cl_lookup[C_PF1];
|
|
lookup2[0xc0] = cl_lookup[C_PF2];
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
int kk = 4;
|
|
do {
|
|
if ((const UBYTE *) t_pm_scanline_ptr >= pm_scanline + 4 * (48 - RCHOP))
|
|
break;
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
UWORD data = lookup2[screendata & 0xc0];
|
|
WRITE_VIDEO(ptr++, data);
|
|
WRITE_VIDEO(ptr++, data);
|
|
WRITE_VIDEO(ptr++, data);
|
|
WRITE_VIDEO(ptr++, data);
|
|
}
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int pm_pixel;
|
|
int colreg = playfield_lookup[screendata & 0xc0];
|
|
int k = 4;
|
|
do {
|
|
DO_PMG_LORES
|
|
} while (--k);
|
|
}
|
|
screendata <<= 2;
|
|
t_pm_scanline_ptr++;
|
|
} while (--kk);
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
ITCM_CODE static void prepare_an_antic_8(int nchars, const UBYTE *ANTIC_memptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
UBYTE *an_ptr = (UBYTE *) t_pm_scanline_ptr + (an_scanline - pm_scanline);
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
int kk = 4;
|
|
do {
|
|
UBYTE data = mode_e_an_lookup[screendata & 0xc0];
|
|
*an_ptr++ = data;
|
|
*an_ptr++ = data;
|
|
*an_ptr++ = data;
|
|
*an_ptr++ = data;
|
|
screendata <<= 2;
|
|
} while (--kk);
|
|
CHAR_LOOP_END
|
|
}
|
|
|
|
DEFINE_DRAW_AN(8)
|
|
|
|
ITCM_CODE static void draw_antic_9(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
lookup2[0x00] = cl_lookup[C_BAK];
|
|
lookup2[0x80] = lookup2[0x40] = cl_lookup[C_PF0];
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
int kk = 4;
|
|
do {
|
|
if ((const UBYTE *) t_pm_scanline_ptr >= pm_scanline + 4 * (48 - RCHOP))
|
|
break;
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x80]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x80]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x40]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x40]);
|
|
screendata <<= 2;
|
|
}
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int pm_pixel;
|
|
int colreg;
|
|
int k = 4;
|
|
do {
|
|
colreg = (screendata & 0x80) ? L_PF0 : L_BAK;
|
|
DO_PMG_LORES
|
|
if (k & 0x01)
|
|
screendata <<= 1;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
} while (--kk);
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
/* ANTIC modes 9, b and c use BAK and PF0 colours only so they're not visible in GTIA modes */
|
|
|
|
static void draw_antic_9_gtia9(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
draw_antic_0();
|
|
}
|
|
|
|
static void draw_antic_9_gtia10(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
draw_antic_0_gtia10();
|
|
}
|
|
|
|
static void draw_antic_9_gtia11(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
draw_antic_0_gtia11();
|
|
}
|
|
|
|
ITCM_CODE static void draw_antic_a(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
lookup2[0x00] = cl_lookup[C_BAK];
|
|
lookup2[0x40] = lookup2[0x10] = cl_lookup[C_PF0];
|
|
lookup2[0x80] = lookup2[0x20] = cl_lookup[C_PF1];
|
|
lookup2[0xc0] = lookup2[0x30] = cl_lookup[C_PF2];
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
int kk = 2;
|
|
do {
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0xc0]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0xc0]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x30]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x30]);
|
|
screendata <<= 4;
|
|
}
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int pm_pixel;
|
|
int colreg;
|
|
int k = 4;
|
|
do {
|
|
colreg = playfield_lookup[screendata & 0xc0];
|
|
DO_PMG_LORES
|
|
if (k & 0x01)
|
|
screendata <<= 2;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
} while (--kk);
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
ITCM_CODE static void prepare_an_antic_a(int nchars, const UBYTE *ANTIC_memptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
UBYTE *an_ptr = (UBYTE *) t_pm_scanline_ptr + (an_scanline - pm_scanline);
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
UBYTE data = mode_e_an_lookup[screendata & 0xc0];
|
|
*an_ptr++ = data;
|
|
*an_ptr++ = data;
|
|
data = mode_e_an_lookup[screendata & 0x30];
|
|
*an_ptr++ = data;
|
|
*an_ptr++ = data;
|
|
data = mode_e_an_lookup[screendata & 0x0c];
|
|
*an_ptr++ = data;
|
|
*an_ptr++ = data;
|
|
data = mode_e_an_lookup[screendata & 0x03];
|
|
*an_ptr++ = data;
|
|
*an_ptr++ = data;
|
|
CHAR_LOOP_END
|
|
}
|
|
|
|
DEFINE_DRAW_AN(a)
|
|
|
|
static void draw_antic_c(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
lookup2[0x00] = cl_lookup[C_BAK];
|
|
lookup2[0x80] = lookup2[0x40] = lookup2[0x20] = lookup2[0x10] = cl_lookup[C_PF0];
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
int kk = 2;
|
|
do {
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x80]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x40]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x20]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x10]);
|
|
screendata <<= 4;
|
|
}
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int pm_pixel;
|
|
int colreg;
|
|
int k = 4;
|
|
do {
|
|
colreg = (screendata & 0x80) ? L_PF0 : L_BAK;
|
|
DO_PMG_LORES
|
|
screendata <<= 1;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
} while (--kk);
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
static void draw_antic_e(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
INIT_BACKGROUND_8
|
|
lookup2[0x00] = cl_lookup[C_BAK];
|
|
lookup2[0x40] = lookup2[0x10] = lookup2[0x04] = lookup2[0x01] = cl_lookup[C_PF0];
|
|
lookup2[0x80] = lookup2[0x20] = lookup2[0x08] = lookup2[0x02] = cl_lookup[C_PF1];
|
|
lookup2[0xc0] = lookup2[0x30] = lookup2[0x0c] = lookup2[0x03] = cl_lookup[C_PF2];
|
|
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
if (screendata) {
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0xc0]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x30]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x0c]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x03]);
|
|
}
|
|
else
|
|
DRAW_BACKGROUND(C_BAK)
|
|
}
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int pm_pixel;
|
|
int colreg;
|
|
int k = 4;
|
|
do {
|
|
colreg = playfield_lookup[screendata & 0xc0];
|
|
DO_PMG_LORES
|
|
screendata <<= 2;
|
|
} while (--k);
|
|
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
static void prepare_an_antic_e(int nchars, const UBYTE *ANTIC_memptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
UBYTE *an_ptr = (UBYTE *) t_pm_scanline_ptr + (an_scanline - pm_scanline);
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
*an_ptr++ = mode_e_an_lookup[screendata & 0xc0];
|
|
*an_ptr++ = mode_e_an_lookup[screendata & 0x30];
|
|
*an_ptr++ = mode_e_an_lookup[screendata & 0x0c];
|
|
*an_ptr++ = mode_e_an_lookup[screendata & 0x03];
|
|
CHAR_LOOP_END
|
|
}
|
|
|
|
static void draw_antic_e_gtia9(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
ULONG lookup[16];
|
|
if ((unsigned long) ptr & 2) { /* HSCROL & 1 */
|
|
prepare_an_antic_e(nchars, ANTIC_memptr, t_pm_scanline_ptr);
|
|
draw_an_gtia9(t_pm_scanline_ptr);
|
|
return;
|
|
}
|
|
lookup[0] = lookup[1] = lookup[4] = lookup[5] = lookup_gtia9[0];
|
|
lookup[2] = lookup[6] = lookup_gtia9[1];
|
|
lookup[3] = lookup[7] = lookup_gtia9[2];
|
|
lookup[8] = lookup[9] = lookup_gtia9[4];
|
|
lookup[10] = lookup_gtia9[5];
|
|
lookup[11] = lookup_gtia9[6];
|
|
lookup[12] = lookup[13] = lookup_gtia9[8];
|
|
lookup[14] = lookup_gtia9[9];
|
|
lookup[15] = lookup_gtia9[10];
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
WRITE_VIDEO_LONG((ULONG *) ptr, lookup[screendata >> 4]);
|
|
WRITE_VIDEO_LONG((ULONG *) ptr + 1, lookup[screendata & 0xf]);
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr))
|
|
ptr += 4;
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int k = 4;
|
|
UBYTE pm_reg;
|
|
do {
|
|
pm_reg = pm_lookup_ptr[*c_pm_scanline_ptr++];
|
|
if (pm_reg) {
|
|
if (pm_reg == L_PF3) {
|
|
UBYTE tmp = k > 2 ? screendata >> 4 : screendata & 0xf;
|
|
WRITE_VIDEO(ptr, tmp | ((UWORD)tmp << 8) | cl_lookup[C_PF3]);
|
|
}
|
|
else
|
|
{
|
|
WRITE_VIDEO(ptr, COLOUR(pm_reg));
|
|
}
|
|
}
|
|
ptr++;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
static void draw_antic_e_gtia10 (int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
prepare_an_antic_e(nchars, ANTIC_memptr, t_pm_scanline_ptr);
|
|
draw_an_gtia10(t_pm_scanline_ptr);
|
|
}
|
|
static void draw_antic_e_gtia11 (int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
prepare_an_antic_e(nchars, ANTIC_memptr, t_pm_scanline_ptr);
|
|
draw_an_gtia11(t_pm_scanline_ptr);
|
|
}
|
|
|
|
static void draw_antic_f(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
INIT_BACKGROUND_6
|
|
INIT_HIRES
|
|
|
|
CHAR_LOOP_BEGIN
|
|
int screendata = *ANTIC_memptr++;
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
if (screendata) {
|
|
WRITE_VIDEO(ptr++, hires_norm(screendata & 0xc0));
|
|
WRITE_VIDEO(ptr++, hires_norm(screendata & 0x30));
|
|
WRITE_VIDEO(ptr++, hires_norm(screendata & 0x0c));
|
|
WRITE_VIDEO(ptr++, hires_norm((screendata & 0x03) << 2));
|
|
}
|
|
else
|
|
DRAW_BACKGROUND(C_PF2)
|
|
}
|
|
else
|
|
DO_PMG_HIRES(screendata)
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
static void draw_antic_f_artif(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
ULONG screendata_tally = *ANTIC_memptr++;
|
|
|
|
setup_art_colours();
|
|
CHAR_LOOP_BEGIN
|
|
int screendata = *ANTIC_memptr++;
|
|
screendata_tally <<= 8;
|
|
screendata_tally |= screendata;
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr))
|
|
DRAW_ARTIF
|
|
else {
|
|
screendata = ANTIC_memptr[-2];
|
|
DO_PMG_HIRES(screendata)
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
|
|
static void prepare_an_antic_f(int nchars, const UBYTE *ANTIC_memptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
UBYTE *an_ptr = (UBYTE *) t_pm_scanline_ptr + (an_scanline - pm_scanline);
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
*an_ptr++ = screendata >> 6;
|
|
*an_ptr++ = (screendata >> 4) & 3;
|
|
*an_ptr++ = (screendata >> 2) & 3;
|
|
*an_ptr++ = screendata & 3;
|
|
CHAR_LOOP_END
|
|
}
|
|
|
|
static void draw_antic_f_gtia9(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
if ((unsigned long) ptr & 2) { /* HSCROL & 1 */
|
|
prepare_an_antic_f(nchars, ANTIC_memptr, t_pm_scanline_ptr);
|
|
draw_an_gtia9(t_pm_scanline_ptr);
|
|
return;
|
|
}
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
WRITE_VIDEO_LONG((ULONG *) ptr, lookup_gtia9[screendata >> 4]);
|
|
WRITE_VIDEO_LONG((ULONG *) ptr + 1, lookup_gtia9[screendata & 0xf]);
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr))
|
|
ptr += 4;
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int k = 4;
|
|
UBYTE pm_reg;
|
|
do {
|
|
pm_reg = pm_lookup_ptr[*c_pm_scanline_ptr++];
|
|
if (pm_reg) {
|
|
if (pm_reg == L_PF3) {
|
|
UBYTE tmp = k > 2 ? screendata >> 4 : screendata & 0xf;
|
|
WRITE_VIDEO(ptr, tmp | ((UWORD)tmp << 8) | cl_lookup[C_PF3]);
|
|
}
|
|
else {
|
|
WRITE_VIDEO(ptr, COLOUR(pm_reg));
|
|
}
|
|
}
|
|
ptr++;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
static void draw_antic_f_gtia10(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
UWORD lookup_gtia10[16];
|
|
|
|
if ((unsigned long) ptr & 2) { /* HSCROL & 1 */
|
|
prepare_an_antic_f(nchars, ANTIC_memptr, t_pm_scanline_ptr);
|
|
draw_an_gtia10(t_pm_scanline_ptr);
|
|
return;
|
|
}
|
|
|
|
lookup_gtia10[0] = cl_lookup[C_PM0];
|
|
lookup_gtia10[1] = cl_lookup[C_PM1];
|
|
lookup_gtia10[2] = cl_lookup[C_PM2];
|
|
lookup_gtia10[3] = cl_lookup[C_PM3];
|
|
lookup_gtia10[12] = lookup_gtia10[4] = cl_lookup[C_PF0];
|
|
lookup_gtia10[13] = lookup_gtia10[5] = cl_lookup[C_PF1];
|
|
lookup_gtia10[14] = lookup_gtia10[6] = cl_lookup[C_PF2];
|
|
lookup_gtia10[15] = lookup_gtia10[7] = cl_lookup[C_PF3];
|
|
lookup_gtia10[8] = lookup_gtia10[9] = lookup_gtia10[10] = lookup_gtia10[11] = cl_lookup[C_BAK];
|
|
|
|
ptr++;
|
|
t_pm_scanline_ptr = (const ULONG *) (((const UBYTE *) t_pm_scanline_ptr) + 1);
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
DO_GTIA_BYTE(ptr, lookup_gtia10, screendata)
|
|
ptr += 4;
|
|
}
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int pm_pixel;
|
|
int colreg;
|
|
int k = 4;
|
|
UBYTE t_screendata = screendata >> 4;
|
|
do {
|
|
colreg = gtia_10_lookup[t_screendata];
|
|
PF_COLLS(colreg) |= pm_pixel = *c_pm_scanline_ptr++;
|
|
pm_pixel |= gtia_10_pm[t_screendata];
|
|
WRITE_VIDEO(ptr++, COLOUR(pm_lookup_ptr[pm_pixel] | colreg));
|
|
if (k == 3)
|
|
t_screendata = screendata & 0x0f;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border_gtia10();
|
|
}
|
|
|
|
static void draw_antic_f_gtia11(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
if ((unsigned long) ptr & 2) { /* HSCROL & 1 */
|
|
prepare_an_antic_f(nchars, ANTIC_memptr, t_pm_scanline_ptr);
|
|
draw_an_gtia11(t_pm_scanline_ptr);
|
|
return;
|
|
}
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
WRITE_VIDEO_LONG((ULONG *) ptr, lookup_gtia11[screendata >> 4]);
|
|
WRITE_VIDEO_LONG((ULONG *) ptr + 1, lookup_gtia11[screendata & 0xf]);
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr))
|
|
ptr += 4;
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int k = 4;
|
|
UBYTE pm_reg;
|
|
do {
|
|
pm_reg = pm_lookup_ptr[*c_pm_scanline_ptr++];
|
|
if (pm_reg) {
|
|
if (pm_reg == L_PF3) {
|
|
UBYTE tmp = k > 2 ? screendata & 0xf0 : screendata << 4;
|
|
WRITE_VIDEO(ptr, tmp ? tmp | ((UWORD)tmp << 8) | cl_lookup[C_PF3] : cl_lookup[C_PF3] & 0xf0f0);
|
|
}
|
|
else
|
|
{
|
|
WRITE_VIDEO(ptr, COLOUR(pm_reg));
|
|
}
|
|
}
|
|
ptr++;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border_gtia11();
|
|
}
|
|
|
|
/* GTIA-switch-to-mode-00 bug
|
|
If while drawing line in hi-res mode PRIOR is changed from 0x40..0xff to
|
|
0x00..0x3f, GTIA doesn't back to hi-res, but starts generating mode similar
|
|
to ANTIC's 0xe, but with colours PF0, PF1, PF2, PF3. */
|
|
|
|
static void draw_antic_f_gtia_bug(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr)
|
|
{
|
|
lookup2[0x00] = cl_lookup[C_PF0];
|
|
lookup2[0x40] = lookup2[0x10] = lookup2[0x04] = lookup2[0x01] = cl_lookup[C_PF1];
|
|
lookup2[0x80] = lookup2[0x20] = lookup2[0x08] = lookup2[0x02] = cl_lookup[C_PF2];
|
|
lookup2[0xc0] = lookup2[0x30] = lookup2[0x0c] = lookup2[0x03] = cl_lookup[C_PF3];
|
|
|
|
CHAR_LOOP_BEGIN
|
|
UBYTE screendata = *ANTIC_memptr++;
|
|
if (IS_ZERO_ULONG(t_pm_scanline_ptr)) {
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0xc0]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x30]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x0c]);
|
|
WRITE_VIDEO(ptr++, lookup2[screendata & 0x03]);
|
|
}
|
|
else {
|
|
const UBYTE *c_pm_scanline_ptr = (const UBYTE *) t_pm_scanline_ptr;
|
|
int pm_pixel;
|
|
int colreg;
|
|
int k = 4;
|
|
do {
|
|
colreg = (playfield_lookup + 0x40)[screendata & 0xc0];
|
|
DO_PMG_LORES
|
|
screendata <<= 2;
|
|
} while (--k);
|
|
}
|
|
t_pm_scanline_ptr++;
|
|
CHAR_LOOP_END
|
|
do_border();
|
|
}
|
|
|
|
/* pointer to a function that draws a single line of graphics */
|
|
typedef void (*draw_antic_function)(int nchars, const UBYTE *ANTIC_memptr, UWORD *ptr, const ULONG *t_pm_scanline_ptr);
|
|
|
|
/* tables for all GTIA and ANTIC modes */
|
|
static draw_antic_function draw_antic_table[4][16] = {
|
|
/* normal */
|
|
{ NULL, NULL, draw_antic_2, draw_antic_2,
|
|
draw_antic_4, draw_antic_4, draw_antic_6, draw_antic_6,
|
|
draw_antic_8, draw_antic_9, draw_antic_a, draw_antic_c,
|
|
draw_antic_c, draw_antic_e, draw_antic_e, draw_antic_f},
|
|
/* GTIA 9 */
|
|
{ NULL, NULL, draw_antic_2_gtia9, draw_antic_2_gtia9,
|
|
draw_antic_4_gtia9, draw_antic_4_gtia9, draw_antic_6_gtia9, draw_antic_6_gtia9,
|
|
draw_antic_8_gtia9, draw_antic_9_gtia9, draw_antic_a_gtia9, draw_antic_9_gtia9,
|
|
draw_antic_9_gtia9, draw_antic_e_gtia9, draw_antic_e_gtia9, draw_antic_f_gtia9},
|
|
/* GTIA 10 */
|
|
{ NULL, NULL, draw_antic_2_gtia10, draw_antic_2_gtia10,
|
|
draw_antic_4_gtia10, draw_antic_4_gtia10, draw_antic_6_gtia10, draw_antic_6_gtia10,
|
|
draw_antic_8_gtia10, draw_antic_9_gtia10, draw_antic_a_gtia10, draw_antic_9_gtia10,
|
|
draw_antic_9_gtia10, draw_antic_e_gtia10, draw_antic_e_gtia10, draw_antic_f_gtia10},
|
|
/* GTIA 11 */
|
|
{ NULL, NULL, draw_antic_2_gtia11, draw_antic_2_gtia11,
|
|
draw_antic_4_gtia11, draw_antic_4_gtia11, draw_antic_6_gtia11, draw_antic_6_gtia11,
|
|
draw_antic_8_gtia11, draw_antic_9_gtia11, draw_antic_a_gtia11, draw_antic_9_gtia11,
|
|
draw_antic_9_gtia11, draw_antic_e_gtia11, draw_antic_e_gtia11, draw_antic_f_gtia11}};
|
|
|
|
/* pointer to current GTIA/ANTIC mode routine */
|
|
static draw_antic_function draw_antic_ptr = draw_antic_8;
|
|
/* pointer to current GTIA mode blank drawing routine */
|
|
static void (*draw_antic_0_ptr)(void) = draw_antic_0;
|
|
|
|
/* Artifacting ------------------------------------------------------------ */
|
|
|
|
void ANTIC_UpdateArtifacting(void)
|
|
{
|
|
#define ART_BROWN 0
|
|
#define ART_BLUE 1
|
|
#define ART_DARK_BROWN 2
|
|
#define ART_DARK_BLUE 3
|
|
#define ART_BRIGHT_BROWN 4
|
|
#define ART_BRIGHT_BLUE 5
|
|
#define ART_RED 6
|
|
#define ART_GREEN 7
|
|
static const UBYTE art_colour_table[4][8] = {
|
|
{ 0x88, 0x14, 0x88, 0x14, 0x8f, 0x1f, 0xbb, 0x5f }, /* brownblue */
|
|
{ 0x14, 0x88, 0x14, 0x88, 0x1f, 0x8f, 0x5f, 0xbb }, /* bluebrown */
|
|
{ 0xd6, 0x46, 0xd6, 0x46, 0xdf, 0x4a, 0x4f, 0xac }, /* redgreen */
|
|
{ 0x46, 0xd6, 0x46, 0xd6, 0x4a, 0xdf, 0xac, 0x4f } /* greenred */
|
|
};
|
|
|
|
int i;
|
|
int j;
|
|
int c;
|
|
const UBYTE *art_colours;
|
|
UBYTE q;
|
|
UBYTE art_white;
|
|
|
|
if (myCart.artifacting == 0) {
|
|
draw_antic_table[0][2] = draw_antic_table[0][3] = draw_antic_2;
|
|
draw_antic_table[0][0xf] = draw_antic_f;
|
|
return;
|
|
}
|
|
|
|
draw_antic_table[0][2] = draw_antic_table[0][3] = draw_antic_2_artif;
|
|
draw_antic_table[0][0xf] = draw_antic_f_artif;
|
|
|
|
art_colours = (myCart.artifacting <= 4 ? art_colour_table[myCart.artifacting - 1] : art_colour_table[2]);
|
|
|
|
art_reverse_colpf1_save = art_normal_colpf1_save = cl_lookup[C_PF1] & 0x0f0f;
|
|
art_reverse_colpf2_save = art_normal_colpf2_save = cl_lookup[C_PF2];
|
|
art_white = (cl_lookup[C_PF2] & 0xf0) | (cl_lookup[C_PF1] & 0x0f);
|
|
|
|
for (i = 0; i <= 255; i++) {
|
|
art_bkmask_normal[i] = 0;
|
|
art_lummask_normal[i] = 0;
|
|
art_bkmask_reverse[255 - i] = 0;
|
|
art_lummask_reverse[255 - i] = 0;
|
|
|
|
for (j = 0; j <= 3; j++) {
|
|
q = i << j;
|
|
if (!(q & 0x20)) {
|
|
if ((q & 0xf8) == 0x50)
|
|
c = ART_BLUE; /* 01010 */
|
|
else if ((q & 0xf8) == 0xD8)
|
|
c = ART_DARK_BLUE; /* 11011 */
|
|
else { /* xx0xx */
|
|
((UBYTE *) art_lookup_normal)[(i << 2) + j] = COLPF2;
|
|
((UBYTE *) art_lookup_reverse)[((255 - i) << 2) + j] = art_white;
|
|
((UBYTE *) art_bkmask_normal)[(i << 2) + j] = 0xff;
|
|
((UBYTE *) art_lummask_reverse)[((255 - i) << 2) + j] = 0x0f;
|
|
((UBYTE *) art_bkmask_reverse)[((255 - i) << 2) + j] = 0xf0;
|
|
continue;
|
|
}
|
|
}
|
|
else if (q & 0x40) {
|
|
if (q & 0x10)
|
|
goto colpf1_pixel; /* x111x */
|
|
else if (q & 0x80) {
|
|
if (q & 0x08)
|
|
c = ART_BRIGHT_BROWN; /* 11101 */
|
|
else
|
|
goto colpf1_pixel; /* 11100 */
|
|
}
|
|
else
|
|
c = ART_GREEN; /* 0110x */
|
|
}
|
|
else if (q & 0x10) {
|
|
if (q & 0x08) {
|
|
if (q & 0x80)
|
|
c = ART_BRIGHT_BROWN; /* 00111 */
|
|
else
|
|
goto colpf1_pixel; /* 10111 */
|
|
}
|
|
else
|
|
c = ART_RED; /* x0110 */
|
|
}
|
|
else
|
|
c = ART_BROWN; /* x010x */
|
|
|
|
((UBYTE *) art_lookup_reverse)[((255 - i) << 2) + j] =
|
|
((UBYTE *) art_lookup_normal)[(i << 2) + j] = art_colours[(j & 1) ^ c];
|
|
continue;
|
|
|
|
colpf1_pixel:
|
|
((UBYTE *) art_lookup_normal)[(i << 2) + j] = art_white;
|
|
((UBYTE *) art_lookup_reverse)[((255 - i) << 2) + j] = COLPF2;
|
|
((UBYTE *) art_bkmask_reverse)[((255 - i) << 2) + j] = 0xff;
|
|
((UBYTE *) art_lummask_normal)[(i << 2) + j] = 0x0f;
|
|
((UBYTE *) art_bkmask_normal)[(i << 2) + j] = 0xf0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Display List ------------------------------------------------------------ */
|
|
|
|
inline UBYTE ANTIC_GetDLByte(UWORD *paddr)
|
|
{
|
|
UBYTE result = dGetByte(*paddr);
|
|
(*paddr)++;
|
|
if ((*paddr & 0x3FF) == 0) *paddr -= 0x400;
|
|
return result;
|
|
}
|
|
|
|
inline UWORD ANTIC_GetDLWord(UWORD *paddr)
|
|
{
|
|
UBYTE lsb = ANTIC_GetDLByte(paddr);
|
|
if (player_flickering && ((VDELAY & 0x80) == 0 || ypos & 1))
|
|
GRAFP3 = lsb;
|
|
return (ANTIC_GetDLByte(paddr) << 8) + lsb;
|
|
}
|
|
|
|
/* Real ANTIC doesn't fetch beginning bytes in HSC
|
|
nor screen+47 in wide playfield. This function does. */
|
|
static void ANTIC_load(void)
|
|
{
|
|
UWORD new_screenaddr = screenaddr + chars_read[md];
|
|
if ((screenaddr ^ new_screenaddr) & 0xf000) {
|
|
int bytes = (-screenaddr) & 0xfff;
|
|
if ((screenaddr & 0xf000) == 0xd000) {
|
|
CopyFromMem(screenaddr, ANTIC_memory + ANTIC_margin, bytes);
|
|
if (new_screenaddr & 0xfff)
|
|
CopyFromMem((UWORD) (screenaddr + bytes - 0x1000), ANTIC_memory + ANTIC_margin + bytes, new_screenaddr & 0xfff);
|
|
}
|
|
else {
|
|
dCopyFromMem(screenaddr, ANTIC_memory + ANTIC_margin, bytes);
|
|
if (new_screenaddr & 0xfff)
|
|
dCopyFromMem(screenaddr + bytes - 0x1000, ANTIC_memory + ANTIC_margin + bytes, new_screenaddr & 0xfff);
|
|
}
|
|
screenaddr = new_screenaddr - 0x1000;
|
|
}
|
|
else {
|
|
if ((screenaddr & 0xf000) == 0xd000)
|
|
CopyFromMem(screenaddr, ANTIC_memory + ANTIC_margin, chars_read[md]);
|
|
else
|
|
dCopyFromMem(screenaddr, ANTIC_memory + ANTIC_margin, chars_read[md]);
|
|
screenaddr = new_screenaddr;
|
|
}
|
|
}
|
|
|
|
UBYTE mode_type[32] __attribute__((section(".dtcm"))) = {
|
|
NORMAL0, NORMAL0, NORMAL0, NORMAL0, NORMAL0, NORMAL0, NORMAL1, NORMAL1,
|
|
NORMAL2, NORMAL2, NORMAL1, NORMAL1, NORMAL1, NORMAL0, NORMAL0, NORMAL0,
|
|
SCROLL0, SCROLL0, SCROLL0, SCROLL0, SCROLL0, SCROLL0, SCROLL1, SCROLL1,
|
|
SCROLL2, SCROLL2, SCROLL1, SCROLL1, SCROLL1, SCROLL0, SCROLL0, SCROLL0
|
|
};
|
|
UBYTE normal_lastline[16] __attribute__((section(".dtcm"))) = { 0, 0, 7, 9, 7, 15, 7, 15, 7, 3, 3, 1, 0, 1, 0, 0 };
|
|
|
|
/* This function emulates one frame drawing screen at atari_screen */
|
|
ITCM_CODE void ANTIC_Frame(int draw_display)
|
|
{
|
|
UBYTE vscrol_flag = FALSE;
|
|
UBYTE no_jvb = TRUE;
|
|
UBYTE need_load;
|
|
|
|
ypos = 0;
|
|
do {
|
|
POKEY_Scanline(); /* check and generate IRQ */
|
|
OVERSCREEN_LINE;
|
|
} while (ypos < 8);
|
|
|
|
scrn_ptr = bgGetGfxPtr(bg2);
|
|
need_dl = TRUE;
|
|
do {
|
|
POKEY_Scanline(); /* check and generate IRQ */
|
|
if (missile_or_player_dma_enabled) pmg_dma();
|
|
need_load = FALSE;
|
|
if (need_dl) {
|
|
if (DMACTL & 0x20) {
|
|
IR = ANTIC_GetDLByte(&dlist);
|
|
anticmode = IR & 0xf;
|
|
xpos++;
|
|
/* PMG flickering :-) */
|
|
if (missile_flickering)
|
|
GRAFM = ypos & 1 ? IR : ((GRAFM ^ IR) & hold_missiles_tab[VDELAY & 0xf]) ^ IR;
|
|
if (player_flickering) {
|
|
UBYTE hold = ypos & 1 ? 0 : VDELAY;
|
|
if ((hold & 0x10) == 0)
|
|
GRAFP0 = dGetByte((UWORD) (regPC - xpos + 8));
|
|
if ((hold & 0x20) == 0)
|
|
GRAFP1 = dGetByte((UWORD) (regPC - xpos + 9));
|
|
if ((hold & 0x40) == 0)
|
|
GRAFP2 = dGetByte((UWORD) (regPC - xpos + 10));
|
|
if ((hold & 0x80) == 0)
|
|
GRAFP3 = dGetByte((UWORD) (regPC - xpos + 11));
|
|
}
|
|
}
|
|
else
|
|
IR &= 0x7f; /* repeat last instruction, but don't generate DLI */
|
|
|
|
dctr = 0;
|
|
need_dl = FALSE;
|
|
vscrol_off = FALSE;
|
|
|
|
switch (anticmode) {
|
|
case 0x00:
|
|
lastline = (IR >> 4) & 7;
|
|
if (vscrol_flag) {
|
|
lastline = VSCROL;
|
|
vscrol_flag = FALSE;
|
|
vscrol_off = TRUE;
|
|
}
|
|
break;
|
|
case 0x01:
|
|
lastline = 0;
|
|
if (IR & 0x40 && DMACTL & 0x20) {
|
|
dlist = ANTIC_GetDLWord(&dlist);
|
|
xpos += 2;
|
|
no_jvb = FALSE;
|
|
}
|
|
else
|
|
if (vscrol_flag) {
|
|
lastline = VSCROL;
|
|
vscrol_flag = FALSE;
|
|
vscrol_off = TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
lastline = normal_lastline[anticmode];
|
|
if (IR & 0x20) {
|
|
if (!vscrol_flag) {
|
|
GO(VSCON_C);
|
|
dctr = VSCROL;
|
|
vscrol_flag = TRUE;
|
|
}
|
|
}
|
|
else if (vscrol_flag) {
|
|
lastline = VSCROL;
|
|
vscrol_flag = FALSE;
|
|
vscrol_off = TRUE;
|
|
}
|
|
if (IR & 0x40 && DMACTL & 0x20) {
|
|
screenaddr = ANTIC_GetDLWord(&dlist);
|
|
xpos += 2;
|
|
}
|
|
md = mode_type[IR & 0x1f];
|
|
need_load = TRUE;
|
|
draw_antic_ptr = draw_antic_table[PRIOR >> 6][anticmode];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((IR & 0x4f) == 1 && (DMACTL & 0x20)) {
|
|
dlist = ANTIC_GetDLWord(&dlist);
|
|
xpos += 2;
|
|
}
|
|
|
|
if (dctr == lastline) {
|
|
if (no_jvb)
|
|
need_dl = TRUE;
|
|
if (IR & 0x80) {
|
|
GO(NMIST_C);
|
|
NMIST = 0x9f;
|
|
if (NMIEN & 0x80) {
|
|
GO(NMI_C);
|
|
NMI();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (need_load && anticmode <= 5 && DMACTL & 3)
|
|
xpos += before_cycles[md];
|
|
|
|
GO(SCR_C);
|
|
if (draw_display) new_pm_scanline();
|
|
|
|
xpos += DMAR;
|
|
|
|
if (anticmode < 2 || (DMACTL & 3) == 0)
|
|
{
|
|
if (draw_display) draw_antic_0_ptr();
|
|
GOEOL;
|
|
scrn_ptr += 256;
|
|
if (no_jvb) {
|
|
dctr++;
|
|
dctr &= 0xf;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (need_load) {
|
|
if (draw_display) ANTIC_load();
|
|
xpos += load_cycles[md];
|
|
if (anticmode <= 5) /* extra cycles in font modes */
|
|
xpos -= extra_cycles[md];
|
|
}
|
|
|
|
if (draw_display) draw_antic_ptr(chars_displayed[md], ANTIC_memory + ANTIC_margin + ch_offset[md], scrn_ptr + x_min[md], (ULONG *) &pm_scanline[x_min[md]]);
|
|
|
|
GOEOL;
|
|
scrn_ptr += 256;
|
|
dctr++;
|
|
dctr &= 0xf;
|
|
} while (ypos < (ATARI_HEIGHT + 8));
|
|
|
|
POKEY_Scanline(); /* check and generate IRQ */
|
|
GO(NMIST_C);
|
|
NMIST = 0x5f; /* Set VBLANK */
|
|
if (NMIEN & 0x40) {
|
|
GO(NMI_C);
|
|
NMI();
|
|
}
|
|
xpos += DMAR;
|
|
GOEOL;
|
|
|
|
do {
|
|
POKEY_Scanline(); /* check and generate IRQ */
|
|
OVERSCREEN_LINE;
|
|
} while (ypos < max_ypos);
|
|
ypos = 0; /* just for monitor.c */
|
|
}
|
|
|
|
/* ANTIC registers --------------------------------------------------------- */
|
|
|
|
UBYTE ANTIC_GetByte(UWORD addr)
|
|
{
|
|
switch (addr & 0xf)
|
|
{
|
|
case _VCOUNT:
|
|
if (XPOS < LINE_C)
|
|
return ypos >> 1;
|
|
if (ypos + 1 < max_ypos)
|
|
return (ypos + 1) >> 1;
|
|
return 0;
|
|
case _PENH:
|
|
return PENH;
|
|
case _PENV:
|
|
return PENV;
|
|
case _NMIST:
|
|
return NMIST;
|
|
default:
|
|
return 0xff;
|
|
}
|
|
}
|
|
|
|
|
|
/* GTIA calls it on write to PRIOR */
|
|
void set_prior(UBYTE byte)
|
|
{
|
|
if ((byte ^ PRIOR) & 0x0f) {
|
|
UWORD cword = 0;
|
|
UWORD cword2 = 0;
|
|
if ((byte & 3) == 0) {
|
|
cword = cl_lookup[C_PF0];
|
|
cword2 = cl_lookup[C_PF1];
|
|
}
|
|
if ((byte & 0xc) == 0) {
|
|
cl_lookup[C_PF0 | C_PM0] = cword | cl_lookup[C_PM0];
|
|
cl_lookup[C_PF0 | C_PM1] = cword | cl_lookup[C_PM1];
|
|
cl_lookup[C_PF0 | C_PM01] = cword | cl_lookup[C_PM01];
|
|
cl_lookup[C_PF1 | C_PM0] = cword2 | cl_lookup[C_PM0];
|
|
cl_lookup[C_PF1 | C_PM1] = cword2 | cl_lookup[C_PM1];
|
|
cl_lookup[C_PF1 | C_PM01] = cword2 | cl_lookup[C_PM01];
|
|
}
|
|
else {
|
|
cl_lookup[C_PF0 | C_PM01] = cl_lookup[C_PF0 | C_PM1] = cl_lookup[C_PF0 | C_PM0] = cword;
|
|
cl_lookup[C_PF1 | C_PM01] = cl_lookup[C_PF1 | C_PM1] = cl_lookup[C_PF1 | C_PM0] = cword2;
|
|
}
|
|
if (byte & 4) {
|
|
cl_lookup[C_PF2 | C_PM01] = cl_lookup[C_PF2 | C_PM1] = cl_lookup[C_PF2 | C_PM0] = cl_lookup[C_PF2];
|
|
cl_lookup[C_PF3 | C_PM01] = cl_lookup[C_PF3 | C_PM1] = cl_lookup[C_PF3 | C_PM0] = cl_lookup[C_PF3];
|
|
}
|
|
else {
|
|
cl_lookup[C_PF3 | C_PM0] = cl_lookup[C_PF2 | C_PM0] = cl_lookup[C_PM0];
|
|
cl_lookup[C_PF3 | C_PM1] = cl_lookup[C_PF2 | C_PM1] = cl_lookup[C_PM1];
|
|
cl_lookup[C_PF3 | C_PM01] = cl_lookup[C_PF2 | C_PM01] = cl_lookup[C_PM01];
|
|
}
|
|
cword = cword2 = 0;
|
|
if ((byte & 9) == 0) {
|
|
cword = cl_lookup[C_PF2];
|
|
cword2 = cl_lookup[C_PF3];
|
|
}
|
|
if ((byte & 6) == 0) {
|
|
cl_lookup[C_PF2 | C_PM2] = cword | cl_lookup[C_PM2];
|
|
cl_lookup[C_PF2 | C_PM3] = cword | cl_lookup[C_PM3];
|
|
cl_lookup[C_PF2 | C_PM23] = cword | cl_lookup[C_PM23];
|
|
cl_lookup[C_PF3 | C_PM2] = cword2 | cl_lookup[C_PM2];
|
|
cl_lookup[C_PF3 | C_PM3] = cword2 | cl_lookup[C_PM3];
|
|
cl_lookup[C_PF3 | C_PM23] = cword2 | cl_lookup[C_PM23];
|
|
}
|
|
else {
|
|
cl_lookup[C_PF2 | C_PM23] = cl_lookup[C_PF2 | C_PM3] = cl_lookup[C_PF2 | C_PM2] = cword;
|
|
cl_lookup[C_PF3 | C_PM23] = cl_lookup[C_PF3 | C_PM3] = cl_lookup[C_PF3 | C_PM2] = cword2;
|
|
}
|
|
|
|
if (byte & 1) {
|
|
cl_lookup[C_PF1 | C_PM2] = cl_lookup[C_PF0 | C_PM2] = cl_lookup[C_PM2];
|
|
cl_lookup[C_PF1 | C_PM3] = cl_lookup[C_PF0 | C_PM3] = cl_lookup[C_PM3];
|
|
cl_lookup[C_PF1 | C_PM23] = cl_lookup[C_PF0 | C_PM23] = cl_lookup[C_PM23];
|
|
}
|
|
else {
|
|
cl_lookup[C_PF0 | C_PM23] = cl_lookup[C_PF0 | C_PM3] = cl_lookup[C_PF0 | C_PM2] = cl_lookup[C_PF0];
|
|
cl_lookup[C_PF1 | C_PM23] = cl_lookup[C_PF1 | C_PM3] = cl_lookup[C_PF1 | C_PM2] = cl_lookup[C_PF1];
|
|
}
|
|
if ((byte & 0xf) == 0xc) {
|
|
cl_lookup[C_PF0 | C_PM0123] = cl_lookup[C_PF0 | C_PM123] = cl_lookup[C_PF0 | C_PM023] = cl_lookup[C_PF0];
|
|
cl_lookup[C_PF1 | C_PM0123] = cl_lookup[C_PF1 | C_PM123] = cl_lookup[C_PF1 | C_PM023] = cl_lookup[C_PF1];
|
|
}
|
|
else
|
|
cl_lookup[C_PF0 | C_PM0123] = cl_lookup[C_PF0 | C_PM123] = cl_lookup[C_PF0 | C_PM023] =
|
|
cl_lookup[C_PF1 | C_PM0123] = cl_lookup[C_PF1 | C_PM123] = cl_lookup[C_PF1 | C_PM023] = COLOUR_BLACK;
|
|
if (byte & 0xf) {
|
|
cl_lookup[C_PF0 | C_PM25] = cl_lookup[C_PF0];
|
|
cl_lookup[C_PF1 | C_PM25] = cl_lookup[C_PF1];
|
|
cl_lookup[C_PF3 | C_PM25] = cl_lookup[C_PF2 | C_PM25] = cl_lookup[C_PM25] = COLOUR_BLACK;
|
|
}
|
|
else {
|
|
cl_lookup[C_PF0 | C_PM235] = cl_lookup[C_PF0 | C_PM35] = cl_lookup[C_PF0 | C_PM25] =
|
|
cl_lookup[C_PF1 | C_PM235] = cl_lookup[C_PF1 | C_PM35] = cl_lookup[C_PF1 | C_PM25] = cl_lookup[C_PF3];
|
|
cl_lookup[C_PF3 | C_PM25] = cl_lookup[C_PF2 | C_PM25] = cl_lookup[C_PM25] = cl_lookup[C_PF3 | C_PM2];
|
|
cl_lookup[C_PF3 | C_PM35] = cl_lookup[C_PF2 | C_PM35] = cl_lookup[C_PM35] = cl_lookup[C_PF3 | C_PM3];
|
|
cl_lookup[C_PF3 | C_PM235] = cl_lookup[C_PF2 | C_PM235] = cl_lookup[C_PM235] = cl_lookup[C_PF3 | C_PM23];
|
|
}
|
|
}
|
|
pm_lookup_ptr = pm_lookup_table[prior_to_pm_lookup[byte & 0x3f]];
|
|
draw_antic_0_ptr = byte < 0x80 ? draw_antic_0 : byte < 0xc0 ? draw_antic_0_gtia10 : draw_antic_0_gtia11;
|
|
if (byte < 0x40 && (PRIOR >= 0x40 || draw_antic_ptr == draw_antic_f_gtia_bug) && anticmode == 0xf && XPOS >= ((DMACTL & 3) == 3 ? 16 : 18))
|
|
draw_antic_ptr = draw_antic_f_gtia_bug;
|
|
else
|
|
draw_antic_ptr = draw_antic_table[byte >> 6][anticmode];
|
|
}
|
|
|
|
ITCM_CODE void ANTIC_PutByte(UWORD addr, UBYTE byte)
|
|
{
|
|
switch (addr & 0xf) {
|
|
case _DLISTL:
|
|
dlist = (dlist & 0xff00) | byte;
|
|
break;
|
|
case _DLISTH:
|
|
dlist = (dlist & 0x00ff) | (byte << 8);
|
|
break;
|
|
case _DMACTL:
|
|
DMACTL = byte;
|
|
switch (byte & 0x03) {
|
|
case 0x00:
|
|
/* no ANTIC_load when screen off */
|
|
break;
|
|
case 0x01:
|
|
chars_read[NORMAL0] = 32;
|
|
chars_read[NORMAL1] = 16;
|
|
chars_read[NORMAL2] = 8;
|
|
chars_read[SCROLL0] = 40;
|
|
chars_read[SCROLL1] = 20;
|
|
chars_read[SCROLL2] = 10;
|
|
chars_displayed[NORMAL0] = 32;
|
|
chars_displayed[NORMAL1] = 16;
|
|
chars_displayed[NORMAL2] = 8;
|
|
x_min[NORMAL0] = 32;
|
|
x_min[NORMAL1] = 32;
|
|
x_min[NORMAL2] = 32;
|
|
ch_offset[NORMAL0] = 0;
|
|
ch_offset[NORMAL1] = 0;
|
|
ch_offset[NORMAL2] = 0;
|
|
font_cycles[NORMAL0] = load_cycles[NORMAL0] = 32;
|
|
font_cycles[NORMAL1] = load_cycles[NORMAL1] = 16;
|
|
load_cycles[NORMAL2] = 8;
|
|
before_cycles[NORMAL0] = BEFORE_CYCLES;
|
|
before_cycles[SCROLL0] = BEFORE_CYCLES + 8;
|
|
extra_cycles[NORMAL0] = 7 + BEFORE_CYCLES;
|
|
extra_cycles[SCROLL0] = 8 + BEFORE_CYCLES + 8;
|
|
left_border_chars = 8 - LCHOP;
|
|
right_border_start = (ATARI_WIDTH - 64) / 2;
|
|
break;
|
|
case 0x02:
|
|
chars_read[NORMAL0] = 40;
|
|
chars_read[NORMAL1] = 20;
|
|
chars_read[NORMAL2] = 10;
|
|
chars_read[SCROLL0] = 48;
|
|
chars_read[SCROLL1] = 24;
|
|
chars_read[SCROLL2] = 12;
|
|
chars_displayed[NORMAL0] = 40;
|
|
chars_displayed[NORMAL1] = 20;
|
|
chars_displayed[NORMAL2] = 10;
|
|
x_min[NORMAL0] = 16;
|
|
x_min[NORMAL1] = 16;
|
|
x_min[NORMAL2] = 16;
|
|
ch_offset[NORMAL0] = 0;
|
|
ch_offset[NORMAL1] = 0;
|
|
ch_offset[NORMAL2] = 0;
|
|
font_cycles[NORMAL0] = load_cycles[NORMAL0] = 40;
|
|
font_cycles[NORMAL1] = load_cycles[NORMAL1] = 20;
|
|
load_cycles[NORMAL2] = 10;
|
|
before_cycles[NORMAL0] = BEFORE_CYCLES + 8;
|
|
before_cycles[SCROLL0] = BEFORE_CYCLES + 16;
|
|
extra_cycles[NORMAL0] = 8 + BEFORE_CYCLES + 8;
|
|
extra_cycles[SCROLL0] = 7 + BEFORE_CYCLES + 16;
|
|
left_border_chars = 4 - LCHOP;
|
|
right_border_start = (ATARI_WIDTH - 32) / 2;
|
|
break;
|
|
case 0x03:
|
|
chars_read[NORMAL0] = 48;
|
|
chars_read[NORMAL1] = 24;
|
|
chars_read[NORMAL2] = 12;
|
|
chars_read[SCROLL0] = 48;
|
|
chars_read[SCROLL1] = 24;
|
|
chars_read[SCROLL2] = 12;
|
|
chars_displayed[NORMAL0] = 42;
|
|
chars_displayed[NORMAL1] = 22;
|
|
chars_displayed[NORMAL2] = 12;
|
|
x_min[NORMAL0] = 12;
|
|
x_min[NORMAL1] = 8;
|
|
x_min[NORMAL2] = 0;
|
|
ch_offset[NORMAL0] = 3;
|
|
ch_offset[NORMAL1] = 1;
|
|
ch_offset[NORMAL2] = 0;
|
|
font_cycles[NORMAL0] = load_cycles[NORMAL0] = 47;
|
|
font_cycles[NORMAL1] = load_cycles[NORMAL1] = 24;
|
|
load_cycles[NORMAL2] = 12;
|
|
before_cycles[NORMAL0] = BEFORE_CYCLES + 16;
|
|
before_cycles[SCROLL0] = BEFORE_CYCLES + 16;
|
|
extra_cycles[NORMAL0] = 7 + BEFORE_CYCLES + 16;
|
|
extra_cycles[SCROLL0] = 7 + BEFORE_CYCLES + 16;
|
|
left_border_chars = 3 - LCHOP;
|
|
right_border_start = (ATARI_WIDTH - 8) / 2;
|
|
break;
|
|
}
|
|
|
|
missile_dma_enabled = (byte & 0x0c); /* no player dma without missile */
|
|
player_dma_enabled = (byte & 0x08);
|
|
singleline = (byte & 0x10);
|
|
player_flickering = ((player_dma_enabled | player_gra_enabled) == 0x02);
|
|
missile_flickering = ((missile_dma_enabled | missile_gra_enabled) == 0x01);
|
|
missile_or_player_dma_enabled = (missile_dma_enabled | player_dma_enabled);
|
|
|
|
byte = HSCROL; /* update horizontal scroll data */
|
|
/* ******* FALLTHROUGH ******* */
|
|
case _HSCROL:
|
|
HSCROL = byte &= 0x0f;
|
|
if (DMACTL & 3) {
|
|
chars_displayed[SCROLL0] = chars_displayed[NORMAL0];
|
|
ch_offset[SCROLL0] = 4 - (byte >> 2);
|
|
x_min[SCROLL0] = x_min[NORMAL0];
|
|
if (byte & 3) {
|
|
x_min[SCROLL0] += (byte & 3) - 4;
|
|
chars_displayed[SCROLL0]++;
|
|
ch_offset[SCROLL0]--;
|
|
}
|
|
chars_displayed[SCROLL2] = chars_displayed[NORMAL2];
|
|
if ((DMACTL & 3) == 3) { /* wide playfield */
|
|
ch_offset[SCROLL0]--;
|
|
if (byte == 4 || byte == 12)
|
|
chars_displayed[SCROLL1] = 21;
|
|
else
|
|
chars_displayed[SCROLL1] = 22;
|
|
if (byte <= 4) {
|
|
x_min[SCROLL1] = byte + 8;
|
|
ch_offset[SCROLL1] = 1;
|
|
}
|
|
else if (byte <= 12) {
|
|
x_min[SCROLL1] = byte;
|
|
ch_offset[SCROLL1] = 0;
|
|
}
|
|
else {
|
|
x_min[SCROLL1] = byte - 8;
|
|
ch_offset[SCROLL1] = -1;
|
|
}
|
|
/* technically, the part below is wrong */
|
|
/* scrolling in mode 8,9 with HSCROL=13,14,15 */
|
|
/* will set x_min=13,14,15 > 4*LCHOP = 12 */
|
|
/* so that nothing is drawn on the far left side */
|
|
/* of the screen. We could fix this, but only */
|
|
/* by setting x_min to be negative. */
|
|
x_min[SCROLL2] = byte;
|
|
ch_offset[SCROLL2] = 0;
|
|
}
|
|
else {
|
|
chars_displayed[SCROLL1] = chars_displayed[NORMAL1];
|
|
ch_offset[SCROLL1] = 2 - (byte >> 3);
|
|
x_min[SCROLL1] = x_min[NORMAL0];
|
|
if (byte) {
|
|
if (byte & 7) {
|
|
x_min[SCROLL1] += (byte & 7) - 8;
|
|
chars_displayed[SCROLL1]++;
|
|
ch_offset[SCROLL1]--;
|
|
}
|
|
x_min[SCROLL2] = x_min[NORMAL2] + byte - 16;
|
|
chars_displayed[SCROLL2]++;
|
|
ch_offset[SCROLL2] = 0;
|
|
}
|
|
else {
|
|
x_min[SCROLL2] = x_min[NORMAL2];
|
|
ch_offset[SCROLL2] = 1;
|
|
}
|
|
}
|
|
|
|
if (DMACTL & 2) { /* normal & wide playfield */
|
|
load_cycles[SCROLL0] = 47 - (byte >> 2);
|
|
font_cycles[SCROLL0] = (47 * 4 + 1 - byte) >> 2;
|
|
load_cycles[SCROLL1] = (24 * 8 + 3 - byte) >> 3;
|
|
font_cycles[SCROLL1] = (24 * 8 + 1 - byte) >> 3;
|
|
load_cycles[SCROLL2] = byte < 0xc ? 12 : 11;
|
|
}
|
|
else { /* narrow playfield */
|
|
font_cycles[SCROLL0] = load_cycles[SCROLL0] = 40;
|
|
font_cycles[SCROLL1] = load_cycles[SCROLL1] = 20;
|
|
load_cycles[SCROLL2] = 16;
|
|
}
|
|
}
|
|
break;
|
|
case _VSCROL:
|
|
VSCROL = byte & 0x0f;
|
|
if (vscrol_off) {
|
|
lastline = VSCROL;
|
|
if (XPOS < VSCOF_C)
|
|
need_dl = dctr == lastline;
|
|
}
|
|
break;
|
|
case _PMBASE:
|
|
PMBASE = byte;
|
|
pmbase_d = (byte & 0xfc) << 8;
|
|
pmbase_s = pmbase_d & 0xf8ff;
|
|
break;
|
|
case _CHACTL:
|
|
invert_mask = byte & 2 ? 0x80 : 0;
|
|
blank_mask = byte & 1 ? 0xe0 : 0x60;
|
|
if ((CHACTL ^ byte) & 4) {
|
|
chbase_20 ^= 7;
|
|
}
|
|
CHACTL = byte;
|
|
break;
|
|
case _CHBASE:
|
|
CHBASE = byte;
|
|
chbase_20 = (byte & 0xfe) << 8;
|
|
if (CHACTL & 4)
|
|
chbase_20 ^= 7;
|
|
break;
|
|
|
|
case _WSYNC:
|
|
if (xpos <= WSYNC_C && xpos_limit >= WSYNC_C)
|
|
xpos = WSYNC_C;
|
|
else {
|
|
wsync_halt = TRUE;
|
|
xpos = xpos_limit;
|
|
}
|
|
break;
|
|
case _NMIEN:
|
|
NMIEN = byte;
|
|
break;
|
|
case _NMIRES:
|
|
NMIST = 0x1f;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|