mame/src/emu/video/voodoo.c
Aaron Giles af071893a6 Cleanup of machine.h. Shuffled some fields around, and moved several
to private member variables with accessors:

machine->m_respool     ==> machine->respool()
machine->config        ==> machine->config()
machine->gamedrv       ==> machine->system()
machine->m_regionlist  ==> machine->first_region()
machine->sample_rate   ==> machine->sample_rate()

Also converted internal lists to use simple_list.
2011-03-28 09:10:17 +00:00

5873 lines
208 KiB
C

/***************************************************************************
voodoo.c
3dfx Voodoo Graphics SST-1/2 emulator.
****************************************************************************
Copyright Aaron Giles
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name 'MAME' nor the names of its contributors may be
used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
****************************************************************************
//fix me -- blitz2k dies when starting a game with heavy fog (in DRC)
****************************************************************************
3dfx Voodoo Graphics SST-1/2 emulator
emulator by Aaron Giles
--------------------------
Specs:
Voodoo 1 (SST1):
2,4MB frame buffer RAM
1,2,4MB texture RAM
50MHz clock frequency
clears @ 2 pixels/clock (RGB and depth simultaneously)
renders @ 1 pixel/clock
64 entry PCI FIFO
memory FIFO up to 65536 entries
Voodoo 2:
2,4MB frame buffer RAM
2,4,8,16MB texture RAM
90MHz clock frquency
clears @ 2 pixels/clock (RGB and depth simultaneously)
renders @ 1 pixel/clock
ultrafast clears @ 16 pixels/clock
128 entry PCI FIFO
memory FIFO up to 65536 entries
Voodoo Banshee (h3):
Integrated VGA support
2,4,8MB frame buffer RAM
90MHz clock frquency
clears @ 2 pixels/clock (RGB and depth simultaneously)
renders @ 1 pixel/clock
ultrafast clears @ 32 pixels/clock
Voodoo 3 ("Avenger"/h4):
Integrated VGA support
4,8,16MB frame buffer RAM
143MHz clock frquency
clears @ 2 pixels/clock (RGB and depth simultaneously)
renders @ 1 pixel/clock
ultrafast clears @ 32 pixels/clock
--------------------------
still to be implemented:
* trilinear textures
things to verify:
* floating Z buffer
iterated RGBA = 12.12 [24 bits]
iterated Z = 20.12 [32 bits]
iterated W = 18.32 [48 bits]
>mamepm blitz
Stall PCI for HWM: 1
PCI FIFO Empty Entries LWM: D
LFB -> FIFO: 1
Texture -> FIFO: 1
Memory FIFO: 1
Memory FIFO HWM: 2000
Memory FIFO Write Burst HWM: 36
Memory FIFO LWM for PCI: 5
Memory FIFO row start: 120
Memory FIFO row rollover: 3FF
Video dither subtract: 0
DRAM banking: 1
Triple buffer: 0
Video buffer offset: 60
DRAM banking: 1
>mamepm wg3dh
Stall PCI for HWM: 1
PCI FIFO Empty Entries LWM: D
LFB -> FIFO: 1
Texture -> FIFO: 1
Memory FIFO: 1
Memory FIFO HWM: 2000
Memory FIFO Write Burst HWM: 36
Memory FIFO LWM for PCI: 5
Memory FIFO row start: C0
Memory FIFO row rollover: 3FF
Video dither subtract: 0
DRAM banking: 1
Triple buffer: 0
Video buffer offset: 40
DRAM banking: 1
As a point of reference, the 3D engine uses the following algorithm to calculate the linear memory address as a
function of the video buffer offset (fbiInit2 bits(19:11)), the number of 32x32 tiles in the X dimension (fbiInit1
bits(7:4) and bit(24)), X, and Y:
tilesInX[4:0] = {fbiInit1[24], fbiInit1[7:4], fbiInit6[30]}
rowBase = fbiInit2[19:11]
rowStart = ((Y>>5) * tilesInX) >> 1
if (!(tilesInX & 1))
{
rowOffset = (X>>6);
row[9:0] = rowStart + rowOffset (for color buffer 0)
row[9:0] = rowBase + rowStart + rowOffset (for color buffer 1)
row[9:0] = (rowBase<<1) + rowStart + rowOffset (for depth/alpha buffer when double color buffering[fbiInit5[10:9]=0])
row[9:0] = (rowBase<<1) + rowStart + rowOffset (for color buffer 2 when triple color buffering[fbiInit5[10:9]=1 or 2])
row[9:0] = (rowBase<<1) + rowBase + rowStart + rowOffset (for depth/alpha buffer when triple color buffering[fbiInit5[10:9]=2])
column[8:0] = ((Y % 32) <<4) + ((X % 32)>>1)
ramSelect[1] = ((X&0x20) ? 1 : 0) (for color buffers)
ramSelect[1] = ((X&0x20) ? 0 : 1) (for depth/alpha buffers)
}
else
{
rowOffset = (!(Y&0x20)) ? (X>>6) : ((X>31) ? (((X-32)>>6)+1) : 0)
row[9:0] = rowStart + rowOffset (for color buffer 0)
row[9:0] = rowBase + rowStart + rowOffset (for color buffer 1)
row[9:0] = (rowBase<<1) + rowStart + rowOffset (for depth/alpha buffer when double color buffering[fbiInit5[10:9]=0])
row[9:0] = (rowBase<<1) + rowStart + rowOffset (for color buffer 2 when triple color buffering[fbiInit5[10:9]=1 or 2])
row[9:0] = (rowBase<<1) + rowBase + rowStart + rowOffset (for depth/alpha buffer when triple color buffering[fbiInit5[10:9]=2])
column[8:0] = ((Y % 32) <<4) + ((X % 32)>>1)
ramSelect[1] = (((X&0x20)^(Y&0x20)) ? 1 : 0) (for color buffers)
ramSelect[1] = (((X&0x20)^(Y&0x20)) ? 0 : 1) (for depth/alpha buffers)
}
ramSelect[0] = X % 2
pixelMemoryAddress[21:0] = (row[9:0]<<12) + (column[8:0]<<3) + (ramSelect[1:0]<<1)
bankSelect = pixelMemoryAddress[21]
**************************************************************************/
#ifndef EXPAND_RASTERIZERS
#define EXPAND_RASTERIZERS
#include "emu.h"
#include "profiler.h"
#include "video/poly.h"
#include "video/rgbutil.h"
#include "voodoo.h"
#include "vooddefs.h"
#include "ui.h"
/*************************************
*
* Debugging
*
*************************************/
#define DEBUG_DEPTH (0)
#define DEBUG_LOD (0)
#define LOG_VBLANK_SWAP (0)
#define LOG_FIFO (0)
#define LOG_FIFO_VERBOSE (0)
#define LOG_REGISTERS (0)
#define LOG_WAITS (0)
#define LOG_LFB (0)
#define LOG_TEXTURE_RAM (0)
#define LOG_RASTERIZERS (0)
#define LOG_CMDFIFO (0)
#define LOG_CMDFIFO_VERBOSE (0)
#define MODIFY_PIXEL(VV)
/*************************************
*
* Statics
*
*************************************/
/* fast dither lookup */
static UINT8 dither4_lookup[256*16*2];
static UINT8 dither2_lookup[256*16*2];
/* fast reciprocal+log2 lookup */
UINT32 voodoo_reciplog[(2 << RECIPLOG_LOOKUP_BITS) + 2];
/*************************************
*
* Prototypes
*
*************************************/
static void init_fbi(voodoo_state *v, fbi_state *f, void *memory, int fbmem);
static void init_tmu_shared(tmu_shared_state *s);
static void init_tmu(voodoo_state *v, tmu_state *t, voodoo_reg *reg, void *memory, int tmem);
static void soft_reset(voodoo_state *v);
static void recompute_video_memory(voodoo_state *v);
static void check_stalled_cpu(voodoo_state *v, attotime current_time);
static void flush_fifos(voodoo_state *v, attotime current_time);
static TIMER_CALLBACK( stall_cpu_callback );
static void stall_cpu(voodoo_state *v, int state, attotime current_time);
static TIMER_CALLBACK( vblank_callback );
static INT32 register_w(voodoo_state *v, offs_t offset, UINT32 data);
static INT32 lfb_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask, int forcefront);
static INT32 texture_w(voodoo_state *v, offs_t offset, UINT32 data);
/* command handlers */
static INT32 fastfill(voodoo_state *v);
static INT32 swapbuffer(voodoo_state *v, UINT32 data);
static INT32 triangle(voodoo_state *v);
static INT32 begin_triangle(voodoo_state *v);
static INT32 draw_triangle(voodoo_state *v);
/* triangle helpers */
static INT32 setup_and_draw_triangle(voodoo_state *v);
static INT32 triangle_create_work_item(voodoo_state *v, UINT16 *drawbuf, int texcount);
/* rasterizer management */
static raster_info *add_rasterizer(voodoo_state *v, const raster_info *cinfo);
static raster_info *find_rasterizer(voodoo_state *v, int texcount);
static void dump_rasterizer_stats(voodoo_state *v);
/* generic rasterizers */
static void raster_fastfill(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
static void raster_generic_0tmu(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
static void raster_generic_1tmu(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
static void raster_generic_2tmu(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid);
/*************************************
*
* Specific rasterizers
*
*************************************/
#define RASTERIZER_ENTRY(fbzcp, alpha, fog, fbz, tex0, tex1) \
RASTERIZER(fbzcp##_##alpha##_##fog##_##fbz##_##tex0##_##tex1, (((tex0) == 0xffffffff) ? 0 : ((tex1) == 0xffffffff) ? 1 : 2), fbzcp, fbz, alpha, fog, tex0, tex1)
#include "voodoo.c"
#undef RASTERIZER_ENTRY
/*************************************
*
* Rasterizer table
*
*************************************/
#define RASTERIZER_ENTRY(fbzcp, alpha, fog, fbz, tex0, tex1) \
{ NULL, raster_##fbzcp##_##alpha##_##fog##_##fbz##_##tex0##_##tex1, FALSE, 0, 0, 0, fbzcp, alpha, fog, fbz, tex0, tex1 },
static const raster_info predef_raster_table[] =
{
#include "voodoo.c"
{ 0 }
};
#undef RASTERIZER_ENTRY
/***************************************************************************
INLINE FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
get_safe_token - makes sure that the passed
in device is, in fact, a voodoo device
-------------------------------------------------*/
INLINE voodoo_state *get_safe_token(device_t *device)
{
assert(device != NULL);
assert(device->type() == VOODOO_GRAPHICS);
return (voodoo_state *)downcast<legacy_device_base *>(device)->token();
}
/*************************************
*
* Video update
*
*************************************/
int voodoo_update(device_t *device, bitmap_t *bitmap, const rectangle *cliprect)
{
voodoo_state *v = get_safe_token(device);
int changed = v->fbi.video_changed;
int drawbuf = v->fbi.frontbuf;
int statskey;
int x, y;
/* reset the video changed flag */
v->fbi.video_changed = FALSE;
/* if we are blank, just fill with black */
if (v->type <= VOODOO_2 && FBIINIT1_SOFTWARE_BLANK(v->reg[fbiInit1].u))
{
bitmap_fill(bitmap, cliprect, 0);
return changed;
}
/* if the CLUT is dirty, recompute the pens array */
if (v->fbi.clut_dirty)
{
UINT8 rtable[32], gtable[64], btable[32];
/* Voodoo/Voodoo-2 have an internal 33-entry CLUT */
if (v->type <= VOODOO_2)
{
/* kludge: some of the Midway games write 0 to the last entry when they obviously mean FF */
if ((v->fbi.clut[32] & 0xffffff) == 0 && (v->fbi.clut[31] & 0xffffff) != 0)
v->fbi.clut[32] = 0x20ffffff;
/* compute the R/G/B pens first */
for (x = 0; x < 32; x++)
{
/* treat X as a 5-bit value, scale up to 8 bits, and linear interpolate for red/blue */
y = (x << 3) | (x >> 2);
rtable[x] = (RGB_RED(v->fbi.clut[y >> 3]) * (8 - (y & 7)) + RGB_RED(v->fbi.clut[(y >> 3) + 1]) * (y & 7)) >> 3;
btable[x] = (RGB_BLUE(v->fbi.clut[y >> 3]) * (8 - (y & 7)) + RGB_BLUE(v->fbi.clut[(y >> 3) + 1]) * (y & 7)) >> 3;
/* treat X as a 6-bit value with LSB=0, scale up to 8 bits, and linear interpolate */
y = (x * 2) + 0;
y = (y << 2) | (y >> 4);
gtable[x*2+0] = (RGB_GREEN(v->fbi.clut[y >> 3]) * (8 - (y & 7)) + RGB_GREEN(v->fbi.clut[(y >> 3) + 1]) * (y & 7)) >> 3;
/* treat X as a 6-bit value with LSB=1, scale up to 8 bits, and linear interpolate */
y = (x * 2) + 1;
y = (y << 2) | (y >> 4);
gtable[x*2+1] = (RGB_GREEN(v->fbi.clut[y >> 3]) * (8 - (y & 7)) + RGB_GREEN(v->fbi.clut[(y >> 3) + 1]) * (y & 7)) >> 3;
}
}
/* Banshee and later have a 512-entry CLUT that can be bypassed */
else
{
int which = (v->banshee.io[io_vidProcCfg] >> 13) & 1;
int bypass = (v->banshee.io[io_vidProcCfg] >> 11) & 1;
/* compute R/G/B pens first */
for (x = 0; x < 32; x++)
{
/* treat X as a 5-bit value, scale up to 8 bits */
y = (x << 3) | (x >> 2);
rtable[x] = bypass ? y : RGB_RED(v->fbi.clut[which * 256 + y]);
btable[x] = bypass ? y : RGB_BLUE(v->fbi.clut[which * 256 + y]);
/* treat X as a 6-bit value with LSB=0, scale up to 8 bits */
y = (x * 2) + 0;
y = (y << 2) | (y >> 4);
gtable[x*2+0] = bypass ? y : RGB_GREEN(v->fbi.clut[which * 256 + y]);
/* treat X as a 6-bit value with LSB=1, scale up to 8 bits, and linear interpolate */
y = (x * 2) + 1;
y = (y << 2) | (y >> 4);
gtable[x*2+1] = bypass ? y : RGB_GREEN(v->fbi.clut[which * 256 + y]);
}
}
/* now compute the actual pens array */
for (x = 0; x < 65536; x++)
{
int r = rtable[(x >> 11) & 0x1f];
int g = gtable[(x >> 5) & 0x3f];
int b = btable[x & 0x1f];
v->fbi.pen[x] = MAKE_RGB(r, g, b);
}
/* no longer dirty */
v->fbi.clut_dirty = FALSE;
changed = TRUE;
}
/* debugging! */
if (input_code_pressed(device->machine, KEYCODE_L))
drawbuf = v->fbi.backbuf;
/* copy from the current front buffer */
for (y = cliprect->min_y; y <= cliprect->max_y; y++)
if (y >= v->fbi.yoffs)
{
UINT16 *src = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[drawbuf]) + (y - v->fbi.yoffs) * v->fbi.rowpixels - v->fbi.xoffs;
UINT32 *dst = BITMAP_ADDR32(bitmap, y, 0);
for (x = cliprect->min_x; x <= cliprect->max_x; x++)
dst[x] = v->fbi.pen[src[x]];
}
/* update stats display */
statskey = (input_code_pressed(device->machine, KEYCODE_BACKSLASH) != 0);
if (statskey && statskey != v->stats.lastkey)
v->stats.display = !v->stats.display;
v->stats.lastkey = statskey;
/* display stats */
if (v->stats.display)
popmessage(v->stats.buffer, 0, 0);
/* update render override */
v->stats.render_override = input_code_pressed(device->machine, KEYCODE_ENTER);
if (DEBUG_DEPTH && v->stats.render_override)
{
for (y = cliprect->min_y; y <= cliprect->max_y; y++)
{
UINT16 *src = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs) + (y - v->fbi.yoffs) * v->fbi.rowpixels - v->fbi.xoffs;
UINT32 *dst = BITMAP_ADDR32(bitmap, y, 0);
for (x = cliprect->min_x; x <= cliprect->max_x; x++)
dst[x] = ((src[x] << 8) & 0xff0000) | ((src[x] >> 0) & 0xff00) | ((src[x] >> 8) & 0xff);
}
}
return changed;
}
/*************************************
*
* Chip reset
*
*************************************/
int voodoo_get_type(device_t *device)
{
voodoo_state *v = get_safe_token(device);
return v->type;
}
int voodoo_is_stalled(device_t *device)
{
voodoo_state *v = get_safe_token(device);
return (v->pci.stall_state != NOT_STALLED);
}
void voodoo_set_init_enable(device_t *device, UINT32 newval)
{
voodoo_state *v = get_safe_token(device);
v->pci.init_enable = newval;
if (LOG_REGISTERS)
logerror("VOODOO.%d.REG:initEnable write = %08X\n", v->index, newval);
}
/*************************************
*
* Common initialization
*
*************************************/
static void init_fbi(voodoo_state *v, fbi_state *f, void *memory, int fbmem)
{
int pen;
/* allocate frame buffer RAM and set pointers */
f->ram = (UINT8 *)memory;
f->mask = fbmem - 1;
f->rgboffs[0] = f->rgboffs[1] = f->rgboffs[2] = 0;
f->auxoffs = ~0;
/* default to 0x0 */
f->frontbuf = 0;
f->backbuf = 1;
f->width = 512;
f->height = 384;
/* init the pens */
f->clut_dirty = TRUE;
if (v->type <= VOODOO_2)
{
for (pen = 0; pen < 32; pen++)
v->fbi.clut[pen] = MAKE_ARGB(pen, pal5bit(pen), pal5bit(pen), pal5bit(pen));
v->fbi.clut[32] = MAKE_ARGB(32,0xff,0xff,0xff);
}
else
{
for (pen = 0; pen < 512; pen++)
v->fbi.clut[pen] = MAKE_RGB(pen,pen,pen);
}
/* allocate a VBLANK timer */
f->vblank_timer = v->device->machine->scheduler().timer_alloc(FUNC(vblank_callback), v);
f->vblank = FALSE;
/* initialize the memory FIFO */
f->fifo.base = NULL;
f->fifo.size = f->fifo.in = f->fifo.out = 0;
/* set the fog delta mask */
f->fogdelta_mask = (v->type < VOODOO_2) ? 0xff : 0xfc;
}
static void init_tmu_shared(tmu_shared_state *s)
{
int val;
/* build static 8-bit texel tables */
for (val = 0; val < 256; val++)
{
int r, g, b, a;
/* 8-bit RGB (3-3-2) */
EXTRACT_332_TO_888(val, r, g, b);
s->rgb332[val] = MAKE_ARGB(0xff, r, g, b);
/* 8-bit alpha */
s->alpha8[val] = MAKE_ARGB(val, val, val, val);
/* 8-bit intensity */
s->int8[val] = MAKE_ARGB(0xff, val, val, val);
/* 8-bit alpha, intensity */
a = ((val >> 0) & 0xf0) | ((val >> 4) & 0x0f);
r = ((val << 4) & 0xf0) | ((val << 0) & 0x0f);
s->ai44[val] = MAKE_ARGB(a, r, r, r);
}
/* build static 16-bit texel tables */
for (val = 0; val < 65536; val++)
{
int r, g, b, a;
/* table 10 = 16-bit RGB (5-6-5) */
EXTRACT_565_TO_888(val, r, g, b);
s->rgb565[val] = MAKE_ARGB(0xff, r, g, b);
/* table 11 = 16 ARGB (1-5-5-5) */
EXTRACT_1555_TO_8888(val, a, r, g, b);
s->argb1555[val] = MAKE_ARGB(a, r, g, b);
/* table 12 = 16-bit ARGB (4-4-4-4) */
EXTRACT_4444_TO_8888(val, a, r, g, b);
s->argb4444[val] = MAKE_ARGB(a, r, g, b);
}
}
static void init_tmu(voodoo_state *v, tmu_state *t, voodoo_reg *reg, void *memory, int tmem)
{
/* allocate texture RAM */
t->ram = (UINT8 *)memory;
t->mask = tmem - 1;
t->reg = reg;
t->regdirty = TRUE;
t->bilinear_mask = (v->type >= VOODOO_2) ? 0xff : 0xf0;
/* mark the NCC tables dirty and configure their registers */
t->ncc[0].dirty = t->ncc[1].dirty = TRUE;
t->ncc[0].reg = &t->reg[nccTable+0];
t->ncc[1].reg = &t->reg[nccTable+12];
/* create pointers to all the tables */
t->texel[0] = v->tmushare.rgb332;
t->texel[1] = t->ncc[0].texel;
t->texel[2] = v->tmushare.alpha8;
t->texel[3] = v->tmushare.int8;
t->texel[4] = v->tmushare.ai44;
t->texel[5] = t->palette;
t->texel[6] = (v->type >= VOODOO_2) ? t->palettea : NULL;
t->texel[7] = NULL;
t->texel[8] = v->tmushare.rgb332;
t->texel[9] = t->ncc[0].texel;
t->texel[10] = v->tmushare.rgb565;
t->texel[11] = v->tmushare.argb1555;
t->texel[12] = v->tmushare.argb4444;
t->texel[13] = v->tmushare.int8;
t->texel[14] = t->palette;
t->texel[15] = NULL;
t->lookup = t->texel[0];
/* attach the palette to NCC table 0 */
t->ncc[0].palette = t->palette;
if (v->type >= VOODOO_2)
t->ncc[0].palettea = t->palettea;
/* set up texture address calculations */
if (v->type <= VOODOO_2)
{
t->texaddr_mask = 0x0fffff;
t->texaddr_shift = 3;
}
else
{
t->texaddr_mask = 0xfffff0;
t->texaddr_shift = 0;
}
}
static STATE_POSTLOAD( voodoo_postload )
{
voodoo_state *v = (voodoo_state *)param;
int index, subindex;
v->fbi.clut_dirty = TRUE;
for (index = 0; index < ARRAY_LENGTH(v->tmu); index++)
{
v->tmu[index].regdirty = TRUE;
for (subindex = 0; subindex < ARRAY_LENGTH(v->tmu[index].ncc); subindex++)
v->tmu[index].ncc[subindex].dirty = TRUE;
}
/* recompute video memory to get the FBI FIFO base recomputed */
if (v->type <= VOODOO_2)
recompute_video_memory(v);
}
static void init_save_state(device_t *device)
{
voodoo_state *v = get_safe_token(device);
int index, subindex;
device->machine->state().register_postload(voodoo_postload, v);
/* register states: core */
device->save_item(NAME(v->extra_cycles));
device->save_pointer(NAME(&v->reg[0].u), ARRAY_LENGTH(v->reg));
device->save_item(NAME(v->alt_regmap));
/* register states: pci */
device->save_item(NAME(v->pci.fifo.in));
device->save_item(NAME(v->pci.fifo.out));
device->save_item(NAME(v->pci.init_enable));
device->save_item(NAME(v->pci.stall_state));
device->save_item(NAME(v->pci.op_pending));
device->save_item(NAME(v->pci.op_end_time));
device->save_item(NAME(v->pci.fifo_mem));
/* register states: dac */
device->save_item(NAME(v->dac.reg));
device->save_item(NAME(v->dac.read_result));
/* register states: fbi */
device->save_pointer(NAME(v->fbi.ram), v->fbi.mask + 1);
device->save_item(NAME(v->fbi.rgboffs));
device->save_item(NAME(v->fbi.auxoffs));
device->save_item(NAME(v->fbi.frontbuf));
device->save_item(NAME(v->fbi.backbuf));
device->save_item(NAME(v->fbi.swaps_pending));
device->save_item(NAME(v->fbi.video_changed));
device->save_item(NAME(v->fbi.yorigin));
device->save_item(NAME(v->fbi.lfb_base));
device->save_item(NAME(v->fbi.lfb_stride));
device->save_item(NAME(v->fbi.width));
device->save_item(NAME(v->fbi.height));
device->save_item(NAME(v->fbi.xoffs));
device->save_item(NAME(v->fbi.yoffs));
device->save_item(NAME(v->fbi.vsyncscan));
device->save_item(NAME(v->fbi.rowpixels));
device->save_item(NAME(v->fbi.vblank));
device->save_item(NAME(v->fbi.vblank_count));
device->save_item(NAME(v->fbi.vblank_swap_pending));
device->save_item(NAME(v->fbi.vblank_swap));
device->save_item(NAME(v->fbi.vblank_dont_swap));
device->save_item(NAME(v->fbi.cheating_allowed));
device->save_item(NAME(v->fbi.sign));
device->save_item(NAME(v->fbi.ax));
device->save_item(NAME(v->fbi.ay));
device->save_item(NAME(v->fbi.bx));
device->save_item(NAME(v->fbi.by));
device->save_item(NAME(v->fbi.cx));
device->save_item(NAME(v->fbi.cy));
device->save_item(NAME(v->fbi.startr));
device->save_item(NAME(v->fbi.startg));
device->save_item(NAME(v->fbi.startb));
device->save_item(NAME(v->fbi.starta));
device->save_item(NAME(v->fbi.startz));
device->save_item(NAME(v->fbi.startw));
device->save_item(NAME(v->fbi.drdx));
device->save_item(NAME(v->fbi.dgdx));
device->save_item(NAME(v->fbi.dbdx));
device->save_item(NAME(v->fbi.dadx));
device->save_item(NAME(v->fbi.dzdx));
device->save_item(NAME(v->fbi.dwdx));
device->save_item(NAME(v->fbi.drdy));
device->save_item(NAME(v->fbi.dgdy));
device->save_item(NAME(v->fbi.dbdy));
device->save_item(NAME(v->fbi.dady));
device->save_item(NAME(v->fbi.dzdy));
device->save_item(NAME(v->fbi.dwdy));
device->save_item(NAME(v->fbi.lfb_stats.pixels_in));
device->save_item(NAME(v->fbi.lfb_stats.pixels_out));
device->save_item(NAME(v->fbi.lfb_stats.chroma_fail));
device->save_item(NAME(v->fbi.lfb_stats.zfunc_fail));
device->save_item(NAME(v->fbi.lfb_stats.afunc_fail));
device->save_item(NAME(v->fbi.lfb_stats.clip_fail));
device->save_item(NAME(v->fbi.lfb_stats.stipple_count));
device->save_item(NAME(v->fbi.sverts));
for (index = 0; index < ARRAY_LENGTH(v->fbi.svert); index++)
{
device->save_item(NAME(v->fbi.svert[index].x), index);
device->save_item(NAME(v->fbi.svert[index].y), index);
device->save_item(NAME(v->fbi.svert[index].a), index);
device->save_item(NAME(v->fbi.svert[index].r), index);
device->save_item(NAME(v->fbi.svert[index].g), index);
device->save_item(NAME(v->fbi.svert[index].b), index);
device->save_item(NAME(v->fbi.svert[index].z), index);
device->save_item(NAME(v->fbi.svert[index].wb), index);
device->save_item(NAME(v->fbi.svert[index].w0), index);
device->save_item(NAME(v->fbi.svert[index].s0), index);
device->save_item(NAME(v->fbi.svert[index].t0), index);
device->save_item(NAME(v->fbi.svert[index].w1), index);
device->save_item(NAME(v->fbi.svert[index].s1), index);
device->save_item(NAME(v->fbi.svert[index].t1), index);
}
device->save_item(NAME(v->fbi.fifo.size));
device->save_item(NAME(v->fbi.fifo.in));
device->save_item(NAME(v->fbi.fifo.out));
for (index = 0; index < ARRAY_LENGTH(v->fbi.cmdfifo); index++)
{
device->save_item(NAME(v->fbi.cmdfifo[index].enable), index);
device->save_item(NAME(v->fbi.cmdfifo[index].count_holes), index);
device->save_item(NAME(v->fbi.cmdfifo[index].base), index);
device->save_item(NAME(v->fbi.cmdfifo[index].end), index);
device->save_item(NAME(v->fbi.cmdfifo[index].rdptr), index);
device->save_item(NAME(v->fbi.cmdfifo[index].amin), index);
device->save_item(NAME(v->fbi.cmdfifo[index].amax), index);
device->save_item(NAME(v->fbi.cmdfifo[index].depth), index);
device->save_item(NAME(v->fbi.cmdfifo[index].holes), index);
}
device->save_item(NAME(v->fbi.fogblend));
device->save_item(NAME(v->fbi.fogdelta));
device->save_item(NAME(v->fbi.clut));
/* register states: tmu */
for (index = 0; index < ARRAY_LENGTH(v->tmu); index++)
{
tmu_state *tmu = &v->tmu[index];
if (tmu->ram == NULL)
continue;
if (tmu->ram != v->fbi.ram)
device->save_pointer(NAME(tmu->ram), tmu->mask + 1, index);
device->save_item(NAME(tmu->starts), index);
device->save_item(NAME(tmu->startt), index);
device->save_item(NAME(tmu->startw), index);
device->save_item(NAME(tmu->dsdx), index);
device->save_item(NAME(tmu->dtdx), index);
device->save_item(NAME(tmu->dwdx), index);
device->save_item(NAME(tmu->dsdy), index);
device->save_item(NAME(tmu->dtdy), index);
device->save_item(NAME(tmu->dwdy), index);
for (subindex = 0; subindex < ARRAY_LENGTH(tmu->ncc); subindex++)
{
device->save_item(NAME(tmu->ncc[subindex].ir), index * ARRAY_LENGTH(tmu->ncc) + subindex);
device->save_item(NAME(tmu->ncc[subindex].ig), index * ARRAY_LENGTH(tmu->ncc) + subindex);
device->save_item(NAME(tmu->ncc[subindex].ib), index * ARRAY_LENGTH(tmu->ncc) + subindex);
device->save_item(NAME(tmu->ncc[subindex].qr), index * ARRAY_LENGTH(tmu->ncc) + subindex);
device->save_item(NAME(tmu->ncc[subindex].qg), index * ARRAY_LENGTH(tmu->ncc) + subindex);
device->save_item(NAME(tmu->ncc[subindex].qb), index * ARRAY_LENGTH(tmu->ncc) + subindex);
device->save_item(NAME(tmu->ncc[subindex].y), index * ARRAY_LENGTH(tmu->ncc) + subindex);
}
}
/* register states: banshee */
if (v->type >= VOODOO_BANSHEE)
{
device->save_item(NAME(v->banshee.io));
device->save_item(NAME(v->banshee.agp));
device->save_item(NAME(v->banshee.vga));
device->save_item(NAME(v->banshee.crtc));
device->save_item(NAME(v->banshee.seq));
device->save_item(NAME(v->banshee.gc));
device->save_item(NAME(v->banshee.att));
device->save_item(NAME(v->banshee.attff));
}
}
/*************************************
*
* Statistics management
*
*************************************/
static void accumulate_statistics(voodoo_state *v, const stats_block *stats)
{
/* apply internal voodoo statistics */
v->reg[fbiPixelsIn].u += stats->pixels_in;
v->reg[fbiPixelsOut].u += stats->pixels_out;
v->reg[fbiChromaFail].u += stats->chroma_fail;
v->reg[fbiZfuncFail].u += stats->zfunc_fail;
v->reg[fbiAfuncFail].u += stats->afunc_fail;
/* apply emulation statistics */
v->stats.total_pixels_in += stats->pixels_in;
v->stats.total_pixels_out += stats->pixels_out;
v->stats.total_chroma_fail += stats->chroma_fail;
v->stats.total_zfunc_fail += stats->zfunc_fail;
v->stats.total_afunc_fail += stats->afunc_fail;
v->stats.total_clipped += stats->clip_fail;
v->stats.total_stippled += stats->stipple_count;
}
static void update_statistics(voodoo_state *v, int accumulate)
{
int threadnum;
/* accumulate/reset statistics from all units */
for (threadnum = 0; threadnum < WORK_MAX_THREADS; threadnum++)
{
if (accumulate)
accumulate_statistics(v, &v->thread_stats[threadnum]);
memset(&v->thread_stats[threadnum], 0, sizeof(v->thread_stats[threadnum]));
}
/* accumulate/reset statistics from the LFB */
if (accumulate)
accumulate_statistics(v, &v->fbi.lfb_stats);
memset(&v->fbi.lfb_stats, 0, sizeof(v->fbi.lfb_stats));
}
/*************************************
*
* VBLANK management
*
*************************************/
static void swap_buffers(voodoo_state *v)
{
int count;
if (LOG_VBLANK_SWAP) logerror("--- swap_buffers @ %d\n", v->screen->vpos());
/* force a partial update */
v->screen->update_partial(v->screen->vpos());
v->fbi.video_changed = TRUE;
/* keep a history of swap intervals */
count = v->fbi.vblank_count;
if (count > 15)
count = 15;
v->reg[fbiSwapHistory].u = (v->reg[fbiSwapHistory].u << 4) | count;
/* rotate the buffers */
if (v->type <= VOODOO_2)
{
if (v->type < VOODOO_2 || !v->fbi.vblank_dont_swap)
{
if (v->fbi.rgboffs[2] == ~0)
{
v->fbi.frontbuf = 1 - v->fbi.frontbuf;
v->fbi.backbuf = 1 - v->fbi.frontbuf;
}
else
{
v->fbi.frontbuf = (v->fbi.frontbuf + 1) % 3;
v->fbi.backbuf = (v->fbi.frontbuf + 1) % 3;
}
}
}
else
v->fbi.rgboffs[0] = v->reg[leftOverlayBuf].u & v->fbi.mask & ~0x0f;
/* decrement the pending count and reset our state */
if (v->fbi.swaps_pending)
v->fbi.swaps_pending--;
v->fbi.vblank_count = 0;
v->fbi.vblank_swap_pending = FALSE;
/* reset the last_op_time to now and start processing the next command */
if (v->pci.op_pending)
{
v->pci.op_end_time = v->device->machine->time();
flush_fifos(v, v->pci.op_end_time);
}
/* we may be able to unstall now */
if (v->pci.stall_state != NOT_STALLED)
check_stalled_cpu(v, v->device->machine->time());
/* periodically log rasterizer info */
v->stats.swaps++;
if (LOG_RASTERIZERS && v->stats.swaps % 100 == 0)
dump_rasterizer_stats(v);
/* update the statistics (debug) */
if (v->stats.display)
{
const rectangle &visible_area = v->screen->visible_area();
int screen_area = (visible_area.max_x - visible_area.min_x + 1) * (visible_area.max_y - visible_area.min_y + 1);
char *statsptr = v->stats.buffer;
int pixelcount;
int i;
update_statistics(v, TRUE);
pixelcount = v->stats.total_pixels_out;
statsptr += sprintf(statsptr, "Swap:%6d\n", v->stats.swaps);
statsptr += sprintf(statsptr, "Hist:%08X\n", v->reg[fbiSwapHistory].u);
statsptr += sprintf(statsptr, "Stal:%6d\n", v->stats.stalls);
statsptr += sprintf(statsptr, "Rend:%6d%%\n", pixelcount * 100 / screen_area);
statsptr += sprintf(statsptr, "Poly:%6d\n", v->stats.total_triangles);
statsptr += sprintf(statsptr, "PxIn:%6d\n", v->stats.total_pixels_in);
statsptr += sprintf(statsptr, "POut:%6d\n", v->stats.total_pixels_out);
statsptr += sprintf(statsptr, "Clip:%6d\n", v->stats.total_clipped);
statsptr += sprintf(statsptr, "Stip:%6d\n", v->stats.total_stippled);
statsptr += sprintf(statsptr, "Chro:%6d\n", v->stats.total_chroma_fail);
statsptr += sprintf(statsptr, "ZFun:%6d\n", v->stats.total_zfunc_fail);
statsptr += sprintf(statsptr, "AFun:%6d\n", v->stats.total_afunc_fail);
statsptr += sprintf(statsptr, "RegW:%6d\n", v->stats.reg_writes);
statsptr += sprintf(statsptr, "RegR:%6d\n", v->stats.reg_reads);
statsptr += sprintf(statsptr, "LFBW:%6d\n", v->stats.lfb_writes);
statsptr += sprintf(statsptr, "LFBR:%6d\n", v->stats.lfb_reads);
statsptr += sprintf(statsptr, "TexW:%6d\n", v->stats.tex_writes);
statsptr += sprintf(statsptr, "TexM:");
for (i = 0; i < 16; i++)
if (v->stats.texture_mode[i])
*statsptr++ = "0123456789ABCDEF"[i];
*statsptr = 0;
}
/* update statistics */
v->stats.stalls = 0;
v->stats.total_triangles = 0;
v->stats.total_pixels_in = 0;
v->stats.total_pixels_out = 0;
v->stats.total_chroma_fail = 0;
v->stats.total_zfunc_fail = 0;
v->stats.total_afunc_fail = 0;
v->stats.total_clipped = 0;
v->stats.total_stippled = 0;
v->stats.reg_writes = 0;
v->stats.reg_reads = 0;
v->stats.lfb_writes = 0;
v->stats.lfb_reads = 0;
v->stats.tex_writes = 0;
memset(v->stats.texture_mode, 0, sizeof(v->stats.texture_mode));
}
static void adjust_vblank_timer(voodoo_state *v)
{
attotime vblank_period = v->screen->time_until_pos(v->fbi.vsyncscan);
/* if zero, adjust to next frame, otherwise we may get stuck in an infinite loop */
if (vblank_period == attotime::zero)
vblank_period = v->screen->frame_period();
v->fbi.vblank_timer->adjust(vblank_period);
}
static TIMER_CALLBACK( vblank_off_callback )
{
voodoo_state *v = (voodoo_state *)ptr;
if (LOG_VBLANK_SWAP) logerror("--- vblank end\n");
/* set internal state and call the client */
v->fbi.vblank = FALSE;
if (v->fbi.vblank_client != NULL)
(*v->fbi.vblank_client)(v->device, FALSE);
/* go to the end of the next frame */
adjust_vblank_timer(v);
}
static TIMER_CALLBACK( vblank_callback )
{
voodoo_state *v = (voodoo_state *)ptr;
if (LOG_VBLANK_SWAP) logerror("--- vblank start\n");
/* flush the pipes */
if (v->pci.op_pending)
{
if (LOG_VBLANK_SWAP) logerror("---- vblank flush begin\n");
flush_fifos(v, machine->time());
if (LOG_VBLANK_SWAP) logerror("---- vblank flush end\n");
}
/* increment the count */
v->fbi.vblank_count++;
if (v->fbi.vblank_count > 250)
v->fbi.vblank_count = 250;
if (LOG_VBLANK_SWAP) logerror("---- vblank count = %d", v->fbi.vblank_count);
if (v->fbi.vblank_swap_pending)
if (LOG_VBLANK_SWAP) logerror(" (target=%d)", v->fbi.vblank_swap);
if (LOG_VBLANK_SWAP) logerror("\n");
/* if we're past the swap count, do the swap */
if (v->fbi.vblank_swap_pending && v->fbi.vblank_count >= v->fbi.vblank_swap)
swap_buffers(v);
/* set a timer for the next off state */
machine->scheduler().timer_set(v->screen->time_until_pos(0), FUNC(vblank_off_callback), 0, v);
/* set internal state and call the client */
v->fbi.vblank = TRUE;
if (v->fbi.vblank_client != NULL)
(*v->fbi.vblank_client)(v->device, TRUE);
}
/*************************************
*
* Chip reset
*
*************************************/
static void reset_counters(voodoo_state *v)
{
update_statistics(v, FALSE);
v->reg[fbiPixelsIn].u = 0;
v->reg[fbiChromaFail].u = 0;
v->reg[fbiZfuncFail].u = 0;
v->reg[fbiAfuncFail].u = 0;
v->reg[fbiPixelsOut].u = 0;
}
static void soft_reset(voodoo_state *v)
{
reset_counters(v);
v->reg[fbiTrianglesOut].u = 0;
fifo_reset(&v->fbi.fifo);
fifo_reset(&v->pci.fifo);
}
/*************************************
*
* Recompute video memory layout
*
*************************************/
static void recompute_video_memory(voodoo_state *v)
{
UINT32 buffer_pages = FBIINIT2_VIDEO_BUFFER_OFFSET(v->reg[fbiInit2].u);
UINT32 fifo_start_page = FBIINIT4_MEMORY_FIFO_START_ROW(v->reg[fbiInit4].u);
UINT32 fifo_last_page = FBIINIT4_MEMORY_FIFO_STOP_ROW(v->reg[fbiInit4].u);
UINT32 memory_config;
int buf;
/* memory config is determined differently between V1 and V2 */
memory_config = FBIINIT2_ENABLE_TRIPLE_BUF(v->reg[fbiInit2].u);
if (v->type == VOODOO_2 && memory_config == 0)
memory_config = FBIINIT5_BUFFER_ALLOCATION(v->reg[fbiInit5].u);
/* tiles are 64x16/32; x_tiles specifies how many half-tiles */
v->fbi.tile_width = (v->type == VOODOO_1) ? 64 : 32;
v->fbi.tile_height = (v->type == VOODOO_1) ? 16 : 32;
v->fbi.x_tiles = FBIINIT1_X_VIDEO_TILES(v->reg[fbiInit1].u);
if (v->type == VOODOO_2)
{
v->fbi.x_tiles = (v->fbi.x_tiles << 1) |
(FBIINIT1_X_VIDEO_TILES_BIT5(v->reg[fbiInit1].u) << 5) |
(FBIINIT6_X_VIDEO_TILES_BIT0(v->reg[fbiInit6].u));
}
v->fbi.rowpixels = v->fbi.tile_width * v->fbi.x_tiles;
// logerror("VOODOO.%d.VIDMEM: buffer_pages=%X fifo=%X-%X tiles=%X rowpix=%d\n", v->index, buffer_pages, fifo_start_page, fifo_last_page, v->fbi.x_tiles, v->fbi.rowpixels);
/* first RGB buffer always starts at 0 */
v->fbi.rgboffs[0] = 0;
/* second RGB buffer starts immediately afterwards */
v->fbi.rgboffs[1] = buffer_pages * 0x1000;
/* remaining buffers are based on the config */
switch (memory_config)
{
case 3: /* reserved */
logerror("VOODOO.%d.ERROR:Unexpected memory configuration in recompute_video_memory!\n", v->index);
case 0: /* 2 color buffers, 1 aux buffer */
v->fbi.rgboffs[2] = ~0;
v->fbi.auxoffs = 2 * buffer_pages * 0x1000;
break;
case 1: /* 3 color buffers, 0 aux buffers */
v->fbi.rgboffs[2] = 2 * buffer_pages * 0x1000;
v->fbi.auxoffs = ~0;
break;
case 2: /* 3 color buffers, 1 aux buffers */
v->fbi.rgboffs[2] = 2 * buffer_pages * 0x1000;
v->fbi.auxoffs = 3 * buffer_pages * 0x1000;
break;
}
/* clamp the RGB buffers to video memory */
for (buf = 0; buf < 3; buf++)
if (v->fbi.rgboffs[buf] != ~0 && v->fbi.rgboffs[buf] > v->fbi.mask)
v->fbi.rgboffs[buf] = v->fbi.mask;
/* clamp the aux buffer to video memory */
if (v->fbi.auxoffs != ~0 && v->fbi.auxoffs > v->fbi.mask)
v->fbi.auxoffs = v->fbi.mask;
/* mame_printf_debug("rgb[0] = %08X rgb[1] = %08X rgb[2] = %08X aux = %08X\n",
v->fbi.rgboffs[0], v->fbi.rgboffs[1], v->fbi.rgboffs[2], v->fbi.auxoffs);*/
/* compute the memory FIFO location and size */
if (fifo_last_page > v->fbi.mask / 0x1000)
fifo_last_page = v->fbi.mask / 0x1000;
/* is it valid and enabled? */
if (fifo_start_page <= fifo_last_page && FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u))
{
v->fbi.fifo.base = (UINT32 *)(v->fbi.ram + fifo_start_page * 0x1000);
v->fbi.fifo.size = (fifo_last_page + 1 - fifo_start_page) * 0x1000 / 4;
if (v->fbi.fifo.size > 65536*2)
v->fbi.fifo.size = 65536*2;
}
/* if not, disable the FIFO */
else
{
v->fbi.fifo.base = NULL;
v->fbi.fifo.size = 0;
}
/* reset the FIFO */
fifo_reset(&v->fbi.fifo);
/* reset our front/back buffers if they are out of range */
if (v->fbi.rgboffs[2] == ~0)
{
if (v->fbi.frontbuf == 2)
v->fbi.frontbuf = 0;
if (v->fbi.backbuf == 2)
v->fbi.backbuf = 0;
}
}
/*************************************
*
* NCC table management
*
*************************************/
static void ncc_table_write(ncc_table *n, offs_t regnum, UINT32 data)
{
/* I/Q entries reference the plaette if the high bit is set */
if (regnum >= 4 && (data & 0x80000000) && n->palette)
{
int index = ((data >> 23) & 0xfe) | (regnum & 1);
/* set the ARGB for this palette index */
n->palette[index] = 0xff000000 | data;
/* if we have an ARGB palette as well, compute its value */
if (n->palettea)
{
int a = ((data >> 16) & 0xfc) | ((data >> 22) & 0x03);
int r = ((data >> 10) & 0xfc) | ((data >> 16) & 0x03);
int g = ((data >> 4) & 0xfc) | ((data >> 10) & 0x03);
int b = ((data << 2) & 0xfc) | ((data >> 4) & 0x03);
n->palettea[index] = MAKE_ARGB(a, r, g, b);
}
/* this doesn't dirty the table or go to the registers, so bail */
return;
}
/* if the register matches, don't update */
if (data == n->reg[regnum].u)
return;
n->reg[regnum].u = data;
/* first four entries are packed Y values */
if (regnum < 4)
{
regnum *= 4;
n->y[regnum+0] = (data >> 0) & 0xff;
n->y[regnum+1] = (data >> 8) & 0xff;
n->y[regnum+2] = (data >> 16) & 0xff;
n->y[regnum+3] = (data >> 24) & 0xff;
}
/* the second four entries are the I RGB values */
else if (regnum < 8)
{
regnum &= 3;
n->ir[regnum] = (INT32)(data << 5) >> 23;
n->ig[regnum] = (INT32)(data << 14) >> 23;
n->ib[regnum] = (INT32)(data << 23) >> 23;
}
/* the final four entries are the Q RGB values */
else
{
regnum &= 3;
n->qr[regnum] = (INT32)(data << 5) >> 23;
n->qg[regnum] = (INT32)(data << 14) >> 23;
n->qb[regnum] = (INT32)(data << 23) >> 23;
}
/* mark the table dirty */
n->dirty = TRUE;
}
static void ncc_table_update(ncc_table *n)
{
int r, g, b, i;
/* generte all 256 possibilities */
for (i = 0; i < 256; i++)
{
int vi = (i >> 2) & 0x03;
int vq = (i >> 0) & 0x03;
/* start with the intensity */
r = g = b = n->y[(i >> 4) & 0x0f];
/* add the coloring */
r += n->ir[vi] + n->qr[vq];
g += n->ig[vi] + n->qg[vq];
b += n->ib[vi] + n->qb[vq];
/* clamp */
CLAMP(r, 0, 255);
CLAMP(g, 0, 255);
CLAMP(b, 0, 255);
/* fill in the table */
n->texel[i] = MAKE_ARGB(0xff, r, g, b);
}
/* no longer dirty */
n->dirty = FALSE;
}
/*************************************
*
* Faux DAC implementation
*
*************************************/
static void dacdata_w(dac_state *d, UINT8 regnum, UINT8 data)
{
d->reg[regnum] = data;
}
static void dacdata_r(dac_state *d, UINT8 regnum)
{
UINT8 result = 0xff;
/* switch off the DAC register requested */
switch (regnum)
{
case 5:
/* this is just to make startup happy */
switch (d->reg[7])
{
case 0x01: result = 0x55; break;
case 0x07: result = 0x71; break;
case 0x0b: result = 0x79; break;
}
break;
default:
result = d->reg[regnum];
break;
}
/* remember the read result; it is fetched elsewhere */
d->read_result = result;
}
/*************************************
*
* Texuture parameter computation
*
*************************************/
static void recompute_texture_params(tmu_state *t)
{
int bppscale;
UINT32 base;
int lod;
/* extract LOD parameters */
t->lodmin = TEXLOD_LODMIN(t->reg[tLOD].u) << 6;
t->lodmax = TEXLOD_LODMAX(t->reg[tLOD].u) << 6;
t->lodbias = (INT8)(TEXLOD_LODBIAS(t->reg[tLOD].u) << 2) << 4;
/* determine which LODs are present */
t->lodmask = 0x1ff;
if (TEXLOD_LOD_TSPLIT(t->reg[tLOD].u))
{
if (!TEXLOD_LOD_ODD(t->reg[tLOD].u))
t->lodmask = 0x155;
else
t->lodmask = 0x0aa;
}
/* determine base texture width/height */
t->wmask = t->hmask = 0xff;
if (TEXLOD_LOD_S_IS_WIDER(t->reg[tLOD].u))
t->hmask >>= TEXLOD_LOD_ASPECT(t->reg[tLOD].u);
else
t->wmask >>= TEXLOD_LOD_ASPECT(t->reg[tLOD].u);
/* determine the bpp of the texture */
bppscale = TEXMODE_FORMAT(t->reg[textureMode].u) >> 3;
/* start with the base of LOD 0 */
if (t->texaddr_shift == 0 && (t->reg[texBaseAddr].u & 1))
mame_printf_debug("Tiled texture\n");
base = (t->reg[texBaseAddr].u & t->texaddr_mask) << t->texaddr_shift;
t->lodoffset[0] = base & t->mask;
/* LODs 1-3 are different depending on whether we are in multitex mode */
/* Several Voodoo 2 games leave the upper bits of TLOD == 0xff, meaning we think */
/* they want multitex mode when they really don't -- disable for now */
if (0)//TEXLOD_TMULTIBASEADDR(t->reg[tLOD].u))
{
base = (t->reg[texBaseAddr_1].u & t->texaddr_mask) << t->texaddr_shift;
t->lodoffset[1] = base & t->mask;
base = (t->reg[texBaseAddr_2].u & t->texaddr_mask) << t->texaddr_shift;
t->lodoffset[2] = base & t->mask;
base = (t->reg[texBaseAddr_3_8].u & t->texaddr_mask) << t->texaddr_shift;
t->lodoffset[3] = base & t->mask;
}
else
{
if (t->lodmask & (1 << 0))
base += (((t->wmask >> 0) + 1) * ((t->hmask >> 0) + 1)) << bppscale;
t->lodoffset[1] = base & t->mask;
if (t->lodmask & (1 << 1))
base += (((t->wmask >> 1) + 1) * ((t->hmask >> 1) + 1)) << bppscale;
t->lodoffset[2] = base & t->mask;
if (t->lodmask & (1 << 2))
base += (((t->wmask >> 2) + 1) * ((t->hmask >> 2) + 1)) << bppscale;
t->lodoffset[3] = base & t->mask;
}
/* remaining LODs make sense */
for (lod = 4; lod <= 8; lod++)
{
if (t->lodmask & (1 << (lod - 1)))
{
UINT32 size = ((t->wmask >> (lod - 1)) + 1) * ((t->hmask >> (lod - 1)) + 1);
if (size < 4) size = 4;
base += size << bppscale;
}
t->lodoffset[lod] = base & t->mask;
}
/* set the NCC lookup appropriately */
t->texel[1] = t->texel[9] = t->ncc[TEXMODE_NCC_TABLE_SELECT(t->reg[textureMode].u)].texel;
/* pick the lookup table */
t->lookup = t->texel[TEXMODE_FORMAT(t->reg[textureMode].u)];
/* compute the detail parameters */
t->detailmax = TEXDETAIL_DETAIL_MAX(t->reg[tDetail].u);
t->detailbias = (INT8)(TEXDETAIL_DETAIL_BIAS(t->reg[tDetail].u) << 2) << 6;
t->detailscale = TEXDETAIL_DETAIL_SCALE(t->reg[tDetail].u);
/* no longer dirty */
t->regdirty = FALSE;
/* check for separate RGBA filtering */
if (TEXDETAIL_SEPARATE_RGBA_FILTER(t->reg[tDetail].u))
fatalerror("Separate RGBA filters!");
}
INLINE INT32 prepare_tmu(tmu_state *t)
{
INT64 texdx, texdy;
INT32 lodbase;
/* if the texture parameters are dirty, update them */
if (t->regdirty)
{
recompute_texture_params(t);
/* ensure that the NCC tables are up to date */
if ((TEXMODE_FORMAT(t->reg[textureMode].u) & 7) == 1)
{
ncc_table *n = &t->ncc[TEXMODE_NCC_TABLE_SELECT(t->reg[textureMode].u)];
t->texel[1] = t->texel[9] = n->texel;
if (n->dirty)
ncc_table_update(n);
}
}
/* compute (ds^2 + dt^2) in both X and Y as 28.36 numbers */
texdx = (INT64)(t->dsdx >> 14) * (INT64)(t->dsdx >> 14) + (INT64)(t->dtdx >> 14) * (INT64)(t->dtdx >> 14);
texdy = (INT64)(t->dsdy >> 14) * (INT64)(t->dsdy >> 14) + (INT64)(t->dtdy >> 14) * (INT64)(t->dtdy >> 14);
/* pick whichever is larger and shift off some high bits -> 28.20 */
if (texdx < texdy)
texdx = texdy;
texdx >>= 16;
/* use our fast reciprocal/log on this value; it expects input as a */
/* 16.32 number, and returns the log of the reciprocal, so we have to */
/* adjust the result: negative to get the log of the original value */
/* plus 12 to account for the extra exponent, and divided by 2 to */
/* get the log of the square root of texdx */
(void)fast_reciplog(texdx, &lodbase);
return (-lodbase + (12 << 8)) / 2;
}
/*************************************
*
* Command FIFO depth computation
*
*************************************/
static int cmdfifo_compute_expected_depth(voodoo_state *v, cmdfifo_info *f)
{
UINT32 *fifobase = (UINT32 *)v->fbi.ram;
UINT32 readptr = f->rdptr;
UINT32 command = fifobase[readptr / 4];
int i, count = 0;
/* low 3 bits specify the packet type */
switch (command & 7)
{
/*
Packet type 0: 1 or 2 words
Word Bits
0 31:29 = reserved
0 28:6 = Address [24:2]
0 5:3 = Function (0 = NOP, 1 = JSR, 2 = RET, 3 = JMP LOCAL, 4 = JMP AGP)
0 2:0 = Packet type (0)
1 31:11 = reserved (JMP AGP only)
1 10:0 = Address [35:25]
*/
case 0:
if (((command >> 3) & 7) == 4)
return 2;
return 1;
/*
Packet type 1: 1 + N words
Word Bits
0 31:16 = Number of words
0 15 = Increment?
0 14:3 = Register base
0 2:0 = Packet type (1)
1 31:0 = Data word
*/
case 1:
return 1 + (command >> 16);
/*
Packet type 2: 1 + N words
Word Bits
0 31:3 = 2D Register mask
0 2:0 = Packet type (2)
1 31:0 = Data word
*/
case 2:
for (i = 3; i <= 31; i++)
if (command & (1 << i)) count++;
return 1 + count;
/*
Packet type 3: 1 + N words
Word Bits
0 31:29 = Number of dummy entries following the data
0 28 = Packed color data?
0 25 = Disable ping pong sign correction (0=normal, 1=disable)
0 24 = Culling sign (0=positive, 1=negative)
0 23 = Enable culling (0=disable, 1=enable)
0 22 = Strip mode (0=strip, 1=fan)
0 17 = Setup S1 and T1
0 16 = Setup W1
0 15 = Setup S0 and T0
0 14 = Setup W0
0 13 = Setup Wb
0 12 = Setup Z
0 11 = Setup Alpha
0 10 = Setup RGB
0 9:6 = Number of vertices
0 5:3 = Command (0=Independent tris, 1=Start new strip, 2=Continue strip)
0 2:0 = Packet type (3)
1 31:0 = Data word
*/
case 3:
count = 2; /* X/Y */
if (command & (1 << 28))
{
if (command & (3 << 10)) count++; /* ARGB */
}
else
{
if (command & (1 << 10)) count += 3; /* RGB */
if (command & (1 << 11)) count++; /* A */
}
if (command & (1 << 12)) count++; /* Z */
if (command & (1 << 13)) count++; /* Wb */
if (command & (1 << 14)) count++; /* W0 */
if (command & (1 << 15)) count += 2; /* S0/T0 */
if (command & (1 << 16)) count++; /* W1 */
if (command & (1 << 17)) count += 2; /* S1/T1 */
count *= (command >> 6) & 15; /* numverts */
return 1 + count + (command >> 29);
/*
Packet type 4: 1 + N words
Word Bits
0 31:29 = Number of dummy entries following the data
0 28:15 = General register mask
0 14:3 = Register base
0 2:0 = Packet type (4)
1 31:0 = Data word
*/
case 4:
for (i = 15; i <= 28; i++)
if (command & (1 << i)) count++;
return 1 + count + (command >> 29);
/*
Packet type 5: 2 + N words
Word Bits
0 31:30 = Space (0,1=reserved, 2=LFB, 3=texture)
0 29:26 = Byte disable W2
0 25:22 = Byte disable WN
0 21:3 = Num words
0 2:0 = Packet type (5)
1 31:30 = Reserved
1 29:0 = Base address [24:0]
2 31:0 = Data word
*/
case 5:
return 2 + ((command >> 3) & 0x7ffff);
default:
mame_printf_debug("UNKNOWN PACKET TYPE %d\n", command & 7);
return 1;
}
}
/*************************************
*
* Command FIFO execution
*
*************************************/
static UINT32 cmdfifo_execute(voodoo_state *v, cmdfifo_info *f)
{
UINT32 *fifobase = (UINT32 *)v->fbi.ram;
UINT32 readptr = f->rdptr;
UINT32 *src = &fifobase[readptr / 4];
UINT32 command = *src++;
int count, inc, code, i;
setup_vertex svert = {0};
offs_t target;
int cycles = 0;
switch (command & 7)
{
/*
Packet type 0: 1 or 2 words
Word Bits
0 31:29 = reserved
0 28:6 = Address [24:2]
0 5:3 = Function (0 = NOP, 1 = JSR, 2 = RET, 3 = JMP LOCAL, 4 = JMP AGP)
0 2:0 = Packet type (0)
1 31:11 = reserved (JMP AGP only)
1 10:0 = Address [35:25]
*/
case 0:
/* extract parameters */
target = (command >> 4) & 0x1fffffc;
/* switch off of the specific command */
switch ((command >> 3) & 7)
{
case 0: /* NOP */
if (LOG_CMDFIFO) logerror(" NOP\n");
break;
case 1: /* JSR */
if (LOG_CMDFIFO) logerror(" JSR $%06X\n", target);
mame_printf_debug("JSR in CMDFIFO!\n");
src = &fifobase[target / 4];
break;
case 2: /* RET */
if (LOG_CMDFIFO) logerror(" RET $%06X\n", target);
fatalerror("RET in CMDFIFO!");
break;
case 3: /* JMP LOCAL FRAME BUFFER */
if (LOG_CMDFIFO) logerror(" JMP LOCAL FRAMEBUF $%06X\n", target);
src = &fifobase[target / 4];
break;
case 4: /* JMP AGP */
if (LOG_CMDFIFO) logerror(" JMP AGP $%06X\n", target);
fatalerror("JMP AGP in CMDFIFO!");
src = &fifobase[target / 4];
break;
default:
mame_printf_debug("INVALID JUMP COMMAND!\n");
fatalerror(" INVALID JUMP COMMAND");
break;
}
break;
/*
Packet type 1: 1 + N words
Word Bits
0 31:16 = Number of words
0 15 = Increment?
0 14:3 = Register base
0 2:0 = Packet type (1)
1 31:0 = Data word
*/
case 1:
/* extract parameters */
count = command >> 16;
inc = (command >> 15) & 1;
target = (command >> 3) & 0xfff;
if (LOG_CMDFIFO) logerror(" PACKET TYPE 1: count=%d inc=%d reg=%04X\n", count, inc, target);
/* loop over all registers and write them one at a time */
for (i = 0; i < count; i++, target += inc)
cycles += register_w(v, target, *src++);
break;
/*
Packet type 2: 1 + N words
Word Bits
0 31:3 = 2D Register mask
0 2:0 = Packet type (2)
1 31:0 = Data word
*/
case 2:
if (LOG_CMDFIFO) logerror(" PACKET TYPE 2: mask=%X\n", (command >> 3) & 0x1ffffff);
/* loop over all registers and write them one at a time */
for (i = 3; i <= 31; i++)
if (command & (1 << i))
cycles += register_w(v, bltSrcBaseAddr + (i - 3), *src++);
break;
/*
Packet type 3: 1 + N words
Word Bits
0 31:29 = Number of dummy entries following the data
0 28 = Packed color data?
0 25 = Disable ping pong sign correction (0=normal, 1=disable)
0 24 = Culling sign (0=positive, 1=negative)
0 23 = Enable culling (0=disable, 1=enable)
0 22 = Strip mode (0=strip, 1=fan)
0 17 = Setup S1 and T1
0 16 = Setup W1
0 15 = Setup S0 and T0
0 14 = Setup W0
0 13 = Setup Wb
0 12 = Setup Z
0 11 = Setup Alpha
0 10 = Setup RGB
0 9:6 = Number of vertices
0 5:3 = Command (0=Independent tris, 1=Start new strip, 2=Continue strip)
0 2:0 = Packet type (3)
1 31:0 = Data word
*/
case 3:
/* extract parameters */
count = (command >> 6) & 15;
code = (command >> 3) & 7;
if (LOG_CMDFIFO) logerror(" PACKET TYPE 3: count=%d code=%d mask=%03X smode=%02X pc=%d\n", count, code, (command >> 10) & 0xfff, (command >> 22) & 0x3f, (command >> 28) & 1);
/* copy relevant bits into the setup mode register */
v->reg[sSetupMode].u = ((command >> 10) & 0xff) | ((command >> 6) & 0xf0000);
/* loop over triangles */
for (i = 0; i < count; i++)
{
/* always extract X/Y */
svert.x = *(float *)src++;
svert.y = *(float *)src++;
/* load ARGB values if packed */
if (command & (1 << 28))
{
if (command & (3 << 10))
{
UINT32 argb = *src++;
if (command & (1 << 10))
{
svert.r = RGB_RED(argb);
svert.g = RGB_GREEN(argb);
svert.b = RGB_BLUE(argb);
}
if (command & (1 << 11))
svert.a = RGB_ALPHA(argb);
}
}
/* load ARGB values if not packed */
else
{
if (command & (1 << 10))
{
svert.r = *(float *)src++;
svert.g = *(float *)src++;
svert.b = *(float *)src++;
}
if (command & (1 << 11))
svert.a = *(float *)src++;
}
/* load Z and Wb values */
if (command & (1 << 12))
svert.z = *(float *)src++;
if (command & (1 << 13))
svert.wb = *(float *)src++;
/* load W0, S0, T0 values */
if (command & (1 << 14))
svert.w0 = *(float *)src++;
if (command & (1 << 15))
{
svert.s0 = *(float *)src++;
svert.t0 = *(float *)src++;
}
/* load W1, S1, T1 values */
if (command & (1 << 16))
svert.w1 = *(float *)src++;
if (command & (1 << 17))
{
svert.s1 = *(float *)src++;
svert.t1 = *(float *)src++;
}
/* if we're starting a new strip, or if this is the first of a set of verts */
/* for a series of individual triangles, initialize all the verts */
if ((code == 1 && i == 0) || (code == 0 && i % 3 == 0))
{
v->fbi.sverts = 1;
v->fbi.svert[0] = v->fbi.svert[1] = v->fbi.svert[2] = svert;
}
/* otherwise, add this to the list */
else
{
/* for strip mode, shuffle vertex 1 down to 0 */
if (!(command & (1 << 22)))
v->fbi.svert[0] = v->fbi.svert[1];
/* copy 2 down to 1 and add our new one regardless */
v->fbi.svert[1] = v->fbi.svert[2];
v->fbi.svert[2] = svert;
/* if we have enough, draw */
if (++v->fbi.sverts >= 3)
cycles += setup_and_draw_triangle(v);
}
}
/* account for the extra dummy words */
src += command >> 29;
break;
/*
Packet type 4: 1 + N words
Word Bits
0 31:29 = Number of dummy entries following the data
0 28:15 = General register mask
0 14:3 = Register base
0 2:0 = Packet type (4)
1 31:0 = Data word
*/
case 4:
/* extract parameters */
target = (command >> 3) & 0xfff;
if (LOG_CMDFIFO) logerror(" PACKET TYPE 4: mask=%X reg=%04X pad=%d\n", (command >> 15) & 0x3fff, target, command >> 29);
/* loop over all registers and write them one at a time */
for (i = 15; i <= 28; i++)
if (command & (1 << i))
cycles += register_w(v, target + (i - 15), *src++);
/* account for the extra dummy words */
src += command >> 29;
break;
/*
Packet type 5: 2 + N words
Word Bits
0 31:30 = Space (0,1=reserved, 2=LFB, 3=texture)
0 29:26 = Byte disable W2
0 25:22 = Byte disable WN
0 21:3 = Num words
0 2:0 = Packet type (5)
1 31:30 = Reserved
1 29:0 = Base address [24:0]
2 31:0 = Data word
*/
case 5:
/* extract parameters */
count = (command >> 3) & 0x7ffff;
target = *src++ / 4;
/* handle LFB writes */
if ((command >> 30) == 2)
{
if (LOG_CMDFIFO) logerror(" PACKET TYPE 5: LFB count=%d dest=%08X bd2=%X bdN=%X\n", count, target, (command >> 26) & 15, (command >> 22) & 15);
/* loop over words */
for (i = 0; i < count; i++)
cycles += lfb_w(v, target++, *src++, 0xffffffff, FALSE);
}
else if ((command >> 30) == 3)
{
if (LOG_CMDFIFO) logerror(" PACKET TYPE 5: textureRAM count=%d dest=%08X bd2=%X bdN=%X\n", count, target, (command >> 26) & 15, (command >> 22) & 15);
/* loop over words */
for (i = 0; i < count; i++)
cycles += texture_w(v, target++, *src++);
}
break;
default:
fprintf(stderr, "PACKET TYPE %d\n", command & 7);
break;
}
/* by default just update the read pointer past all the data we consumed */
f->rdptr = 4 * (src - fifobase);
return cycles;
}
/*************************************
*
* Handle execution if we're ready
*
*************************************/
static INT32 cmdfifo_execute_if_ready(voodoo_state *v, cmdfifo_info *f)
{
int needed_depth;
int cycles;
/* all CMDFIFO commands need at least one word */
if (f->depth == 0)
return -1;
/* see if we have enough for the current command */
needed_depth = cmdfifo_compute_expected_depth(v, f);
if (f->depth < needed_depth)
return -1;
/* execute */
cycles = cmdfifo_execute(v, f);
f->depth -= needed_depth;
return cycles;
}
/*************************************
*
* Handle writes to the CMD FIFO
*
*************************************/
static void cmdfifo_w(voodoo_state *v, cmdfifo_info *f, offs_t offset, UINT32 data)
{
UINT32 addr = f->base + offset * 4;
UINT32 *fifobase = (UINT32 *)v->fbi.ram;
if (LOG_CMDFIFO_VERBOSE) logerror("CMDFIFO_w(%04X) = %08X\n", offset, data);
/* write the data */
if (addr < f->end)
fifobase[addr / 4] = data;
/* count holes? */
if (f->count_holes)
{
/* in-order, no holes */
if (f->holes == 0 && addr == f->amin + 4)
{
f->amin = f->amax = addr;
f->depth++;
}
/* out-of-order, below the minimum */
else if (addr < f->amin)
{
if (f->holes != 0)
logerror("Unexpected CMDFIFO: AMin=%08X AMax=%08X Holes=%d WroteTo:%08X\n",
f->amin, f->amax, f->holes, addr);
f->amin = f->amax = addr;
f->depth++;
}
/* out-of-order, but within the min-max range */
else if (addr < f->amax)
{
f->holes--;
if (f->holes == 0)
{
f->depth += (f->amax - f->amin) / 4;
f->amin = f->amax;
}
}
/* out-of-order, bumping max */
else
{
f->holes += (addr - f->amax) / 4 - 1;
f->amax = addr;
}
}
/* execute if we can */
if (!v->pci.op_pending)
{
INT32 cycles = cmdfifo_execute_if_ready(v, f);
if (cycles > 0)
{
v->pci.op_pending = TRUE;
v->pci.op_end_time = v->device->machine->time() + attotime(0, (attoseconds_t)cycles * v->attoseconds_per_cycle);
if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:direct write start at %d.%08X%08X end at %d.%08X%08X\n", v->index,
v->device->machine->time().seconds, (UINT32)(v->device->machine->time().attoseconds >> 32), (UINT32)v->device->machine->time().attoseconds,
v->pci.op_end_time.seconds, (UINT32)(v->pci.op_end_time.attoseconds >> 32), (UINT32)v->pci.op_end_time.attoseconds);
}
}
}
/*************************************
*
* Stall the active cpu until we are
* ready
*
*************************************/
static TIMER_CALLBACK( stall_cpu_callback )
{
check_stalled_cpu((voodoo_state *)ptr, machine->time());
}
static void check_stalled_cpu(voodoo_state *v, attotime current_time)
{
int resume = FALSE;
/* flush anything we can */
if (v->pci.op_pending)
flush_fifos(v, current_time);
/* if we're just stalled until the LWM is passed, see if we're ok now */
if (v->pci.stall_state == STALLED_UNTIL_FIFO_LWM)
{
/* if there's room in the memory FIFO now, we can proceed */
if (FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u))
{
if (fifo_items(&v->fbi.fifo) < 2 * 32 * FBIINIT0_MEMORY_FIFO_HWM(v->reg[fbiInit0].u))
resume = TRUE;
}
else if (fifo_space(&v->pci.fifo) > 2 * FBIINIT0_PCI_FIFO_LWM(v->reg[fbiInit0].u))
resume = TRUE;
}
/* if we're stalled until the FIFOs are empty, check now */
else if (v->pci.stall_state == STALLED_UNTIL_FIFO_EMPTY)
{
if (FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u))
{
if (fifo_empty(&v->fbi.fifo) && fifo_empty(&v->pci.fifo))
resume = TRUE;
}
else if (fifo_empty(&v->pci.fifo))
resume = TRUE;
}
/* resume if necessary */
if (resume || !v->pci.op_pending)
{
if (LOG_FIFO) logerror("VOODOO.%d.FIFO:Stall condition cleared; resuming\n", v->index);
v->pci.stall_state = NOT_STALLED;
/* either call the callback, or trigger the trigger */
if (v->pci.stall_callback)
(*v->pci.stall_callback)(v->device, FALSE);
else
v->device->machine->scheduler().trigger(v->trigger);
}
/* if not, set a timer for the next one */
else
{
v->pci.continue_timer->adjust(v->pci.op_end_time - current_time);
}
}
static void stall_cpu(voodoo_state *v, int state, attotime current_time)
{
/* sanity check */
if (!v->pci.op_pending) fatalerror("FIFOs not empty, no op pending!");
/* set the state and update statistics */
v->pci.stall_state = state;
v->stats.stalls++;
/* either call the callback, or spin the CPU */
if (v->pci.stall_callback)
(*v->pci.stall_callback)(v->device, TRUE);
else
device_spin_until_trigger(v->cpu, v->trigger);
/* set a timer to clear the stall */
v->pci.continue_timer->adjust(v->pci.op_end_time - current_time);
}
/*************************************
*
* Voodoo register writes
*
*************************************/
static INT32 register_w(voodoo_state *v, offs_t offset, UINT32 data)
{
UINT32 origdata = data;
INT32 cycles = 0;
INT64 data64;
UINT8 regnum;
UINT8 chips;
/* statistics */
v->stats.reg_writes++;
/* determine which chips we are addressing */
chips = (offset >> 8) & 0xf;
if (chips == 0)
chips = 0xf;
chips &= v->chipmask;
/* the first 64 registers can be aliased differently */
if ((offset & 0x800c0) == 0x80000 && v->alt_regmap)
regnum = register_alias_map[offset & 0x3f];
else
regnum = offset & 0xff;
/* first make sure this register is readable */
if (!(v->regaccess[regnum] & REGISTER_WRITE))
{
logerror("VOODOO.%d.ERROR:Invalid attempt to write %s\n", v->index, v->regnames[regnum]);
return 0;
}
/* switch off the register */
switch (regnum)
{
/* Vertex data is 12.4 formatted fixed point */
case fvertexAx:
data = float_to_int32(data, 4);
case vertexAx:
if (chips & 1) v->fbi.ax = (INT16)data;
break;
case fvertexAy:
data = float_to_int32(data, 4);
case vertexAy:
if (chips & 1) v->fbi.ay = (INT16)data;
break;
case fvertexBx:
data = float_to_int32(data, 4);
case vertexBx:
if (chips & 1) v->fbi.bx = (INT16)data;
break;
case fvertexBy:
data = float_to_int32(data, 4);
case vertexBy:
if (chips & 1) v->fbi.by = (INT16)data;
break;
case fvertexCx:
data = float_to_int32(data, 4);
case vertexCx:
if (chips & 1) v->fbi.cx = (INT16)data;
break;
case fvertexCy:
data = float_to_int32(data, 4);
case vertexCy:
if (chips & 1) v->fbi.cy = (INT16)data;
break;
/* RGB data is 12.12 formatted fixed point */
case fstartR:
data = float_to_int32(data, 12);
case startR:
if (chips & 1) v->fbi.startr = (INT32)(data << 8) >> 8;
break;
case fstartG:
data = float_to_int32(data, 12);
case startG:
if (chips & 1) v->fbi.startg = (INT32)(data << 8) >> 8;
break;
case fstartB:
data = float_to_int32(data, 12);
case startB:
if (chips & 1) v->fbi.startb = (INT32)(data << 8) >> 8;
break;
case fstartA:
data = float_to_int32(data, 12);
case startA:
if (chips & 1) v->fbi.starta = (INT32)(data << 8) >> 8;
break;
case fdRdX:
data = float_to_int32(data, 12);
case dRdX:
if (chips & 1) v->fbi.drdx = (INT32)(data << 8) >> 8;
break;
case fdGdX:
data = float_to_int32(data, 12);
case dGdX:
if (chips & 1) v->fbi.dgdx = (INT32)(data << 8) >> 8;
break;
case fdBdX:
data = float_to_int32(data, 12);
case dBdX:
if (chips & 1) v->fbi.dbdx = (INT32)(data << 8) >> 8;
break;
case fdAdX:
data = float_to_int32(data, 12);
case dAdX:
if (chips & 1) v->fbi.dadx = (INT32)(data << 8) >> 8;
break;
case fdRdY:
data = float_to_int32(data, 12);
case dRdY:
if (chips & 1) v->fbi.drdy = (INT32)(data << 8) >> 8;
break;
case fdGdY:
data = float_to_int32(data, 12);
case dGdY:
if (chips & 1) v->fbi.dgdy = (INT32)(data << 8) >> 8;
break;
case fdBdY:
data = float_to_int32(data, 12);
case dBdY:
if (chips & 1) v->fbi.dbdy = (INT32)(data << 8) >> 8;
break;
case fdAdY:
data = float_to_int32(data, 12);
case dAdY:
if (chips & 1) v->fbi.dady = (INT32)(data << 8) >> 8;
break;
/* Z data is 20.12 formatted fixed point */
case fstartZ:
data = float_to_int32(data, 12);
case startZ:
if (chips & 1) v->fbi.startz = (INT32)data;
break;
case fdZdX:
data = float_to_int32(data, 12);
case dZdX:
if (chips & 1) v->fbi.dzdx = (INT32)data;
break;
case fdZdY:
data = float_to_int32(data, 12);
case dZdY:
if (chips & 1) v->fbi.dzdy = (INT32)data;
break;
/* S,T data is 14.18 formatted fixed point, converted to 16.32 internally */
case fstartS:
data64 = float_to_int64(data, 32);
if (chips & 2) v->tmu[0].starts = data64;
if (chips & 4) v->tmu[1].starts = data64;
break;
case startS:
if (chips & 2) v->tmu[0].starts = (INT64)(INT32)data << 14;
if (chips & 4) v->tmu[1].starts = (INT64)(INT32)data << 14;
break;
case fstartT:
data64 = float_to_int64(data, 32);
if (chips & 2) v->tmu[0].startt = data64;
if (chips & 4) v->tmu[1].startt = data64;
break;
case startT:
if (chips & 2) v->tmu[0].startt = (INT64)(INT32)data << 14;
if (chips & 4) v->tmu[1].startt = (INT64)(INT32)data << 14;
break;
case fdSdX:
data64 = float_to_int64(data, 32);
if (chips & 2) v->tmu[0].dsdx = data64;
if (chips & 4) v->tmu[1].dsdx = data64;
break;
case dSdX:
if (chips & 2) v->tmu[0].dsdx = (INT64)(INT32)data << 14;
if (chips & 4) v->tmu[1].dsdx = (INT64)(INT32)data << 14;
break;
case fdTdX:
data64 = float_to_int64(data, 32);
if (chips & 2) v->tmu[0].dtdx = data64;
if (chips & 4) v->tmu[1].dtdx = data64;
break;
case dTdX:
if (chips & 2) v->tmu[0].dtdx = (INT64)(INT32)data << 14;
if (chips & 4) v->tmu[1].dtdx = (INT64)(INT32)data << 14;
break;
case fdSdY:
data64 = float_to_int64(data, 32);
if (chips & 2) v->tmu[0].dsdy = data64;
if (chips & 4) v->tmu[1].dsdy = data64;
break;
case dSdY:
if (chips & 2) v->tmu[0].dsdy = (INT64)(INT32)data << 14;
if (chips & 4) v->tmu[1].dsdy = (INT64)(INT32)data << 14;
break;
case fdTdY:
data64 = float_to_int64(data, 32);
if (chips & 2) v->tmu[0].dtdy = data64;
if (chips & 4) v->tmu[1].dtdy = data64;
break;
case dTdY:
if (chips & 2) v->tmu[0].dtdy = (INT64)(INT32)data << 14;
if (chips & 4) v->tmu[1].dtdy = (INT64)(INT32)data << 14;
break;
/* W data is 2.30 formatted fixed point, converted to 16.32 internally */
case fstartW:
data64 = float_to_int64(data, 32);
if (chips & 1) v->fbi.startw = data64;
if (chips & 2) v->tmu[0].startw = data64;
if (chips & 4) v->tmu[1].startw = data64;
break;
case startW:
if (chips & 1) v->fbi.startw = (INT64)(INT32)data << 2;
if (chips & 2) v->tmu[0].startw = (INT64)(INT32)data << 2;
if (chips & 4) v->tmu[1].startw = (INT64)(INT32)data << 2;
break;
case fdWdX:
data64 = float_to_int64(data, 32);
if (chips & 1) v->fbi.dwdx = data64;
if (chips & 2) v->tmu[0].dwdx = data64;
if (chips & 4) v->tmu[1].dwdx = data64;
break;
case dWdX:
if (chips & 1) v->fbi.dwdx = (INT64)(INT32)data << 2;
if (chips & 2) v->tmu[0].dwdx = (INT64)(INT32)data << 2;
if (chips & 4) v->tmu[1].dwdx = (INT64)(INT32)data << 2;
break;
case fdWdY:
data64 = float_to_int64(data, 32);
if (chips & 1) v->fbi.dwdy = data64;
if (chips & 2) v->tmu[0].dwdy = data64;
if (chips & 4) v->tmu[1].dwdy = data64;
break;
case dWdY:
if (chips & 1) v->fbi.dwdy = (INT64)(INT32)data << 2;
if (chips & 2) v->tmu[0].dwdy = (INT64)(INT32)data << 2;
if (chips & 4) v->tmu[1].dwdy = (INT64)(INT32)data << 2;
break;
/* setup bits */
case sARGB:
if (chips & 1)
{
v->reg[sAlpha].f = RGB_ALPHA(data);
v->reg[sRed].f = RGB_RED(data);
v->reg[sGreen].f = RGB_GREEN(data);
v->reg[sBlue].f = RGB_BLUE(data);
}
break;
/* mask off invalid bits for different cards */
case fbzColorPath:
poly_wait(v->poly, v->regnames[regnum]);
if (v->type < VOODOO_2)
data &= 0x0fffffff;
if (chips & 1) v->reg[fbzColorPath].u = data;
break;
case fbzMode:
poly_wait(v->poly, v->regnames[regnum]);
if (v->type < VOODOO_2)
data &= 0x001fffff;
if (chips & 1) v->reg[fbzMode].u = data;
break;
case fogMode:
poly_wait(v->poly, v->regnames[regnum]);
if (v->type < VOODOO_2)
data &= 0x0000003f;
if (chips & 1) v->reg[fogMode].u = data;
break;
/* triangle drawing */
case triangleCMD:
v->fbi.cheating_allowed = (v->fbi.ax != 0 || v->fbi.ay != 0 || v->fbi.bx > 50 || v->fbi.by != 0 || v->fbi.cx != 0 || v->fbi.cy > 50);
v->fbi.sign = data;
cycles = triangle(v);
break;
case ftriangleCMD:
v->fbi.cheating_allowed = TRUE;
v->fbi.sign = data;
cycles = triangle(v);
break;
case sBeginTriCMD:
cycles = begin_triangle(v);
break;
case sDrawTriCMD:
cycles = draw_triangle(v);
break;
/* other commands */
case nopCMD:
poly_wait(v->poly, v->regnames[regnum]);
if (data & 1)
reset_counters(v);
if (data & 2)
v->reg[fbiTrianglesOut].u = 0;
break;
case fastfillCMD:
cycles = fastfill(v);
break;
case swapbufferCMD:
poly_wait(v->poly, v->regnames[regnum]);
cycles = swapbuffer(v, data);
break;
case userIntrCMD:
poly_wait(v->poly, v->regnames[regnum]);
fatalerror("userIntrCMD");
break;
/* gamma table access -- Voodoo/Voodoo2 only */
case clutData:
if (v->type <= VOODOO_2 && (chips & 1))
{
poly_wait(v->poly, v->regnames[regnum]);
if (!FBIINIT1_VIDEO_TIMING_RESET(v->reg[fbiInit1].u))
{
int index = data >> 24;
if (index <= 32)
{
v->fbi.clut[index] = data;
v->fbi.clut_dirty = TRUE;
}
}
else
logerror("clutData ignored because video timing reset = 1\n");
}
break;
/* external DAC access -- Voodoo/Voodoo2 only */
case dacData:
if (v->type <= VOODOO_2 && (chips & 1))
{
poly_wait(v->poly, v->regnames[regnum]);
if (!(data & 0x800))
dacdata_w(&v->dac, (data >> 8) & 7, data & 0xff);
else
dacdata_r(&v->dac, (data >> 8) & 7);
}
break;
/* vertical sync rate -- Voodoo/Voodoo2 only */
case hSync:
case vSync:
case backPorch:
case videoDimensions:
if (v->type <= VOODOO_2 && (chips & 1))
{
poly_wait(v->poly, v->regnames[regnum]);
v->reg[regnum].u = data;
if (v->reg[hSync].u != 0 && v->reg[vSync].u != 0 && v->reg[videoDimensions].u != 0)
{
int htotal = ((v->reg[hSync].u >> 16) & 0x3ff) + 1 + (v->reg[hSync].u & 0xff) + 1;
int vtotal = ((v->reg[vSync].u >> 16) & 0xfff) + (v->reg[vSync].u & 0xfff);
int hvis = v->reg[videoDimensions].u & 0x3ff;
int vvis = (v->reg[videoDimensions].u >> 16) & 0x3ff;
int hbp = (v->reg[backPorch].u & 0xff) + 2;
int vbp = (v->reg[backPorch].u >> 16) & 0xff;
attoseconds_t refresh = v->screen->frame_period().attoseconds;
attoseconds_t stdperiod, medperiod, vgaperiod;
attoseconds_t stddiff, meddiff, vgadiff;
rectangle visarea;
/* create a new visarea */
visarea.min_x = hbp;
visarea.max_x = hbp + hvis - 1;
visarea.min_y = vbp;
visarea.max_y = vbp + vvis - 1;
/* keep within bounds */
visarea.max_x = MIN(visarea.max_x, htotal - 1);
visarea.max_y = MIN(visarea.max_y, vtotal - 1);
/* compute the new period for standard res, medium res, and VGA res */
stdperiod = HZ_TO_ATTOSECONDS(15750) * vtotal;
medperiod = HZ_TO_ATTOSECONDS(25000) * vtotal;
vgaperiod = HZ_TO_ATTOSECONDS(31500) * vtotal;
/* compute a diff against the current refresh period */
stddiff = stdperiod - refresh;
if (stddiff < 0) stddiff = -stddiff;
meddiff = medperiod - refresh;
if (meddiff < 0) meddiff = -meddiff;
vgadiff = vgaperiod - refresh;
if (vgadiff < 0) vgadiff = -vgadiff;
mame_printf_debug("hSync=%08X vSync=%08X backPorch=%08X videoDimensions=%08X\n",
v->reg[hSync].u, v->reg[vSync].u, v->reg[backPorch].u, v->reg[videoDimensions].u);
mame_printf_debug("Horiz: %d-%d (%d total) Vert: %d-%d (%d total) -- ", visarea.min_x, visarea.max_x, htotal, visarea.min_y, visarea.max_y, vtotal);
/* configure the screen based on which one matches the closest */
if (stddiff < meddiff && stddiff < vgadiff)
{
v->screen->configure(htotal, vtotal, visarea, stdperiod);
mame_printf_debug("Standard resolution, %f Hz\n", ATTOSECONDS_TO_HZ(stdperiod));
}
else if (meddiff < vgadiff)
{
v->screen->configure(htotal, vtotal, visarea, medperiod);
mame_printf_debug("Medium resolution, %f Hz\n", ATTOSECONDS_TO_HZ(medperiod));
}
else
{
v->screen->configure(htotal, vtotal, visarea, vgaperiod);
mame_printf_debug("VGA resolution, %f Hz\n", ATTOSECONDS_TO_HZ(vgaperiod));
}
/* configure the new framebuffer info */
v->fbi.width = hvis;
v->fbi.height = vvis;
v->fbi.xoffs = hbp;
v->fbi.yoffs = vbp;
v->fbi.vsyncscan = (v->reg[vSync].u >> 16) & 0xfff;
/* recompute the time of VBLANK */
adjust_vblank_timer(v);
/* if changing dimensions, update video memory layout */
if (regnum == videoDimensions)
recompute_video_memory(v);
}
}
break;
/* fbiInit0 can only be written if initEnable says we can -- Voodoo/Voodoo2 only */
case fbiInit0:
poly_wait(v->poly, v->regnames[regnum]);
if (v->type <= VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
{
v->reg[fbiInit0].u = data;
if (FBIINIT0_GRAPHICS_RESET(data))
soft_reset(v);
if (FBIINIT0_FIFO_RESET(data))
fifo_reset(&v->pci.fifo);
recompute_video_memory(v);
}
break;
/* fbiInit5-7 are Voodoo 2-only; ignore them on anything else */
case fbiInit5:
case fbiInit6:
if (v->type < VOODOO_2)
break;
/* else fall through... */
/* fbiInitX can only be written if initEnable says we can -- Voodoo/Voodoo2 only */
/* most of these affect memory layout, so always recompute that when done */
case fbiInit1:
case fbiInit2:
case fbiInit4:
poly_wait(v->poly, v->regnames[regnum]);
if (v->type <= VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
{
v->reg[regnum].u = data;
recompute_video_memory(v);
v->fbi.video_changed = TRUE;
}
break;
case fbiInit3:
poly_wait(v->poly, v->regnames[regnum]);
if (v->type <= VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
{
v->reg[regnum].u = data;
v->alt_regmap = FBIINIT3_TRI_REGISTER_REMAP(data);
v->fbi.yorigin = FBIINIT3_YORIGIN_SUBTRACT(v->reg[fbiInit3].u);
recompute_video_memory(v);
}
break;
case fbiInit7:
/* case swapPending: -- Banshee */
if (v->type == VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
{
poly_wait(v->poly, v->regnames[regnum]);
v->reg[regnum].u = data;
v->fbi.cmdfifo[0].enable = FBIINIT7_CMDFIFO_ENABLE(data);
v->fbi.cmdfifo[0].count_holes = !FBIINIT7_DISABLE_CMDFIFO_HOLES(data);
}
else if (v->type >= VOODOO_BANSHEE)
v->fbi.swaps_pending++;
break;
/* cmdFifo -- Voodoo2 only */
case cmdFifoBaseAddr:
if (v->type == VOODOO_2 && (chips & 1))
{
poly_wait(v->poly, v->regnames[regnum]);
v->reg[regnum].u = data;
v->fbi.cmdfifo[0].base = (data & 0x3ff) << 12;
v->fbi.cmdfifo[0].end = (((data >> 16) & 0x3ff) + 1) << 12;
}
break;
case cmdFifoBump:
if (v->type == VOODOO_2 && (chips & 1))
fatalerror("cmdFifoBump");
break;
case cmdFifoRdPtr:
if (v->type == VOODOO_2 && (chips & 1))
v->fbi.cmdfifo[0].rdptr = data;
break;
case cmdFifoAMin:
/* case colBufferAddr: -- Banshee */
if (v->type == VOODOO_2 && (chips & 1))
v->fbi.cmdfifo[0].amin = data;
else if (v->type >= VOODOO_BANSHEE && (chips & 1))
v->fbi.rgboffs[1] = data & v->fbi.mask & ~0x0f;
break;
case cmdFifoAMax:
/* case colBufferStride: -- Banshee */
if (v->type == VOODOO_2 && (chips & 1))
v->fbi.cmdfifo[0].amax = data;
else if (v->type >= VOODOO_BANSHEE && (chips & 1))
{
if (data & 0x8000)
v->fbi.rowpixels = (data & 0x7f) << 6;
else
v->fbi.rowpixels = (data & 0x3fff) >> 1;
}
break;
case cmdFifoDepth:
/* case auxBufferAddr: -- Banshee */
if (v->type == VOODOO_2 && (chips & 1))
v->fbi.cmdfifo[0].depth = data;
else if (v->type >= VOODOO_BANSHEE && (chips & 1))
v->fbi.auxoffs = data & v->fbi.mask & ~0x0f;
break;
case cmdFifoHoles:
/* case auxBufferStride: -- Banshee */
if (v->type == VOODOO_2 && (chips & 1))
v->fbi.cmdfifo[0].holes = data;
else if (v->type >= VOODOO_BANSHEE && (chips & 1))
{
int rowpixels;
if (data & 0x8000)
rowpixels = (data & 0x7f) << 6;
else
rowpixels = (data & 0x3fff) >> 1;
if (v->fbi.rowpixels != rowpixels)
fatalerror("aux buffer stride differs from color buffer stride");
}
break;
/* nccTable entries are processed and expanded immediately */
case nccTable+0:
case nccTable+1:
case nccTable+2:
case nccTable+3:
case nccTable+4:
case nccTable+5:
case nccTable+6:
case nccTable+7:
case nccTable+8:
case nccTable+9:
case nccTable+10:
case nccTable+11:
poly_wait(v->poly, v->regnames[regnum]);
if (chips & 2) ncc_table_write(&v->tmu[0].ncc[0], regnum - nccTable, data);
if (chips & 4) ncc_table_write(&v->tmu[1].ncc[0], regnum - nccTable, data);
break;
case nccTable+12:
case nccTable+13:
case nccTable+14:
case nccTable+15:
case nccTable+16:
case nccTable+17:
case nccTable+18:
case nccTable+19:
case nccTable+20:
case nccTable+21:
case nccTable+22:
case nccTable+23:
poly_wait(v->poly, v->regnames[regnum]);
if (chips & 2) ncc_table_write(&v->tmu[0].ncc[1], regnum - (nccTable+12), data);
if (chips & 4) ncc_table_write(&v->tmu[1].ncc[1], regnum - (nccTable+12), data);
break;
/* fogTable entries are processed and expanded immediately */
case fogTable+0:
case fogTable+1:
case fogTable+2:
case fogTable+3:
case fogTable+4:
case fogTable+5:
case fogTable+6:
case fogTable+7:
case fogTable+8:
case fogTable+9:
case fogTable+10:
case fogTable+11:
case fogTable+12:
case fogTable+13:
case fogTable+14:
case fogTable+15:
case fogTable+16:
case fogTable+17:
case fogTable+18:
case fogTable+19:
case fogTable+20:
case fogTable+21:
case fogTable+22:
case fogTable+23:
case fogTable+24:
case fogTable+25:
case fogTable+26:
case fogTable+27:
case fogTable+28:
case fogTable+29:
case fogTable+30:
case fogTable+31:
poly_wait(v->poly, v->regnames[regnum]);
if (chips & 1)
{
int base = 2 * (regnum - fogTable);
v->fbi.fogdelta[base + 0] = (data >> 0) & 0xff;
v->fbi.fogblend[base + 0] = (data >> 8) & 0xff;
v->fbi.fogdelta[base + 1] = (data >> 16) & 0xff;
v->fbi.fogblend[base + 1] = (data >> 24) & 0xff;
}
break;
/* texture modifications cause us to recompute everything */
case textureMode:
case tLOD:
case tDetail:
case texBaseAddr:
case texBaseAddr_1:
case texBaseAddr_2:
case texBaseAddr_3_8:
poly_wait(v->poly, v->regnames[regnum]);
if (chips & 2)
{
v->tmu[0].reg[regnum].u = data;
v->tmu[0].regdirty = TRUE;
}
if (chips & 4)
{
v->tmu[1].reg[regnum].u = data;
v->tmu[1].regdirty = TRUE;
}
break;
/* these registers are referenced in the renderer; we must wait for pending work before changing */
case chromaRange:
case chromaKey:
case alphaMode:
case fogColor:
case stipple:
case zaColor:
case color1:
case color0:
case clipLowYHighY:
case clipLeftRight:
poly_wait(v->poly, v->regnames[regnum]);
/* fall through to default implementation */
/* by default, just feed the data to the chips */
default:
if (chips & 1) v->reg[0x000 + regnum].u = data;
if (chips & 2) v->reg[0x100 + regnum].u = data;
if (chips & 4) v->reg[0x200 + regnum].u = data;
if (chips & 8) v->reg[0x300 + regnum].u = data;
break;
}
if (LOG_REGISTERS)
{
if (regnum < fvertexAx || regnum > fdWdY)
logerror("VOODOO.%d.REG:%s(%d) write = %08X\n", v->index, (regnum < 0x384/4) ? v->regnames[regnum] : "oob", chips, origdata);
else
logerror("VOODOO.%d.REG:%s(%d) write = %f\n", v->index, (regnum < 0x384/4) ? v->regnames[regnum] : "oob", chips, u2f(origdata));
}
return cycles;
}
/*************************************
*
* Voodoo LFB writes
*
*************************************/
static INT32 lfb_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask, int forcefront)
{
UINT16 *dest, *depth;
UINT32 destmax, depthmax;
int sr[2], sg[2], sb[2], sa[2], sw[2];
int x, y, scry, mask;
int pix, destbuf;
/* statistics */
v->stats.lfb_writes++;
/* byte swizzling */
if (LFBMODE_BYTE_SWIZZLE_WRITES(v->reg[lfbMode].u))
{
data = FLIPENDIAN_INT32(data);
mem_mask = FLIPENDIAN_INT32(mem_mask);
}
/* word swapping */
if (LFBMODE_WORD_SWAP_WRITES(v->reg[lfbMode].u))
{
data = (data << 16) | (data >> 16);
mem_mask = (mem_mask << 16) | (mem_mask >> 16);
}
/* extract default depth and alpha values */
sw[0] = sw[1] = v->reg[zaColor].u & 0xffff;
sa[0] = sa[1] = v->reg[zaColor].u >> 24;
/* first extract A,R,G,B from the data */
switch (LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u) + 16 * LFBMODE_RGBA_LANES(v->reg[lfbMode].u))
{
case 16*0 + 0: /* ARGB, 16-bit RGB 5-6-5 */
case 16*2 + 0: /* RGBA, 16-bit RGB 5-6-5 */
EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]);
EXTRACT_565_TO_888(data >> 16, sr[1], sg[1], sb[1]);
mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
offset <<= 1;
break;
case 16*1 + 0: /* ABGR, 16-bit RGB 5-6-5 */
case 16*3 + 0: /* BGRA, 16-bit RGB 5-6-5 */
EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]);
EXTRACT_565_TO_888(data >> 16, sb[1], sg[1], sr[1]);
mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
offset <<= 1;
break;
case 16*0 + 1: /* ARGB, 16-bit RGB x-5-5-5 */
EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]);
EXTRACT_x555_TO_888(data >> 16, sr[1], sg[1], sb[1]);
mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
offset <<= 1;
break;
case 16*1 + 1: /* ABGR, 16-bit RGB x-5-5-5 */
EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]);
EXTRACT_x555_TO_888(data >> 16, sb[1], sg[1], sr[1]);
mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
offset <<= 1;
break;
case 16*2 + 1: /* RGBA, 16-bit RGB x-5-5-5 */
EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]);
EXTRACT_555x_TO_888(data >> 16, sr[1], sg[1], sb[1]);
mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
offset <<= 1;
break;
case 16*3 + 1: /* BGRA, 16-bit RGB x-5-5-5 */
EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]);
EXTRACT_555x_TO_888(data >> 16, sb[1], sg[1], sr[1]);
mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
offset <<= 1;
break;
case 16*0 + 2: /* ARGB, 16-bit ARGB 1-5-5-5 */
EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
EXTRACT_1555_TO_8888(data >> 16, sa[1], sr[1], sg[1], sb[1]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
offset <<= 1;
break;
case 16*1 + 2: /* ABGR, 16-bit ARGB 1-5-5-5 */
EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
EXTRACT_1555_TO_8888(data >> 16, sa[1], sb[1], sg[1], sr[1]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
offset <<= 1;
break;
case 16*2 + 2: /* RGBA, 16-bit ARGB 1-5-5-5 */
EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
EXTRACT_5551_TO_8888(data >> 16, sr[1], sg[1], sb[1], sa[1]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
offset <<= 1;
break;
case 16*3 + 2: /* BGRA, 16-bit ARGB 1-5-5-5 */
EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
EXTRACT_5551_TO_8888(data >> 16, sb[1], sg[1], sr[1], sa[1]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
offset <<= 1;
break;
case 16*0 + 4: /* ARGB, 32-bit RGB x-8-8-8 */
EXTRACT_x888_TO_888(data, sr[0], sg[0], sb[0]);
mask = LFB_RGB_PRESENT;
break;
case 16*1 + 4: /* ABGR, 32-bit RGB x-8-8-8 */
EXTRACT_x888_TO_888(data, sb[0], sg[0], sr[0]);
mask = LFB_RGB_PRESENT;
break;
case 16*2 + 4: /* RGBA, 32-bit RGB x-8-8-8 */
EXTRACT_888x_TO_888(data, sr[0], sg[0], sb[0]);
mask = LFB_RGB_PRESENT;
break;
case 16*3 + 4: /* BGRA, 32-bit RGB x-8-8-8 */
EXTRACT_888x_TO_888(data, sb[0], sg[0], sr[0]);
mask = LFB_RGB_PRESENT;
break;
case 16*0 + 5: /* ARGB, 32-bit ARGB 8-8-8-8 */
EXTRACT_8888_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
break;
case 16*1 + 5: /* ABGR, 32-bit ARGB 8-8-8-8 */
EXTRACT_8888_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
break;
case 16*2 + 5: /* RGBA, 32-bit ARGB 8-8-8-8 */
EXTRACT_8888_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
break;
case 16*3 + 5: /* BGRA, 32-bit ARGB 8-8-8-8 */
EXTRACT_8888_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
break;
case 16*0 + 12: /* ARGB, 32-bit depth+RGB 5-6-5 */
case 16*2 + 12: /* RGBA, 32-bit depth+RGB 5-6-5 */
sw[0] = data >> 16;
EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]);
mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
break;
case 16*1 + 12: /* ABGR, 32-bit depth+RGB 5-6-5 */
case 16*3 + 12: /* BGRA, 32-bit depth+RGB 5-6-5 */
sw[0] = data >> 16;
EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]);
mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
break;
case 16*0 + 13: /* ARGB, 32-bit depth+RGB x-5-5-5 */
sw[0] = data >> 16;
EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]);
mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
break;
case 16*1 + 13: /* ABGR, 32-bit depth+RGB x-5-5-5 */
sw[0] = data >> 16;
EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]);
mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
break;
case 16*2 + 13: /* RGBA, 32-bit depth+RGB x-5-5-5 */
sw[0] = data >> 16;
EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]);
mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
break;
case 16*3 + 13: /* BGRA, 32-bit depth+RGB x-5-5-5 */
sw[0] = data >> 16;
EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]);
mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
break;
case 16*0 + 14: /* ARGB, 32-bit depth+ARGB 1-5-5-5 */
sw[0] = data >> 16;
EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
break;
case 16*1 + 14: /* ABGR, 32-bit depth+ARGB 1-5-5-5 */
sw[0] = data >> 16;
EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
break;
case 16*2 + 14: /* RGBA, 32-bit depth+ARGB 1-5-5-5 */
sw[0] = data >> 16;
EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
break;
case 16*3 + 14: /* BGRA, 32-bit depth+ARGB 1-5-5-5 */
sw[0] = data >> 16;
EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
break;
case 16*0 + 15: /* ARGB, 16-bit depth */
case 16*1 + 15: /* ARGB, 16-bit depth */
case 16*2 + 15: /* ARGB, 16-bit depth */
case 16*3 + 15: /* ARGB, 16-bit depth */
sw[0] = data & 0xffff;
sw[1] = data >> 16;
mask = LFB_DEPTH_PRESENT | (LFB_DEPTH_PRESENT << 4);
offset <<= 1;
break;
default: /* reserved */
return 0;
}
/* compute X,Y */
x = (offset << 0) & ((1 << v->fbi.lfb_stride) - 1);
y = (offset >> v->fbi.lfb_stride) & ((1 << v->fbi.lfb_stride) - 1);
/* adjust the mask based on which half of the data is written */
if (!ACCESSING_BITS_0_15)
mask &= ~(0x0f - LFB_DEPTH_PRESENT_MSW);
if (!ACCESSING_BITS_16_31)
mask &= ~(0xf0 + LFB_DEPTH_PRESENT_MSW);
/* select the target buffer */
destbuf = (v->type >= VOODOO_BANSHEE) ? (!forcefront) : LFBMODE_WRITE_BUFFER_SELECT(v->reg[lfbMode].u);
switch (destbuf)
{
case 0: /* front buffer */
dest = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
destmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.frontbuf]) / 2;
v->fbi.video_changed = TRUE;
break;
case 1: /* back buffer */
dest = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
destmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.backbuf]) / 2;
break;
default: /* reserved */
return 0;
}
depth = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs);
depthmax = (v->fbi.mask + 1 - v->fbi.auxoffs) / 2;
/* wait for any outstanding work to finish */
poly_wait(v->poly, "LFB Write");
/* simple case: no pipeline */
if (!LFBMODE_ENABLE_PIXEL_PIPELINE(v->reg[lfbMode].u))
{
DECLARE_DITHER_POINTERS;
UINT32 bufoffs;
if (LOG_LFB) logerror("VOODOO.%d.LFB:write raw mode %X (%d,%d) = %08X & %08X\n", v->index, LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u), x, y, data, mem_mask);
/* determine the screen Y */
scry = y;
if (LFBMODE_Y_ORIGIN(v->reg[lfbMode].u))
scry = (v->fbi.yorigin - y) & 0x3ff;
/* advance pointers to the proper row */
bufoffs = scry * v->fbi.rowpixels + x;
/* compute dithering */
COMPUTE_DITHER_POINTERS(v->reg[fbzMode].u, y);
/* loop over up to two pixels */
for (pix = 0; mask; pix++)
{
/* make sure we care about this pixel */
if (mask & 0x0f)
{
/* write to the RGB buffer */
if ((mask & LFB_RGB_PRESENT) && bufoffs < destmax)
{
/* apply dithering and write to the screen */
APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, sr[pix], sg[pix], sb[pix]);
dest[bufoffs] = (sr[pix] << 11) | (sg[pix] << 5) | sb[pix];
}
/* make sure we have an aux buffer to write to */
if (depth && bufoffs < depthmax)
{
/* write to the alpha buffer */
if ((mask & LFB_ALPHA_PRESENT) && FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u))
depth[bufoffs] = sa[pix];
/* write to the depth buffer */
if ((mask & (LFB_DEPTH_PRESENT | LFB_DEPTH_PRESENT_MSW)) && !FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u))
depth[bufoffs] = sw[pix];
}
/* track pixel writes to the frame buffer regardless of mask */
v->reg[fbiPixelsOut].u++;
}
/* advance our pointers */
bufoffs++;
x++;
mask >>= 4;
}
}
/* tricky case: run the full pixel pipeline on the pixel */
else
{
DECLARE_DITHER_POINTERS;
if (LOG_LFB) logerror("VOODOO.%d.LFB:write pipelined mode %X (%d,%d) = %08X & %08X\n", v->index, LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u), x, y, data, mem_mask);
/* determine the screen Y */
scry = y;
if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
scry = (v->fbi.yorigin - y) & 0x3ff;
/* advance pointers to the proper row */
dest += scry * v->fbi.rowpixels;
if (depth)
depth += scry * v->fbi.rowpixels;
/* compute dithering */
COMPUTE_DITHER_POINTERS(v->reg[fbzMode].u, y);
/* loop over up to two pixels */
for (pix = 0; mask; pix++)
{
/* make sure we care about this pixel */
if (mask & 0x0f)
{
stats_block *stats = &v->fbi.lfb_stats;
INT64 iterw = sw[pix] << (30-16);
INT32 iterz = sw[pix] << 12;
rgb_union color;
/* apply clipping */
if (FBZMODE_ENABLE_CLIPPING(v->reg[fbzMode].u))
{
if (x < ((v->reg[clipLeftRight].u >> 16) & 0x3ff) ||
x >= (v->reg[clipLeftRight].u & 0x3ff) ||
scry < ((v->reg[clipLowYHighY].u >> 16) & 0x3ff) ||
scry >= (v->reg[clipLowYHighY].u & 0x3ff))
{
stats->pixels_in++;
stats->clip_fail++;
goto nextpixel;
}
}
/* pixel pipeline part 1 handles depth testing and stippling */
PIXEL_PIPELINE_BEGIN(v, stats, x, y, v->reg[fbzColorPath].u, v->reg[fbzMode].u, iterz, iterw);
/* use the RGBA we stashed above */
color.rgb.r = r = sr[pix];
color.rgb.g = g = sg[pix];
color.rgb.b = b = sb[pix];
color.rgb.a = a = sa[pix];
/* apply chroma key, alpha mask, and alpha testing */
APPLY_CHROMAKEY(v, stats, v->reg[fbzMode].u, color);
APPLY_ALPHAMASK(v, stats, v->reg[fbzMode].u, color.rgb.a);
APPLY_ALPHATEST(v, stats, v->reg[alphaMode].u, color.rgb.a);
/* pixel pipeline part 2 handles color combine, fog, alpha, and final output */
PIXEL_PIPELINE_END(v, stats, dither, dither4, dither_lookup, x, dest, depth, v->reg[fbzMode].u, v->reg[fbzColorPath].u, v->reg[alphaMode].u, v->reg[fogMode].u, iterz, iterw, v->reg[zaColor]);
}
nextpixel:
/* advance our pointers */
x++;
mask >>= 4;
}
}
return 0;
}
/*************************************
*
* Voodoo texture RAM writes
*
*************************************/
static INT32 texture_w(voodoo_state *v, offs_t offset, UINT32 data)
{
int tmunum = (offset >> 19) & 0x03;
tmu_state *t;
/* statistics */
v->stats.tex_writes++;
/* point to the right TMU */
if (!(v->chipmask & (2 << tmunum)))
return 0;
t = &v->tmu[tmunum];
if (TEXLOD_TDIRECT_WRITE(t->reg[tLOD].u))
fatalerror("Texture direct write!");
/* wait for any outstanding work to finish */
poly_wait(v->poly, "Texture write");
/* update texture info if dirty */
if (t->regdirty)
recompute_texture_params(t);
/* swizzle the data */
if (TEXLOD_TDATA_SWIZZLE(t->reg[tLOD].u))
data = FLIPENDIAN_INT32(data);
if (TEXLOD_TDATA_SWAP(t->reg[tLOD].u))
data = (data >> 16) | (data << 16);
/* 8-bit texture case */
if (TEXMODE_FORMAT(t->reg[textureMode].u) < 8)
{
int lod, tt, ts;
UINT32 tbaseaddr;
UINT8 *dest;
/* extract info */
if (v->type <= VOODOO_2)
{
lod = (offset >> 15) & 0x0f;
tt = (offset >> 7) & 0xff;
/* old code has a bit about how this is broken in gauntleg unless we always look at TMU0 */
if (TEXMODE_SEQ_8_DOWNLD(v->tmu[0].reg/*t->reg*/[textureMode].u))
ts = (offset << 2) & 0xfc;
else
ts = (offset << 1) & 0xfc;
/* validate parameters */
if (lod > 8)
return 0;
/* compute the base address */
tbaseaddr = t->lodoffset[lod];
tbaseaddr += tt * ((t->wmask >> lod) + 1) + ts;
if (LOG_TEXTURE_RAM) logerror("Texture 8-bit w: lod=%d s=%d t=%d data=%08X\n", lod, ts, tt, data);
}
else
{
tbaseaddr = t->lodoffset[0] + offset*4;
if (LOG_TEXTURE_RAM) logerror("Texture 16-bit w: offset=%X data=%08X\n", offset*4, data);
}
/* write the four bytes in little-endian order */
dest = t->ram;
tbaseaddr &= t->mask;
dest[BYTE4_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xff;
dest[BYTE4_XOR_LE(tbaseaddr + 1)] = (data >> 8) & 0xff;
dest[BYTE4_XOR_LE(tbaseaddr + 2)] = (data >> 16) & 0xff;
dest[BYTE4_XOR_LE(tbaseaddr + 3)] = (data >> 24) & 0xff;
}
/* 16-bit texture case */
else
{
int lod, tt, ts;
UINT32 tbaseaddr;
UINT16 *dest;
/* extract info */
if (v->type <= VOODOO_2)
{
tmunum = (offset >> 19) & 0x03;
lod = (offset >> 15) & 0x0f;
tt = (offset >> 7) & 0xff;
ts = (offset << 1) & 0xfe;
/* validate parameters */
if (lod > 8)
return 0;
/* compute the base address */
tbaseaddr = t->lodoffset[lod];
tbaseaddr += 2 * (tt * ((t->wmask >> lod) + 1) + ts);
if (LOG_TEXTURE_RAM) logerror("Texture 16-bit w: lod=%d s=%d t=%d data=%08X\n", lod, ts, tt, data);
}
else
{
tbaseaddr = t->lodoffset[0] + offset*4;
if (LOG_TEXTURE_RAM) logerror("Texture 16-bit w: offset=%X data=%08X\n", offset*4, data);
}
/* write the two words in little-endian order */
dest = (UINT16 *)t->ram;
tbaseaddr &= t->mask;
tbaseaddr >>= 1;
dest[BYTE_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xffff;
dest[BYTE_XOR_LE(tbaseaddr + 1)] = (data >> 16) & 0xffff;
}
return 0;
}
/*************************************
*
* Flush data from the FIFOs
*
*************************************/
static void flush_fifos(voodoo_state *v, attotime current_time)
{
static UINT8 in_flush;
/* check for recursive calls */
if (in_flush)
return;
in_flush = TRUE;
if (!v->pci.op_pending) fatalerror("flush_fifos called with no pending operation");
if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos start -- pending=%d.%08X%08X cur=%d.%08X%08X\n", v->index,
v->pci.op_end_time.seconds, (UINT32)(v->pci.op_end_time.attoseconds >> 32), (UINT32)v->pci.op_end_time.attoseconds,
current_time.seconds, (UINT32)(current_time.attoseconds >> 32), (UINT32)current_time.attoseconds);
/* loop while we still have cycles to burn */
while (v->pci.op_end_time <= current_time)
{
INT32 extra_cycles = 0;
INT32 cycles;
/* loop over 0-cycle stuff; this constitutes the bulk of our writes */
do
{
fifo_state *fifo;
UINT32 address;
UINT32 data;
/* we might be in CMDFIFO mode */
if (v->fbi.cmdfifo[0].enable)
{
/* if we don't have anything to execute, we're done for now */
cycles = cmdfifo_execute_if_ready(v, &v->fbi.cmdfifo[0]);
if (cycles == -1)
{
v->pci.op_pending = FALSE;
in_flush = FALSE;
if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- CMDFIFO empty\n", v->index);
return;
}
}
else if (v->fbi.cmdfifo[1].enable)
{
/* if we don't have anything to execute, we're done for now */
cycles = cmdfifo_execute_if_ready(v, &v->fbi.cmdfifo[1]);
if (cycles == -1)
{
v->pci.op_pending = FALSE;
in_flush = FALSE;
if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- CMDFIFO empty\n", v->index);
return;
}
}
/* else we are in standard PCI/memory FIFO mode */
else
{
/* choose which FIFO to read from */
if (!fifo_empty(&v->fbi.fifo))
fifo = &v->fbi.fifo;
else if (!fifo_empty(&v->pci.fifo))
fifo = &v->pci.fifo;
else
{
v->pci.op_pending = FALSE;
in_flush = FALSE;
if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- FIFOs empty\n", v->index);
return;
}
/* extract address and data */
address = fifo_remove(fifo);
data = fifo_remove(fifo);
/* target the appropriate location */
if ((address & (0xc00000/4)) == 0)
cycles = register_w(v, address, data);
else if (address & (0x800000/4))
cycles = texture_w(v, address, data);
else
{
UINT32 mem_mask = 0xffffffff;
/* compute mem_mask */
if (address & 0x80000000)
mem_mask &= 0x0000ffff;
if (address & 0x40000000)
mem_mask &= 0xffff0000;
address &= 0xffffff;
cycles = lfb_w(v, address, data, mem_mask, FALSE);
}
}
/* accumulate smaller operations */
if (cycles < ACCUMULATE_THRESHOLD)
{
extra_cycles += cycles;
cycles = 0;
}
}
while (cycles == 0);
/* account for extra cycles */
cycles += extra_cycles;
/* account for those cycles */
v->pci.op_end_time += attotime(0, (attoseconds_t)cycles * v->attoseconds_per_cycle);
if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:update -- pending=%d.%08X%08X cur=%d.%08X%08X\n", v->index,
v->pci.op_end_time.seconds, (UINT32)(v->pci.op_end_time.attoseconds >> 32), (UINT32)v->pci.op_end_time.attoseconds,
current_time.seconds, (UINT32)(current_time.attoseconds >> 32), (UINT32)current_time.attoseconds);
}
if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- pending command complete at %d.%08X%08X\n", v->index,
v->pci.op_end_time.seconds, (UINT32)(v->pci.op_end_time.attoseconds >> 32), (UINT32)v->pci.op_end_time.attoseconds);
in_flush = FALSE;
}
/*************************************
*
* Handle a write to the Voodoo
* memory space
*
*************************************/
WRITE32_DEVICE_HANDLER( voodoo_w )
{
voodoo_state *v = get_safe_token(device);
int stall = FALSE;
g_profiler.start(PROFILER_USER1);
/* should not be getting accesses while stalled */
if (v->pci.stall_state != NOT_STALLED)
logerror("voodoo_w while stalled!\n");
/* if we have something pending, flush the FIFOs up to the current time */
if (v->pci.op_pending)
flush_fifos(v, device->machine->time());
/* special handling for registers */
if ((offset & 0xc00000/4) == 0)
{
UINT8 access;
/* some special stuff for Voodoo 2 */
if (v->type >= VOODOO_2)
{
/* we might be in CMDFIFO mode */
if (FBIINIT7_CMDFIFO_ENABLE(v->reg[fbiInit7].u))
{
/* if bit 21 is set, we're writing to the FIFO */
if (offset & 0x200000/4)
{
/* check for byte swizzling (bit 18) */
if (offset & 0x40000/4)
data = FLIPENDIAN_INT32(data);
cmdfifo_w(v, &v->fbi.cmdfifo[0], offset & 0xffff, data);
g_profiler.stop();
return;
}
/* we're a register access; but only certain ones are allowed */
access = v->regaccess[offset & 0xff];
if (!(access & REGISTER_WRITETHRU))
{
/* track swap buffers regardless */
if ((offset & 0xff) == swapbufferCMD)
v->fbi.swaps_pending++;
logerror("Ignoring write to %s in CMDFIFO mode\n", v->regnames[offset & 0xff]);
g_profiler.stop();
return;
}
}
/* if not, we might be byte swizzled (bit 20) */
else if (offset & 0x100000/4)
data = FLIPENDIAN_INT32(data);
}
/* check the access behavior; note that the table works even if the */
/* alternate mapping is used */
access = v->regaccess[offset & 0xff];
/* ignore if writes aren't allowed */
if (!(access & REGISTER_WRITE))
{
g_profiler.stop();
return;
}
/* if this is a non-FIFO command, let it go to the FIFO, but stall until it completes */
if (!(access & REGISTER_FIFO))
stall = TRUE;
/* track swap buffers */
if ((offset & 0xff) == swapbufferCMD)
v->fbi.swaps_pending++;
}
/* if we don't have anything pending, or if FIFOs are disabled, just execute */
if (!v->pci.op_pending || !INITEN_ENABLE_PCI_FIFO(v->pci.init_enable))
{
int cycles;
/* target the appropriate location */
if ((offset & (0xc00000/4)) == 0)
cycles = register_w(v, offset, data);
else if (offset & (0x800000/4))
cycles = texture_w(v, offset, data);
else
cycles = lfb_w(v, offset, data, mem_mask, FALSE);
/* if we ended up with cycles, mark the operation pending */
if (cycles)
{
v->pci.op_pending = TRUE;
v->pci.op_end_time = device->machine->time() + attotime(0, (attoseconds_t)cycles * v->attoseconds_per_cycle);
if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:direct write start at %d.%08X%08X end at %d.%08X%08X\n", v->index,
device->machine->time().seconds, (UINT32)(device->machine->time().attoseconds >> 32), (UINT32)device->machine->time().attoseconds,
v->pci.op_end_time.seconds, (UINT32)(v->pci.op_end_time.attoseconds >> 32), (UINT32)v->pci.op_end_time.attoseconds);
}
g_profiler.stop();
return;
}
/* modify the offset based on the mem_mask */
if (mem_mask != 0xffffffff)
{
if (!ACCESSING_BITS_16_31)
offset |= 0x80000000;
if (!ACCESSING_BITS_0_15)
offset |= 0x40000000;
}
/* if there's room in the PCI FIFO, add there */
if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:voodoo_w adding to PCI FIFO @ %08X=%08X\n", v->index, offset, data);
if (!fifo_full(&v->pci.fifo))
{
fifo_add(&v->pci.fifo, offset);
fifo_add(&v->pci.fifo, data);
}
else
fatalerror("PCI FIFO full");
/* handle flushing to the memory FIFO */
if (FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u) &&
fifo_space(&v->pci.fifo) <= 2 * FBIINIT4_MEMORY_FIFO_LWM(v->reg[fbiInit4].u))
{
UINT8 valid[4];
/* determine which types of data can go to the memory FIFO */
valid[0] = TRUE;
valid[1] = FBIINIT0_LFB_TO_MEMORY_FIFO(v->reg[fbiInit0].u);
valid[2] = valid[3] = FBIINIT0_TEXMEM_TO_MEMORY_FIFO(v->reg[fbiInit0].u);
/* flush everything we can */
if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:voodoo_w moving PCI FIFO to memory FIFO\n", v->index);
while (!fifo_empty(&v->pci.fifo) && valid[(fifo_peek(&v->pci.fifo) >> 22) & 3])
{
fifo_add(&v->fbi.fifo, fifo_remove(&v->pci.fifo));
fifo_add(&v->fbi.fifo, fifo_remove(&v->pci.fifo));
}
/* if we're above the HWM as a result, stall */
if (FBIINIT0_STALL_PCIE_FOR_HWM(v->reg[fbiInit0].u) &&
fifo_items(&v->fbi.fifo) >= 2 * 32 * FBIINIT0_MEMORY_FIFO_HWM(v->reg[fbiInit0].u))
{
if (LOG_FIFO) logerror("VOODOO.%d.FIFO:voodoo_w hit memory FIFO HWM -- stalling\n", v->index);
stall_cpu(v, STALLED_UNTIL_FIFO_LWM, device->machine->time());
}
}
/* if we're at the LWM for the PCI FIFO, stall */
if (FBIINIT0_STALL_PCIE_FOR_HWM(v->reg[fbiInit0].u) &&
fifo_space(&v->pci.fifo) <= 2 * FBIINIT0_PCI_FIFO_LWM(v->reg[fbiInit0].u))
{
if (LOG_FIFO) logerror("VOODOO.%d.FIFO:voodoo_w hit PCI FIFO free LWM -- stalling\n", v->index);
stall_cpu(v, STALLED_UNTIL_FIFO_LWM, device->machine->time());
}
/* if we weren't ready, and this is a non-FIFO access, stall until the FIFOs are clear */
if (stall)
{
if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:voodoo_w wrote non-FIFO register -- stalling until clear\n", v->index);
stall_cpu(v, STALLED_UNTIL_FIFO_EMPTY, device->machine->time());
}
g_profiler.stop();
}
/*************************************
*
* Handle a register read
*
*************************************/
static UINT32 register_r(voodoo_state *v, offs_t offset)
{
int regnum = offset & 0xff;
UINT32 result;
/* statistics */
v->stats.reg_reads++;
/* first make sure this register is readable */
if (!(v->regaccess[regnum] & REGISTER_READ))
{
logerror("VOODOO.%d.ERROR:Invalid attempt to read %s\n", v->index, v->regnames[regnum]);
return 0xffffffff;
}
/* default result is the FBI register value */
result = v->reg[regnum].u;
/* some registers are dynamic; compute them */
switch (regnum)
{
case status:
/* start with a blank slate */
result = 0;
/* bits 5:0 are the PCI FIFO free space */
if (fifo_empty(&v->pci.fifo))
result |= 0x3f << 0;
else
{
int temp = fifo_space(&v->pci.fifo)/2;
if (temp > 0x3f)
temp = 0x3f;
result |= temp << 0;
}
/* bit 6 is the vertical retrace */
result |= v->fbi.vblank << 6;
/* bit 7 is FBI graphics engine busy */
if (v->pci.op_pending)
result |= 1 << 7;
/* bit 8 is TREX busy */
if (v->pci.op_pending)
result |= 1 << 8;
/* bit 9 is overall busy */
if (v->pci.op_pending)
result |= 1 << 9;
/* Banshee is different starting here */
if (v->type < VOODOO_BANSHEE)
{
/* bits 11:10 specifies which buffer is visible */
result |= v->fbi.frontbuf << 10;
/* bits 27:12 indicate memory FIFO freespace */
if (!FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u) || fifo_empty(&v->fbi.fifo))
result |= 0xffff << 12;
else
{
int temp = fifo_space(&v->fbi.fifo)/2;
if (temp > 0xffff)
temp = 0xffff;
result |= temp << 12;
}
}
else
{
/* bit 10 is 2D busy */
/* bit 11 is cmd FIFO 0 busy */
if (v->fbi.cmdfifo[0].enable && v->fbi.cmdfifo[0].depth > 0)
result |= 1 << 11;
/* bit 12 is cmd FIFO 1 busy */
if (v->fbi.cmdfifo[1].enable && v->fbi.cmdfifo[1].depth > 0)
result |= 1 << 12;
}
/* bits 30:28 are the number of pending swaps */
if (v->fbi.swaps_pending > 7)
result |= 7 << 28;
else
result |= v->fbi.swaps_pending << 28;
/* bit 31 is not used */
/* eat some cycles since people like polling here */
device_eat_cycles(v->cpu, 1000);
break;
/* bit 2 of the initEnable register maps this to dacRead */
case fbiInit2:
if (INITEN_REMAP_INIT_TO_DAC(v->pci.init_enable))
result = v->dac.read_result;
break;
/* return the current scanline for now */
case vRetrace:
/* eat some cycles since people like polling here */
device_eat_cycles(v->cpu, 10);
result = v->screen->vpos();
break;
/* reserved area in the TMU read by the Vegas startup sequence */
case hvRetrace:
result = 0x200 << 16; /* should be between 0x7b and 0x267 */
result |= 0x80; /* should be between 0x17 and 0x103 */
break;
/* cmdFifo -- Voodoo2 only */
case cmdFifoRdPtr:
result = v->fbi.cmdfifo[0].rdptr;
/* eat some cycles since people like polling here */
device_eat_cycles(v->cpu, 1000);
break;
case cmdFifoAMin:
result = v->fbi.cmdfifo[0].amin;
break;
case cmdFifoAMax:
result = v->fbi.cmdfifo[0].amax;
break;
case cmdFifoDepth:
result = v->fbi.cmdfifo[0].depth;
break;
case cmdFifoHoles:
result = v->fbi.cmdfifo[0].holes;
break;
/* all counters are 24-bit only */
case fbiPixelsIn:
case fbiChromaFail:
case fbiZfuncFail:
case fbiAfuncFail:
case fbiPixelsOut:
update_statistics(v, TRUE);
case fbiTrianglesOut:
result = v->reg[regnum].u & 0xffffff;
break;
}
if (LOG_REGISTERS)
{
int logit = TRUE;
/* don't log multiple identical status reads from the same address */
if (regnum == status)
{
offs_t pc = cpu_get_pc(v->cpu);
if (pc == v->last_status_pc && result == v->last_status_value)
logit = FALSE;
v->last_status_pc = pc;
v->last_status_value = result;
}
if (regnum == cmdFifoRdPtr)
logit = FALSE;
if (logit)
logerror("VOODOO.%d.REG:%s read = %08X\n", v->index, v->regnames[regnum], result);
}
return result;
}
/*************************************
*
* Handle an LFB read
*
*************************************/
static UINT32 lfb_r(voodoo_state *v, offs_t offset, int forcefront)
{
UINT16 *buffer;
UINT32 bufmax;
UINT32 bufoffs;
UINT32 data;
int x, y, scry, destbuf;
/* statistics */
v->stats.lfb_reads++;
/* compute X,Y */
x = (offset << 1) & 0x3fe;
y = (offset >> 9) & 0x3ff;
/* select the target buffer */
destbuf = (v->type >= VOODOO_BANSHEE) ? (!forcefront) : LFBMODE_READ_BUFFER_SELECT(v->reg[lfbMode].u);
switch (destbuf)
{
case 0: /* front buffer */
buffer = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
bufmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.frontbuf]) / 2;
break;
case 1: /* back buffer */
buffer = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
bufmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.backbuf]) / 2;
break;
case 2: /* aux buffer */
if (v->fbi.auxoffs == ~0)
return 0xffffffff;
buffer = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs);
bufmax = (v->fbi.mask + 1 - v->fbi.auxoffs) / 2;
break;
default: /* reserved */
return 0xffffffff;
}
/* determine the screen Y */
scry = y;
if (LFBMODE_Y_ORIGIN(v->reg[lfbMode].u))
scry = (v->fbi.yorigin - y) & 0x3ff;
/* advance pointers to the proper row */
bufoffs = scry * v->fbi.rowpixels + x;
if (bufoffs >= bufmax)
return 0xffffffff;
/* wait for any outstanding work to finish */
poly_wait(v->poly, "LFB read");
/* compute the data */
data = buffer[bufoffs + 0] | (buffer[bufoffs + 1] << 16);
/* word swapping */
if (LFBMODE_WORD_SWAP_READS(v->reg[lfbMode].u))
data = (data << 16) | (data >> 16);
/* byte swizzling */
if (LFBMODE_BYTE_SWIZZLE_READS(v->reg[lfbMode].u))
data = FLIPENDIAN_INT32(data);
if (LOG_LFB) logerror("VOODOO.%d.LFB:read (%d,%d) = %08X\n", v->index, x, y, data);
return data;
}
/*************************************
*
* Handle a read from the Voodoo
* memory space
*
*************************************/
READ32_DEVICE_HANDLER( voodoo_r )
{
voodoo_state *v = get_safe_token(device);
/* if we have something pending, flush the FIFOs up to the current time */
if (v->pci.op_pending)
flush_fifos(v, device->machine->time());
/* target the appropriate location */
if (!(offset & (0xc00000/4)))
return register_r(v, offset);
else if (!(offset & (0x800000/4)))
return lfb_r(v, offset, FALSE);
return 0xffffffff;
}
/*************************************
*
* Handle a read from the Banshee
* I/O space
*
*************************************/
static READ32_DEVICE_HANDLER( banshee_agp_r )
{
voodoo_state *v = get_safe_token(device);
UINT32 result;
offset &= 0x1ff/4;
/* switch off the offset */
switch (offset)
{
case cmdRdPtrL0:
result = v->fbi.cmdfifo[0].rdptr;
break;
case cmdAMin0:
result = v->fbi.cmdfifo[0].amin;
break;
case cmdAMax0:
result = v->fbi.cmdfifo[0].amax;
break;
case cmdFifoDepth0:
result = v->fbi.cmdfifo[0].depth;
break;
case cmdHoleCnt0:
result = v->fbi.cmdfifo[0].holes;
break;
case cmdRdPtrL1:
result = v->fbi.cmdfifo[1].rdptr;
break;
case cmdAMin1:
result = v->fbi.cmdfifo[1].amin;
break;
case cmdAMax1:
result = v->fbi.cmdfifo[1].amax;
break;
case cmdFifoDepth1:
result = v->fbi.cmdfifo[1].depth;
break;
case cmdHoleCnt1:
result = v->fbi.cmdfifo[1].holes;
break;
default:
result = v->banshee.agp[offset];
break;
}
if (LOG_REGISTERS)
logerror("%s:banshee_r(AGP:%s)\n", v->device->machine->describe_context(), banshee_agp_reg_name[offset]);
return result;
}
READ32_DEVICE_HANDLER( banshee_r )
{
voodoo_state *v = get_safe_token(device);
UINT32 result = 0xffffffff;
/* if we have something pending, flush the FIFOs up to the current time */
if (v->pci.op_pending)
flush_fifos(v, device->machine->time());
if (offset < 0x80000/4)
result = banshee_io_r(device, offset, mem_mask);
else if (offset < 0x100000/4)
result = banshee_agp_r(device, offset, mem_mask);
else if (offset < 0x200000/4)
logerror("%s:banshee_r(2D:%X)\n", device->machine->describe_context(), (offset*4) & 0xfffff);
else if (offset < 0x600000/4)
result = register_r(v, offset & 0x1fffff/4);
else if (offset < 0x800000/4)
logerror("%s:banshee_r(TEX:%X)\n", device->machine->describe_context(), (offset*4) & 0x1fffff);
else if (offset < 0xc00000/4)
logerror("%s:banshee_r(RES:%X)\n", device->machine->describe_context(), (offset*4) & 0x3fffff);
else if (offset < 0x1000000/4)
logerror("%s:banshee_r(YUV:%X)\n", device->machine->describe_context(), (offset*4) & 0x3fffff);
else if (offset < 0x2000000/4)
{
UINT8 temp = v->fbi.lfb_stride;
v->fbi.lfb_stride = 11;
result = lfb_r(v, offset & 0xffffff/4, FALSE);
v->fbi.lfb_stride = temp;
}
return result;
}
READ32_DEVICE_HANDLER( banshee_fb_r )
{
voodoo_state *v = get_safe_token(device);
UINT32 result = 0xffffffff;
/* if we have something pending, flush the FIFOs up to the current time */
if (v->pci.op_pending)
flush_fifos(v, device->machine->time());
if (offset < v->fbi.lfb_base)
{
logerror("%s:banshee_fb_r(%X)\n", device->machine->describe_context(), offset*4);
if (offset*4 <= v->fbi.mask)
result = ((UINT32 *)v->fbi.ram)[offset];
}
else
result = lfb_r(v, offset - v->fbi.lfb_base, FALSE);
return result;
}
static READ8_DEVICE_HANDLER( banshee_vga_r )
{
voodoo_state *v = get_safe_token(device);
UINT8 result = 0xff;
offset &= 0x1f;
/* switch off the offset */
switch (offset + 0x3c0)
{
/* attribute access */
case 0x3c0:
if (v->banshee.vga[0x3c1 & 0x1f] < ARRAY_LENGTH(v->banshee.att))
result = v->banshee.att[v->banshee.vga[0x3c1 & 0x1f]];
if (LOG_REGISTERS)
logerror("%s:banshee_att_r(%X)\n", device->machine->describe_context(), v->banshee.vga[0x3c1 & 0x1f]);
break;
/* Input status 0 */
case 0x3c2:
/*
bit 7 = Interrupt Status. When its value is ?1?, denotes that an interrupt is pending.
bit 6:5 = Feature Connector. These 2 bits are readable bits from the feature connector.
bit 4 = Sense. This bit reflects the state of the DAC monitor sense logic.
bit 3:0 = Reserved. Read back as 0.
*/
result = 0x00;
if (LOG_REGISTERS)
logerror("%s:banshee_vga_r(%X)\n", device->machine->describe_context(), 0x300+offset);
break;
/* Sequencer access */
case 0x3c5:
if (v->banshee.vga[0x3c4 & 0x1f] < ARRAY_LENGTH(v->banshee.seq))
result = v->banshee.seq[v->banshee.vga[0x3c4 & 0x1f]];
if (LOG_REGISTERS)
logerror("%s:banshee_seq_r(%X)\n", device->machine->describe_context(), v->banshee.vga[0x3c4 & 0x1f]);
break;
/* Feature control */
case 0x3ca:
result = v->banshee.vga[0x3da & 0x1f];
v->banshee.attff = 0;
if (LOG_REGISTERS)
logerror("%s:banshee_vga_r(%X)\n", device->machine->describe_context(), 0x300+offset);
break;
/* Miscellaneous output */
case 0x3cc:
result = v->banshee.vga[0x3c2 & 0x1f];
if (LOG_REGISTERS)
logerror("%s:banshee_vga_r(%X)\n", device->machine->describe_context(), 0x300+offset);
break;
/* Graphics controller access */
case 0x3cf:
if (v->banshee.vga[0x3ce & 0x1f] < ARRAY_LENGTH(v->banshee.gc))
result = v->banshee.gc[v->banshee.vga[0x3ce & 0x1f]];
if (LOG_REGISTERS)
logerror("%s:banshee_gc_r(%X)\n", device->machine->describe_context(), v->banshee.vga[0x3ce & 0x1f]);
break;
/* CRTC access */
case 0x3d5:
if (v->banshee.vga[0x3d4 & 0x1f] < ARRAY_LENGTH(v->banshee.crtc))
result = v->banshee.crtc[v->banshee.vga[0x3d4 & 0x1f]];
if (LOG_REGISTERS)
logerror("%s:banshee_crtc_r(%X)\n", device->machine->describe_context(), v->banshee.vga[0x3d4 & 0x1f]);
break;
/* Input status 1 */
case 0x3da:
/*
bit 7:6 = Reserved. These bits read back 0.
bit 5:4 = Display Status. These 2 bits reflect 2 of the 8 pixel data outputs from the Attribute
controller, as determined by the Attribute controller index 0x12 bits 4 and 5.
bit 3 = Vertical sync Status. A ?1? indicates vertical retrace is in progress.
bit 2:1 = Reserved. These bits read back 0x2.
bit 0 = Display Disable. When this bit is 1, either horizontal or vertical display end has occurred,
otherwise video data is being displayed.
*/
result = 0x04;
if (LOG_REGISTERS)
logerror("%s:banshee_vga_r(%X)\n", device->machine->describe_context(), 0x300+offset);
break;
default:
result = v->banshee.vga[offset];
if (LOG_REGISTERS)
logerror("%s:banshee_vga_r(%X)\n", device->machine->describe_context(), 0x300+offset);
break;
}
return result;
}
READ32_DEVICE_HANDLER( banshee_io_r )
{
voodoo_state *v = get_safe_token(device);
UINT32 result;
offset &= 0xff/4;
/* switch off the offset */
switch (offset)
{
case io_status:
result = register_r(v, 0);
break;
case io_dacData:
result = v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff] = v->banshee.io[offset];
if (LOG_REGISTERS)
logerror("%s:banshee_dac_r(%X)\n", device->machine->describe_context(), v->banshee.io[io_dacAddr] & 0x1ff);
break;
case io_vgab0: case io_vgab4: case io_vgab8: case io_vgabc:
case io_vgac0: case io_vgac4: case io_vgac8: case io_vgacc:
case io_vgad0: case io_vgad4: case io_vgad8: case io_vgadc:
result = 0;
if (ACCESSING_BITS_0_7)
result |= banshee_vga_r(device, offset*4+0) << 0;
if (ACCESSING_BITS_8_15)
result |= banshee_vga_r(device, offset*4+1) << 8;
if (ACCESSING_BITS_16_23)
result |= banshee_vga_r(device, offset*4+2) << 16;
if (ACCESSING_BITS_24_31)
result |= banshee_vga_r(device, offset*4+3) << 24;
break;
default:
result = v->banshee.io[offset];
if (LOG_REGISTERS)
logerror("%s:banshee_io_r(%s)\n", device->machine->describe_context(), banshee_io_reg_name[offset]);
break;
}
return result;
}
READ32_DEVICE_HANDLER( banshee_rom_r )
{
logerror("%s:banshee_rom_r(%X)\n", device->machine->describe_context(), offset*4);
return 0xffffffff;
}
static WRITE32_DEVICE_HANDLER( banshee_agp_w )
{
voodoo_state *v = get_safe_token(device);
offset &= 0x1ff/4;
/* switch off the offset */
switch (offset)
{
case cmdBaseAddr0:
COMBINE_DATA(&v->banshee.agp[offset]);
v->fbi.cmdfifo[0].base = (data & 0xffffff) << 12;
v->fbi.cmdfifo[0].end = v->fbi.cmdfifo[0].base + (((v->banshee.agp[cmdBaseSize0] & 0xff) + 1) << 12);
break;
case cmdBaseSize0:
COMBINE_DATA(&v->banshee.agp[offset]);
v->fbi.cmdfifo[0].end = v->fbi.cmdfifo[0].base + (((v->banshee.agp[cmdBaseSize0] & 0xff) + 1) << 12);
v->fbi.cmdfifo[0].enable = (data >> 8) & 1;
v->fbi.cmdfifo[0].count_holes = (~data >> 10) & 1;
break;
case cmdBump0:
fatalerror("cmdBump0");
break;
case cmdRdPtrL0:
v->fbi.cmdfifo[0].rdptr = data;
break;
case cmdAMin0:
v->fbi.cmdfifo[0].amin = data;
break;
case cmdAMax0:
v->fbi.cmdfifo[0].amax = data;
break;
case cmdFifoDepth0:
v->fbi.cmdfifo[0].depth = data;
break;
case cmdHoleCnt0:
v->fbi.cmdfifo[0].holes = data;
break;
case cmdBaseAddr1:
COMBINE_DATA(&v->banshee.agp[offset]);
v->fbi.cmdfifo[1].base = (data & 0xffffff) << 12;
v->fbi.cmdfifo[1].end = v->fbi.cmdfifo[1].base + (((v->banshee.agp[cmdBaseSize1] & 0xff) + 1) << 12);
break;
case cmdBaseSize1:
COMBINE_DATA(&v->banshee.agp[offset]);
v->fbi.cmdfifo[1].end = v->fbi.cmdfifo[1].base + (((v->banshee.agp[cmdBaseSize1] & 0xff) + 1) << 12);
v->fbi.cmdfifo[1].enable = (data >> 8) & 1;
v->fbi.cmdfifo[1].count_holes = (~data >> 10) & 1;
break;
case cmdBump1:
fatalerror("cmdBump1");
break;
case cmdRdPtrL1:
v->fbi.cmdfifo[1].rdptr = data;
break;
case cmdAMin1:
v->fbi.cmdfifo[1].amin = data;
break;
case cmdAMax1:
v->fbi.cmdfifo[1].amax = data;
break;
case cmdFifoDepth1:
v->fbi.cmdfifo[1].depth = data;
break;
case cmdHoleCnt1:
v->fbi.cmdfifo[1].holes = data;
break;
default:
COMBINE_DATA(&v->banshee.agp[offset]);
break;
}
if (LOG_REGISTERS)
logerror("%s:banshee_w(AGP:%s) = %08X & %08X\n", device->machine->describe_context(), banshee_agp_reg_name[offset], data, mem_mask);
}
WRITE32_DEVICE_HANDLER( banshee_w )
{
voodoo_state *v = get_safe_token(device);
/* if we have something pending, flush the FIFOs up to the current time */
if (v->pci.op_pending)
flush_fifos(v, device->machine->time());
if (offset < 0x80000/4)
banshee_io_w(device, offset, data, mem_mask);
else if (offset < 0x100000/4)
banshee_agp_w(device, offset, data, mem_mask);
else if (offset < 0x200000/4)
logerror("%s:banshee_w(2D:%X) = %08X & %08X\n", device->machine->describe_context(), (offset*4) & 0xfffff, data, mem_mask);
else if (offset < 0x600000/4)
register_w(v, offset & 0x1fffff/4, data);
else if (offset < 0x800000/4)
logerror("%s:banshee_w(TEX:%X) = %08X & %08X\n", device->machine->describe_context(), (offset*4) & 0x1fffff, data, mem_mask);
else if (offset < 0xc00000/4)
logerror("%s:banshee_w(RES:%X) = %08X & %08X\n", device->machine->describe_context(), (offset*4) & 0x3fffff, data, mem_mask);
else if (offset < 0x1000000/4)
logerror("%s:banshee_w(YUV:%X) = %08X & %08X\n", device->machine->describe_context(), (offset*4) & 0x3fffff, data, mem_mask);
else if (offset < 0x2000000/4)
{
UINT8 temp = v->fbi.lfb_stride;
v->fbi.lfb_stride = 11;
lfb_w(v, offset & 0xffffff/4, data, mem_mask, FALSE);
v->fbi.lfb_stride = temp;
}
}
WRITE32_DEVICE_HANDLER( banshee_fb_w )
{
voodoo_state *v = get_safe_token(device);
UINT32 addr = offset*4;
/* if we have something pending, flush the FIFOs up to the current time */
if (v->pci.op_pending)
flush_fifos(v, device->machine->time());
if (offset < v->fbi.lfb_base)
{
if (v->fbi.cmdfifo[0].enable && addr >= v->fbi.cmdfifo[0].base && addr < v->fbi.cmdfifo[0].end)
cmdfifo_w(v, &v->fbi.cmdfifo[0], (addr - v->fbi.cmdfifo[0].base) / 4, data);
else if (v->fbi.cmdfifo[1].enable && addr >= v->fbi.cmdfifo[1].base && addr < v->fbi.cmdfifo[1].end)
cmdfifo_w(v, &v->fbi.cmdfifo[1], (addr - v->fbi.cmdfifo[1].base) / 4, data);
else
{
if (offset*4 <= v->fbi.mask)
COMBINE_DATA(&((UINT32 *)v->fbi.ram)[offset]);
logerror("%s:banshee_fb_w(%X) = %08X & %08X\n", device->machine->describe_context(), offset*4, data, mem_mask);
}
}
else
lfb_w(v, offset - v->fbi.lfb_base, data, mem_mask, FALSE);
}
static WRITE8_DEVICE_HANDLER( banshee_vga_w )
{
voodoo_state *v = get_safe_token(device);
offset &= 0x1f;
/* switch off the offset */
switch (offset + 0x3c0)
{
/* attribute access */
case 0x3c0:
case 0x3c1:
if (v->banshee.attff == 0)
{
v->banshee.vga[0x3c1 & 0x1f] = data;
if (LOG_REGISTERS)
logerror("%s:banshee_vga_w(%X) = %02X\n", device->machine->describe_context(), 0x3c0+offset, data);
}
else
{
if (v->banshee.vga[0x3c1 & 0x1f] < ARRAY_LENGTH(v->banshee.att))
v->banshee.att[v->banshee.vga[0x3c1 & 0x1f]] = data;
if (LOG_REGISTERS)
logerror("%s:banshee_att_w(%X) = %02X\n", device->machine->describe_context(), v->banshee.vga[0x3c1 & 0x1f], data);
}
v->banshee.attff ^= 1;
break;
/* Sequencer access */
case 0x3c5:
if (v->banshee.vga[0x3c4 & 0x1f] < ARRAY_LENGTH(v->banshee.seq))
v->banshee.seq[v->banshee.vga[0x3c4 & 0x1f]] = data;
if (LOG_REGISTERS)
logerror("%s:banshee_seq_w(%X) = %02X\n", device->machine->describe_context(), v->banshee.vga[0x3c4 & 0x1f], data);
break;
/* Graphics controller access */
case 0x3cf:
if (v->banshee.vga[0x3ce & 0x1f] < ARRAY_LENGTH(v->banshee.gc))
v->banshee.gc[v->banshee.vga[0x3ce & 0x1f]] = data;
if (LOG_REGISTERS)
logerror("%s:banshee_gc_w(%X) = %02X\n", device->machine->describe_context(), v->banshee.vga[0x3ce & 0x1f], data);
break;
/* CRTC access */
case 0x3d5:
if (v->banshee.vga[0x3d4 & 0x1f] < ARRAY_LENGTH(v->banshee.crtc))
v->banshee.crtc[v->banshee.vga[0x3d4 & 0x1f]] = data;
if (LOG_REGISTERS)
logerror("%s:banshee_crtc_w(%X) = %02X\n", device->machine->describe_context(), v->banshee.vga[0x3d4 & 0x1f], data);
break;
default:
v->banshee.vga[offset] = data;
if (LOG_REGISTERS)
logerror("%s:banshee_vga_w(%X) = %02X\n", device->machine->describe_context(), 0x3c0+offset, data);
break;
}
}
WRITE32_DEVICE_HANDLER( banshee_io_w )
{
voodoo_state *v = get_safe_token(device);
UINT32 old;
offset &= 0xff/4;
old = v->banshee.io[offset];
/* switch off the offset */
switch (offset)
{
case io_vidProcCfg:
COMBINE_DATA(&v->banshee.io[offset]);
if ((v->banshee.io[offset] ^ old) & 0x2800)
v->fbi.clut_dirty = TRUE;
if (LOG_REGISTERS)
logerror("%s:banshee_io_w(%s) = %08X & %08X\n", device->machine->describe_context(), banshee_io_reg_name[offset], data, mem_mask);
break;
case io_dacData:
COMBINE_DATA(&v->banshee.io[offset]);
if (v->banshee.io[offset] != v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff])
{
v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff] = v->banshee.io[offset];
v->fbi.clut_dirty = TRUE;
}
if (LOG_REGISTERS)
logerror("%s:banshee_dac_w(%X) = %08X & %08X\n", device->machine->describe_context(), v->banshee.io[io_dacAddr] & 0x1ff, data, mem_mask);
break;
case io_miscInit0:
COMBINE_DATA(&v->banshee.io[offset]);
v->fbi.yorigin = (data >> 18) & 0xfff;
if (LOG_REGISTERS)
logerror("%s:banshee_io_w(%s) = %08X & %08X\n", device->machine->describe_context(), banshee_io_reg_name[offset], data, mem_mask);
break;
case io_vidScreenSize:
/* warning: this is a hack for now! We should really compute the screen size */
/* from the CRTC registers */
COMBINE_DATA(&v->banshee.io[offset]);
if (data & 0xfff)
v->fbi.width = data & 0xfff;
if (data & 0xfff000)
v->fbi.height = (data >> 12) & 0xfff;
v->screen->set_visible_area(0, v->fbi.width - 1, 0, v->fbi.height - 1);
adjust_vblank_timer(v);
if (LOG_REGISTERS)
logerror("%s:banshee_io_w(%s) = %08X & %08X\n", device->machine->describe_context(), banshee_io_reg_name[offset], data, mem_mask);
break;
case io_lfbMemoryConfig:
v->fbi.lfb_base = (data & 0x1fff) << 10;
v->fbi.lfb_stride = ((data >> 13) & 7) + 9;
if (LOG_REGISTERS)
logerror("%s:banshee_io_w(%s) = %08X & %08X\n", device->machine->describe_context(), banshee_io_reg_name[offset], data, mem_mask);
break;
case io_vgab0: case io_vgab4: case io_vgab8: case io_vgabc:
case io_vgac0: case io_vgac4: case io_vgac8: case io_vgacc:
case io_vgad0: case io_vgad4: case io_vgad8: case io_vgadc:
if (ACCESSING_BITS_0_7)
banshee_vga_w(device, offset*4+0, data >> 0);
if (ACCESSING_BITS_8_15)
banshee_vga_w(device, offset*4+1, data >> 8);
if (ACCESSING_BITS_16_23)
banshee_vga_w(device, offset*4+2, data >> 16);
if (ACCESSING_BITS_24_31)
banshee_vga_w(device, offset*4+3, data >> 24);
break;
default:
COMBINE_DATA(&v->banshee.io[offset]);
if (LOG_REGISTERS)
logerror("%s:banshee_io_w(%s) = %08X & %08X\n", device->machine->describe_context(), banshee_io_reg_name[offset], data, mem_mask);
break;
}
}
/***************************************************************************
DEVICE INTERFACE
***************************************************************************/
/*-------------------------------------------------
device start callback
-------------------------------------------------*/
static DEVICE_START( voodoo )
{
const voodoo_config *config = (const voodoo_config *)downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
voodoo_state *v = get_safe_token(device);
const raster_info *info;
void *fbmem, *tmumem[2];
UINT32 tmumem0;
int val;
/* validate some basic stuff */
assert(device->baseconfig().static_config() == NULL);
assert(downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config() != NULL);
assert(device->machine != NULL);
/* validate configuration */
assert(config->screen != NULL);
assert(config->cputag != NULL);
assert(config->type >= VOODOO_1 && config->type < MAX_VOODOO_TYPES);
assert(config->fbmem > 0);
assert(config->type >= VOODOO_BANSHEE || config->tmumem0 > 0);
/* store a pointer back to the device */
v->device = device;
/* copy config data */
v->freq = device->clock();
v->fbi.vblank_client = config->vblank;
v->pci.stall_callback = config->stall;
/* create a multiprocessor work queue */
v->poly = poly_alloc(device->machine, 64, sizeof(poly_extra_data), 0);
v->thread_stats = auto_alloc_array(device->machine, stats_block, WORK_MAX_THREADS);
/* create a table of precomputed 1/n and log2(n) values */
/* n ranges from 1.0000 to 2.0000 */
for (val = 0; val <= (1 << RECIPLOG_LOOKUP_BITS); val++)
{
UINT32 value = (1 << RECIPLOG_LOOKUP_BITS) + val;
voodoo_reciplog[val*2 + 0] = (1 << (RECIPLOG_LOOKUP_PREC + RECIPLOG_LOOKUP_BITS)) / value;
voodoo_reciplog[val*2 + 1] = (UINT32)(LOGB2((double)value / (double)(1 << RECIPLOG_LOOKUP_BITS)) * (double)(1 << RECIPLOG_LOOKUP_PREC));
}
/* create dithering tables */
for (val = 0; val < 256*16*2; val++)
{
int g = (val >> 0) & 1;
int x = (val >> 1) & 3;
int color = (val >> 3) & 0xff;
int y = (val >> 11) & 3;
if (!g)
{
dither4_lookup[val] = DITHER_RB(color, dither_matrix_4x4[y * 4 + x]) >> 3;
dither2_lookup[val] = DITHER_RB(color, dither_matrix_2x2[y * 4 + x]) >> 3;
}
else
{
dither4_lookup[val] = DITHER_G(color, dither_matrix_4x4[y * 4 + x]) >> 2;
dither2_lookup[val] = DITHER_G(color, dither_matrix_2x2[y * 4 + x]) >> 2;
}
}
/* configure type-specific values */
switch (config->type)
{
case VOODOO_1:
v->regaccess = voodoo_register_access;
v->regnames = voodoo_reg_name;
v->alt_regmap = 0;
v->fbi.lfb_stride = 10;
break;
case VOODOO_2:
v->regaccess = voodoo2_register_access;
v->regnames = voodoo_reg_name;
v->alt_regmap = 0;
v->fbi.lfb_stride = 10;
break;
case VOODOO_BANSHEE:
v->regaccess = banshee_register_access;
v->regnames = banshee_reg_name;
v->alt_regmap = 1;
v->fbi.lfb_stride = 11;
break;
case VOODOO_3:
v->regaccess = banshee_register_access;
v->regnames = banshee_reg_name;
v->alt_regmap = 1;
v->fbi.lfb_stride = 11;
break;
default:
fatalerror("Unsupported voodoo card in voodoo_start!");
break;
}
/* set the type, and initialize the chip mask */
v->index = device->machine->m_devicelist.indexof(device->type(), device->tag());
v->screen = downcast<screen_device *>(device->machine->device(config->screen));
assert_always(v->screen != NULL, "Unable to find screen attached to voodoo");
v->cpu = device->machine->device(config->cputag);
assert_always(v->cpu != NULL, "Unable to find CPU attached to voodoo");
v->type = config->type;
v->chipmask = 0x01;
v->attoseconds_per_cycle = ATTOSECONDS_PER_SECOND / v->freq;
v->trigger = 51324 + v->index;
/* build the rasterizer table */
for (info = predef_raster_table; info->callback; info++)
add_rasterizer(v, info);
/* set up the PCI FIFO */
v->pci.fifo.base = v->pci.fifo_mem;
v->pci.fifo.size = 64*2;
v->pci.fifo.in = v->pci.fifo.out = 0;
v->pci.stall_state = NOT_STALLED;
v->pci.continue_timer = v->device->machine->scheduler().timer_alloc(FUNC(stall_cpu_callback), v);
/* allocate memory */
tmumem0 = config->tmumem0;
if (config->type <= VOODOO_2)
{
/* separate FB/TMU memory */
fbmem = auto_alloc_array(device->machine, UINT8, config->fbmem << 20);
tmumem[0] = auto_alloc_array(device->machine, UINT8, config->tmumem0 << 20);
tmumem[1] = (config->tmumem1 != 0) ? auto_alloc_array(device->machine, UINT8, config->tmumem1 << 20) : NULL;
}
else
{
/* shared memory */
tmumem[0] = tmumem[1] = fbmem = auto_alloc_array(device->machine, UINT8, config->fbmem << 20);
tmumem0 = config->fbmem;
}
/* set up frame buffer */
init_fbi(v, &v->fbi, fbmem, config->fbmem << 20);
/* build shared TMU tables */
init_tmu_shared(&v->tmushare);
/* set up the TMUs */
init_tmu(v, &v->tmu[0], &v->reg[0x100], tmumem[0], tmumem0 << 20);
v->chipmask |= 0x02;
if (config->tmumem1 != 0)
{
init_tmu(v, &v->tmu[1], &v->reg[0x200], tmumem[1], config->tmumem1 << 20);
v->chipmask |= 0x04;
}
/* initialize some registers */
memset(v->reg, 0, sizeof(v->reg));
v->pci.init_enable = 0;
v->reg[fbiInit0].u = (1 << 4) | (0x10 << 6);
v->reg[fbiInit1].u = (1 << 1) | (1 << 8) | (1 << 12) | (2 << 20);
v->reg[fbiInit2].u = (1 << 6) | (0x100 << 23);
v->reg[fbiInit3].u = (2 << 13) | (0xf << 17);
v->reg[fbiInit4].u = (1 << 0);
/* initialize banshee registers */
memset(v->banshee.io, 0, sizeof(v->banshee.io));
v->banshee.io[io_pciInit0] = 0x01800040;
v->banshee.io[io_sipMonitor] = 0x40000000;
v->banshee.io[io_lfbMemoryConfig] = 0x000a2200;
v->banshee.io[io_dramInit0] = 0x00579d29;
v->banshee.io[io_dramInit1] = 0x00f02200;
v->banshee.io[io_tmuGbeInit] = 0x00000bfb;
/* do a soft reset to reset everything else */
soft_reset(v);
/* register for save states */
init_save_state(device);
}
/*-------------------------------------------------
device exit callback
-------------------------------------------------*/
static DEVICE_STOP( voodoo )
{
voodoo_state *v = get_safe_token(device);
/* release the work queue, ensuring all work is finished */
if (v->poly != NULL)
poly_free(v->poly);
}
/*-------------------------------------------------
device reset callback
-------------------------------------------------*/
static DEVICE_RESET( voodoo )
{
voodoo_state *v = get_safe_token(device);
soft_reset(v);
}
/*-------------------------------------------------
device definition
-------------------------------------------------*/
INLINE const char *get_voodoo_name(const device_config *devconfig)
{
const voodoo_config *config = (devconfig != NULL) ? (const voodoo_config *)downcast<const legacy_device_config_base *>(devconfig)->inline_config() : NULL;
switch (config->type)
{
default:
case VOODOO_1: return "3dfx Voodoo Graphics";
case VOODOO_2: return "3dfx Voodoo 2";
case VOODOO_BANSHEE: return "3dfx Voodoo Banshee";
case VOODOO_3: return "3dfx Voodoo 3";
}
}
static const char DEVTEMPLATE_SOURCE[] = __FILE__;
#define DEVTEMPLATE_ID(p,s) p##voodoo##s
#define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_RESET | DT_HAS_STOP | DT_HAS_INLINE_CONFIG
#define DEVTEMPLATE_NAME get_voodoo_name(device)
#define DEVTEMPLATE_FAMILY "3dfx Voodoo Graphics"
#include "devtempl.h"
/***************************************************************************
COMMAND HANDLERS
***************************************************************************/
/*-------------------------------------------------
fastfill - execute the 'fastfill'
command
-------------------------------------------------*/
static INT32 fastfill(voodoo_state *v)
{
int sx = (v->reg[clipLeftRight].u >> 16) & 0x3ff;
int ex = (v->reg[clipLeftRight].u >> 0) & 0x3ff;
int sy = (v->reg[clipLowYHighY].u >> 16) & 0x3ff;
int ey = (v->reg[clipLowYHighY].u >> 0) & 0x3ff;
poly_extent extents[64];
UINT16 dithermatrix[16];
UINT16 *drawbuf = NULL;
UINT32 pixels = 0;
int extnum, x, y;
/* if we're not clearing either, take no time */
if (!FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u) && !FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u))
return 0;
/* are we clearing the RGB buffer? */
if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u))
{
/* determine the draw buffer */
int destbuf = (v->type >= VOODOO_BANSHEE) ? 1 : FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u);
switch (destbuf)
{
case 0: /* front buffer */
drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
break;
case 1: /* back buffer */
drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
break;
default: /* reserved */
break;
}
/* determine the dither pattern */
for (y = 0; y < 4; y++)
{
DECLARE_DITHER_POINTERS;
COMPUTE_DITHER_POINTERS(v->reg[fbzMode].u, y);
for (x = 0; x < 4; x++)
{
int r = v->reg[color1].rgb.r;
int g = v->reg[color1].rgb.g;
int b = v->reg[color1].rgb.b;
APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, r, g, b);
dithermatrix[y*4 + x] = (r << 11) | (g << 5) | b;
}
}
}
/* fill in a block of extents */
extents[0].startx = sx;
extents[0].stopx = ex;
for (extnum = 1; extnum < ARRAY_LENGTH(extents); extnum++)
extents[extnum] = extents[0];
/* iterate over blocks of extents */
for (y = sy; y < ey; y += ARRAY_LENGTH(extents))
{
poly_extra_data *extra = (poly_extra_data *)poly_get_extra_data(v->poly);
int count = MIN(ey - y, ARRAY_LENGTH(extents));
extra->state = v;
memcpy(extra->dither, dithermatrix, sizeof(extra->dither));
pixels += poly_render_triangle_custom(v->poly, drawbuf, NULL, raster_fastfill, y, count, extents);
}
/* 2 pixels per clock */
return pixels / 2;
}
/*-------------------------------------------------
swapbuffer - execute the 'swapbuffer'
command
-------------------------------------------------*/
static INT32 swapbuffer(voodoo_state *v, UINT32 data)
{
/* set the don't swap value for Voodoo 2 */
v->fbi.vblank_swap_pending = TRUE;
v->fbi.vblank_swap = (data >> 1) & 0xff;
v->fbi.vblank_dont_swap = (data >> 9) & 1;
/* if we're not syncing to the retrace, process the command immediately */
if (!(data & 1))
{
swap_buffers(v);
return 0;
}
/* determine how many cycles to wait; we deliberately overshoot here because */
/* the final count gets updated on the VBLANK */
return (v->fbi.vblank_swap + 1) * v->freq / 30;
}
/*-------------------------------------------------
triangle - execute the 'triangle'
command
-------------------------------------------------*/
static INT32 triangle(voodoo_state *v)
{
int texcount = 0;
UINT16 *drawbuf;
int destbuf;
int pixels;
g_profiler.start(PROFILER_USER2);
/* determine the number of TMUs involved */
texcount = 0;
if (!FBIINIT3_DISABLE_TMUS(v->reg[fbiInit3].u) && FBZCP_TEXTURE_ENABLE(v->reg[fbzColorPath].u))
{
texcount = 1;
if (v->chipmask & 0x04)
texcount = 2;
}
/* perform subpixel adjustments */
if (FBZCP_CCA_SUBPIXEL_ADJUST(v->reg[fbzColorPath].u))
{
INT32 dx = 8 - (v->fbi.ax & 15);
INT32 dy = 8 - (v->fbi.ay & 15);
/* adjust iterated R,G,B,A and W/Z */
v->fbi.startr += (dy * v->fbi.drdy + dx * v->fbi.drdx) >> 4;
v->fbi.startg += (dy * v->fbi.dgdy + dx * v->fbi.dgdx) >> 4;
v->fbi.startb += (dy * v->fbi.dbdy + dx * v->fbi.dbdx) >> 4;
v->fbi.starta += (dy * v->fbi.dady + dx * v->fbi.dadx) >> 4;
v->fbi.startw += (dy * v->fbi.dwdy + dx * v->fbi.dwdx) >> 4;
v->fbi.startz += mul_32x32_shift(dy, v->fbi.dzdy, 4) + mul_32x32_shift(dx, v->fbi.dzdx, 4);
/* adjust iterated W/S/T for TMU 0 */
if (texcount >= 1)
{
v->tmu[0].startw += (dy * v->tmu[0].dwdy + dx * v->tmu[0].dwdx) >> 4;
v->tmu[0].starts += (dy * v->tmu[0].dsdy + dx * v->tmu[0].dsdx) >> 4;
v->tmu[0].startt += (dy * v->tmu[0].dtdy + dx * v->tmu[0].dtdx) >> 4;
/* adjust iterated W/S/T for TMU 1 */
if (texcount >= 2)
{
v->tmu[1].startw += (dy * v->tmu[1].dwdy + dx * v->tmu[1].dwdx) >> 4;
v->tmu[1].starts += (dy * v->tmu[1].dsdy + dx * v->tmu[1].dsdx) >> 4;
v->tmu[1].startt += (dy * v->tmu[1].dtdy + dx * v->tmu[1].dtdx) >> 4;
}
}
}
/* wait for any outstanding work to finish */
// poly_wait(v->poly, "triangle");
/* determine the draw buffer */
destbuf = (v->type >= VOODOO_BANSHEE) ? 1 : FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u);
switch (destbuf)
{
case 0: /* front buffer */
drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
v->fbi.video_changed = TRUE;
break;
case 1: /* back buffer */
drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
break;
default: /* reserved */
return TRIANGLE_SETUP_CLOCKS;
}
/* find a rasterizer that matches our current state */
pixels = triangle_create_work_item(v, drawbuf, texcount);
/* update stats */
v->reg[fbiTrianglesOut].u++;
/* update stats */
v->stats.total_triangles++;
g_profiler.stop();
/* 1 pixel per clock, plus some setup time */
if (LOG_REGISTERS) logerror("cycles = %d\n", TRIANGLE_SETUP_CLOCKS + pixels);
return TRIANGLE_SETUP_CLOCKS + pixels;
}
/*-------------------------------------------------
begin_triangle - execute the 'beginTri'
command
-------------------------------------------------*/
static INT32 begin_triangle(voodoo_state *v)
{
setup_vertex *sv = &v->fbi.svert[2];
/* extract all the data from registers */
sv->x = v->reg[sVx].f;
sv->y = v->reg[sVy].f;
sv->wb = v->reg[sWb].f;
sv->w0 = v->reg[sWtmu0].f;
sv->s0 = v->reg[sS_W0].f;
sv->t0 = v->reg[sT_W0].f;
sv->w1 = v->reg[sWtmu1].f;
sv->s1 = v->reg[sS_Wtmu1].f;
sv->t1 = v->reg[sT_Wtmu1].f;
sv->a = v->reg[sAlpha].f;
sv->r = v->reg[sRed].f;
sv->g = v->reg[sGreen].f;
sv->b = v->reg[sBlue].f;
/* spread it across all three verts and reset the count */
v->fbi.svert[0] = v->fbi.svert[1] = v->fbi.svert[2];
v->fbi.sverts = 1;
return 0;
}
/*-------------------------------------------------
draw_triangle - execute the 'DrawTri'
command
-------------------------------------------------*/
static INT32 draw_triangle(voodoo_state *v)
{
setup_vertex *sv = &v->fbi.svert[2];
int cycles = 0;
/* for strip mode, shuffle vertex 1 down to 0 */
if (!(v->reg[sSetupMode].u & (1 << 16)))
v->fbi.svert[0] = v->fbi.svert[1];
/* copy 2 down to 1 regardless */
v->fbi.svert[1] = v->fbi.svert[2];
/* extract all the data from registers */
sv->x = v->reg[sVx].f;
sv->y = v->reg[sVy].f;
sv->wb = v->reg[sWb].f;
sv->w0 = v->reg[sWtmu0].f;
sv->s0 = v->reg[sS_W0].f;
sv->t0 = v->reg[sT_W0].f;
sv->w1 = v->reg[sWtmu1].f;
sv->s1 = v->reg[sS_Wtmu1].f;
sv->t1 = v->reg[sT_Wtmu1].f;
sv->a = v->reg[sAlpha].f;
sv->r = v->reg[sRed].f;
sv->g = v->reg[sGreen].f;
sv->b = v->reg[sBlue].f;
/* if we have enough verts, go ahead and draw */
if (++v->fbi.sverts >= 3)
cycles = setup_and_draw_triangle(v);
return cycles;
}
/***************************************************************************
TRIANGLE HELPERS
***************************************************************************/
/*-------------------------------------------------
setup_and_draw_triangle - process the setup
parameters and render the triangle
-------------------------------------------------*/
static INT32 setup_and_draw_triangle(voodoo_state *v)
{
float dx1, dy1, dx2, dy2;
float divisor, tdiv;
/* grab the X/Ys at least */
v->fbi.ax = (INT16)(v->fbi.svert[0].x * 16.0);
v->fbi.ay = (INT16)(v->fbi.svert[0].y * 16.0);
v->fbi.bx = (INT16)(v->fbi.svert[1].x * 16.0);
v->fbi.by = (INT16)(v->fbi.svert[1].y * 16.0);
v->fbi.cx = (INT16)(v->fbi.svert[2].x * 16.0);
v->fbi.cy = (INT16)(v->fbi.svert[2].y * 16.0);
/* compute the divisor */
divisor = 1.0f / ((v->fbi.svert[0].x - v->fbi.svert[1].x) * (v->fbi.svert[0].y - v->fbi.svert[2].y) -
(v->fbi.svert[0].x - v->fbi.svert[2].x) * (v->fbi.svert[0].y - v->fbi.svert[1].y));
/* backface culling */
if (v->reg[sSetupMode].u & 0x20000)
{
int culling_sign = (v->reg[sSetupMode].u >> 18) & 1;
int divisor_sign = (divisor < 0);
/* if doing strips and ping pong is enabled, apply the ping pong */
if ((v->reg[sSetupMode].u & 0x90000) == 0x00000)
culling_sign ^= (v->fbi.sverts - 3) & 1;
/* if our sign matches the culling sign, we're done for */
if (divisor_sign == culling_sign)
return TRIANGLE_SETUP_CLOCKS;
}
/* compute the dx/dy values */
dx1 = v->fbi.svert[0].y - v->fbi.svert[2].y;
dx2 = v->fbi.svert[0].y - v->fbi.svert[1].y;
dy1 = v->fbi.svert[0].x - v->fbi.svert[1].x;
dy2 = v->fbi.svert[0].x - v->fbi.svert[2].x;
/* set up R,G,B */
tdiv = divisor * 4096.0f;
if (v->reg[sSetupMode].u & (1 << 0))
{
v->fbi.startr = (INT32)(v->fbi.svert[0].r * 4096.0f);
v->fbi.drdx = (INT32)(((v->fbi.svert[0].r - v->fbi.svert[1].r) * dx1 - (v->fbi.svert[0].r - v->fbi.svert[2].r) * dx2) * tdiv);
v->fbi.drdy = (INT32)(((v->fbi.svert[0].r - v->fbi.svert[2].r) * dy1 - (v->fbi.svert[0].r - v->fbi.svert[1].r) * dy2) * tdiv);
v->fbi.startg = (INT32)(v->fbi.svert[0].g * 4096.0f);
v->fbi.dgdx = (INT32)(((v->fbi.svert[0].g - v->fbi.svert[1].g) * dx1 - (v->fbi.svert[0].g - v->fbi.svert[2].g) * dx2) * tdiv);
v->fbi.dgdy = (INT32)(((v->fbi.svert[0].g - v->fbi.svert[2].g) * dy1 - (v->fbi.svert[0].g - v->fbi.svert[1].g) * dy2) * tdiv);
v->fbi.startb = (INT32)(v->fbi.svert[0].b * 4096.0f);
v->fbi.dbdx = (INT32)(((v->fbi.svert[0].b - v->fbi.svert[1].b) * dx1 - (v->fbi.svert[0].b - v->fbi.svert[2].b) * dx2) * tdiv);
v->fbi.dbdy = (INT32)(((v->fbi.svert[0].b - v->fbi.svert[2].b) * dy1 - (v->fbi.svert[0].b - v->fbi.svert[1].b) * dy2) * tdiv);
}
/* set up alpha */
if (v->reg[sSetupMode].u & (1 << 1))
{
v->fbi.starta = (INT32)(v->fbi.svert[0].a * 4096.0);
v->fbi.dadx = (INT32)(((v->fbi.svert[0].a - v->fbi.svert[1].a) * dx1 - (v->fbi.svert[0].a - v->fbi.svert[2].a) * dx2) * tdiv);
v->fbi.dady = (INT32)(((v->fbi.svert[0].a - v->fbi.svert[2].a) * dy1 - (v->fbi.svert[0].a - v->fbi.svert[1].a) * dy2) * tdiv);
}
/* set up Z */
if (v->reg[sSetupMode].u & (1 << 2))
{
v->fbi.startz = (INT32)(v->fbi.svert[0].z * 4096.0);
v->fbi.dzdx = (INT32)(((v->fbi.svert[0].z - v->fbi.svert[1].z) * dx1 - (v->fbi.svert[0].z - v->fbi.svert[2].z) * dx2) * tdiv);
v->fbi.dzdy = (INT32)(((v->fbi.svert[0].z - v->fbi.svert[2].z) * dy1 - (v->fbi.svert[0].z - v->fbi.svert[1].z) * dy2) * tdiv);
}
/* set up Wb */
tdiv = divisor * 65536.0f * 65536.0f;
if (v->reg[sSetupMode].u & (1 << 3))
{
v->fbi.startw = v->tmu[0].startw = v->tmu[1].startw = (INT64)(v->fbi.svert[0].wb * 65536.0f * 65536.0f);
v->fbi.dwdx = v->tmu[0].dwdx = v->tmu[1].dwdx = ((v->fbi.svert[0].wb - v->fbi.svert[1].wb) * dx1 - (v->fbi.svert[0].wb - v->fbi.svert[2].wb) * dx2) * tdiv;
v->fbi.dwdy = v->tmu[0].dwdy = v->tmu[1].dwdy = ((v->fbi.svert[0].wb - v->fbi.svert[2].wb) * dy1 - (v->fbi.svert[0].wb - v->fbi.svert[1].wb) * dy2) * tdiv;
}
/* set up W0 */
if (v->reg[sSetupMode].u & (1 << 4))
{
v->tmu[0].startw = v->tmu[1].startw = (INT64)(v->fbi.svert[0].w0 * 65536.0f * 65536.0f);
v->tmu[0].dwdx = v->tmu[1].dwdx = ((v->fbi.svert[0].w0 - v->fbi.svert[1].w0) * dx1 - (v->fbi.svert[0].w0 - v->fbi.svert[2].w0) * dx2) * tdiv;
v->tmu[0].dwdy = v->tmu[1].dwdy = ((v->fbi.svert[0].w0 - v->fbi.svert[2].w0) * dy1 - (v->fbi.svert[0].w0 - v->fbi.svert[1].w0) * dy2) * tdiv;
}
/* set up S0,T0 */
if (v->reg[sSetupMode].u & (1 << 5))
{
v->tmu[0].starts = v->tmu[1].starts = (INT64)(v->fbi.svert[0].s0 * 65536.0f * 65536.0f);
v->tmu[0].dsdx = v->tmu[1].dsdx = ((v->fbi.svert[0].s0 - v->fbi.svert[1].s0) * dx1 - (v->fbi.svert[0].s0 - v->fbi.svert[2].s0) * dx2) * tdiv;
v->tmu[0].dsdy = v->tmu[1].dsdy = ((v->fbi.svert[0].s0 - v->fbi.svert[2].s0) * dy1 - (v->fbi.svert[0].s0 - v->fbi.svert[1].s0) * dy2) * tdiv;
v->tmu[0].startt = v->tmu[1].startt = (INT64)(v->fbi.svert[0].t0 * 65536.0f * 65536.0f);
v->tmu[0].dtdx = v->tmu[1].dtdx = ((v->fbi.svert[0].t0 - v->fbi.svert[1].t0) * dx1 - (v->fbi.svert[0].t0 - v->fbi.svert[2].t0) * dx2) * tdiv;
v->tmu[0].dtdy = v->tmu[1].dtdy = ((v->fbi.svert[0].t0 - v->fbi.svert[2].t0) * dy1 - (v->fbi.svert[0].t0 - v->fbi.svert[1].t0) * dy2) * tdiv;
}
/* set up W1 */
if (v->reg[sSetupMode].u & (1 << 6))
{
v->tmu[1].startw = (INT64)(v->fbi.svert[0].w1 * 65536.0f * 65536.0f);
v->tmu[1].dwdx = ((v->fbi.svert[0].w1 - v->fbi.svert[1].w1) * dx1 - (v->fbi.svert[0].w1 - v->fbi.svert[2].w1) * dx2) * tdiv;
v->tmu[1].dwdy = ((v->fbi.svert[0].w1 - v->fbi.svert[2].w1) * dy1 - (v->fbi.svert[0].w1 - v->fbi.svert[1].w1) * dy2) * tdiv;
}
/* set up S1,T1 */
if (v->reg[sSetupMode].u & (1 << 7))
{
v->tmu[1].starts = (INT64)(v->fbi.svert[0].s1 * 65536.0f * 65536.0f);
v->tmu[1].dsdx = ((v->fbi.svert[0].s1 - v->fbi.svert[1].s1) * dx1 - (v->fbi.svert[0].s1 - v->fbi.svert[2].s1) * dx2) * tdiv;
v->tmu[1].dsdy = ((v->fbi.svert[0].s1 - v->fbi.svert[2].s1) * dy1 - (v->fbi.svert[0].s1 - v->fbi.svert[1].s1) * dy2) * tdiv;
v->tmu[1].startt = (INT64)(v->fbi.svert[0].t1 * 65536.0f * 65536.0f);
v->tmu[1].dtdx = ((v->fbi.svert[0].t1 - v->fbi.svert[1].t1) * dx1 - (v->fbi.svert[0].t1 - v->fbi.svert[2].t1) * dx2) * tdiv;
v->tmu[1].dtdy = ((v->fbi.svert[0].t1 - v->fbi.svert[2].t1) * dy1 - (v->fbi.svert[0].t1 - v->fbi.svert[1].t1) * dy2) * tdiv;
}
/* draw the triangle */
v->fbi.cheating_allowed = 1;
return triangle(v);
}
/*-------------------------------------------------
triangle_create_work_item - finish triangle
setup and create the work item
-------------------------------------------------*/
static INT32 triangle_create_work_item(voodoo_state *v, UINT16 *drawbuf, int texcount)
{
poly_extra_data *extra = (poly_extra_data *)poly_get_extra_data(v->poly);
raster_info *info = find_rasterizer(v, texcount);
poly_vertex vert[3];
/* fill in the vertex data */
vert[0].x = (float)v->fbi.ax * (1.0f / 16.0f);
vert[0].y = (float)v->fbi.ay * (1.0f / 16.0f);
vert[1].x = (float)v->fbi.bx * (1.0f / 16.0f);
vert[1].y = (float)v->fbi.by * (1.0f / 16.0f);
vert[2].x = (float)v->fbi.cx * (1.0f / 16.0f);
vert[2].y = (float)v->fbi.cy * (1.0f / 16.0f);
/* fill in the extra data */
extra->state = v;
extra->info = info;
/* fill in triangle parameters */
extra->ax = v->fbi.ax;
extra->ay = v->fbi.ay;
extra->startr = v->fbi.startr;
extra->startg = v->fbi.startg;
extra->startb = v->fbi.startb;
extra->starta = v->fbi.starta;
extra->startz = v->fbi.startz;
extra->startw = v->fbi.startw;
extra->drdx = v->fbi.drdx;
extra->dgdx = v->fbi.dgdx;
extra->dbdx = v->fbi.dbdx;
extra->dadx = v->fbi.dadx;
extra->dzdx = v->fbi.dzdx;
extra->dwdx = v->fbi.dwdx;
extra->drdy = v->fbi.drdy;
extra->dgdy = v->fbi.dgdy;
extra->dbdy = v->fbi.dbdy;
extra->dady = v->fbi.dady;
extra->dzdy = v->fbi.dzdy;
extra->dwdy = v->fbi.dwdy;
/* fill in texture 0 parameters */
if (texcount > 0)
{
extra->starts0 = v->tmu[0].starts;
extra->startt0 = v->tmu[0].startt;
extra->startw0 = v->tmu[0].startw;
extra->ds0dx = v->tmu[0].dsdx;
extra->dt0dx = v->tmu[0].dtdx;
extra->dw0dx = v->tmu[0].dwdx;
extra->ds0dy = v->tmu[0].dsdy;
extra->dt0dy = v->tmu[0].dtdy;
extra->dw0dy = v->tmu[0].dwdy;
extra->lodbase0 = prepare_tmu(&v->tmu[0]);
v->stats.texture_mode[TEXMODE_FORMAT(v->tmu[0].reg[textureMode].u)]++;
/* fill in texture 1 parameters */
if (texcount > 1)
{
extra->starts1 = v->tmu[1].starts;
extra->startt1 = v->tmu[1].startt;
extra->startw1 = v->tmu[1].startw;
extra->ds1dx = v->tmu[1].dsdx;
extra->dt1dx = v->tmu[1].dtdx;
extra->dw1dx = v->tmu[1].dwdx;
extra->ds1dy = v->tmu[1].dsdy;
extra->dt1dy = v->tmu[1].dtdy;
extra->dw1dy = v->tmu[1].dwdy;
extra->lodbase1 = prepare_tmu(&v->tmu[1]);
v->stats.texture_mode[TEXMODE_FORMAT(v->tmu[1].reg[textureMode].u)]++;
}
}
/* farm the rasterization out to other threads */
info->polys++;
return poly_render_triangle(v->poly, drawbuf, NULL, info->callback, 0, &vert[0], &vert[1], &vert[2]);
}
/***************************************************************************
RASTERIZER MANAGEMENT
***************************************************************************/
/*-------------------------------------------------
add_rasterizer - add a rasterizer to our
hash table
-------------------------------------------------*/
static raster_info *add_rasterizer(voodoo_state *v, const raster_info *cinfo)
{
raster_info *info = &v->rasterizer[v->next_rasterizer++];
int hash = compute_raster_hash(cinfo);
assert_always(v->next_rasterizer <= MAX_RASTERIZERS, "Out of space for new rasterizers!");
/* make a copy of the info */
*info = *cinfo;
/* fill in the data */
info->hits = 0;
info->polys = 0;
/* hook us into the hash table */
info->next = v->raster_hash[hash];
v->raster_hash[hash] = info;
if (LOG_RASTERIZERS)
printf("Adding rasterizer @ %p : %08X %08X %08X %08X %08X %08X (hash=%d)\n",
info->callback,
info->eff_color_path, info->eff_alpha_mode, info->eff_fog_mode, info->eff_fbz_mode,
info->eff_tex_mode_0, info->eff_tex_mode_1, hash);
return info;
}
/*-------------------------------------------------
find_rasterizer - find a rasterizer that
matches our current parameters and return
it, creating a new one if necessary
-------------------------------------------------*/
static raster_info *find_rasterizer(voodoo_state *v, int texcount)
{
raster_info *info, *prev = NULL;
raster_info curinfo;
int hash;
/* build an info struct with all the parameters */
curinfo.eff_color_path = normalize_color_path(v->reg[fbzColorPath].u);
curinfo.eff_alpha_mode = normalize_alpha_mode(v->reg[alphaMode].u);
curinfo.eff_fog_mode = normalize_fog_mode(v->reg[fogMode].u);
curinfo.eff_fbz_mode = normalize_fbz_mode(v->reg[fbzMode].u);
curinfo.eff_tex_mode_0 = (texcount >= 1) ? normalize_tex_mode(v->tmu[0].reg[textureMode].u) : 0xffffffff;
curinfo.eff_tex_mode_1 = (texcount >= 2) ? normalize_tex_mode(v->tmu[1].reg[textureMode].u) : 0xffffffff;
/* compute the hash */
hash = compute_raster_hash(&curinfo);
/* find the appropriate hash entry */
for (info = v->raster_hash[hash]; info; prev = info, info = info->next)
if (info->eff_color_path == curinfo.eff_color_path &&
info->eff_alpha_mode == curinfo.eff_alpha_mode &&
info->eff_fog_mode == curinfo.eff_fog_mode &&
info->eff_fbz_mode == curinfo.eff_fbz_mode &&
info->eff_tex_mode_0 == curinfo.eff_tex_mode_0 &&
info->eff_tex_mode_1 == curinfo.eff_tex_mode_1)
{
/* got it, move us to the head of the list */
if (prev)
{
prev->next = info->next;
info->next = v->raster_hash[hash];
v->raster_hash[hash] = info;
}
/* return the result */
return info;
}
/* generate a new one using the generic entry */
curinfo.callback = (texcount == 0) ? raster_generic_0tmu : (texcount == 1) ? raster_generic_1tmu : raster_generic_2tmu;
curinfo.is_generic = TRUE;
curinfo.display = 0;
curinfo.polys = 0;
curinfo.hits = 0;
curinfo.next = 0;
return add_rasterizer(v, &curinfo);
}
/*-------------------------------------------------
dump_rasterizer_stats - dump statistics on
the current rasterizer usage patterns
-------------------------------------------------*/
static void dump_rasterizer_stats(voodoo_state *v)
{
static UINT8 display_index;
raster_info *cur, *best;
int hash;
printf("----\n");
display_index++;
/* loop until we've displayed everything */
while (1)
{
best = NULL;
/* find the highest entry */
for (hash = 0; hash < RASTER_HASH_SIZE; hash++)
for (cur = v->raster_hash[hash]; cur; cur = cur->next)
if (cur->display != display_index && (best == NULL || cur->hits > best->hits))
best = cur;
/* if we're done, we're done */
if (best == NULL || best->hits == 0)
break;
/* print it */
printf("RASTERIZER_ENTRY( 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X ) /* %c %8d %10d */\n",
best->eff_color_path,
best->eff_alpha_mode,
best->eff_fog_mode,
best->eff_fbz_mode,
best->eff_tex_mode_0,
best->eff_tex_mode_1,
best->is_generic ? '*' : ' ',
best->polys,
best->hits);
/* reset */
best->display = display_index;
}
}
DEFINE_LEGACY_DEVICE(VOODOO_GRAPHICS, voodoo);
/***************************************************************************
GENERIC RASTERIZERS
***************************************************************************/
/*-------------------------------------------------
raster_fastfill - per-scanline
implementation of the 'fastfill' command
-------------------------------------------------*/
static void raster_fastfill(void *destbase, INT32 y, const poly_extent *extent, const void *extradata, int threadid)
{
const poly_extra_data *extra = (const poly_extra_data *)extradata;
voodoo_state *v = extra->state;
stats_block *stats = &v->thread_stats[threadid];
INT32 startx = extent->startx;
INT32 stopx = extent->stopx;
int scry, x;
/* determine the screen Y */
scry = y;
if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
scry = (v->fbi.yorigin - y) & 0x3ff;
/* fill this RGB row */
if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u))
{
const UINT16 *ditherow = &extra->dither[(y & 3) * 4];
UINT64 expanded = *(UINT64 *)ditherow;
UINT16 *dest = (UINT16 *)destbase + scry * v->fbi.rowpixels;
for (x = startx; x < stopx && (x & 3) != 0; x++)
dest[x] = ditherow[x & 3];
for ( ; x < (stopx & ~3); x += 4)
*(UINT64 *)&dest[x] = expanded;
for ( ; x < stopx; x++)
dest[x] = ditherow[x & 3];
stats->pixels_out += stopx - startx;
}
/* fill this dest buffer row */
if (FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u) && v->fbi.auxoffs != ~0)
{
UINT16 color = v->reg[zaColor].u;
UINT64 expanded = ((UINT64)color << 48) | ((UINT64)color << 32) | (color << 16) | color;
UINT16 *dest = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs) + scry * v->fbi.rowpixels;
for (x = startx; x < stopx && (x & 3) != 0; x++)
dest[x] = color;
for ( ; x < (stopx & ~3); x += 4)
*(UINT64 *)&dest[x] = expanded;
for ( ; x < stopx; x++)
dest[x] = color;
}
}
/*-------------------------------------------------
generic_0tmu - generic rasterizer for 0 TMUs
-------------------------------------------------*/
RASTERIZER(generic_0tmu, 0, v->reg[fbzColorPath].u, v->reg[fbzMode].u, v->reg[alphaMode].u,
v->reg[fogMode].u, 0, 0)
/*-------------------------------------------------
generic_1tmu - generic rasterizer for 1 TMU
-------------------------------------------------*/
RASTERIZER(generic_1tmu, 1, v->reg[fbzColorPath].u, v->reg[fbzMode].u, v->reg[alphaMode].u,
v->reg[fogMode].u, v->tmu[0].reg[textureMode].u, 0)
/*-------------------------------------------------
generic_2tmu - generic rasterizer for 2 TMUs
-------------------------------------------------*/
RASTERIZER(generic_2tmu, 2, v->reg[fbzColorPath].u, v->reg[fbzMode].u, v->reg[alphaMode].u,
v->reg[fogMode].u, v->tmu[0].reg[textureMode].u, v->tmu[1].reg[textureMode].u)
#else
/***************************************************************************
GAME-SPECIFIC RASTERIZERS
***************************************************************************/
/* blitz ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 284269 914846168 */
RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 485421 440309121 */
RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 31606 230753709 */
RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 76742 211701679 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* 6188 152109056 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* 1100 108134400 */
RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 6229525 106197740 */
RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0799, 0x0C261A0F, 0xFFFFFFFF ) /* 905641 75886220 */
RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 205236 53317253 */
RASTERIZER_ENTRY( 0x01422439, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* 817356 48881349 */
RASTERIZER_ENTRY( 0x00000035, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 37979 41687251 */
RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 26014 41183295 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 2512 37911104 */
RASTERIZER_ENTRY( 0x00006136, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 28834 15527654 */
RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 9878 4979429 */
RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 199952 4622064 */
RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* 8672 3676949 */
RASTERIZER_ENTRY( 0x00582C35, 0x00515010, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* 616 2743972 */
RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 81380 2494832 */
//RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000000, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* 7670 2235587 */
//RASTERIZER_ENTRY( 0x00592136, 0x00515110, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* 210 1639140 */
//RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* 108 1154736 */
//RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* 2152 1150842 */
//RASTERIZER_ENTRY( 0x00592136, 0x00515110, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* 152 880560 */
//RASTERIZER_ENTRY( 0x00008035, 0x00515119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 90848 805730 */
//RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261AC9, 0xFFFFFFFF ) /* 2024 571406 */
//RASTERIZER_ENTRY( 0x00012136, 0x00515110, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 1792 494592 */
//RASTERIZER_ENTRY( 0x00000002, 0x00000000, 0x00000000, 0x00000300, 0xFFFFFFFF, 0xFFFFFFFF ) /* 256 161280 */
/* blitz99 ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 6297478 149465839 */
RASTERIZER_ENTRY( 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 210693 6285480 */
RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* * 20180 2718710 */
RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* * 360 2425416 */
RASTERIZER_ENTRY( 0x00002C35, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 67059 1480978 */
RASTERIZER_ENTRY( 0x00008035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 24811 400666 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* * 10304 324468 */
RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 1024 112665 */
/* blitz2k ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 3880 95344128 */
RASTERIZER_ENTRY( 0x00582C35, 0x00514110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 148 1785480 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610CF, 0xFFFFFFFF ) /* * 9976 314244 */
/* carnevil ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 492 84128082 */
RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 1988398 36166780 */
RASTERIZER_ENTRY( 0x00486116, 0x00045119, 0x00000000, 0x00030279, 0x0C26180F, 0xFFFFFFFF ) /* * 34424 28788847 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 514 26316800 */
RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000000, 0x000306F9, 0x0C261AC9, 0xFFFFFFFF ) /* * 7346 18805760 */
RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000302F9, 0x0C26180F, 0xFFFFFFFF ) /* * 130764 18678972 */
RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x000306F9, 0x0C2618C9, 0xFFFFFFFF ) /* * 7244 12179040 */
RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x000306F9, 0x0C26180F, 0xFFFFFFFF ) /* * 84520 12059721 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000306F9, 0x0C261AC9, 0xFFFFFFFF ) /* * 21926 11226112 */
RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030679, 0x0C2618C9, 0xFFFFFFFF ) /* * 92115 8926536 */
RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 1730 7629334 */
RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x0C26180F, 0xFFFFFFFF ) /* * 37408 5545956 */
RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x00030679, 0x0C26180F, 0xFFFFFFFF ) /* * 26528 4225026 */
RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000306F9, 0x0C26180F, 0xFFFFFFFF ) /* * 35764 3230884 */
RASTERIZER_ENTRY( 0x01422409, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 96020 1226438 */
RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030279, 0x0C2618C9, 0xFFFFFFFF ) /* * 1020 574649 */
RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 360 370008 */
RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000000, 0x000306F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 576 334404 */
/* calspeed ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26100F, 0xFFFFFFFF ) /* * 99120 1731923836 */
RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 9955804 1526119944 */
RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C26180F, 0xFFFFFFFF ) /* * 1898207 1124776864 */
RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 3487467 1101663125 */
RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 1079277 609256033 */
RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A0723, 0x0C261ACF, 0xFFFFFFFF ) /* * 11880 583925760 */
RASTERIZER_ENTRY( 0x00602819, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 63644 582469888 */
RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 22688 556797972 */
RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 1360254 417068457 */
RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 3427489 405421272 */
RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0739, 0x0C26180F, 0xFFFFFFFF ) /* * 286809 238944049 */
RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 28160 231084818 */
RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 183564 201014424 */
RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 15275 168207109 */
RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C26100F, 0xFFFFFFFF ) /* * 2856 134400000 */
RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 98551 110417974 */
RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C2610CF, 0xFFFFFFFF ) /* * 47040 107360728 */
RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 13128 86876789 */
RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 257515 76329054 */
RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 3934 64958208 */
//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 77400 63786236 */
//RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 12500 63151200 */
//RASTERIZER_ENTRY( 0x0102001A, 0x00045119, 0x00000001, 0x000A0321, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 8764 57629312 */
//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 3257 32708448 */
//RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A07E3, 0x0C2610CF, 0xFFFFFFFF ) /* * 28364 31195605 */
//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 409001 30699647 */
//RASTERIZER_ENTRY( 0x00482C35, 0x00045119, 0x00000001, 0x000A0321, 0x0C26100F, 0xFFFFFFFF ) /* * 17669 11214172 */
//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 5844 6064373 */
//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 626 4651080 */
//RASTERIZER_ENTRY( 0x00482C35, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 5887 2945500 */
//RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 1090 2945093 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 228 1723908 */
//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000A0321, 0x0C261A0F, 0xFFFFFFFF ) /* * 112 1433600 */
//RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 3091 1165805 */
//RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 620 791202 */
/* hyprdriv ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 60860 498565120 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 28688 235012096 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* * 11844 156499968 */
RASTERIZER_ENTRY( 0x00580035, 0x00045119, 0x00000001, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 175990 146518715 */
RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000001, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 2336 114819072 */
RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 363325 100404294 */
RASTERIZER_ENTRY( 0x00582C35, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 40918 96318738 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 54815 94990269 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 123032 91652828 */
RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 82767 86431997 */
RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 9874 78101834 */
RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 102146 72570879 */
RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 657804 67229658 */
RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B03F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 10428 63173865 */
RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 230145 57902926 */
RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 769654 53992486 */
RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 85365 51865697 */
RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000001, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* * 454674 46165536 */
RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 101889 33337987 */
RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 255952 29810993 */
//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 106190 25430383 */
//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 595001 23268601 */
//RASTERIZER_ENTRY( 0x0142612A, 0x00000000, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 946410 22589110 */
//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 330036 21323230 */
//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 40089 13470498 */
//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 90906 12850855 */
//RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 9492 12115280 */
//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 453515 12013961 */
//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 33829 8384312 */
//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 83986 7841206 */
//RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 42515 7242660 */
//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 706 6158684 */
//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 62051 5819485 */
//RASTERIZER_ENTRY( 0x0142612A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 135139 5063467 */
//RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 10359 5135837 */
//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 170159 4449246 */
//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 19037 4371219 */
//RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 8963 4352501 */
//RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 47712 4159994 */
//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* * 47525 4151435 */
//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 34980 3794066 */
//RASTERIZER_ENTRY( 0x0142613A, 0x00045110, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 6540 2358068 */
//RASTERIZER_ENTRY( 0x0142611A, 0x00045110, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 703308 2096781 */
//RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B0339, 0x0C261A1F, 0xFFFFFFFF ) /* * 3963 2079440 */
//RASTERIZER_ENTRY( 0x01422439, 0x00000000, 0x00000001, 0x000B073B, 0x0C261AC9, 0xFFFFFFFF ) /* * 22866 2008397 */
//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 69705 1673671 */
//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 13366 1575120 */
//RASTERIZER_ENTRY( 0x0142613A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 50625 1408211 */
//RASTERIZER_ENTRY( 0x0142613A, 0x00045110, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 1244348 1244346 */
//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 13791 1222735 */
//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 33064 943590 */
//RASTERIZER_ENTRY( 0x0142610A, 0x00045110, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 2041 926507 */
//RASTERIZER_ENTRY( 0x00480019, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 2722 453924 */
//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 68232 306869 */
//RASTERIZER_ENTRY( 0x0142611A, 0x00045110, 0x00000001, 0x000B0379, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 7164 269002 */
/* mace -------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824100F, 0xFFFFFFFF ) /* * 7204150 1340201579 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0xFFFFFFFF ) /* * 15332 1181663232 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 104456 652582379 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824180F, 0xFFFFFFFF ) /* * 488613 368880164 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082418CF, 0xFFFFFFFF ) /* * 352924 312417405 */
RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 15024 291762384 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082410CF, 0xFFFFFFFF ) /* * 711824 279246170 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824100F, 0xFFFFFFFF ) /* * 735574 171881981 */
RASTERIZER_ENTRY( 0x00602401, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 943006 154374023 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082410CF, 0xFFFFFFFF ) /* * 103877 101077498 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824108F, 0xFFFFFFFF ) /* * 710125 87547221 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x08241ACF, 0xFFFFFFFF ) /* * 9834 79774966 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 17644 70187036 */
RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 11324 56633925 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 96743 40820171 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 166053 29100794 */
RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 166053 29100697 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0379, 0x0824188F, 0xFFFFFFFF ) /* * 6723 29076516 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824188F, 0xFFFFFFFF ) /* * 53297 23928976 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824180F, 0xFFFFFFFF ) /* * 10309 19001776 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 22105 17473157 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824188F, 0xFFFFFFFF ) /* * 11304 17236698 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0xFFFFFFFF ) /* * 1664 17180883 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x08241A0F, 0xFFFFFFFF ) /* * 148606 12274278 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418CF, 0xFFFFFFFF ) /* * 80692 9248007 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 37819 8080994 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000001, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 37819 8080969 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 536 7930305 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 27601 7905364 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 27601 7905364 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 36314 7667917 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 36314 7667917 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 31109 6020110 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 31109 6020110 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 42689 5959231 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 42689 5959231 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824188F, 0xFFFFFFFF ) /* * 11965 5118044 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 11923 4662909 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x082410CF, 0xFFFFFFFF ) /* * 4422 4624260 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824100F, 0xFFFFFFFF ) /* * 3853 3596375 */
//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 400 3555759 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 3755 3453084 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 4170 2425016 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824184F, 0xFFFFFFFF ) /* * 322 2220073 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x082418CF, 0xFFFFFFFF ) /* * 4008 1201335 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824108F, 0xFFFFFFFF ) /* * 13704 883585 */
/* sfrush -----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0824101F ) /* * 590139 246714190 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824101F, 0x0824101F ) /* * 397774 153418144 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x082410DF ) /* * 22732 146975666 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0824101F ) /* * 306398 130393278 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0x0824101F ) /* * 437743 117403881 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0x0824101F ) /* * 66608 109289500 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x082410DF ) /* * 19101 92573085 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0824181F ) /* * 258287 78618228 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824181F, 0x0824101F ) /* * 61814 68788856 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x0824181F ) /* * 149792 61464124 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0x0824181F ) /* * 109988 55083276 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x00000000 ) /* * 478 46989312 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x0824181F ) /* * 468 46006272 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0824181F ) /* * 125204 39023396 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x082410DB ) /* * 394 38731776 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 12890 36333568 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0824101F, 0x0824101F ) /* * 147995 31086325 */
RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B077B, 0x00000000, 0x082410DB ) /* * 3576 29294592 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824181F, 0x0824181F ) /* * 76059 29282981 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 12632 29173808 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x082418DF ) /* * 14040 24318118 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0379, 0x0824101F, 0x0824101F ) /* * 56586 17643207 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 9130 17277440 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 66302 17049921 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x0824101F ) /* * 64380 16463672 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x0824181F ) /* * 152 14942208 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 8748 13810176 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082708DF, 0x0824101F ) /* * 216634 10628656 */
//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B077B, 0x00000000, 0x082410DB ) /* * 1282 10502144 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 74636 9758030 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 58652 9353671 */
//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 5242 8038747 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x082410DB ) /* * 11048 7538060 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0x0824181F ) /* * 121630 6906591 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x082418DF ) /* * 19553 6864245 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x082418DF ) /* * 1287 6648834 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082708DF, 0x0824101F ) /* * 197766 6617876 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082700DF, 0x0824101F ) /* * 75470 6231739 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x08241ADF, 0x0824101F ) /* * 180 5898240 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 7692 5743360 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 20128 4980591 */
//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 1144 4685824 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082700DF, 0x0824101F ) /* * 72299 4466336 */
//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 3750 4018176 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DF ) /* * 7533 3692141 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 9484 3610674 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824101F, 0x0824181F ) /* * 128660 3216280 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 22214 3172813 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824181F ) /* * 5094 3099098 */
//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 1954 2850924 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 1542 2434304 */
//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x00000000 ) /* * 478 1957888 */
//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 468 1916928 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 11664 1729188 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x082410DB ) /* * 1282 1640960 */
//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 388 1589248 */
//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 1282 1312768 */
//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x0824181F ) /* * 3928 1046582 */
/* vaportrx ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x00482405, 0x00000000, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 2226138 592165102 */
RASTERIZER_ENTRY( 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 53533 281405105 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* * 314131 219103141 */
RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 216329 95014510 */
RASTERIZER_ENTRY( 0x00482405, 0x00000009, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 317128 92010096 */
RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B07F9, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 13728 88595930 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261ACF, 0xFFFFFFFF ) /* * 649448 81449105 */
RASTERIZER_ENTRY( 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 444231 60067944 */
RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C26184F, 0xFFFFFFFF ) /* * 36057 58970468 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 53147 48856709 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x0C2610C9, 0xFFFFFFFF ) /* * 447654 47171792 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 207392 38933691 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 2015632 33364173 */
RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 196361 30395218 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 110898 28973006 */
RASTERIZER_ENTRY( 0x00482435, 0x00000009, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 135107 16301589 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A8F, 0xFFFFFFFF ) /* * 22375 15797748 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C26184F, 0xFFFFFFFF ) /* * 141539 7513140 */
RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 621403 5369705 */
RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 30443 4070277 */
//RASTERIZER_ENTRY( 0x00482405, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 22121 3129894 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 9187 1864599 */
//RASTERIZER_ENTRY( 0x00482405, 0x00044110, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 10390 1694950 */
//RASTERIZER_ENTRY( 0x0142610A, 0x00000009, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 25366 1624563 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 69033 1607970 */
//RASTERIZER_ENTRY( 0x0142610A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 36316 1084818 */
//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 1813 816763 */
//RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B0339, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 6602 767221 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 2547 646048 */
//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A8F, 0xFFFFFFFF ) /* * 2394 501590 */
//RASTERIZER_ENTRY( 0x0142613A, 0x00000009, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 14078 440086 */
//RASTERIZER_ENTRY( 0x0142610A, 0x00045119, 0x00000000, 0x000B0339, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 9877 429160 */
//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261ACF, 0xFFFFFFFF ) /* * 3222 366052 */
//RASTERIZER_ENTRY( 0x00482435, 0x00000009, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 5942 285657 */
//RASTERIZER_ENTRY( 0x00482405, 0x00044119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 2328 239688 */
//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 1129 208448 */
/* wg3dh ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0xFFFFFFFF ) /* * 127676 116109477 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824189F, 0xFFFFFFFF ) /* * 96310 112016758 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824109F, 0xFFFFFFFF ) /* * 1412831 108682642 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0xFFFFFFFF ) /* * 1612798 45952714 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241AD9, 0xFFFFFFFF ) /* * 5960 6103040 */
RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 56512 4856542 */
RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x0824109F, 0xFFFFFFFF ) /* * 8480 2045940 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0379, 0x0824181F, 0xFFFFFFFF ) /* * 2779 1994317 */
RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824105F, 0xFFFFFFFF ) /* * 154691 1922774 */
RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0xFFFFFFFF ) /* * 18114 776139 */
/* gauntleg ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24100F ) /* * 157050 668626339 */
RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 1079126 580272490 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A4F, 0x0C24100F ) /* * 49686 232178144 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C24104F, 0x0C24100F ) /* * 1048560 206304396 */
RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C2240CF, 0x0C241ACF ) /* * 59176 182444375 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A4F ) /* * 66342 179689728 */
RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 72264 109413344 */
RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 281243 75399210 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24104F ) /* * 126384 68412120 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A0F, 0x0C24100F ) /* * 26864 43754988 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241ACF ) /* * 30510 32759936 */
RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 44783 31884168 */
RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 34946 31359362 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241ACF ) /* * 8006 28367999 */
RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 15430 27908213 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A0F ) /* * 29306 25166802 */
RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 27737 24517949 */
RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 6783 21292092 */
RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 9591 17815763 */
RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 343966 13864759 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 11842 12126208 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A8F, 0x0C24100F ) /* * 6648 9788508 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C2418CF ) /* * 8444 8646656 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 9677 8365606 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 844920 8289326 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24184F ) /* * 3108 8010176 */
//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x00000000, 0x0C24180F ) /* * 1435 6209238 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 5754 5617499 */
//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 1608 5557253 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 105127 5133321 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 3460 4689138 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 7025 4629550 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 7164 4407683 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24188F ) /* * 1922 3924179 */
//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 4116 3733777 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A8F ) /* * 2626 3732809 */
//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C24180F ) /* * 778 3202973 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C24184F, 0x0C24100F ) /* * 1525 2997446 */
//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C241A0F ) /* * 645 2975266 */
//RASTERIZER_ENTRY( 0x00600039, 0x00044119, 0x00000000, 0x000B0379, 0x00000000, 0x0C241A0F ) /* * 5212 2491361 */
//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 825 1996513 */
//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C241A0F ) /* * 466 1967163 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0580000F, 0x0C24180F ) /* * 77400 1883434 */
//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 472 1698177 */
//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 2476 1678760 */
//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 4054 1541748 */
//RASTERIZER_ENTRY( 0x00600039, 0x00044119, 0x00000000, 0x000B0379, 0x0C241A0F, 0x0C24180F ) /* * 3132 1509438 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0580080F, 0x0C24180F ) /* * 8582 1324196 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00044119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24100F ) /* * 1436 1239704 */
//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C24100F ) /* * 253 1220316 */
//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 2433 1014668 */
/* gauntdl ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C241ACF ) /* * 30860 1128173568 */
RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 2631692 1117011118 */
RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 2429239 826969012 */
RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 454056 468285142 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C2418CF ) /* * 257586 355634672 */
RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 10898 134362122 */
RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C241A0F ) /* * 32195 126327049 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2410CF, 0x0C24100F ) /* * 855240 123899880 */
RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 1718 120629204 */
RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22488F, 0x0C241ACF ) /* * 186839 120281357 */
RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0379, 0x0C22480F, 0x0C241ACF ) /* * 14102 115428820 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C2410CF ) /* * 88530 98271949 */
RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0379, 0x0C22480F, 0x0C241ACF ) /* * 12994 68053222 */
RASTERIZER_ENTRY( 0x00602439, 0x00044110, 0x00000000, 0x000B0379, 0x00000009, 0x0C24100F ) /* * 68273 67454880 */
RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 100026 62271618 */
RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 153285 44411342 */
RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 157545 40702131 */
RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 7800 31948800 */
RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22408F, 0x0C241ACF ) /* * 47623 20321183 */
RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24188F ) /* * 21570 19324892 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x000000C1, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 3698 15147008 */
//RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22408F, 0x0C241ACF ) /* * 19765 12383722 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 662274 10563855 */
//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 27909 10462997 */
//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 78671 10286957 */
//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 52038 9928244 */
//RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C224A0F, 0x0C241ACF ) /* * 27469 9239782 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 757116 8072783 */
//RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22488F, 0x0C241ACF ) /* * 18018 7035833 */
//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C241A0F ) /* * 50339 5976564 */
//RASTERIZER_ENTRY( 0x00603430, 0x00040219, 0x00000000, 0x000B0379, 0x00000009, 0x0C2410CE ) /* * 29385 5466384 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 423347 5355017 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 162620 4709092 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 463705 4642480 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 280337 4425529 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 212646 3432265 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 5788 2963456 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 460800 2609198 */
//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 251108 2392362 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 297219 2352862 */
//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0584180F, 0x0C2410CF ) /* * 9913 2097069 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 142722 2091569 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 8820 2053325 */
//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 10346 2033427 */
//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24188F, 0x0C241ACF ) /* * 2136 2017241 */
//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24100F ) /* * 1505 1928490 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 176734 1842440 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 262577 1799080 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 83179 1534171 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 3863 1527077 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 8021 1472661 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C241A0F, 0x0C241ACF ) /* * 85416 1342195 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 261360 1335048 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00000009, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 74811 1320900 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 239331 1268661 */
//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 107769 1244175 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 3706 1216182 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24188F ) /* * 49608 1206129 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00000009, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C241ACF ) /* * 42440 1204109 */
//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x000000C1, 0x000B0779, 0x0C2410CF, 0x0C24100F ) /* * 29584 1168568 */
//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 17729 1152869 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 4052 1108726 */
//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 7082 1079348 */
//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 7761 1023855 */
/* gradius4 ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
//RASTERIZER_ENTRY( 0x02420002, 0x00000009, 0x00000000, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* intro */
//RASTERIZER_ENTRY( 0x01420021, 0x00005119, 0x00000000, 0x00030F7B, 0x14261AC7, 0xFFFFFFFF ) /* intro */
//RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030F7B, 0x14261A87, 0xFFFFFFFF ) /* in-game */
/* nbapbp ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */
//RASTERIZER_ENTRY( 0x00424219, 0x00000000, 0x00000001, 0x00030B7B, 0x08241AC7, 0xFFFFFFFF ) /* intro */
//RASTERIZER_ENTRY( 0x00002809, 0x00004110, 0x00000001, 0x00030FFB, 0x08241AC7, 0xFFFFFFFF ) /* in-game */
//RASTERIZER_ENTRY( 0x00424219, 0x00000000, 0x00000001, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* in-game */
//RASTERIZER_ENTRY( 0x0200421A, 0x00001510, 0x00000001, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* in-game */
#endif