📄 avgdvg.c
字号:
/*
* avgdvg.c: Atari DVG and AVG simulators
*
* Copyright 1991, 1992, 1996 Eric Smith
*
* Modified for the MAME project 1997 by
* Brad Oliver, Bernd Wiebelt, Aaron Giles, Andrew Caldwell
*
* 971108 Disabled vector timing routines, introduced an ugly (but fast!)
* busy flag hack instead. BW
* 980202 New anti aliasing code by Andrew Caldwell (.ac)
* 980206 New (cleaner) busy flag handling.
* Moved LBO's buffered point into generic vector code. BW
* 980212 Introduced timing code based on Aaron timer routines. BW
* 980318 Better color handling, Bzone and MHavoc clipping. BW
*
* Battlezone uses a red overlay for the top of the screen and a green one
* for the rest. There is a circuit to clip color 0 lines extending to the
* red zone. This is emulated now. Thanks to Neil Bradley for the info. BW
*
* Frame and interrupt rates (Neil Bradley) BW
* ~60 fps/4.0ms: Asteroid, Asteroid Deluxe
* ~40 fps/4.0ms: Lunar Lander
* ~40 fps/4.1ms: Battle Zone
* ~45 fps/5.4ms: Space Duel, Red Baron
* ~30 fps/5.4ms: StarWars
*
* Games with self adjusting framerate
*
* 4.1ms: Black Widow, Gravitar
* 4.1ms: Tempest
* Major Havoc
* Quantum
*
* TODO: accurate vector timing (need timing diagramm)
*/
#include "driver.h"
#include "avgdvg.h"
#include "vector.h"
#define VEC_SHIFT 16 /* fixed for the moment */
#define BRIGHTNESS 12 /* for maximum brightness, use 16! */
/* the screen is red above this Y coordinate */
#define BZONE_TOP 0x0050
#define BZONE_CLIP \
vector_add_clip (xmin<<VEC_SHIFT, BZONE_TOP<<VEC_SHIFT, \
xmax<<VEC_SHIFT, ymax<<VEC_SHIFT)
#define BZONE_NOCLIP \
vector_add_clip (xmin<<VEC_SHIFT, ymin <<VEC_SHIFT, \
xmax<<VEC_SHIFT, ymax<<VEC_SHIFT)
#define MHAVOC_YWINDOW 0x0048
#define MHAVOC_CLIP \
vector_add_clip (xmin<<VEC_SHIFT, MHAVOC_YWINDOW<<VEC_SHIFT, \
xmax<<VEC_SHIFT, ymax<<VEC_SHIFT)
#define MHAVOC_NOCLIP \
vector_add_clip (xmin<<VEC_SHIFT, ymin <<VEC_SHIFT, \
xmax<<VEC_SHIFT, ymax<<VEC_SHIFT)
static int vectorEngine = USE_DVG;
static int flipword = 0; /* little/big endian issues */
static int busy = 0; /* vector engine busy? */
static int colorram[16]; /* colorram entries */
/* These hold the X/Y coordinates the vector engine uses */
static int width; int height;
static int xcenter; int ycenter;
static int xmin; int xmax;
static int ymin; int ymax;
int vector_updates; /* avgdvg_go()'s per Mame frame, should be 1 */
static int vg_step = 0; /* single step the vector generator */
static int total_length; /* length of all lines drawn in a frame */
/* Use overlay if present MLR OCT0598 */
/*static struct artwork *backdrop = NULL;*/
/*static struct artwork *overlay = NULL;*/
#define MAXSTACK 8 /* Tempest needs more than 4 BW 210797 */
/* AVG commands */
#define VCTR 0
#define HALT 1
#define SVEC 2
#define STAT 3
#define CNTR 4
#define JSRL 5
#define RTSL 6
#define JMPL 7
#define SCAL 8
/* DVG commands */
#define DVCTR 0x01
#define DLABS 0x0a
#define DHALT 0x0b
#define DJSRL 0x0c
#define DRTSL 0x0d
#define DJMPL 0x0e
#define DSVEC 0x0f
#define twos_comp_val(num,bits) ((num&(1<<(bits-1)))?(num|~((1<<bits)-1)):(num&((1<<bits)-1)))
char *avg_mnem[] = { "vctr", "halt", "svec", "stat", "cntr",
"jsrl", "rtsl", "jmpl", "scal" };
char *dvg_mnem[] = { "????", "vct1", "vct2", "vct3",
"vct4", "vct5", "vct6", "vct7",
"vct8", "vct9", "labs", "halt",
"jsrl", "rtsl", "jmpl", "svec" };
/* ASG 971210 -- added banks and modified the read macros to use them */
#define BANK_BITS 13
#define BANK_SIZE (1<<BANK_BITS)
#define NUM_BANKS (0x4000/BANK_SIZE)
#define VECTORRAM(offset) (vectorbank[(offset)>>BANK_BITS][(offset)&(BANK_SIZE-1)])
static unsigned char *vectorbank[NUM_BANKS];
#define map_addr(n) (((n)<<1))
#define memrdwd(offset) (VECTORRAM(offset) | (VECTORRAM(offset+1)<<8))
/* The AVG used by Star Wars reads the bytes in the opposite order */
#define memrdwd_flip(offset) (VECTORRAM(offset+1) | (VECTORRAM(offset)<<8))
#define max(x,y) (((x)>(y))?(x):(y))
INLINE void vector_timer (int deltax, int deltay)
{
deltax = abs (deltax);
deltay = abs (deltay);
total_length += max (deltax, deltay) >> VEC_SHIFT;
}
INLINE void dvg_vector_timer (int scale)
{
total_length += scale;
}
static void dvg_generate_vector_list(void)
{
int pc;
int sp;
int stack [MAXSTACK];
int scale;
int statz;
int currentx, currenty;
int done = 0;
int firstwd;
int secondwd = 0; /* Initialize to tease the compiler */
int opcode;
int x, y;
int z, temp;
int a;
int deltax, deltay;
vector_clear_list();
pc = 0;
sp = 0;
scale = 0;
statz = 0;
currentx = 0;
currenty = 0;
while (!done)
{
firstwd = memrdwd (map_addr (pc));
opcode = firstwd >> 12;
pc++;
if ((opcode >= 0 /* DVCTR */) && (opcode <= DLABS))
{
secondwd = memrdwd (map_addr (pc));
pc++;
}
switch (opcode)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
y = firstwd & 0x03ff;
if (firstwd & 0x400)
y=-y;
x = secondwd & 0x3ff;
if (secondwd & 0x400)
x=-x;
z = secondwd >> 12;
temp = ((scale + opcode) & 0x0f);
if (temp > 9)
temp = -1;
deltax = (x << VEC_SHIFT) >> (9-temp); /* ASG 080497 */
deltay = (y << VEC_SHIFT) >> (9-temp); /* ASG 080497 */
currentx += deltax;
currenty -= deltay;
dvg_vector_timer(temp);
/* ASG 080497, .ac JAN2498 - V.V */
if (translucency)
z = z * BRIGHTNESS;
else
if (z) z = (z << 4) | 0x0f;
vector_add_point (currentx, currenty, colorram[1], z);
break;
case DLABS:
x = twos_comp_val (secondwd, 12);
y = twos_comp_val (firstwd, 12);
scale = (secondwd >> 12);
currentx = ((x-xmin) << VEC_SHIFT); /* ASG 080497 */
currenty = ((ymax-y) << VEC_SHIFT); /* ASG 080497 */
break;
case DHALT:
done = 1;
break;
case DJSRL:
a = firstwd & 0x0fff;
stack [sp] = pc;
if (sp == (MAXSTACK - 1))
{
done = 1;
sp = 0;
}
else
sp++;
pc = a;
break;
case DRTSL:
if (sp == 0)
{
done = 1;
sp = MAXSTACK - 1;
}
else
sp--;
pc = stack [sp];
break;
case DJMPL:
a = firstwd & 0x0fff;
pc = a;
break;
case DSVEC:
y = firstwd & 0x0300;
if (firstwd & 0x0400)
y = -y;
x = (firstwd & 0x03) << 8;
if (firstwd & 0x04)
x = -x;
z = (firstwd >> 4) & 0x0f;
temp = 2 + ((firstwd >> 2) & 0x02) + ((firstwd >>11) & 0x01);
temp = ((scale + temp) & 0x0f);
if (temp > 9)
temp = -1;
deltax = (x << VEC_SHIFT) >> (9-temp); /* ASG 080497 */
deltay = (y << VEC_SHIFT) >> (9-temp); /* ASG 080497 */
currentx += deltax;
currenty -= deltay;
dvg_vector_timer(temp);
/* ASG 080497, .ac JAN2498 */
if (translucency)
z = z * BRIGHTNESS;
else
if (z) z = (z << 4) | 0x0f;
vector_add_point (currentx, currenty, colorram[1], z);
break;
default:
done = 1;
}
}
}
/*
Atari Analog Vector Generator Instruction Set
Compiled from Atari schematics and specifications
Eric Smith 7/2/92
---------------------------------------------
NOTE: The vector generator is little-endian. The instructions are 16 bit
words, which need to be stored with the least significant byte in the
lower (even) address. They are shown here with the MSB on the left.
The stack allows four levels of subroutine calls in the TTL version, but only
three levels in the gate array version.
inst bit pattern description
---- ------------------- -------------------
VCTR 000- yyyy yyyy yyyy normal vector
zzz- xxxx xxxx xxxx
HALT 001- ---- ---- ---- halt - does CNTR also on newer hardware
SVEC 010y yyyy zzzx xxxx short vector - don't use zero length
STAT 0110 ---- zzzz cccc status
SCAL 0111 -bbb llll llll scaling
CNTR 100- ---- dddd dddd center
JSRL 101a aaaa aaaa aaaa jump to subroutine
RTSL 110- ---- ---- ---- return
JMPL 111a aaaa aaaa aaaa jump
- unused bits
x, y relative x and y coordinates in two's complement (5 or 13 bit,
5 bit quantities are scaled by 2, so x=1 is really a length 2 vector.
z intensity, 0 = blank, 1 means use z from STAT instruction, 2-7 are
doubled for actual range of 4-14
c color
b binary scaling, multiplies all lengths by 2**(1-b), 0 is double size,
1 is normal, 2 is half, 3 is 1/4, etc.
l linear scaling, multiplies all lengths by 1-l/256, don't exceed $80
d delay time, use $40
a address (word address relative to base of vector memory)
Notes:
Quantum:
the VCTR instruction has a four bit Z field, that is not
doubled. The value 2 means use Z from STAT instruction.
the SVEC instruction can't be used
Major Havoc:
SCAL bit 11 is used for setting a Y axis window.
STAT bit 11 is used to enable "sparkle" color.
STAT bit 10 inverts the X axis of vectors.
STAT bits 9 and 8 are the Vector ROM bank select.
Star Wars:
STAT bits 10, 9, and 8 are used directly for R, G, and B.
*/
static void avg_generate_vector_list (void)
{
int pc;
int sp;
int stack [MAXSTACK];
int scale;
int statz = 0;
int sparkle = 0;
int xflip = 0;
int color = 0;
int bz_col = -1; /* Battle Zone color selection */
int ywindow = -1; /* Major Havoc Y-Window */
int currentx, currenty;
int done = 0;
int firstwd, secondwd;
int opcode;
int x, y, z=0, b, l, d, a;
int deltax, deltay;
pc = 0;
sp = 0;
statz = 0;
color = 0;
if (flipword)
{
firstwd = memrdwd_flip (map_addr (pc));
secondwd = memrdwd_flip (map_addr (pc+1));
}
else
{
firstwd = memrdwd (map_addr (pc));
secondwd = memrdwd (map_addr (pc+1));
}
if ((firstwd == 0) && (secondwd == 0))
{
return;
}
/* kludge to bypass Major Havoc's empty frames. BW 980216 */
if (vectorEngine == USE_AVG_MHAVOC && firstwd == 0xafe2)
return;
scale = 0; /* ASG 080497 */
currentx = xcenter; /* ASG 080497 */ /*.ac JAN2498 */
currenty = ycenter; /* ASG 080497 */ /*.ac JAN2498 */
vector_clear_list();
while (!done)
{
#ifdef VG_DEBUG
if (vg_step) getchar();
#endif
if (flipword) firstwd = memrdwd_flip (map_addr (pc));
else firstwd = memrdwd (map_addr (pc));
opcode = firstwd >> 13;
pc++;
if (opcode == VCTR)
{
if (flipword) secondwd = memrdwd_flip (map_addr (pc));
else secondwd = memrdwd (map_addr (pc));
pc++;
}
if ((opcode == STAT) && ((firstwd & 0x1000) != 0))
opcode = SCAL;
switch (opcode)
{
case VCTR:
if (vectorEngine == USE_AVG_QUANTUM)
{
x = twos_comp_val (secondwd, 12);
y = twos_comp_val (firstwd, 12);
}
else
{
/* These work for all other games. */
x = twos_comp_val (secondwd, 13);
y = twos_comp_val (firstwd, 13);
}
z = (secondwd >> 12) & ~0x01;
/* z is the maximum DAC output, and */
/* the 8 bit value from STAT does some */
/* fine tuning. STATs of 128 should give */
/* highest intensity. */
if (vectorEngine == USE_AVG_SWARS)
{
if (translucency)
z = (statz * z) / 12;
else
z = (statz * z) >> 3;
if (z > 0xff)
z = 0xff;
}
else
{
if (z == 2)
z = statz;
if (translucency)
z = z * BRIGHTNESS;
else
if (z) z = (z << 4) | 0x1f;
}
deltax = x * scale;
if (xflip) deltax = -deltax;
deltay = y * scale;
currentx += deltax;
currenty -= deltay;
vector_timer(deltax, deltay);
if (sparkle)
{
color = rand() & 0x07;
}
if ((vectorEngine == USE_AVG_BZONE) && (bz_col != 0))
{
if (currenty < (BZONE_TOP<<16))
color = 4;
else
color = 2;
}
vector_add_point (currentx, currenty, colorram[color], z);
break;
case SVEC:
x = twos_comp_val (firstwd, 5) << 1;
y = twos_comp_val (firstwd >> 8, 5) << 1;
z = ((firstwd >> 4) & 0x0e);
if (vectorEngine == USE_AVG_SWARS)
{
if (translucency)
z = (statz * z) / 12;
else
z = (statz * z) >> 3;
if (z > 0xff) z = 0xff;
}
else
{
if (z == 2)
z = statz;
if (translucency)
z = z * BRIGHTNESS;
else
if (z) z = (z << 4) | 0x1f;
}
deltax = x * scale;
if (xflip) deltax = -deltax;
deltay = y * scale;
currentx += deltax;
currenty -= deltay;
vector_timer(deltax, deltay);
if (sparkle)
{
color = rand() & 0x07;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -