/*
 *  Portion of this software comes with the following license
 */

/***************************************************************************

    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"


#include "voodoo_types.h"
voodoo_state *v;

#include "voodoo_main.h"
#include "voodoo_func.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 Bit8u dither4_lookup[256*16*2];
static Bit8u dither2_lookup[256*16*2];

/* fast reciprocal+log2 lookup */
Bit32u 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 Bit32s register_w(voodoo_state *v, offs_t offset, Bit32u data);
static Bit32s lfb_w(voodoo_state *v, offs_t offset, Bit32u data, Bit32u mem_mask, int forcefront);
static Bit32s texture_w(voodoo_state *v, offs_t offset, Bit32u data);

/* command handlers */
static Bit32s fastfill(voodoo_state *v);
static Bit32s swapbuffer(voodoo_state *v, Bit32u data);
static Bit32s triangle(voodoo_state *v);
static Bit32s begin_triangle(voodoo_state *v);
static Bit32s draw_triangle(voodoo_state *v);

/* triangle helpers */
static Bit32s setup_and_draw_triangle(voodoo_state *v);
static Bit32s triangle_create_work_item(voodoo_state *v, Bit16u *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, Bit32s scanline, const poly_extent *extent, const void *extradata, int threadid);
static void raster_generic_0tmu(void *dest, Bit32s scanline, const poly_extent *extent, const void *extradata, int threadid);
static void raster_generic_1tmu(void *dest, Bit32s scanline, const poly_extent *extent, const void *extradata, int threadid);
static void raster_generic_2tmu(void *dest, Bit32s 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
***************************************************************************/
#if 0

/*-------------------------------------------------
    get_safe_token - makes sure that the passed
    in device is, in fact, a voodoo device
-------------------------------------------------*/

INLINE voodoo_state *get_safe_token(running_device *device)
{
	assert(device != NULL);
	assert(device->token != NULL);
	assert(device->type == VOODOO_GRAPHICS);

	return (voodoo_state *)device->token;
}



/*************************************
 *
 *  Video update
 *
 *************************************/

int voodoo_update(running_device *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)
	{
		Bit8u 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)
		{
			Bit16u *src = (Bit16u *)(v->fbi.ram + v->fbi.rgboffs[drawbuf]) + (y - v->fbi.yoffs) * v->fbi.rowpixels - v->fbi.xoffs;
			Bit32u *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++)
		{
			Bit16u *src = (Bit16u *)(v->fbi.ram + v->fbi.auxoffs) + (y - v->fbi.yoffs) * v->fbi.rowpixels - v->fbi.xoffs;
			Bit32u *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(running_device *device)
{
	voodoo_state *v = get_safe_token(device);
	return v->type;
}



int voodoo_is_stalled(running_device *device)
{
	voodoo_state *v = get_safe_token(device);
	return (v->pci.stall_state != NOT_STALLED);
}


void voodoo_set_init_enable(running_device *device, Bit32u newval)
{
	voodoo_state *v = get_safe_token(device);
	v->pci.init_enable = newval;
	if (LOG_REGISTERS)
		LOG_VOODOO("VOODOO.%d.REG:initEnable write = %08X\n", v->index, newval);
}

#endif

/*************************************
 *
 *  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 = (Bit8u *)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 = timer_alloc(v->device->machine, 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->Bit8s[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 = (Bit8u *)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.Bit8s;
	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.Bit8s;
	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;
	}
}

#if 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(running_device *device)
{
	voodoo_state *v = get_safe_token(device);
	int index, subindex;

	state_save_register_postload(device->machine, voodoo_postload, v);

	/* register states: core */
	state_save_register_device_item(device, 0, v->extra_cycles);
	state_save_register_device_item_pointer(device, 0, (&v->reg[0].u), ARRAY_LENGTH(v->reg));
	state_save_register_device_item(device, 0, v->alt_regmap);

	/* register states: pci */
	state_save_register_device_item(device, 0, v->pci.fifo.in);
	state_save_register_device_item(device, 0, v->pci.fifo.out);
	state_save_register_device_item(device, 0, v->pci.init_enable);
	state_save_register_device_item(device, 0, v->pci.stall_state);
	state_save_register_device_item(device, 0, v->pci.op_pending);
	state_save_register_device_item(device, 0, v->pci.op_end_time.seconds);
	state_save_register_device_item(device, 0, v->pci.op_end_time.attoseconds);
	state_save_register_device_item_array(device, 0, v->pci.fifo_mem);

	/* register states: dac */
	state_save_register_device_item_array(device, 0, v->dac.reg);
	state_save_register_device_item(device, 0, v->dac.read_result);

	/* register states: fbi */
	state_save_register_device_item_pointer(device, 0, v->fbi.ram, v->fbi.mask + 1);
	state_save_register_device_item_array(device, 0, v->fbi.rgboffs);
	state_save_register_device_item(device, 0, v->fbi.auxoffs);
	state_save_register_device_item(device, 0, v->fbi.frontbuf);
	state_save_register_device_item(device, 0, v->fbi.backbuf);
	state_save_register_device_item(device, 0, v->fbi.swaps_pending);
	state_save_register_device_item(device, 0, v->fbi.video_changed);
	state_save_register_device_item(device, 0, v->fbi.yorigin);
	state_save_register_device_item(device, 0, v->fbi.lfb_base);
	state_save_register_device_item(device, 0, v->fbi.lfb_stride);
	state_save_register_device_item(device, 0, v->fbi.width);
	state_save_register_device_item(device, 0, v->fbi.height);
	state_save_register_device_item(device, 0, v->fbi.xoffs);
	state_save_register_device_item(device, 0, v->fbi.yoffs);
	state_save_register_device_item(device, 0, v->fbi.vsyncscan);
	state_save_register_device_item(device, 0, v->fbi.rowpixels);
	state_save_register_device_item(device, 0, v->fbi.vblank);
	state_save_register_device_item(device, 0, v->fbi.vblank_count);
	state_save_register_device_item(device, 0, v->fbi.vblank_swap_pending);
	state_save_register_device_item(device, 0, v->fbi.vblank_swap);
	state_save_register_device_item(device, 0, v->fbi.vblank_dont_swap);
	state_save_register_device_item(device, 0, v->fbi.cheating_allowed);
	state_save_register_device_item(device, 0, v->fbi.sign);
	state_save_register_device_item(device, 0, v->fbi.ax);
	state_save_register_device_item(device, 0, v->fbi.ay);
	state_save_register_device_item(device, 0, v->fbi.bx);
	state_save_register_device_item(device, 0, v->fbi.by);
	state_save_register_device_item(device, 0, v->fbi.cx);
	state_save_register_device_item(device, 0, v->fbi.cy);
	state_save_register_device_item(device, 0, v->fbi.startr);
	state_save_register_device_item(device, 0, v->fbi.startg);
	state_save_register_device_item(device, 0, v->fbi.startb);
	state_save_register_device_item(device, 0, v->fbi.starta);
	state_save_register_device_item(device, 0, v->fbi.startz);
	state_save_register_device_item(device, 0, v->fbi.startw);
	state_save_register_device_item(device, 0, v->fbi.drdx);
	state_save_register_device_item(device, 0, v->fbi.dgdx);
	state_save_register_device_item(device, 0, v->fbi.dbdx);
	state_save_register_device_item(device, 0, v->fbi.dadx);
	state_save_register_device_item(device, 0, v->fbi.dzdx);
	state_save_register_device_item(device, 0, v->fbi.dwdx);
	state_save_register_device_item(device, 0, v->fbi.drdy);
	state_save_register_device_item(device, 0, v->fbi.dgdy);
	state_save_register_device_item(device, 0, v->fbi.dbdy);
	state_save_register_device_item(device, 0, v->fbi.dady);
	state_save_register_device_item(device, 0, v->fbi.dzdy);
	state_save_register_device_item(device, 0, v->fbi.dwdy);
	state_save_register_device_item(device, 0, v->fbi.lfb_stats.pixels_in);
	state_save_register_device_item(device, 0, v->fbi.lfb_stats.pixels_out);
	state_save_register_device_item(device, 0, v->fbi.lfb_stats.chroma_fail);
	state_save_register_device_item(device, 0, v->fbi.lfb_stats.zfunc_fail);
	state_save_register_device_item(device, 0, v->fbi.lfb_stats.afunc_fail);
	state_save_register_device_item(device, 0, v->fbi.lfb_stats.clip_fail);
	state_save_register_device_item(device, 0, v->fbi.lfb_stats.stipple_count);
	state_save_register_device_item(device, 0, v->fbi.sverts);
	for (index = 0; index < ARRAY_LENGTH(v->fbi.svert); index++)
	{
		state_save_register_device_item(device, index, v->fbi.svert[index].x);
		state_save_register_device_item(device, index, v->fbi.svert[index].y);
		state_save_register_device_item(device, index, v->fbi.svert[index].a);
		state_save_register_device_item(device, index, v->fbi.svert[index].r);
		state_save_register_device_item(device, index, v->fbi.svert[index].g);
		state_save_register_device_item(device, index, v->fbi.svert[index].b);
		state_save_register_device_item(device, index, v->fbi.svert[index].z);
		state_save_register_device_item(device, index, v->fbi.svert[index].wb);
		state_save_register_device_item(device, index, v->fbi.svert[index].w0);
		state_save_register_device_item(device, index, v->fbi.svert[index].s0);
		state_save_register_device_item(device, index, v->fbi.svert[index].t0);
		state_save_register_device_item(device, index, v->fbi.svert[index].w1);
		state_save_register_device_item(device, index, v->fbi.svert[index].s1);
		state_save_register_device_item(device, index, v->fbi.svert[index].t1);
	}
	state_save_register_device_item(device, 0, v->fbi.fifo.size);
	state_save_register_device_item(device, 0, v->fbi.fifo.in);
	state_save_register_device_item(device, 0, v->fbi.fifo.out);
	for (index = 0; index < ARRAY_LENGTH(v->fbi.cmdfifo); index++)
	{
		state_save_register_device_item(device, index, v->fbi.cmdfifo[index].enable);
		state_save_register_device_item(device, index, v->fbi.cmdfifo[index].count_holes);
		state_save_register_device_item(device, index, v->fbi.cmdfifo[index].base);
		state_save_register_device_item(device, index, v->fbi.cmdfifo[index].end);
		state_save_register_device_item(device, index, v->fbi.cmdfifo[index].rdptr);
		state_save_register_device_item(device, index, v->fbi.cmdfifo[index].amin);
		state_save_register_device_item(device, index, v->fbi.cmdfifo[index].amax);
		state_save_register_device_item(device, index, v->fbi.cmdfifo[index].depth);
		state_save_register_device_item(device, index, v->fbi.cmdfifo[index].holes);
	}
	state_save_register_device_item_array(device, 0, v->fbi.fogblend);
	state_save_register_device_item_array(device, 0, v->fbi.fogdelta);
	state_save_register_device_item_array(device, 0, 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)
			state_save_register_device_item_pointer(device, index, tmu->ram, tmu->mask + 1);
		state_save_register_device_item(device, index, tmu->starts);
		state_save_register_device_item(device, index, tmu->startt);
		state_save_register_device_item(device, index, tmu->startw);
		state_save_register_device_item(device, index, tmu->dsdx);
		state_save_register_device_item(device, index, tmu->dtdx);
		state_save_register_device_item(device, index, tmu->dwdx);
		state_save_register_device_item(device, index, tmu->dsdy);
		state_save_register_device_item(device, index, tmu->dtdy);
		state_save_register_device_item(device, index, tmu->dwdy);
		for (subindex = 0; subindex < ARRAY_LENGTH(tmu->ncc); subindex++)
		{
			state_save_register_device_item_array(device, index * ARRAY_LENGTH(tmu->ncc) + subindex, tmu->ncc[subindex].ir);
			state_save_register_device_item_array(device, index * ARRAY_LENGTH(tmu->ncc) + subindex, tmu->ncc[subindex].ig);
			state_save_register_device_item_array(device, index * ARRAY_LENGTH(tmu->ncc) + subindex, tmu->ncc[subindex].ib);
			state_save_register_device_item_array(device, index * ARRAY_LENGTH(tmu->ncc) + subindex, tmu->ncc[subindex].qr);
			state_save_register_device_item_array(device, index * ARRAY_LENGTH(tmu->ncc) + subindex, tmu->ncc[subindex].qg);
			state_save_register_device_item_array(device, index * ARRAY_LENGTH(tmu->ncc) + subindex, tmu->ncc[subindex].qb);
			state_save_register_device_item_array(device, index * ARRAY_LENGTH(tmu->ncc) + subindex, tmu->ncc[subindex].y);
		}
	}

	/* register states: banshee */
	if (v->type >= VOODOO_BANSHEE)
	{
		state_save_register_device_item_array(device, 0, v->banshee.io);
		state_save_register_device_item_array(device, 0, v->banshee.agp);
		state_save_register_device_item_array(device, 0, v->banshee.vga);
		state_save_register_device_item_array(device, 0, v->banshee.crtc);
		state_save_register_device_item_array(device, 0, v->banshee.seq);
		state_save_register_device_item_array(device, 0, v->banshee.gc);
		state_save_register_device_item_array(device, 0, v->banshee.att);
		state_save_register_device_item(device, 0, v->banshee.attff);
	}
}

#endif

/*************************************
 *
 *  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) LOG_VOODOO("--- swap_buffers @ %d\n", video_screen_get_vpos(v->screen));

	/* force a partial update */
//	video_screen_update_partial(v->screen, video_screen_get_vpos(v->screen));
	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 = timer_get_time(v->device->machine);
		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, timer_get_time(v->device->machine));

	/* 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 = video_screen_get_visible_area(v->screen);
		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)
{
#if 0
	attotime vblank_period = video_screen_get_time_until_pos(v->screen, v->fbi.vsyncscan, 0);

	/* if zero, adjust to next frame, otherwise we may get stuck in an infinite loop */
	if (attotime_compare(vblank_period, attotime_zero) == 0)
		vblank_period = video_screen_get_frame_period(v->screen);
	timer_adjust_oneshot(v->fbi.vblank_timer, vblank_period, 0);
#endif
}

#if 0
static TIMER_CALLBACK( vblank_off_callback )
{
	voodoo_state *v = (voodoo_state *)ptr;

	if (LOG_VBLANK_SWAP) LOG_VOODOO("--- 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) LOG_VOODOO("--- vblank start\n");

	/* flush the pipes */
	if (v->pci.op_pending)
	{
		if (LOG_VBLANK_SWAP) LOG_VOODOO("---- vblank flush begin\n");
		flush_fifos(v, timer_get_time(machine));
		if (LOG_VBLANK_SWAP) LOG_VOODOO("---- 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) LOG_VOODOO("---- vblank count = %d", v->fbi.vblank_count);
	if (v->fbi.vblank_swap_pending)
		if (LOG_VBLANK_SWAP) LOG_VOODOO(" (target=%d)", v->fbi.vblank_swap);
	if (LOG_VBLANK_SWAP) LOG_VOODOO("\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 */
	timer_set(machine, video_screen_get_time_until_pos(v->screen, 0, 0), v, 0, vblank_off_callback);

	/* set internal state and call the client */
	v->fbi.vblank = TRUE;
	if (v->fbi.vblank_client != NULL)
		(*v->fbi.vblank_client)(v->device, TRUE);
}

#endif

/*************************************
 *
 *  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)
{
	Bit32u buffer_pages = FBIINIT2_VIDEO_BUFFER_OFFSET(v->reg[fbiInit2].u);
	Bit32u fifo_start_page = FBIINIT4_MEMORY_FIFO_START_ROW(v->reg[fbiInit4].u);
	Bit32u fifo_last_page = FBIINIT4_MEMORY_FIFO_STOP_ROW(v->reg[fbiInit4].u);
	Bit32u 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;

//  LOG_VOODOO("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 */
			LOG_VOODOO("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;

/*  LOG_VOODOO("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 = (Bit32u *)(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, Bit32u 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] = (Bit32s)(data <<  5) >> 23;
		n->ig[regnum] = (Bit32s)(data << 14) >> 23;
		n->ib[regnum] = (Bit32s)(data << 23) >> 23;
	}

	/* the final four entries are the Q RGB values */
	else
	{
		regnum &= 3;
		n->qr[regnum] = (Bit32s)(data <<  5) >> 23;
		n->qg[regnum] = (Bit32s)(data << 14) >> 23;
		n->qb[regnum] = (Bit32s)(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, Bit8u regnum, Bit8u data)
{
	d->reg[regnum] = data;
}


static void dacdata_r(dac_state *d, Bit8u regnum)
{
	Bit8u 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;
	Bit32u 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 = (Bit8s)(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))
		LOG_VOODOO("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)))
		{
			Bit32u 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 = (Bit8s)(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))
		E_Exit("Separate RGBA filters!");
}


INLINE Bit32s prepare_tmu(tmu_state *t)
{
	Bit64s texdx, texdy;
	Bit32s 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 = (Bit64s)(t->dsdx >> 14) * (Bit64s)(t->dsdx >> 14) + (Bit64s)(t->dtdx >> 14) * (Bit64s)(t->dtdx >> 14);
	texdy = (Bit64s)(t->dsdy >> 14) * (Bit64s)(t->dsdy >> 14) + (Bit64s)(t->dtdy >> 14) * (Bit64s)(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)
{
	Bit32u *fifobase = (Bit32u *)v->fbi.ram;
	Bit32u readptr = f->rdptr;
	Bit32u 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:
			LOG_VOODOO("UNKNOWN PACKET TYPE %d\n", command & 7);
			return 1;
	}
}



/*************************************
 *
 *  Command FIFO execution
 *
 *************************************/

static Bit32u cmdfifo_execute(voodoo_state *v, cmdfifo_info *f)
{
	Bit32u *fifobase = (Bit32u *)v->fbi.ram;
	Bit32u readptr = f->rdptr;
	Bit32u *src = &fifobase[readptr / 4];
	Bit32u 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) LOG_VOODOO("  NOP\n");
					break;

				case 1:		/* JSR */
					if (LOG_CMDFIFO) LOG_VOODOO("  JSR $%06X\n", target);
					LOG_VOODOO("JSR in CMDFIFO!\n");
					src = &fifobase[target / 4];
					break;

				case 2:		/* RET */
					if (LOG_CMDFIFO) LOG_VOODOO("  RET $%06X\n", target);
					E_Exit("RET in CMDFIFO!");
					break;

				case 3:		/* JMP LOCAL FRAME BUFFER */
					if (LOG_CMDFIFO) LOG_VOODOO("  JMP LOCAL FRAMEBUF $%06X\n", target);
					src = &fifobase[target / 4];
					break;

				case 4:		/* JMP AGP */
					if (LOG_CMDFIFO) LOG_VOODOO("  JMP AGP $%06X\n", target);
					E_Exit("JMP AGP in CMDFIFO!");
					src = &fifobase[target / 4];
					break;

				default:
					LOG_VOODOO("INVALID JUMP COMMAND!\n");
					E_Exit("  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) LOG_VOODOO("  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) LOG_VOODOO("  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) LOG_VOODOO("  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))
					{
						Bit32u 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) LOG_VOODOO("  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) LOG_VOODOO("  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) LOG_VOODOO("  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 Bit32s 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, Bit32u data)
{
	Bit32u addr = f->base + offset * 4;
	Bit32u *fifobase = (Bit32u *)v->fbi.ram;

	if (LOG_CMDFIFO_VERBOSE) LOG_VOODOO("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)
				LOG_VOODOO("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)
	{
		Bit32s cycles = cmdfifo_execute_if_ready(v, f);
		if (cycles > 0)
		{
			v->pci.op_pending = TRUE;
/*
			v->pci.op_end_time = attotime_add_attoseconds(timer_get_time(v->device->machine), (attoseconds_t)cycles * v->attoseconds_per_cycle);

			if (LOG_FIFO_VERBOSE) LOG_VOODOO("VOODOO.%d.FIFO:direct write start at %d.%08X%08X end at %d.%08X%08X\n", v->index,
				timer_get_time(v->device->machine).seconds, (Bit32u)(timer_get_time(v->device->machine).attoseconds >> 32), (Bit32u)timer_get_time(v->device->machine).attoseconds,
				v->pci.op_end_time.seconds, (Bit32u)(v->pci.op_end_time.attoseconds >> 32), (Bit32u)v->pci.op_end_time.attoseconds);
*/
		}
	}
}



/*************************************
 *
 *  Stall the active cpu until we are
 *  ready
 *
 *************************************/
#if 0
static TIMER_CALLBACK( stall_cpu_callback )
{
	check_stalled_cpu((voodoo_state *)ptr, timer_get_time(machine));
}


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) LOG_VOODOO("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
			cpuexec_trigger(v->device->machine, v->trigger);
	}

	/* if not, set a timer for the next one */
	else
	{
		timer_adjust_oneshot(v->pci.continue_timer, attotime_sub(v->pci.op_end_time, current_time), 0);
	}
}


static void stall_cpu(voodoo_state *v, int state, attotime current_time)
{
	/* sanity check */
	if (!v->pci.op_pending) E_Exit("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
		cpu_spinuntil_trigger(v->cpu, v->trigger);

	/* set a timer to clear the stall */
	timer_adjust_oneshot(v->pci.continue_timer, attotime_sub(v->pci.op_end_time, current_time), 0);
}

#endif

/*************************************
 *
 *  Voodoo register writes
 *
 *************************************/

static Bit32s register_w(voodoo_state *v, offs_t offset, Bit32u data)
{
	Bit32u origdata = data;
	Bit32s cycles = 0;
	Bit64s data64;
	Bit8u regnum;
	Bit8u 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))
	{
		LOG_VOODOO("VOODOO.%d.ERROR:Invalid attempt to write %s\n", v->index, v->regnames[regnum]);
		return 0;
	}

	LOG_VOODOO("Voodoo:write value %x chip %x reg %x (%s)", data, chips, regnum<<2, voodoo_reg_name[regnum]);
	voodoo_last_msg=regnum;

	/* switch off the register */
	switch (regnum)
	{
		/* Vertex data is 12.4 formatted fixed point */
		case fvertexAx:
			data = float_to_Bit32s(data, 4);
		case vertexAx:
			if (chips & 1) v->fbi.ax = (Bit16s)data;
			break;

		case fvertexAy:
			data = float_to_Bit32s(data, 4);
		case vertexAy:
			if (chips & 1) v->fbi.ay = (Bit16s)data;
			break;

		case fvertexBx:
			data = float_to_Bit32s(data, 4);
		case vertexBx:
			if (chips & 1) v->fbi.bx = (Bit16s)data;
			break;

		case fvertexBy:
			data = float_to_Bit32s(data, 4);
		case vertexBy:
			if (chips & 1) v->fbi.by = (Bit16s)data;
			break;

		case fvertexCx:
			data = float_to_Bit32s(data, 4);
		case vertexCx:
			if (chips & 1) v->fbi.cx = (Bit16s)data;
			break;

		case fvertexCy:
			data = float_to_Bit32s(data, 4);
		case vertexCy:
			if (chips & 1) v->fbi.cy = (Bit16s)data;
			break;

		/* RGB data is 12.12 formatted fixed point */
		case fstartR:
			data = float_to_Bit32s(data, 12);
		case startR:
			if (chips & 1) v->fbi.startr = (Bit32s)(data << 8) >> 8;
			break;

		case fstartG:
			data = float_to_Bit32s(data, 12);
		case startG:
			if (chips & 1) v->fbi.startg = (Bit32s)(data << 8) >> 8;
			break;

		case fstartB:
			data = float_to_Bit32s(data, 12);
		case startB:
			if (chips & 1) v->fbi.startb = (Bit32s)(data << 8) >> 8;
			break;

		case fstartA:
			data = float_to_Bit32s(data, 12);
		case startA:
			if (chips & 1) v->fbi.starta = (Bit32s)(data << 8) >> 8;
			break;

		case fdRdX:
			data = float_to_Bit32s(data, 12);
		case dRdX:
			if (chips & 1) v->fbi.drdx = (Bit32s)(data << 8) >> 8;
			break;

		case fdGdX:
			data = float_to_Bit32s(data, 12);
		case dGdX:
			if (chips & 1) v->fbi.dgdx = (Bit32s)(data << 8) >> 8;
			break;

		case fdBdX:
			data = float_to_Bit32s(data, 12);
		case dBdX:
			if (chips & 1) v->fbi.dbdx = (Bit32s)(data << 8) >> 8;
			break;

		case fdAdX:
			data = float_to_Bit32s(data, 12);
		case dAdX:
			if (chips & 1) v->fbi.dadx = (Bit32s)(data << 8) >> 8;
			break;

		case fdRdY:
			data = float_to_Bit32s(data, 12);
		case dRdY:
			if (chips & 1) v->fbi.drdy = (Bit32s)(data << 8) >> 8;
			break;

		case fdGdY:
			data = float_to_Bit32s(data, 12);
		case dGdY:
			if (chips & 1) v->fbi.dgdy = (Bit32s)(data << 8) >> 8;
			break;

		case fdBdY:
			data = float_to_Bit32s(data, 12);
		case dBdY:
			if (chips & 1) v->fbi.dbdy = (Bit32s)(data << 8) >> 8;
			break;

		case fdAdY:
			data = float_to_Bit32s(data, 12);
		case dAdY:
			if (chips & 1) v->fbi.dady = (Bit32s)(data << 8) >> 8;
			break;

		/* Z data is 20.12 formatted fixed point */
		case fstartZ:
			data = float_to_Bit32s(data, 12);
		case startZ:
			if (chips & 1) v->fbi.startz = (Bit32s)data;
			break;

		case fdZdX:
			data = float_to_Bit32s(data, 12);
		case dZdX:
			if (chips & 1) v->fbi.dzdx = (Bit32s)data;
			break;

		case fdZdY:
			data = float_to_Bit32s(data, 12);
		case dZdY:
			if (chips & 1) v->fbi.dzdy = (Bit32s)data;
			break;

		/* S,T data is 14.18 formatted fixed point, converted to 16.32 internally */
		case fstartS:
			data64 = float_to_Bit64s(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 = (Bit64s)(Bit32s)data << 14;
			if (chips & 4) v->tmu[1].starts = (Bit64s)(Bit32s)data << 14;
			break;

		case fstartT:
			data64 = float_to_Bit64s(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 = (Bit64s)(Bit32s)data << 14;
			if (chips & 4) v->tmu[1].startt = (Bit64s)(Bit32s)data << 14;
			break;

		case fdSdX:
			data64 = float_to_Bit64s(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 = (Bit64s)(Bit32s)data << 14;
			if (chips & 4) v->tmu[1].dsdx = (Bit64s)(Bit32s)data << 14;
			break;

		case fdTdX:
			data64 = float_to_Bit64s(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 = (Bit64s)(Bit32s)data << 14;
			if (chips & 4) v->tmu[1].dtdx = (Bit64s)(Bit32s)data << 14;
			break;

		case fdSdY:
			data64 = float_to_Bit64s(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 = (Bit64s)(Bit32s)data << 14;
			if (chips & 4) v->tmu[1].dsdy = (Bit64s)(Bit32s)data << 14;
			break;

		case fdTdY:
			data64 = float_to_Bit64s(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 = (Bit64s)(Bit32s)data << 14;
			if (chips & 4) v->tmu[1].dtdy = (Bit64s)(Bit32s)data << 14;
			break;

		/* W data is 2.30 formatted fixed point, converted to 16.32 internally */
		case fstartW:
			data64 = float_to_Bit64s(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 = (Bit64s)(Bit32s)data << 2;
			if (chips & 2) v->tmu[0].startw = (Bit64s)(Bit32s)data << 2;
			if (chips & 4) v->tmu[1].startw = (Bit64s)(Bit32s)data << 2;
			break;

		case fdWdX:
			data64 = float_to_Bit64s(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 = (Bit64s)(Bit32s)data << 2;
			if (chips & 2) v->tmu[0].dwdx = (Bit64s)(Bit32s)data << 2;
			if (chips & 4) v->tmu[1].dwdx = (Bit64s)(Bit32s)data << 2;
			break;

		case fdWdY:
			data64 = float_to_Bit64s(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 = (Bit64s)(Bit32s)data << 2;
			if (chips & 2) v->tmu[0].dwdy = (Bit64s)(Bit32s)data << 2;
			if (chips & 4) v->tmu[1].dwdy = (Bit64s)(Bit32s)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]);
			E_Exit("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
					LOG_VOODOO("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 = video_screen_get_frame_period(v->screen).attoseconds;
					attoseconds_t refresh ;
					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;

					LOG_VOODOO("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);
					LOG_VOODOO("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)
					{
//						video_screen_configure(v->screen, htotal, vtotal, &visarea, stdperiod);
						LOG_VOODOO("Standard resolution, %f Hz\n", ATTOSECONDS_TO_HZ(stdperiod));
					}
					else if (meddiff < vgadiff)
					{
//						video_screen_configure(v->screen, htotal, vtotal, &visarea, medperiod);
						LOG_VOODOO("Medium resolution, %f Hz\n", ATTOSECONDS_TO_HZ(medperiod));
					}
					else
					{
//						video_screen_configure(v->screen, htotal, vtotal, &visarea, vgaperiod);
						LOG_VOODOO("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))
				E_Exit("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)
					E_Exit("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)
			LOG_VOODOO("VOODOO.%d.REG:%s(%d) write = %08X\n", v->index, (regnum < 0x384/4) ? v->regnames[regnum] : "oob", chips, origdata);
		else
			LOG_VOODOO("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 Bit32s lfb_w(voodoo_state *v, offs_t offset, Bit32u data, Bit32u mem_mask, int forcefront)
{
	Bit16u *dest, *depth;
	Bit32u 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 = (Bit16u *)(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 = (Bit16u *)(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 = (Bit16u *)(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;
		Bit32u bufoffs;

		if (LOG_LFB) LOG_VOODOO("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) LOG_VOODOO("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;
				Bit64s iterw = sw[pix] << (30-16);
				Bit32s 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 Bit32s texture_w(voodoo_state *v, offs_t offset, Bit32u 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))
		E_Exit("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;
		Bit32u tbaseaddr;
		Bit8u *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) LOG_VOODOO("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) LOG_VOODOO("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;
		Bit32u tbaseaddr;
		Bit16u *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) LOG_VOODOO("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) LOG_VOODOO("Texture 16-bit w: offset=%X data=%08X\n", offset*4, data);
		}

		/* write the two words in little-endian order */
		dest = (Bit16u *)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)
{
#if 0
	static Bit8u in_flush;

	/* check for recursive calls */
	if (in_flush)
		return;
	in_flush = TRUE;

	if (!v->pci.op_pending) E_Exit("flush_fifos called with no pending operation");

	if (LOG_FIFO_VERBOSE) LOG_VOODOO("VOODOO.%d.FIFO:flush_fifos start -- pending=%d.%08X%08X cur=%d.%08X%08X\n", v->index,
		v->pci.op_end_time.seconds, (Bit32u)(v->pci.op_end_time.attoseconds >> 32), (Bit32u)v->pci.op_end_time.attoseconds,
		current_time.seconds, (Bit32u)(current_time.attoseconds >> 32), (Bit32u)current_time.attoseconds);

	/* loop while we still have cycles to burn */
	while (attotime_compare(v->pci.op_end_time, current_time) <= 0)
	{
		Bit32s extra_cycles = 0;
		Bit32s cycles;

		/* loop over 0-cycle stuff; this constitutes the bulk of our writes */
		do
		{
			fifo_state *fifo;
			Bit32u address;
			Bit32u 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) LOG_VOODOO("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) LOG_VOODOO("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) LOG_VOODOO("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
				{
					Bit32u 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_add_attoseconds(v->pci.op_end_time, (attoseconds_t)cycles * v->attoseconds_per_cycle);

		if (LOG_FIFO_VERBOSE) LOG_VOODOO("VOODOO.%d.FIFO:update -- pending=%d.%08X%08X cur=%d.%08X%08X\n", v->index,
			v->pci.op_end_time.seconds, (Bit32u)(v->pci.op_end_time.attoseconds >> 32), (Bit32u)v->pci.op_end_time.attoseconds,
			current_time.seconds, (Bit32u)(current_time.attoseconds >> 32), (Bit32u)current_time.attoseconds);
	}

	if (LOG_FIFO_VERBOSE) LOG_VOODOO("VOODOO.%d.FIFO:flush_fifos end -- pending command complete at %d.%08X%08X\n", v->index,
		v->pci.op_end_time.seconds, (Bit32u)(v->pci.op_end_time.attoseconds >> 32), (Bit32u)v->pci.op_end_time.attoseconds);

	in_flush = FALSE;
#endif
}


/*************************************
 *
 *  Handle a write to the Voodoo
 *  memory space
 *
 *************************************/

//WRITE32_DEVICE_HANDLER( voodoo_w )
static void voodoo_w(Bitu offset, Bitu data)
{
//	voodoo_state *v = get_safe_token(device);
	int stall = FALSE;
	Bitu mem_mask = 0x3fffff;

	profiler_mark_start(PROFILER_USER1);

	/* should not be getting accesses while stalled */
	if (v->pci.stall_state != NOT_STALLED)
		LOG_VOODOO("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, timer_get_time(device->machine));

	/* special handling for registers */
	if ((offset & 0xc00000/4) == 0)
	{
		Bit8u 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);
					profiler_mark_end();
					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++;

					LOG_VOODOO("Ignoring write to %s in CMDFIFO mode\n", v->regnames[offset & 0xff]);
					profiler_mark_end();
					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))
		{
			profiler_mark_end();
			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 = attotime_add_attoseconds(timer_get_time(device->machine), (attoseconds_t)cycles * v->attoseconds_per_cycle);

			if (LOG_FIFO_VERBOSE) LOG_VOODOO("VOODOO.%d.FIFO:direct write start at %d.%08X%08X end at %d.%08X%08X\n", v->index,
				timer_get_time(device->machine).seconds, (Bit32u)(timer_get_time(device->machine).attoseconds >> 32), (Bit32u)timer_get_time(device->machine).attoseconds,
				v->pci.op_end_time.seconds, (Bit32u)(v->pci.op_end_time.attoseconds >> 32), (Bit32u)v->pci.op_end_time.attoseconds);
*/
		}
		profiler_mark_end();
		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) LOG_VOODOO("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
		E_Exit("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))
	{
		Bit8u 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) LOG_VOODOO("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) LOG_VOODOO("VOODOO.%d.FIFO:voodoo_w hit memory FIFO HWM -- stalling\n", v->index);
//			stall_cpu(v, STALLED_UNTIL_FIFO_LWM, timer_get_time(device->machine));
		}
	}

	/* 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) LOG_VOODOO("VOODOO.%d.FIFO:voodoo_w hit PCI FIFO free LWM -- stalling\n", v->index);
//		stall_cpu(v, STALLED_UNTIL_FIFO_LWM, timer_get_time(device->machine));
	}

	/* if we weren't ready, and this is a non-FIFO access, stall until the FIFOs are clear */
	if (stall)
	{
		if (LOG_FIFO_VERBOSE) LOG_VOODOO("VOODOO.%d.FIFO:voodoo_w wrote non-FIFO register -- stalling until clear\n", v->index);
//		stall_cpu(v, STALLED_UNTIL_FIFO_EMPTY, timer_get_time(device->machine));
	}

	profiler_mark_end();
}



/*************************************
 *
 *  Handle a register read
 *
 *************************************/

static Bit32u register_r(voodoo_state *v, offs_t offset)
{
	int regnum = offset & 0xff;
	Bit32u result;

	/* statistics */
	v->stats.reg_reads++;

	/* first make sure this register is readable */
	if (!(v->regaccess[regnum] & REGISTER_READ))
	{
		LOG_VOODOO("VOODOO.%d.ERROR:Invalid attempt to read %s\n", v->index, v->regnames[regnum]);
		return 0xffffffff;
	}

	if (!((voodoo_last_msg==regnum) && (regnum==status)))	//show status reg only once
	LOG_VOODOO("Voodoo:read reg %x (%s)",  regnum<<2, voodoo_reg_name[regnum]);
	voodoo_last_msg=regnum;

	/* 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 */
			cpu_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 */
			cpu_eat_cycles(v->cpu, 10);
//			result = video_screen_get_vpos(v->screen);
			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 */
			cpu_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)
			LOG_VOODOO("VOODOO.%d.REG:%s read = %08X\n", v->index, v->regnames[regnum], result);
	}

	return result;
}



/*************************************
 *
 *  Handle an LFB read
 *
 *************************************/

static Bit32u lfb_r(voodoo_state *v, offs_t offset, int forcefront)
{
	Bit16u *buffer;
	Bit32u bufmax;
	Bit32u bufoffs;
	Bit32u 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 = (Bit16u *)(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 = (Bit16u *)(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 = (Bit16u *)(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) LOG_VOODOO("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 )
Bitu voodoo_r(Bitu offset)
{
//	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, timer_get_time(device->machine));

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

#if 0

static READ32_DEVICE_HANDLER( banshee_agp_r )
{
	voodoo_state *v = get_safe_token(device);
	Bit32u 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)
		LOG_VOODOO("%s:banshee_r(AGP:%s)\n", cpuexec_describe_context(v->device->machine), banshee_agp_reg_name[offset]);
	return result;
}


READ32_DEVICE_HANDLER( banshee_r )
{
	voodoo_state *v = get_safe_token(device);
	Bit32u result = 0xffffffff;

	/* if we have something pending, flush the FIFOs up to the current time */
	if (v->pci.op_pending)
		flush_fifos(v, timer_get_time(device->machine));

	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)
		LOG_VOODOO("%s:banshee_r(2D:%X)\n", cpuexec_describe_context(device->machine), (offset*4) & 0xfffff);
	else if (offset < 0x600000/4)
		result = register_r(v, offset & 0x1fffff/4);
	else if (offset < 0x800000/4)
		LOG_VOODOO("%s:banshee_r(TEX:%X)\n", cpuexec_describe_context(device->machine), (offset*4) & 0x1fffff);
	else if (offset < 0xc00000/4)
		LOG_VOODOO("%s:banshee_r(RES:%X)\n", cpuexec_describe_context(device->machine), (offset*4) & 0x3fffff);
	else if (offset < 0x1000000/4)
		LOG_VOODOO("%s:banshee_r(YUV:%X)\n", cpuexec_describe_context(device->machine), (offset*4) & 0x3fffff);
	else if (offset < 0x2000000/4)
	{
		Bit8u 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);
	Bit32u result = 0xffffffff;

	/* if we have something pending, flush the FIFOs up to the current time */
	if (v->pci.op_pending)
		flush_fifos(v, timer_get_time(device->machine));

	if (offset < v->fbi.lfb_base)
	{
		LOG_VOODOO("%s:banshee_fb_r(%X)\n", cpuexec_describe_context(device->machine), offset*4);
		if (offset*4 <= v->fbi.mask)
			result = ((Bit32u *)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);
	Bit8u 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)
				LOG_VOODOO("%s:banshee_att_r(%X)\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_vga_r(%X)\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_seq_r(%X)\n", cpuexec_describe_context(device->machine), v->banshee.vga[0x3c4 & 0x1f]);
			break;

		/* Feature control */
		case 0x3ca:
			result = v->banshee.vga[0x3da & 0x1f];
			v->banshee.attff = 0;
			if (LOG_REGISTERS)
				LOG_VOODOO("%s:banshee_vga_r(%X)\n", cpuexec_describe_context(device->machine), 0x300+offset);
			break;

		/* Miscellaneous output */
		case 0x3cc:
			result = v->banshee.vga[0x3c2 & 0x1f];
			if (LOG_REGISTERS)
				LOG_VOODOO("%s:banshee_vga_r(%X)\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_gc_r(%X)\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_crtc_r(%X)\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_vga_r(%X)\n", cpuexec_describe_context(device->machine), 0x300+offset);
			break;

		default:
			result = v->banshee.vga[offset];
			if (LOG_REGISTERS)
				LOG_VOODOO("%s:banshee_vga_r(%X)\n", cpuexec_describe_context(device->machine), 0x300+offset);
			break;
	}
	return result;
}


READ32_DEVICE_HANDLER( banshee_io_r )
{
	voodoo_state *v = get_safe_token(device);
	Bit32u 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)
				LOG_VOODOO("%s:banshee_dac_r(%X)\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_io_r(%s)\n", cpuexec_describe_context(device->machine), banshee_io_reg_name[offset]);
			break;
	}

	return result;
}


READ32_DEVICE_HANDLER( banshee_rom_r )
{
	LOG_VOODOO("%s:banshee_rom_r(%X)\n", cpuexec_describe_context(device->machine), 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:
			E_Exit("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:
			E_Exit("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)
		LOG_VOODOO("%s:banshee_w(AGP:%s) = %08X & %08X\n", cpuexec_describe_context(device->machine), 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, timer_get_time(device->machine));

	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)
		LOG_VOODOO("%s:banshee_w(2D:%X) = %08X & %08X\n", cpuexec_describe_context(device->machine), (offset*4) & 0xfffff, data, mem_mask);
	else if (offset < 0x600000/4)
		register_w(v, offset & 0x1fffff/4, data);
	else if (offset < 0x800000/4)
		LOG_VOODOO("%s:banshee_w(TEX:%X) = %08X & %08X\n", cpuexec_describe_context(device->machine), (offset*4) & 0x1fffff, data, mem_mask);
	else if (offset < 0xc00000/4)
		LOG_VOODOO("%s:banshee_w(RES:%X) = %08X & %08X\n", cpuexec_describe_context(device->machine), (offset*4) & 0x3fffff, data, mem_mask);
	else if (offset < 0x1000000/4)
		LOG_VOODOO("%s:banshee_w(YUV:%X) = %08X & %08X\n", cpuexec_describe_context(device->machine), (offset*4) & 0x3fffff, data, mem_mask);
	else if (offset < 0x2000000/4)
	{
		Bit8u 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);
	Bit32u addr = offset*4;

	/* if we have something pending, flush the FIFOs up to the current time */
	if (v->pci.op_pending)
		flush_fifos(v, timer_get_time(device->machine));

	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(&((Bit32u *)v->fbi.ram)[offset]);
			LOG_VOODOO("%s:banshee_fb_w(%X) = %08X & %08X\n", cpuexec_describe_context(device->machine), 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)
					LOG_VOODOO("%s:banshee_vga_w(%X) = %02X\n", cpuexec_describe_context(device->machine), 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)
					LOG_VOODOO("%s:banshee_att_w(%X) = %02X\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_seq_w(%X) = %02X\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_gc_w(%X) = %02X\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_crtc_w(%X) = %02X\n", cpuexec_describe_context(device->machine), v->banshee.vga[0x3d4 & 0x1f], data);
			break;

		default:
			v->banshee.vga[offset] = data;
			if (LOG_REGISTERS)
				LOG_VOODOO("%s:banshee_vga_w(%X) = %02X\n", cpuexec_describe_context(device->machine), 0x3c0+offset, data);
			break;
	}
}


WRITE32_DEVICE_HANDLER( banshee_io_w )
{
	voodoo_state *v = get_safe_token(device);
	Bit32u 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)
				LOG_VOODOO("%s:banshee_io_w(%s) = %08X & %08X\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_dac_w(%X) = %08X & %08X\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_io_w(%s) = %08X & %08X\n", cpuexec_describe_context(device->machine), 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;
			video_screen_set_visarea(v->screen, 0, v->fbi.width - 1, 0, v->fbi.height - 1);
			adjust_vblank_timer(v);
			if (LOG_REGISTERS)
				LOG_VOODOO("%s:banshee_io_w(%s) = %08X & %08X\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_io_w(%s) = %08X & %08X\n", cpuexec_describe_context(device->machine), 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)
				LOG_VOODOO("%s:banshee_io_w(%s) = %08X & %08X\n", cpuexec_describe_context(device->machine), banshee_io_reg_name[offset], data, mem_mask);
			break;
	}
}

#endif

/***************************************************************************
    DEVICE INTERFACE
***************************************************************************/

/*-------------------------------------------------
    device start callback
-------------------------------------------------*/

static void voodoo_init() {
	void *fbmem, *tmumem[2];
	Bit32u tmumem0;
	int val;

	/* 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++)
	{
		Bit32u value = (1 << RECIPLOG_LOOKUP_BITS) + val;
		voodoo_reciplog[val*2 + 0] = (1 << (RECIPLOG_LOOKUP_PREC + RECIPLOG_LOOKUP_BITS)) / value;
		voodoo_reciplog[val*2 + 1] = (Bit32u)(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;
		}
	}

	v->type = VOODOO_1;
	/* configure type-specific values */
	switch (v->type)
	{
		case VOODOO_1:
			v->regaccess = voodoo_register_access;
			v->regnames = voodoo_reg_name;
			v->alt_regmap = 0;
			v->fbi.lfb_stride = 10;
			break;
		default:
			break;
	}

	
	/* allocate memory */
//	tmumem0 = config->tmumem0;
	tmumem0 = 8;
	if (v->type <= VOODOO_2)
	{
		/* separate FB/TMU memory */
//		fbmem = auto_alloc_array(device->machine, Bit8u, config->fbmem << 20);
		fbmem = (void*)malloc(4<<20);
//		tmumem[0] = auto_alloc_array(device->machine, Bit8u, config->tmumem0 << 20);
		tmumem[0] = (void*)malloc(4<<20);
//		tmumem[1] = (config->tmumem1 != 0) ? auto_alloc_array(device->machine, Bit8u, config->tmumem1 << 20) : NULL;
		tmumem[1] = (void*)malloc(4<<20);
	}
	else
	{
		/* shared memory */
//		tmumem[0] = tmumem[1] = fbmem = auto_alloc_array(device->machine, Bit8u, config->fbmem << 20);
//		tmumem0 = config->fbmem;
	}

	/* set up frame buffer */
	init_fbi(v, &v->fbi, fbmem, 4<<20);//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);
		init_tmu(v, &v->tmu[1], &v->reg[0x200], tmumem[1], 4 << 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);

	memset(v->reg, 0, sizeof(v->reg));
	v->alt_regmap = 0;
	v->regaccess = voodoo_register_access;
	v->regnames = voodoo_reg_name;
	v->type = VOODOO_1;
	v->pci.init_enable = (1<<2) | 1;
	v->chipmask = 0x01 | 0x02 | 0x04 | 0x08;
	memset(v->dac.reg, 0, sizeof(v->dac.reg));
	v->dac.read_result = 0;

	soft_reset(v);

}

#if 0

static DEVICE_START( voodoo )
{
	const voodoo_config *config = (const voodoo_config *)device->baseconfig().inline_config;
	voodoo_state *v = get_safe_token(device);
	const raster_info *info;
	void *fbmem, *tmumem[2];
	Bit32u tmumem0;
	int val;

	/* validate some basic stuff */
	assert(device->baseconfig().static_config == NULL);
	assert(device->baseconfig().inline_config != NULL);
	assert(device->machine != NULL);
	assert(device->machine->config != 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++)
	{
		Bit32u value = (1 << RECIPLOG_LOOKUP_BITS) + val;
		voodoo_reciplog[val*2 + 0] = (1 << (RECIPLOG_LOOKUP_PREC + RECIPLOG_LOOKUP_BITS)) / value;
		voodoo_reciplog[val*2 + 1] = (Bit32u)(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:
			E_Exit("Unsupported voodoo card in voodoo_start!");
			break;
	}

	/* set the type, and initialize the chip mask */
	v->index = device->machine->devicelist.index(device->type, device->tag());
	v->screen = 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 = timer_alloc(v->device->machine, stall_cpu_callback, v);

	/* allocate memory */
	tmumem0 = config->tmumem0;
	if (config->type <= VOODOO_2)
	{
		/* separate FB/TMU memory */
		fbmem = auto_alloc_array(device->machine, Bit8u, config->fbmem << 20);
		tmumem[0] = auto_alloc_array(device->machine, Bit8u, config->tmumem0 << 20);
		tmumem[1] = (config->tmumem1 != 0) ? auto_alloc_array(device->machine, Bit8u, config->tmumem1 << 20) : NULL;
	}
	else
	{
		/* shared memory */
		tmumem[0] = tmumem[1] = fbmem = auto_alloc_array(device->machine, Bit8u, 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 *)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"
#define DEVTEMPLATE_CLASS		DEVICE_CLASS_VIDEO
#include "devtempl.h"

#endif

/***************************************************************************
    COMMAND HANDLERS
***************************************************************************/

/*-------------------------------------------------
    fastfill - execute the 'fastfill'
    command
-------------------------------------------------*/

static Bit32s 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];
	Bit16u dithermatrix[16];
	Bit16u *drawbuf = NULL;
	Bit32u 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 = (Bit16u *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
				break;

			case 1:		/* back buffer */
				drawbuf = (Bit16u *)(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 Bit32s swapbuffer(voodoo_state *v, Bit32u 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 Bit32s triangle(voodoo_state *v)
{
	int texcount = 0;
	Bit16u *drawbuf;
	int destbuf;
	int pixels;

	profiler_mark_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))
	{
		Bit32s dx = 8 - (v->fbi.ax & 15);
		Bit32s 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 = (Bit16u *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
			v->fbi.video_changed = TRUE;
			break;

		case 1:		/* back buffer */
			drawbuf = (Bit16u *)(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++;

	profiler_mark_end();

	/* 1 pixel per clock, plus some setup time */
	if (LOG_REGISTERS) LOG_VOODOO("cycles = %d\n", TRIANGLE_SETUP_CLOCKS + pixels);
	return TRIANGLE_SETUP_CLOCKS + pixels;
}


/*-------------------------------------------------
    begin_triangle - execute the 'beginTri'
    command
-------------------------------------------------*/

static Bit32s 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 Bit32s 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 Bit32s setup_and_draw_triangle(voodoo_state *v)
{
	float dx1, dy1, dx2, dy2;
	float divisor, tdiv;

	/* grab the X/Ys at least */
	v->fbi.ax = (Bit16s)(v->fbi.svert[0].x * 16.0);
	v->fbi.ay = (Bit16s)(v->fbi.svert[0].y * 16.0);
	v->fbi.bx = (Bit16s)(v->fbi.svert[1].x * 16.0);
	v->fbi.by = (Bit16s)(v->fbi.svert[1].y * 16.0);
	v->fbi.cx = (Bit16s)(v->fbi.svert[2].x * 16.0);
	v->fbi.cy = (Bit16s)(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 = (Bit32s)(v->fbi.svert[0].r * 4096.0f);
		v->fbi.drdx = (Bit32s)(((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 = (Bit32s)(((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 = (Bit32s)(v->fbi.svert[0].g * 4096.0f);
		v->fbi.dgdx = (Bit32s)(((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 = (Bit32s)(((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 = (Bit32s)(v->fbi.svert[0].b * 4096.0f);
		v->fbi.dbdx = (Bit32s)(((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 = (Bit32s)(((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 = (Bit32s)(v->fbi.svert[0].a * 4096.0);
		v->fbi.dadx = (Bit32s)(((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 = (Bit32s)(((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 = (Bit32s)(v->fbi.svert[0].z * 4096.0);
		v->fbi.dzdx = (Bit32s)(((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 = (Bit32s)(((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 = (Bit64s)(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 = (Bit64s)(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 = (Bit64s)(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 = (Bit64s)(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 = (Bit64s)(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 = (Bit64s)(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 = (Bit64s)(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 Bit32s triangle_create_work_item(voodoo_state *v, Bit16u *drawbuf, int texcount)
{
#if 0
	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]);
#endif
	return 0;
}



/***************************************************************************
    RASTERIZER MANAGEMENT
***************************************************************************/

/*-------------------------------------------------
    add_rasterizer - add a rasterizer to our
    hash table
-------------------------------------------------*/

static raster_info *add_rasterizer(voodoo_state *v, const raster_info *cinfo)
{
#if 0
	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;
#endif
	return (raster_info*)NULL;
}


/*-------------------------------------------------
    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)
{
#if 0
	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);
#endif
	return (raster_info*)NULL;
}


/*-------------------------------------------------
    dump_rasterizer_stats - dump statistics on
    the current rasterizer usage patterns
-------------------------------------------------*/

static void dump_rasterizer_stats(voodoo_state *v)
{
#if 0
	static Bit8u 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;
	}
#endif
}



/***************************************************************************
    GENERIC RASTERIZERS
***************************************************************************/

/*-------------------------------------------------
    raster_fastfill - per-scanline
    implementation of the 'fastfill' command
-------------------------------------------------*/

static void raster_fastfill(void *destbase, Bit32s 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];
	Bit32s startx = extent->startx;
	Bit32s 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 Bit16u *ditherow = &extra->dither[(y & 3) * 4];
		Bit64u expanded = *(Bit64u *)ditherow;
		Bit16u *dest = (Bit16u *)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)
			*(Bit64u *)&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)
	{
		Bit16u color = v->reg[zaColor].u;
		Bit64u expanded = ((Bit64u)color << 48) | ((Bit64u)color << 32) | (color << 16) | color;
		Bit16u *dest = (Bit16u *)(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)
			*(Bit64u *)&dest[x] = expanded;
		for ( ; x < stopx; x++)
			dest[x] = color;
	}
}

#if 0
/*-------------------------------------------------
    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)
#endif

#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
