#include <math.h>
#include <stddef.h>
#include "ibm.h"
#include "device.h"
#include "mem.h"
#include "thread.h"
#include "video.h"
#include "vid_svga.h"
#include "vid_voodoo.h"
#include "vid_voodoo_common.h"
#include "vid_voodoo_banshee.h"
#include "vid_voodoo_blitter.h"
#include "vid_voodoo_dither.h"
#include "vid_voodoo_fifo.h"
#include "vid_voodoo_reg.h"
#include "vid_voodoo_regs.h"
#include "vid_voodoo_render.h"
#include "vid_voodoo_setup.h"
#include "vid_voodoo_texture.h"

enum {
	CHIP_FBI = 0x1,
	CHIP_TREX0 = 0x2,
	CHIP_TREX1 = 0x4,
	CHIP_TREX2 = 0x8
};

void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) {
	voodoo_t *voodoo = (voodoo_t *)p;
	union {
		uint32_t i;
		float f;
	} tempif;
	int ad21 = addr & (1 << 21);
	int chip = (addr >> 10) & 0xf;
	if (!chip)
		chip = 0xf;

	tempif.i = val;
//pclog("voodoo_reg_write_l: addr=%08x val=%08x(%f) chip=%x\n", addr, val, tempif.f, chip);
	addr &= 0x3fc;

	if ((voodoo->fbiInit3 & FBIINIT3_REMAP) && addr < 0x100 && ad21)
		addr |= 0x400;
	switch (addr) {
	case SST_swapbufferCMD:
		if (voodoo->type >= VOODOO_BANSHEE) {
//                        pclog("swapbufferCMD %08x %08x\n", val, voodoo->leftOverlayBuf);

			voodoo_wait_for_render_thread_idle(voodoo);
			if (!(val & 1)) {
				banshee_set_overlay_addr(voodoo->p, voodoo->leftOverlayBuf);
				thread_lock_mutex(voodoo->swap_mutex);
				if (voodoo->swap_count > 0)
					voodoo->swap_count--;
				thread_unlock_mutex(voodoo->swap_mutex);
				voodoo->frame_count++;
			} else if (TRIPLE_BUFFER) {
				if (voodoo->swap_pending)
					voodoo_wait_for_swap_complete(voodoo);
				voodoo->swap_interval = (val >> 1) & 0xff;
				voodoo->swap_offset = voodoo->leftOverlayBuf;
				voodoo->swap_pending = 1;
			} else {
				voodoo->swap_interval = (val >> 1) & 0xff;
				voodoo->swap_offset = voodoo->leftOverlayBuf;
				voodoo->swap_pending = 1;

				voodoo_wait_for_swap_complete(voodoo);
			}

			voodoo->cmd_read++;
			break;
		}

		if (TRIPLE_BUFFER) {
			voodoo->disp_buffer = (voodoo->disp_buffer + 1) % 3;
			voodoo->draw_buffer = (voodoo->draw_buffer + 1) % 3;
		} else {
			voodoo->disp_buffer = !voodoo->disp_buffer;
			voodoo->draw_buffer = !voodoo->draw_buffer;
		}
		voodoo_recalc(voodoo);

		voodoo->params.swapbufferCMD = val;

//                pclog("Swap buffer %08x %d %p %i\n", val, voodoo->swap_count, &voodoo->swap_count, (voodoo == voodoo->set->voodoos[1]) ? 1 : 0);
//                voodoo->front_offset = params->front_offset;
		voodoo_wait_for_render_thread_idle(voodoo);
		if (!(val & 1)) {
			memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line));
			voodoo->front_offset = voodoo->params.front_offset;
			thread_lock_mutex(voodoo->swap_mutex);
			if (voodoo->swap_count > 0)
				voodoo->swap_count--;
			thread_unlock_mutex(voodoo->swap_mutex);
		} else if (TRIPLE_BUFFER) {
			if (voodoo->swap_pending)
				voodoo_wait_for_swap_complete(voodoo);

			voodoo->swap_interval = (val >> 1) & 0xff;
			voodoo->swap_offset = voodoo->params.front_offset;
			voodoo->swap_pending = 1;
		} else {
			voodoo->swap_interval = (val >> 1) & 0xff;
			voodoo->swap_offset = voodoo->params.front_offset;
			voodoo->swap_pending = 1;

			voodoo_wait_for_swap_complete(voodoo);
		}
		voodoo->cmd_read++;
		break;

	case SST_vertexAx:
	case SST_remap_vertexAx:voodoo->params.vertexAx = val & 0xffff;
		break;
	case SST_vertexAy:
	case SST_remap_vertexAy:voodoo->params.vertexAy = val & 0xffff;
		break;
	case SST_vertexBx:
	case SST_remap_vertexBx:voodoo->params.vertexBx = val & 0xffff;
		break;
	case SST_vertexBy:
	case SST_remap_vertexBy:voodoo->params.vertexBy = val & 0xffff;
		break;
	case SST_vertexCx:
	case SST_remap_vertexCx:voodoo->params.vertexCx = val & 0xffff;
		break;
	case SST_vertexCy:
	case SST_remap_vertexCy:voodoo->params.vertexCy = val & 0xffff;
		break;

	case SST_startR:
	case SST_remap_startR:voodoo->params.startR = val & 0xffffff;
		break;
	case SST_startG:
	case SST_remap_startG:voodoo->params.startG = val & 0xffffff;
		break;
	case SST_startB:
	case SST_remap_startB:voodoo->params.startB = val & 0xffffff;
		break;
	case SST_startZ:
	case SST_remap_startZ:voodoo->params.startZ = val;
		break;
	case SST_startA:
	case SST_remap_startA:voodoo->params.startA = val & 0xffffff;
		break;
	case SST_startS:
	case SST_remap_startS:
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].startS = ((int64_t)(int32_t)val) << 14;
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].startS = ((int64_t)(int32_t)val) << 14;
		break;
	case SST_startT:
	case SST_remap_startT:
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].startT = ((int64_t)(int32_t)val) << 14;
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].startT = ((int64_t)(int32_t)val) << 14;
		break;
	case SST_startW:
	case SST_remap_startW:
		if (chip & CHIP_FBI)
			voodoo->params.startW = (int64_t)(int32_t)val << 2;
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].startW = (int64_t)(int32_t)val << 2;
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].startW = (int64_t)(int32_t)val << 2;
		break;

	case SST_dRdX:
	case SST_remap_dRdX:voodoo->params.dRdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
		break;
	case SST_dGdX:
	case SST_remap_dGdX:voodoo->params.dGdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
		break;
	case SST_dBdX:
	case SST_remap_dBdX:voodoo->params.dBdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
		break;
	case SST_dZdX:
	case SST_remap_dZdX:voodoo->params.dZdX = val;
		break;
	case SST_dAdX:
	case SST_remap_dAdX:voodoo->params.dAdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
		break;
	case SST_dSdX:
	case SST_remap_dSdX:
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dSdX = ((int64_t)(int32_t)val) << 14;
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dSdX = ((int64_t)(int32_t)val) << 14;
		break;
	case SST_dTdX:
	case SST_remap_dTdX:
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dTdX = ((int64_t)(int32_t)val) << 14;
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dTdX = ((int64_t)(int32_t)val) << 14;
		break;
	case SST_dWdX:
	case SST_remap_dWdX:
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dWdX = (int64_t)(int32_t)val << 2;
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dWdX = (int64_t)(int32_t)val << 2;
		if (chip & CHIP_FBI)
			voodoo->params.dWdX = (int64_t)(int32_t)val << 2;
		break;

	case SST_dRdY:
	case SST_remap_dRdY:voodoo->params.dRdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
		break;
	case SST_dGdY:
	case SST_remap_dGdY:voodoo->params.dGdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
		break;
	case SST_dBdY:
	case SST_remap_dBdY:voodoo->params.dBdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
		break;
	case SST_dZdY:
	case SST_remap_dZdY:voodoo->params.dZdY = val;
		break;
	case SST_dAdY:
	case SST_remap_dAdY:voodoo->params.dAdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
		break;
	case SST_dSdY:
	case SST_remap_dSdY:
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dSdY = ((int64_t)(int32_t)val) << 14;
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dSdY = ((int64_t)(int32_t)val) << 14;
		break;
	case SST_dTdY:
	case SST_remap_dTdY:
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dTdY = ((int64_t)(int32_t)val) << 14;
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dTdY = ((int64_t)(int32_t)val) << 14;
		break;
	case SST_dWdY:
	case SST_remap_dWdY:
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dWdY = (int64_t)(int32_t)val << 2;
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dWdY = (int64_t)(int32_t)val << 2;
		if (chip & CHIP_FBI)
			voodoo->params.dWdY = (int64_t)(int32_t)val << 2;
		break;

	case SST_triangleCMD:
	case SST_remap_triangleCMD:voodoo->params.sign = val & (1 << 31);

		if (voodoo->ncc_dirty[0])
			voodoo_update_ncc(voodoo, 0);
		if (voodoo->ncc_dirty[1])
			voodoo_update_ncc(voodoo, 1);
		voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0;

		voodoo_queue_triangle(voodoo, &voodoo->params);

		voodoo->cmd_read++;
		break;

	case SST_fvertexAx:
	case SST_remap_fvertexAx:voodoo->fvertexAx.i = val;
		voodoo->params.vertexAx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAx.f * 16.0f) & 0xffff;
		break;
	case SST_fvertexAy:
	case SST_remap_fvertexAy:voodoo->fvertexAy.i = val;
		voodoo->params.vertexAy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAy.f * 16.0f) & 0xffff;
		break;
	case SST_fvertexBx:
	case SST_remap_fvertexBx:voodoo->fvertexBx.i = val;
		voodoo->params.vertexBx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBx.f * 16.0f) & 0xffff;
		break;
	case SST_fvertexBy:
	case SST_remap_fvertexBy:voodoo->fvertexBy.i = val;
		voodoo->params.vertexBy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBy.f * 16.0f) & 0xffff;
		break;
	case SST_fvertexCx:
	case SST_remap_fvertexCx:voodoo->fvertexCx.i = val;
		voodoo->params.vertexCx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCx.f * 16.0f) & 0xffff;
		break;
	case SST_fvertexCy:
	case SST_remap_fvertexCy:voodoo->fvertexCy.i = val;
		voodoo->params.vertexCy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCy.f * 16.0f) & 0xffff;
		break;

	case SST_fstartR:
	case SST_remap_fstartR:tempif.i = val;
		voodoo->params.startR = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fstartG:
	case SST_remap_fstartG:tempif.i = val;
		voodoo->params.startG = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fstartB:
	case SST_remap_fstartB:tempif.i = val;
		voodoo->params.startB = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fstartZ:
	case SST_remap_fstartZ:tempif.i = val;
		voodoo->params.startZ = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fstartA:
	case SST_remap_fstartA:tempif.i = val;
		voodoo->params.startA = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fstartS:
	case SST_remap_fstartS:tempif.i = val;
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].startS = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].startS = (int64_t)(tempif.f * 4294967296.0f);
		break;
	case SST_fstartT:
	case SST_remap_fstartT:tempif.i = val;
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].startT = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].startT = (int64_t)(tempif.f * 4294967296.0f);
		break;
	case SST_fstartW:
	case SST_remap_fstartW:tempif.i = val;
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].startW = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].startW = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_FBI)
			voodoo->params.startW = (int64_t)(tempif.f * 4294967296.0f);
		break;

	case SST_fdRdX:
	case SST_remap_fdRdX:tempif.i = val;
		voodoo->params.dRdX = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fdGdX:
	case SST_remap_fdGdX:tempif.i = val;
		voodoo->params.dGdX = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fdBdX:
	case SST_remap_fdBdX:tempif.i = val;
		voodoo->params.dBdX = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fdZdX:
	case SST_remap_fdZdX:tempif.i = val;
		voodoo->params.dZdX = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fdAdX:
	case SST_remap_fdAdX:tempif.i = val;
		voodoo->params.dAdX = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fdSdX:
	case SST_remap_fdSdX:tempif.i = val;
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dSdX = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dSdX = (int64_t)(tempif.f * 4294967296.0f);
		break;
	case SST_fdTdX:
	case SST_remap_fdTdX:tempif.i = val;
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dTdX = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dTdX = (int64_t)(tempif.f * 4294967296.0f);
		break;
	case SST_fdWdX:
	case SST_remap_fdWdX:tempif.i = val;
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dWdX = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dWdX = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_FBI)
			voodoo->params.dWdX = (int64_t)(tempif.f * 4294967296.0f);
		break;

	case SST_fdRdY:
	case SST_remap_fdRdY:tempif.i = val;
		voodoo->params.dRdY = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fdGdY:
	case SST_remap_fdGdY:tempif.i = val;
		voodoo->params.dGdY = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fdBdY:
	case SST_remap_fdBdY:tempif.i = val;
		voodoo->params.dBdY = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fdZdY:
	case SST_remap_fdZdY:tempif.i = val;
		voodoo->params.dZdY = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fdAdY:
	case SST_remap_fdAdY:tempif.i = val;
		voodoo->params.dAdY = (int32_t)(tempif.f * 4096.0f);
		break;
	case SST_fdSdY:
	case SST_remap_fdSdY:tempif.i = val;
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dSdY = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dSdY = (int64_t)(tempif.f * 4294967296.0f);
		break;
	case SST_fdTdY:
	case SST_remap_fdTdY:tempif.i = val;
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dTdY = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dTdY = (int64_t)(tempif.f * 4294967296.0f);
		break;
	case SST_fdWdY:
	case SST_remap_fdWdY:tempif.i = val;
		if (chip & CHIP_TREX0)
			voodoo->params.tmu[0].dWdY = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_TREX1)
			voodoo->params.tmu[1].dWdY = (int64_t)(tempif.f * 4294967296.0f);
		if (chip & CHIP_FBI)
			voodoo->params.dWdY = (int64_t)(tempif.f * 4294967296.0f);
		break;

	case SST_ftriangleCMD:voodoo->params.sign = val & (1 << 31);

		if (voodoo->ncc_dirty[0])
			voodoo_update_ncc(voodoo, 0);
		if (voodoo->ncc_dirty[1])
			voodoo_update_ncc(voodoo, 1);
		voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0;

		voodoo_queue_triangle(voodoo, &voodoo->params);

		voodoo->cmd_read++;
		break;

	case SST_fbzColorPath:voodoo->params.fbzColorPath = val;
		voodoo->rgb_sel = val & 3;
		break;

	case SST_fogMode:voodoo->params.fogMode = val;
		break;
	case SST_alphaMode:voodoo->params.alphaMode = val;
		break;
	case SST_fbzMode:voodoo->params.fbzMode = val;
		voodoo_recalc(voodoo);
		break;
	case SST_lfbMode:voodoo->lfbMode = val;
		voodoo_recalc(voodoo);
		break;

	case SST_clipLeftRight:
		if (voodoo->type >= VOODOO_2) {
			voodoo->params.clipRight = val & 0xfff;
			voodoo->params.clipLeft = (val >> 16) & 0xfff;
		} else {
			voodoo->params.clipRight = val & 0x3ff;
			voodoo->params.clipLeft = (val >> 16) & 0x3ff;
		}
		break;
	case SST_clipLowYHighY:
		if (voodoo->type >= VOODOO_2) {
			voodoo->params.clipHighY = val & 0xfff;
			voodoo->params.clipLowY = (val >> 16) & 0xfff;
		} else {
			voodoo->params.clipHighY = val & 0x3ff;
			voodoo->params.clipLowY = (val >> 16) & 0x3ff;
		}
		break;

	case SST_nopCMD:voodoo->cmd_read++;
		voodoo->fbiPixelsIn = 0;
		voodoo->fbiChromaFail = 0;
		voodoo->fbiZFuncFail = 0;
		voodoo->fbiAFuncFail = 0;
		voodoo->fbiPixelsOut = 0;
		break;
	case SST_fastfillCMD:voodoo_wait_for_render_thread_idle(voodoo);
		voodoo_fastfill(voodoo, &voodoo->params);
		voodoo->cmd_read++;
		break;

	case SST_fogColor:voodoo->params.fogColor.r = (val >> 16) & 0xff;
		voodoo->params.fogColor.g = (val >> 8) & 0xff;
		voodoo->params.fogColor.b = val & 0xff;
		break;

	case SST_zaColor:voodoo->params.zaColor = val;
		break;
	case SST_chromaKey:voodoo->params.chromaKey_r = (val >> 16) & 0xff;
		voodoo->params.chromaKey_g = (val >> 8) & 0xff;
		voodoo->params.chromaKey_b = val & 0xff;
		voodoo->params.chromaKey = val & 0xffffff;
		break;
	case SST_stipple:voodoo->params.stipple = val;
		break;
	case SST_color0:voodoo->params.color0 = val;
		break;
	case SST_color1:voodoo->params.color1 = val;
		break;

	case SST_fogTable00:
	case SST_fogTable01:
	case SST_fogTable02:
	case SST_fogTable03:
	case SST_fogTable04:
	case SST_fogTable05:
	case SST_fogTable06:
	case SST_fogTable07:
	case SST_fogTable08:
	case SST_fogTable09:
	case SST_fogTable0a:
	case SST_fogTable0b:
	case SST_fogTable0c:
	case SST_fogTable0d:
	case SST_fogTable0e:
	case SST_fogTable0f:
	case SST_fogTable10:
	case SST_fogTable11:
	case SST_fogTable12:
	case SST_fogTable13:
	case SST_fogTable14:
	case SST_fogTable15:
	case SST_fogTable16:
	case SST_fogTable17:
	case SST_fogTable18:
	case SST_fogTable19:
	case SST_fogTable1a:
	case SST_fogTable1b:
	case SST_fogTable1c:
	case SST_fogTable1d:
	case SST_fogTable1e:
	case SST_fogTable1f:addr = (addr - SST_fogTable00) >> 1;
		voodoo->params.fogTable[addr].dfog = val & 0xff;
		voodoo->params.fogTable[addr].fog = (val >> 8) & 0xff;
		voodoo->params.fogTable[addr + 1].dfog = (val >> 16) & 0xff;
		voodoo->params.fogTable[addr + 1].fog = (val >> 24) & 0xff;
		break;

	case SST_clipLeftRight1:
		if (voodoo->type >= VOODOO_BANSHEE) {
			voodoo->params.clipRight1 = val & 0xfff;
			voodoo->params.clipLeft1 = (val >> 16) & 0xfff;
		}
		break;
	case SST_clipTopBottom1:
		if (voodoo->type >= VOODOO_BANSHEE) {
			voodoo->params.clipHighY1 = val & 0xfff;
			voodoo->params.clipLowY1 = (val >> 16) & 0xfff;
		}
		break;

	case SST_colBufferAddr:
		if (voodoo->type >= VOODOO_BANSHEE) {
			voodoo->params.draw_offset = val & 0xfffff0;
			voodoo->fb_write_offset = voodoo->params.draw_offset;
//                        pclog("colorBufferAddr=%06x\n", voodoo->params.draw_offset);
		}
		break;
	case SST_colBufferStride:
		if (voodoo->type >= VOODOO_BANSHEE) {
			voodoo->col_tiled = val & (1 << 15);
			voodoo->params.col_tiled = voodoo->col_tiled;
			if (voodoo->col_tiled) {
				voodoo->row_width = (val & 0x7f) * 128 * 32;
//                                pclog("colBufferStride tiled = %i bytes, tiled  %08x\n", voodoo->row_width, val);
			} else {
				voodoo->row_width = val & 0x3fff;
//                                pclog("colBufferStride linear = %i bytes, linear\n", voodoo->row_width);
			}
			voodoo->params.row_width = voodoo->row_width;
		}
		break;
	case SST_auxBufferAddr:
		if (voodoo->type >= VOODOO_BANSHEE) {
			voodoo->params.aux_offset = val & 0xfffff0;
//                        pclog("auxBufferAddr=%06x\n", voodoo->params.aux_offset);
		}
		break;
	case SST_auxBufferStride:
		if (voodoo->type >= VOODOO_BANSHEE) {
			voodoo->aux_tiled = val & (1 << 15);
			voodoo->params.aux_tiled = voodoo->aux_tiled;
			if (voodoo->aux_tiled) {
				voodoo->aux_row_width = (val & 0x7f) * 128 * 32;
//                                pclog("auxBufferStride tiled = %i bytes, tiled\n", voodoo->aux_row_width);
			} else {
				voodoo->aux_row_width = val & 0x3fff;
//                                pclog("auxBufferStride linear = %i bytes, linear\n", voodoo->aux_row_width);
			}
			voodoo->params.aux_row_width = voodoo->aux_row_width;
		}
		break;

	case SST_clutData:voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff;
		voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff;
		voodoo->clutData[(val >> 24) & 0x3f].r = (val >> 16) & 0xff;
		if (val & 0x20000000) {
			voodoo->clutData[(val >> 24) & 0x3f].b = 255;
			voodoo->clutData[(val >> 24) & 0x3f].g = 255;
			voodoo->clutData[(val >> 24) & 0x3f].r = 255;
		}
		voodoo->clutData_dirty = 1;
		break;

	case SST_sSetupMode:voodoo->sSetupMode = val;
		break;
	case SST_sVx:tempif.i = val;
		voodoo->verts[3].sVx = tempif.f;
//                pclog("sVx[%i]=%f\n", voodoo->vertex_num, tempif.f);
		break;
	case SST_sVy:tempif.i = val;
		voodoo->verts[3].sVy = tempif.f;
//                pclog("sVy[%i]=%f\n", voodoo->vertex_num, tempif.f);
		break;
	case SST_sARGB:voodoo->verts[3].sBlue = (float)(val & 0xff);
		voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff);
		voodoo->verts[3].sRed = (float)((val >> 16) & 0xff);
		voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff);
		break;
	case SST_sRed:tempif.i = val;
		voodoo->verts[3].sRed = tempif.f;
		break;
	case SST_sGreen:tempif.i = val;
		voodoo->verts[3].sGreen = tempif.f;
		break;
	case SST_sBlue:tempif.i = val;
		voodoo->verts[3].sBlue = tempif.f;
		break;
	case SST_sAlpha:tempif.i = val;
		voodoo->verts[3].sAlpha = tempif.f;
		break;
	case SST_sVz:tempif.i = val;
		voodoo->verts[3].sVz = tempif.f;
		break;
	case SST_sWb:tempif.i = val;
		voodoo->verts[3].sWb = tempif.f;
		break;
	case SST_sW0:tempif.i = val;
		voodoo->verts[3].sW0 = tempif.f;
		break;
	case SST_sS0:tempif.i = val;
		voodoo->verts[3].sS0 = tempif.f;
		break;
	case SST_sT0:tempif.i = val;
		voodoo->verts[3].sT0 = tempif.f;
		break;
	case SST_sW1:tempif.i = val;
		voodoo->verts[3].sW1 = tempif.f;
		break;
	case SST_sS1:tempif.i = val;
		voodoo->verts[3].sS1 = tempif.f;
		break;
	case SST_sT1:tempif.i = val;
		voodoo->verts[3].sT1 = tempif.f;
		break;

	case SST_sBeginTriCMD:
//                pclog("sBeginTriCMD %i %f\n", voodoo->vertex_num, voodoo->verts[4].sVx);
		voodoo->verts[0] = voodoo->verts[3];
		voodoo->verts[1] = voodoo->verts[3];
		voodoo->verts[2] = voodoo->verts[3];
		voodoo->vertex_next_age = 0;
		voodoo->vertex_ages[0] = voodoo->vertex_next_age++;

		voodoo->num_verticies = 1;
		voodoo->cull_pingpong = 0;
		break;
	case SST_sDrawTriCMD:
//                pclog("sDrawTriCMD %i %i\n", voodoo->num_verticies, voodoo->sSetupMode & SETUPMODE_STRIP_MODE);
		/*I'm not sure this is the vertex selection algorithm actually used in the 3dfx
		  chips, but this works with a number of games that switch between strip and fan
		  mode in the middle of a run (eg Black & White, Viper Racing)*/
		if (voodoo->vertex_next_age < 3) {
			/*Fewer than three vertices already written, store in next slot*/
			int vertex_nr = voodoo->vertex_next_age;

			voodoo->verts[vertex_nr] = voodoo->verts[3];
			voodoo->vertex_ages[vertex_nr] = voodoo->vertex_next_age++;
		} else {
			int vertex_nr = 0;

			if (!(voodoo->sSetupMode & SETUPMODE_STRIP_MODE)) {
				/*Strip - find oldest vertex*/
				if ((voodoo->vertex_ages[0] < voodoo->vertex_ages[1]) &&
					(voodoo->vertex_ages[0] < voodoo->vertex_ages[2]))
					vertex_nr = 0;
				else if ((voodoo->vertex_ages[1] < voodoo->vertex_ages[0]) &&
					(voodoo->vertex_ages[1] < voodoo->vertex_ages[2]))
					vertex_nr = 1;
				else
					vertex_nr = 2;
			} else {
				/*Fan - find second oldest vertex (ie pivot around oldest)*/
				if ((voodoo->vertex_ages[1] < voodoo->vertex_ages[0]) &&
					(voodoo->vertex_ages[0] < voodoo->vertex_ages[2]))
					vertex_nr = 0;
				else if ((voodoo->vertex_ages[2] < voodoo->vertex_ages[0]) &&
					(voodoo->vertex_ages[0] < voodoo->vertex_ages[1]))
					vertex_nr = 0;
				else if ((voodoo->vertex_ages[0] < voodoo->vertex_ages[1]) &&
					(voodoo->vertex_ages[1] < voodoo->vertex_ages[2]))
					vertex_nr = 1;
				else if ((voodoo->vertex_ages[2] < voodoo->vertex_ages[1]) &&
					(voodoo->vertex_ages[1] < voodoo->vertex_ages[0]))
					vertex_nr = 1;
				else
					vertex_nr = 2;
			}
			voodoo->verts[vertex_nr] = voodoo->verts[3];
			voodoo->vertex_ages[vertex_nr] = voodoo->vertex_next_age++;
		}

		voodoo->num_verticies++;
		if (voodoo->num_verticies == 3) {
//                        pclog("triangle_setup\n");
			voodoo_triangle_setup(voodoo);
			voodoo->cull_pingpong = !voodoo->cull_pingpong;

			voodoo->num_verticies = 2;
		}
		break;

	case SST_bltSrcBaseAddr:voodoo->bltSrcBaseAddr = val & 0x3fffff;
		break;
	case SST_bltDstBaseAddr:
//                pclog("Write bltDstBaseAddr %08x\n", val);
		voodoo->bltDstBaseAddr = val & 0x3fffff;
		break;
	case SST_bltXYStrides:voodoo->bltSrcXYStride = val & 0xfff;
		voodoo->bltDstXYStride = (val >> 16) & 0xfff;
//                pclog("Write bltXYStrides %08x\n", val);
		break;
	case SST_bltSrcChromaRange:voodoo->bltSrcChromaRange = val;
		voodoo->bltSrcChromaMinB = val & 0x1f;
		voodoo->bltSrcChromaMinG = (val >> 5) & 0x3f;
		voodoo->bltSrcChromaMinR = (val >> 11) & 0x1f;
		voodoo->bltSrcChromaMaxB = (val >> 16) & 0x1f;
		voodoo->bltSrcChromaMaxG = (val >> 21) & 0x3f;
		voodoo->bltSrcChromaMaxR = (val >> 27) & 0x1f;
		break;
	case SST_bltDstChromaRange:voodoo->bltDstChromaRange = val;
		voodoo->bltDstChromaMinB = val & 0x1f;
		voodoo->bltDstChromaMinG = (val >> 5) & 0x3f;
		voodoo->bltDstChromaMinR = (val >> 11) & 0x1f;
		voodoo->bltDstChromaMaxB = (val >> 16) & 0x1f;
		voodoo->bltDstChromaMaxG = (val >> 21) & 0x3f;
		voodoo->bltDstChromaMaxR = (val >> 27) & 0x1f;
		break;
	case SST_bltClipX:voodoo->bltClipRight = val & 0xfff;
		voodoo->bltClipLeft = (val >> 16) & 0xfff;
		break;
	case SST_bltClipY:voodoo->bltClipHighY = val & 0xfff;
		voodoo->bltClipLowY = (val >> 16) & 0xfff;
		break;

	case SST_bltSrcXY:voodoo->bltSrcX = val & 0x7ff;
		voodoo->bltSrcY = (val >> 16) & 0x7ff;
		break;
	case SST_bltDstXY:
//                pclog("Write bltDstXY %08x\n", val);
		voodoo->bltDstX = val & 0x7ff;
		voodoo->bltDstY = (val >> 16) & 0x7ff;
		if (val & (1 << 31))
			voodoo_v2_blit_start(voodoo);
		break;
	case SST_bltSize:
//                pclog("Write bltSize %08x\n", val);
		voodoo->bltSizeX = val & 0xfff;
		if (voodoo->bltSizeX & 0x800)
			voodoo->bltSizeX |= 0xfffff000;
		voodoo->bltSizeY = (val >> 16) & 0xfff;
		if (voodoo->bltSizeY & 0x800)
			voodoo->bltSizeY |= 0xfffff000;
		if (val & (1 << 31))
			voodoo_v2_blit_start(voodoo);
		break;
	case SST_bltRop:voodoo->bltRop[0] = val & 0xf;
		voodoo->bltRop[1] = (val >> 4) & 0xf;
		voodoo->bltRop[2] = (val >> 8) & 0xf;
		voodoo->bltRop[3] = (val >> 12) & 0xf;
		break;
	case SST_bltColor:
//                pclog("Write bltColor %08x\n", val);
		voodoo->bltColorFg = val & 0xffff;
		voodoo->bltColorBg = (val >> 16) & 0xffff;
		break;

	case SST_bltCommand:voodoo->bltCommand = val;
//                pclog("Write bltCommand %08x\n", val);
		if (val & (1 << 31))
			voodoo_v2_blit_start(voodoo);
		break;
	case SST_bltData:voodoo_v2_blit_data(voodoo, val);
		break;

	case SST_textureMode:
		if (chip & CHIP_TREX0) {
			voodoo->params.textureMode[0] = val;
			voodoo->params.tformat[0] = (val >> 8) & 0xf;
		}
		if (chip & CHIP_TREX1) {
			voodoo->params.textureMode[1] = val;
			voodoo->params.tformat[1] = (val >> 8) & 0xf;
		}
		break;
	case SST_tLOD:
		if (chip & CHIP_TREX0) {
			voodoo->params.tLOD[0] = val;
			voodoo_recalc_tex(voodoo, 0);
		}
		if (chip & CHIP_TREX1) {
			voodoo->params.tLOD[1] = val;
			voodoo_recalc_tex(voodoo, 1);
		}
		break;
	case SST_tDetail:
		if (chip & CHIP_TREX0) {
			voodoo->params.detail_max[0] = val & 0xff;
			voodoo->params.detail_bias[0] = (val >> 8) & 0x3f;
			voodoo->params.detail_scale[0] = (val >> 14) & 7;
		}
		if (chip & CHIP_TREX1) {
			voodoo->params.detail_max[1] = val & 0xff;
			voodoo->params.detail_bias[1] = (val >> 8) & 0x3f;
			voodoo->params.detail_scale[1] = (val >> 14) & 7;
		}
		break;
	case SST_texBaseAddr:
		if (chip & CHIP_TREX0) {
			if (voodoo->type >= VOODOO_BANSHEE)
				voodoo->params.texBaseAddr[0] = val & 0xfffff0;
			else
				voodoo->params.texBaseAddr[0] = (val & 0x7ffff) << 3;
//                        pclog("texBaseAddr = %08x %08x\n", voodoo->params.texBaseAddr[0], val);
			voodoo_recalc_tex(voodoo, 0);
		}
		if (chip & CHIP_TREX1) {
			if (voodoo->type >= VOODOO_BANSHEE)
				voodoo->params.texBaseAddr[1] = val & 0xfffff0;
			else
				voodoo->params.texBaseAddr[1] = (val & 0x7ffff) << 3;
			voodoo_recalc_tex(voodoo, 1);
		}
		break;
	case SST_texBaseAddr1:
		if (chip & CHIP_TREX0) {
			if (voodoo->type >= VOODOO_BANSHEE)
				voodoo->params.texBaseAddr1[0] = val & 0xfffff0;
			else
				voodoo->params.texBaseAddr1[0] = (val & 0x7ffff) << 3;
			voodoo_recalc_tex(voodoo, 0);
		}
		if (chip & CHIP_TREX1) {
			if (voodoo->type >= VOODOO_BANSHEE)
				voodoo->params.texBaseAddr1[1] = val & 0xfffff0;
			else
				voodoo->params.texBaseAddr1[1] = (val & 0x7ffff) << 3;
			voodoo_recalc_tex(voodoo, 1);
		}
		break;
	case SST_texBaseAddr2:
		if (chip & CHIP_TREX0) {
			if (voodoo->type >= VOODOO_BANSHEE)
				voodoo->params.texBaseAddr2[0] = val & 0xfffff0;
			else
				voodoo->params.texBaseAddr2[0] = (val & 0x7ffff) << 3;
			voodoo_recalc_tex(voodoo, 0);
		}
		if (chip & CHIP_TREX1) {
			if (voodoo->type >= VOODOO_BANSHEE)
				voodoo->params.texBaseAddr2[1] = val & 0xfffff0;
			else
				voodoo->params.texBaseAddr2[1] = (val & 0x7ffff) << 3;
			voodoo_recalc_tex(voodoo, 1);
		}
		break;
	case SST_texBaseAddr38:
		if (chip & CHIP_TREX0) {
			if (voodoo->type >= VOODOO_BANSHEE)
				voodoo->params.texBaseAddr38[0] = val & 0xfffff0;
			else
				voodoo->params.texBaseAddr38[0] = (val & 0x7ffff) << 3;
			voodoo_recalc_tex(voodoo, 0);
		}
		if (chip & CHIP_TREX1) {
			if (voodoo->type >= VOODOO_BANSHEE)
				voodoo->params.texBaseAddr38[1] = val & 0xfffff0;
			else
				voodoo->params.texBaseAddr38[1] = (val & 0x7ffff) << 3;
			voodoo_recalc_tex(voodoo, 1);
		}
		break;

	case SST_trexInit1:
		if (chip & CHIP_TREX0)
			voodoo->trexInit1[0] = val;
		if (chip & CHIP_TREX1)
			voodoo->trexInit1[1] = val;
		break;

	case SST_nccTable0_Y0:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][0].y[0] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][0].y[0] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable0_Y1:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][0].y[1] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][0].y[1] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable0_Y2:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][0].y[2] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][0].y[2] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable0_Y3:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][0].y[3] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][0].y[3] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;

	case SST_nccTable0_I0:
		if (!(val & (1 << 31))) {
			if (chip & CHIP_TREX0) {
				voodoo->nccTable[0][0].i[0] = val;
				voodoo->ncc_dirty[0] = 1;
			}
			if (chip & CHIP_TREX1) {
				voodoo->nccTable[1][0].i[0] = val;
				voodoo->ncc_dirty[1] = 1;
			}
			break;
		}
	case SST_nccTable0_I2:
		if (!(val & (1 << 31))) {
			if (chip & CHIP_TREX0) {
				voodoo->nccTable[0][0].i[2] = val;
				voodoo->ncc_dirty[0] = 1;
			}
			if (chip & CHIP_TREX1) {
				voodoo->nccTable[1][0].i[2] = val;
				voodoo->ncc_dirty[1] = 1;
			}
			break;
		}
	case SST_nccTable0_Q0:
		if (!(val & (1 << 31))) {
			if (chip & CHIP_TREX0) {
				voodoo->nccTable[0][0].q[0] = val;
				voodoo->ncc_dirty[0] = 1;
			}
			if (chip & CHIP_TREX1) {
				voodoo->nccTable[1][0].q[0] = val;
				voodoo->ncc_dirty[1] = 1;
			}
			break;
		}
	case SST_nccTable0_Q2:
		if (!(val & (1 << 31))) {
			if (chip & CHIP_TREX0) {
				voodoo->nccTable[0][0].i[2] = val;
				voodoo->ncc_dirty[0] = 1;
			}
			if (chip & CHIP_TREX1) {
				voodoo->nccTable[1][0].i[2] = val;
				voodoo->ncc_dirty[1] = 1;
			}
			break;
		}
		if (val & (1 << 31)) {
			int p = (val >> 23) & 0xfe;
			if (chip & CHIP_TREX0) {
				voodoo->palette[0][p].u = val | 0xff000000;
				voodoo->palette_dirty[0] = 1;
			}
			if (chip & CHIP_TREX1) {
				voodoo->palette[1][p].u = val | 0xff000000;
				voodoo->palette_dirty[1] = 1;
			}
		}
		break;

	case SST_nccTable0_I1:
		if (!(val & (1 << 31))) {
			if (chip & CHIP_TREX0) {
				voodoo->nccTable[0][0].i[1] = val;
				voodoo->ncc_dirty[0] = 1;
			}
			if (chip & CHIP_TREX1) {
				voodoo->nccTable[1][0].i[1] = val;
				voodoo->ncc_dirty[1] = 1;
			}
			break;
		}
	case SST_nccTable0_I3:
		if (!(val & (1 << 31))) {
			if (chip & CHIP_TREX0) {
				voodoo->nccTable[0][0].i[3] = val;
				voodoo->ncc_dirty[0] = 1;
			}
			if (chip & CHIP_TREX1) {
				voodoo->nccTable[1][0].i[3] = val;
				voodoo->ncc_dirty[1] = 1;
			}
			break;
		}
	case SST_nccTable0_Q1:
		if (!(val & (1 << 31))) {
			if (chip & CHIP_TREX0) {
				voodoo->nccTable[0][0].q[1] = val;
				voodoo->ncc_dirty[0] = 1;
			}
			if (chip & CHIP_TREX1) {
				voodoo->nccTable[1][0].q[1] = val;
				voodoo->ncc_dirty[1] = 1;
			}
			break;
		}
	case SST_nccTable0_Q3:
		if (!(val & (1 << 31))) {
			if (chip & CHIP_TREX0) {
				voodoo->nccTable[0][0].q[3] = val;
				voodoo->ncc_dirty[0] = 1;
			}
			if (chip & CHIP_TREX1) {
				voodoo->nccTable[1][0].q[3] = val;
				voodoo->ncc_dirty[1] = 1;
			}
			break;
		}
		if (val & (1 << 31)) {
			int p = ((val >> 23) & 0xfe) | 0x01;
			if (chip & CHIP_TREX0) {
				voodoo->palette[0][p].u = val | 0xff000000;
				voodoo->palette_dirty[0] = 1;
			}
			if (chip & CHIP_TREX1) {
				voodoo->palette[1][p].u = val | 0xff000000;
				voodoo->palette_dirty[1] = 1;
			}
		}
		break;

	case SST_nccTable1_Y0:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].y[0] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].y[0] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable1_Y1:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].y[1] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].y[1] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable1_Y2:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].y[2] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].y[2] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable1_Y3:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].y[3] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].y[3] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable1_I0:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].i[0] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].i[0] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable1_I1:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].i[1] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].i[1] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable1_I2:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].i[2] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].i[2] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable1_I3:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].i[3] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].i[3] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable1_Q0:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].q[0] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].q[0] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable1_Q1:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].q[1] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].q[1] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable1_Q2:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].q[2] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].q[2] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;
	case SST_nccTable1_Q3:
		if (chip & CHIP_TREX0) {
			voodoo->nccTable[0][1].q[3] = val;
			voodoo->ncc_dirty[0] = 1;
		}
		if (chip & CHIP_TREX1) {
			voodoo->nccTable[1][1].q[3] = val;
			voodoo->ncc_dirty[1] = 1;
		}
		break;

	case SST_userIntrCMD:fatal("userIntrCMD write %08x from FIFO\n", val);
		break;

	case SST_leftOverlayBuf:voodoo->leftOverlayBuf = val;
		break;
	}
}
