    /**************************************************************************
     *									  *
     *		 Copyright (C) 1994, Silicon Graphics, Inc.		  *
     *									  *
     *  These coded instructions, statements, and computer programs  contain  *
     *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
     *  are protected by Federal copyright law.  They  may  not be disclosed  *
     *  to  third  parties  or copied or duplicated in any form, in whole or  *
     *  in part, without the prior written consent of Silicon Graphics, Inc.  *
     *									  *
     **************************************************************************/
    /**************************************************************************
     *
     *  $Revision: 1.138 $
     *  $Date: 1998/12/24 09:05:08 $
     *  $Source: /hosts/gate3/exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/gbi.h,v $
     *
     **************************************************************************/

    #ifndef _GBI_H_
    #define	_GBI_H_

    #include <PR/ultratypes.h>

    /*
     * To use the F3DEX ucodes, define F3DEX_GBI before include this file.
     *
     *     #define  F3DEX_GBI
     *     #include <ultra64.h>
     *
     *     or
     *
     *     cc -c -DF3DEX_GBI -I.... foo.c
     *
     */

    /**************************************************************************
     *
     * Graphics Binary Interface
     *
     **************************************************************************/

    /*
     * Graphics Commands, 'xxx' parts may be generated from ucode
     *
     * The command format is
     *
     *	|00xxxxxx| = DMA		0,..,127
     *	|10xxxxxx| = Immediate Mode	-65,..,-128
     *	|11xxxxxx| = RDP cmds		-1,..,-64
     *
     * Note: in order for the RSP microcode to process RDP commands opaquely,
     * we need to further identify those RDP commands that need DRAM address
     * "fixup". To do this, we have the dummy command G_RDP_ADDR_FIXUP, and
     * all |RDP commands| less than this are commands with embedded DRAM
     * addresses. Further, the format of these commands should be similar so
     * only one fixup routine is needed.
     *
     * Further explanation:
     * The names of the commands are somewhat misleading. Here is clarification:
     *
     *	- a 'DMA' type command has a pointer to additional data and
     *	  causes a DMA transfer to bring that into DMEM.
     *
     *	- an 'Immediate' type command isn't really 'immediate', in the
     *	  traditional sense. This just means that the entire command fits
     *	  in the 64-bit word, and the ucode can execute it 'immediately'
     *	  without additional memory transfers.
     *
     *	- an 'RDP' command is identified as such because the RDP
     *	  commands can be passed-thru the RSP and sent to the RDP
     *	  directly. One further confusing thing, is that some 'DP'
     *	  macros below actually generate immediate commands, not
     *	  not direct DP commands.
     *
     * IMPLEMENTATION NOTE:
     * There is another group of RDP commands that includes the triangle commands
     * generated by the RSP code. These are the raw commands the rasterizer
     * hardware chews on, with slope info, etc. They will follow the RDP
     * ordering...
     *
     * IMPLEMENTATION NOTE:
     * The RDP hardware has some of these bit patterns wired up. If the hardware
     * changes, we must adjust this table, likewise we can't change/add things
     * once the hardware is frozen. (actually, the RDP hardware only looks at
     * the lower 6 bits of the command byte)
     *
     */

    #ifdef    F3DEX_GBI_2
    # ifndef  F3DEX_GBI
    #  define F3DEX_GBI
    # endif
    #define	G_NOOP			0x00
    #define	G_RDPHALF_2		0xf1
    #define	G_SETOTHERMODE_H	0xe3
    #define	G_SETOTHERMODE_L	0xe2
    #define	G_RDPHALF_1		0xe1
    #define	G_SPNOOP		0xe0
    #define	G_ENDDL			0xdf
    #define	G_DL			0xde
    #define	G_LOAD_UCODE		0xdd
    #define	G_MOVEMEM		0xdc
    #define	G_MOVEWORD		0xdb
    #define	G_MTX			0xda
    #define G_GEOMETRYMODE		0xd9
    #define	G_POPMTX		0xd8
    #define	G_TEXTURE		0xd7
    #define	G_DMA_IO		0xd6
    #define	G_SPECIAL_1		0xd5
    #define	G_SPECIAL_2		0xd4
    #define	G_SPECIAL_3		0xd3

    #define	G_VTX			0x01
    #define	G_MODIFYVTX		0x02
    #define	G_CULLDL		0x03
    #define	G_BRANCH_Z		0x04
    #define	G_TRI1			0x05
    #define G_TRI2			0x06
    #define G_QUAD			0x07
    #define G_LINE3D		0x08
    #else	/* F3DEX_GBI_2 */

    /* DMA commands: */
    #define	G_SPNOOP		0	/* handle 0 gracefully */
    #define	G_MTX			1
    #define G_RESERVED0		2	/* not implemeted */
    #define G_MOVEMEM		3	/* move a block of memory (up to 4 words) to dmem */
    #define	G_VTX			4
    #define G_RESERVED1		5	/* not implemeted */
    #define	G_DL			6
    #define G_RESERVED2		7	/* not implemeted */
    #define G_RESERVED3		8	/* not implemeted */
    #define G_SPRITE2D_BASE		9	/* sprite command */

    /* IMMEDIATE commands: */
    #define	G_IMMFIRST		-65
    #define	G_TRI1			(G_IMMFIRST-0)
    #define G_CULLDL		(G_IMMFIRST-1)
    #define	G_POPMTX		(G_IMMFIRST-2)
    #define	G_MOVEWORD		(G_IMMFIRST-3)
    #define	G_TEXTURE		(G_IMMFIRST-4)
    #define	G_SETOTHERMODE_H	(G_IMMFIRST-5)
    #define	G_SETOTHERMODE_L	(G_IMMFIRST-6)
    #define G_ENDDL			(G_IMMFIRST-7)
    #define G_SETGEOMETRYMODE	(G_IMMFIRST-8)
    #define G_CLEARGEOMETRYMODE	(G_IMMFIRST-9)
    #define G_LINE3D		(G_IMMFIRST-10)
    #define G_RDPHALF_1		(G_IMMFIRST-11)
    #define G_RDPHALF_2		(G_IMMFIRST-12)
    #if (defined(F3DEX_GBI)||defined(F3DLP_GBI))
    #  define G_MODIFYVTX		(G_IMMFIRST-13)
    #  define G_TRI2		(G_IMMFIRST-14)
    #  define G_BRANCH_Z		(G_IMMFIRST-15)
    #  define G_LOAD_UCODE		(G_IMMFIRST-16)
    #else
    #  define G_RDPHALF_CONT	(G_IMMFIRST-13)
    #endif

    /* We are overloading 2 of the immediate commands
       to keep the byte alignment of dmem the same */

    #define G_SPRITE2D_SCALEFLIP    (G_IMMFIRST-1)
    #define G_SPRITE2D_DRAW         (G_IMMFIRST-2)

    /* RDP commands: */
    #define	G_NOOP			0xc0	/*   0 */

    #endif	/* F3DEX_GBI_2 */

    /* RDP commands: */
    #define	G_SETCIMG		0xff	/*  -1 */
    #define	G_SETZIMG		0xfe	/*  -2 */
    #define	G_SETTIMG		0xfd	/*  -3 */
    #define	G_SETCOMBINE		0xfc	/*  -4 */
    #define	G_SETENVCOLOR		0xfb	/*  -5 */
    #define	G_SETPRIMCOLOR		0xfa	/*  -6 */
    #define	G_SETBLENDCOLOR		0xf9	/*  -7 */
    #define	G_SETFOGCOLOR		0xf8	/*  -8 */
    #define	G_SETFILLCOLOR		0xf7	/*  -9 */
    #define	G_FILLRECT		0xf6	/* -10 */
    #define	G_SETTILE		0xf5	/* -11 */
    #define	G_LOADTILE		0xf4	/* -12 */
    #define	G_LOADBLOCK		0xf3	/* -13 */
    #define	G_SETTILESIZE		0xf2	/* -14 */
    #define	G_LOADTLUT		0xf0	/* -16 */
    #define	G_RDPSETOTHERMODE	0xef	/* -17 */
    #define	G_SETPRIMDEPTH		0xee	/* -18 */
    #define	G_SETSCISSOR		0xed	/* -19 */
    #define	G_SETCONVERT		0xec	/* -20 */
    #define	G_SETKEYR		0xeb	/* -21 */
    #define	G_SETKEYGB		0xea	/* -22 */
    #define	G_RDPFULLSYNC		0xe9	/* -23 */
    #define	G_RDPTILESYNC		0xe8	/* -24 */
    #define	G_RDPPIPESYNC		0xe7	/* -25 */
    #define	G_RDPLOADSYNC		0xe6	/* -26 */
    #define G_TEXRECTFLIP		0xe5	/* -27 */
    #define G_TEXRECT		0xe4	/* -28 */

    /*
     * The following commands are the "generated" RDP commands; the user
     * never sees them, the RSP microcode generates them.
     *
     * The layout of the bits is magical, to save work in the ucode.
     * These id's are -56, -52, -54, -50, -55, -51, -53, -49, ...
     *                                 edge, shade, texture, zbuff bits:  estz
     */
    #define G_TRI_FILL		0xc8 /* fill triangle:            11001000 */
    #define G_TRI_SHADE		0xcc /* shade triangle:           11001100 */
    #define G_TRI_TXTR		0xca /* texture triangle:         11001010 */
    #define G_TRI_SHADE_TXTR	0xce /* shade, texture triangle:  11001110 */
    #define G_TRI_FILL_ZBUFF	0xc9 /* fill, zbuff triangle:     11001001 */
    #define G_TRI_SHADE_ZBUFF	0xcd /* shade, zbuff triangle:    11001101 */
    #define G_TRI_TXTR_ZBUFF	0xcb /* texture, zbuff triangle:  11001011 */
    #define G_TRI_SHADE_TXTR_ZBUFF	0xcf /* shade, txtr, zbuff trngl: 11001111 */

    /*
     * A TRI_FILL triangle is just the edges. You need to set the DP
     * to use primcolor, in order to see anything. (it is NOT a triangle
     * that gets rendered in 'fill mode'. Triangles can't be rendered
     * in 'fill mode')
     *
     * A TRI_SHADE is a gouraud triangle that has colors interpolated.
     * Flat-shaded triangles (from the software) are still gouraud shaded,
     * it's just the colors are all the same and the deltas are 0.
     *
     * Other triangle types, and combinations are more obvious.
     */

    /* masks to build RDP triangle commands: */
    #define G_RDP_TRI_FILL_MASK	0x08
    #define G_RDP_TRI_SHADE_MASK	0x04
    #define G_RDP_TRI_TXTR_MASK	0x02
    #define G_RDP_TRI_ZBUFF_MASK	0x01

    /*
     * HACK:
     * This is a dreadful hack. For version 1.0 hardware, there are still
     * some 'bowtie' hangs. This parameter can be increased to avoid
     * the hangs. Every increase of 4 chops one scanline off of every
     * triangle. Values of 4,8,12 should be sufficient to avoid any
     * bowtie hang.
     *
     * Change this value, then recompile ALL of your program (including static
     * display lists!)
     *
     * THIS WILL BE REMOVED FOR HARDWARE VERSION 2.0!
     */
    #define BOWTIE_VAL	0

    /* gets added to RDP command, in order to test for addres fixup: */
    #define G_RDP_ADDR_FIXUP	3	/* |RDP cmds| <= this, do addr fixup */
    #ifdef _LANGUAGE_ASSEMBLY
    #define G_RDP_TEXRECT_CHECK	((-1*G_TEXRECTFLIP)& 0xff)
    #endif

    /* macros for command parsing: */
    #define	GDMACMD(x)		(x)
    #define	GIMMCMD(x)		(G_IMMFIRST-(x))
    #define	GRDPCMD(x)		(0xff-(x))

    #define	G_DMACMDSIZ		128
    #define	G_IMMCMDSIZ		64
    #define	G_RDPCMDSIZ		64

    /*
     * Coordinate shift values, number of bits of fraction
     */
    #define	G_TEXTURE_IMAGE_FRAC	2
    #define	G_TEXTURE_SCALE_FRAC	16
    #define	G_SCALE_FRAC		8
    #define	G_ROTATE_FRAC		16

    /*
     * Parameters to graphics commands
     */

    /*
     * Data packing macros
     */

    /*
     * Maximum z-buffer value, used to initialize the z-buffer.
     * Note : this number is NOT the viewport z-scale constant.
     * See the comment next to G_MAXZ for more info.
     */
    #define	G_MAXFBZ		0x3fff	/* 3b exp, 11b mantissa */

    #define	GPACK_RGBA5551(r, g, b, a)	((((r)<<8) & 0xf800) | 		\
    					 (((g)<<3) & 0x7c0) |		\
    					 (((b)>>2) & 0x3e) | ((a) & 0x1))
    #define	GPACK_ZDZ(z, dz)		((z) << 2 | (dz))

    /*
     * G_MTX: parameter flags
     */
    #ifdef	F3DEX_GBI_2
    # define G_MTX_MODELVIEW	0x00	/* matrix types */
    # define G_MTX_PROJECTION	0x04
    # define G_MTX_MUL		0x00	/* concat or load */
    # define G_MTX_LOAD		0x02
    # define G_MTX_NOPUSH		0x00	/* push or not */
    # define G_MTX_PUSH		0x01
    #else	/* F3DEX_GBI_2 */
    # define G_MTX_MODELVIEW	0x00	/* matrix types */
    # define G_MTX_PROJECTION	0x01
    # define G_MTX_MUL		0x00	/* concat or load */
    # define G_MTX_LOAD		0x02
    # define G_MTX_NOPUSH		0x00	/* push or not */
    # define G_MTX_PUSH		0x04
    #endif	/* F3DEX_GBI_2 */

    /*
     * flags for G_SETGEOMETRYMODE
     * (this rendering state is maintained in RSP)
     *
     * DO NOT USE THE LOW 8 BITS OF GEOMETRYMODE:
     * The weird bit-ordering is for the micro-code: the lower byte
     * can be OR'd in with G_TRI_SHADE (11001100) to construct
     * the triangle command directly. Don't break it...
     *
     * DO NOT USE THE HIGH 8 BITS OF GEOMETRYMODE:
     * The high byte is OR'd with 0x703 to form the clip code mask.
     * If it is set to 0x04, this will cause near clipping to occur.
     * If it is zero, near clipping will not occur.
     *
     * Further explanation:
     * G_SHADE is necessary in order to see the color that you passed
     * down with the vertex. If G_SHADE isn't set, you need to set the DP
     * appropriately and use primcolor to see anything.
     *
     * G_SHADING_SMOOTH enabled means use all 3 colors of the triangle.
     * If it is not set, then do 'flat shading', where only one vertex color
     * is used (and all 3 vertices are set to that same color by the ucode)
     * See the man page for gSP1Triangle().
     *
     */
    #define G_ZBUFFER		0x00000001
    #define G_SHADE			0x00000004	/* enable Gouraud interp */
    /* rest of low byte reserved for setup ucode */
    #ifdef	F3DEX_GBI_2
    # define G_TEXTURE_ENABLE	0x00000000	/* Ignored               */
    # define G_SHADING_SMOOTH	0x00200000	/* flat or smooth shaded */
    # define G_CULL_FRONT		0x00000200
    # define G_CULL_BACK		0x00000400
    # define G_CULL_BOTH		0x00000600	/* To make code cleaner */
    #else
    # define G_TEXTURE_ENABLE	0x00000002	/* Microcode use only */
    # define G_SHADING_SMOOTH	0x00000200	/* flat or smooth shaded */
    # define G_CULL_FRONT		0x00001000
    # define G_CULL_BACK		0x00002000
    # define G_CULL_BOTH		0x00003000	/* To make code cleaner */
    #endif
    #define G_FOG			0x00010000
    #define G_LIGHTING		0x00020000
    #define G_TEXTURE_GEN		0x00040000
    #define G_TEXTURE_GEN_LINEAR	0x00080000
    #define G_LOD			0x00100000	/* NOT IMPLEMENTED */
    #if	(defined(F3DEX_GBI)||defined(F3DLP_GBI))
    # define G_CLIPPING		0x00800000
    #else
    # define G_CLIPPING		0x00000000
    #endif

    #ifdef _LANGUAGE_ASSEMBLY
    #define G_FOG_H			(G_FOG/0x10000)
    #define G_LIGHTING_H		(G_LIGHTING/0x10000)
    #define G_TEXTURE_GEN_H		(G_TEXTURE_GEN/0x10000)
    #define G_TEXTURE_GEN_LINEAR_H	(G_TEXTURE_GEN_LINEAR/0x10000)
    #define G_LOD_H			(G_LOD/0x10000)	/* NOT IMPLEMENTED */
    #if	(defined(F3DEX_GBI)||defined(F3DLP_GBI))
    #  define G_CLIPPING_H		(G_CLIPPING/0x10000)
    #endif
    #endif

    /* Need these defined for Sprite Microcode */
    #ifdef _LANGUAGE_ASSEMBLY
    #define	G_TX_LOADTILE	7
    #define	G_TX_RENDERTILE	0

    #define	G_TX_NOMIRROR	0
    #define	G_TX_WRAP	0
    #define	G_TX_MIRROR	0x1
    #define	G_TX_CLAMP	0x2
    #define	G_TX_NOMASK	0
    #define	G_TX_NOLOD	0
    #endif

    /*
     * G_SETIMG fmt: set image formats
     */
    #define G_IM_FMT_RGBA	0
    #define G_IM_FMT_YUV	1
    #define G_IM_FMT_CI	2
    #define G_IM_FMT_IA	3
    #define G_IM_FMT_I	4

    /*
     * G_SETIMG siz: set image pixel size
     */
    #define G_IM_SIZ_4b	0
    #define G_IM_SIZ_8b	1
    #define G_IM_SIZ_16b	2
    #define G_IM_SIZ_32b	3
    #define G_IM_SIZ_DD	5

    #define G_IM_SIZ_4b_BYTES		0
    #define G_IM_SIZ_4b_TILE_BYTES	G_IM_SIZ_4b_BYTES
    #define G_IM_SIZ_4b_LINE_BYTES	G_IM_SIZ_4b_BYTES

    #define G_IM_SIZ_8b_BYTES		1
    #define G_IM_SIZ_8b_TILE_BYTES	G_IM_SIZ_8b_BYTES
    #define G_IM_SIZ_8b_LINE_BYTES	G_IM_SIZ_8b_BYTES

    #define G_IM_SIZ_16b_BYTES		2
    #define G_IM_SIZ_16b_TILE_BYTES	G_IM_SIZ_16b_BYTES
    #define G_IM_SIZ_16b_LINE_BYTES	G_IM_SIZ_16b_BYTES

    #define G_IM_SIZ_32b_BYTES		4
    #define G_IM_SIZ_32b_TILE_BYTES	2
    #define G_IM_SIZ_32b_LINE_BYTES	2

    #define G_IM_SIZ_4b_LOAD_BLOCK	G_IM_SIZ_16b
    #define G_IM_SIZ_8b_LOAD_BLOCK	G_IM_SIZ_16b
    #define G_IM_SIZ_16b_LOAD_BLOCK	G_IM_SIZ_16b
    #define G_IM_SIZ_32b_LOAD_BLOCK	G_IM_SIZ_32b

    #define G_IM_SIZ_4b_SHIFT  2
    #define G_IM_SIZ_8b_SHIFT  1
    #define G_IM_SIZ_16b_SHIFT 0
    #define G_IM_SIZ_32b_SHIFT 0

    #define G_IM_SIZ_4b_INCR  3
    #define G_IM_SIZ_8b_INCR  1
    #define G_IM_SIZ_16b_INCR 0
    #define G_IM_SIZ_32b_INCR 0

    /*
     * G_SETCOMBINE: color combine modes
     */
    /* Color combiner constants: */
    #define G_CCMUX_COMBINED	0
    #define G_CCMUX_TEXEL0		1
    #define G_CCMUX_TEXEL1		2
    #define G_CCMUX_PRIMITIVE	3
    #define G_CCMUX_SHADE		4
    #define G_CCMUX_ENVIRONMENT	5
    #define G_CCMUX_CENTER		6
    #define G_CCMUX_SCALE		6
    #define G_CCMUX_COMBINED_ALPHA	7
    #define G_CCMUX_TEXEL0_ALPHA	8
    #define G_CCMUX_TEXEL1_ALPHA	9
    #define G_CCMUX_PRIMITIVE_ALPHA	10
    #define G_CCMUX_SHADE_ALPHA	11
    #define G_CCMUX_ENV_ALPHA	12
    #define G_CCMUX_LOD_FRACTION	13
    #define G_CCMUX_PRIM_LOD_FRAC	14
    #define G_CCMUX_NOISE		7
    #define G_CCMUX_K4		7
    #define G_CCMUX_K5		15
    #define G_CCMUX_1		6
    #define G_CCMUX_0		31

    /* Alpha combiner constants: */
    #define G_ACMUX_COMBINED	0
    #define G_ACMUX_TEXEL0		1
    #define G_ACMUX_TEXEL1		2
    #define G_ACMUX_PRIMITIVE	3
    #define G_ACMUX_SHADE		4
    #define G_ACMUX_ENVIRONMENT	5
    #define G_ACMUX_LOD_FRACTION	0
    #define G_ACMUX_PRIM_LOD_FRAC	6
    #define G_ACMUX_1		6
    #define G_ACMUX_0		7

    /* typical CC cycle 1 modes */
    #define	G_CC_PRIMITIVE		0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE
    #define	G_CC_SHADE		0, 0, 0, SHADE, 0, 0, 0, SHADE
    #define	G_CC_MODULATEI		TEXEL0, 0, SHADE, 0, 0, 0, 0, SHADE
    #define	G_CC_MODULATEIA		TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0
    #define	G_CC_MODULATEIDECALA	TEXEL0, 0, SHADE, 0, 0, 0, 0, TEXEL0
    #define	G_CC_MODULATERGB	G_CC_MODULATEI
    #define	G_CC_MODULATERGBA	G_CC_MODULATEIA
    #define	G_CC_MODULATERGBDECALA	G_CC_MODULATEIDECALA
    #define	G_CC_MODULATEI_PRIM	TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE
    #define	G_CC_MODULATEIA_PRIM	TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0
    #define	G_CC_MODULATEIDECALA_PRIM	TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, TEXEL0
    #define	G_CC_MODULATERGB_PRIM	G_CC_MODULATEI_PRIM
    #define	G_CC_MODULATERGBA_PRIM	G_CC_MODULATEIA_PRIM
    #define	G_CC_MODULATERGBDECALA_PRIM	G_CC_MODULATEIDECALA_PRIM
    #define	G_CC_DECALRGB		0, 0, 0, TEXEL0, 0, 0, 0, SHADE
    #define	G_CC_DECALRGBA		0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0
    #define	G_CC_BLENDI		ENVIRONMENT, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE
    #define	G_CC_BLENDIA		ENVIRONMENT, SHADE, TEXEL0, SHADE, TEXEL0, 0, SHADE, 0
    #define	G_CC_BLENDIDECALA	ENVIRONMENT, SHADE, TEXEL0, SHADE, 0, 0, 0, TEXEL0
    #define	G_CC_BLENDRGBA		TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, 0, 0, 0, SHADE
    #define	G_CC_BLENDRGBDECALA	TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, 0, 0, 0, TEXEL0
    #define G_CC_ADDRGB		1, 0, TEXEL0, SHADE, 0, 0, 0, SHADE
    #define G_CC_ADDRGBDECALA	1, 0, TEXEL0, SHADE, 0, 0, 0, TEXEL0
    #define G_CC_REFLECTRGB		ENVIRONMENT, 0, TEXEL0, SHADE, 0, 0, 0, SHADE
    #define G_CC_REFLECTRGBDECALA	ENVIRONMENT, 0, TEXEL0, SHADE, 0, 0, 0, TEXEL0
    #define G_CC_HILITERGB		PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE
    #define G_CC_HILITERGBA		PRIMITIVE, SHADE, TEXEL0, SHADE, PRIMITIVE, SHADE, TEXEL0, SHADE
    #define G_CC_HILITERGBDECALA	PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, TEXEL0
    #define G_CC_SHADEDECALA	0, 0, 0, SHADE, 0, 0, 0, TEXEL0
    #define	G_CC_BLENDPE		PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, SHADE, 0
    #define	G_CC_BLENDPEDECALA	PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, 0, 0, 0, TEXEL0

    /* oddball modes */
    #define	_G_CC_BLENDPE		ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, TEXEL0, 0, SHADE, 0
    #define	_G_CC_BLENDPEDECALA	ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, 0, 0, 0, TEXEL0
    #define	_G_CC_TWOCOLORTEX	PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE
    /* used for 1-cycle sparse mip-maps, primitive color has color of lowest LOD */
    #define	_G_CC_SPARSEST		PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0, PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0
    #define G_CC_TEMPLERP   TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0, TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0

    /* typical CC cycle 1 modes, usually followed by other cycle 2 modes */
    #define	G_CC_TRILERP		TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0
    #define	G_CC_INTERFERENCE	TEXEL0, 0, TEXEL1, 0, TEXEL0, 0, TEXEL1, 0

    /*
     *  One-cycle color convert operation
     */
    #define	G_CC_1CYUV2RGB		TEXEL0, K4, K5, TEXEL0, 0, 0, 0, SHADE

    /*
     *  NOTE: YUV2RGB expects TF step1 color conversion to occur in 2nd clock.
     * Therefore, CC looks for step1 results in TEXEL1
     */
    #define	G_CC_YUV2RGB		TEXEL1, K4, K5, TEXEL1, 0, 0, 0, 0

    /* typical CC cycle 2 modes */
    #define	G_CC_PASS2		0, 0, 0, COMBINED, 0, 0, 0, COMBINED
    #define	G_CC_MODULATEI2		COMBINED, 0, SHADE, 0, 0, 0, 0, SHADE
    #define	G_CC_MODULATEIA2	COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, 0
    #define	G_CC_MODULATERGB2	G_CC_MODULATEI2
    #define	G_CC_MODULATERGBA2	G_CC_MODULATEIA2
    #define	G_CC_MODULATEI_PRIM2	COMBINED, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE
    #define	G_CC_MODULATEIA_PRIM2	COMBINED, 0, PRIMITIVE, 0, COMBINED, 0, PRIMITIVE, 0
    #define	G_CC_MODULATERGB_PRIM2	G_CC_MODULATEI_PRIM2
    #define	G_CC_MODULATERGBA_PRIM2	G_CC_MODULATEIA_PRIM2
    #define	G_CC_DECALRGB2		0, 0, 0, COMBINED, 0, 0, 0, SHADE
    /*
     * ?
    #define	G_CC_DECALRGBA2		COMBINED, SHADE, COMBINED_ALPHA, SHADE, 0, 0, 0, SHADE
    */
    #define	G_CC_BLENDI2		ENVIRONMENT, SHADE, COMBINED, SHADE, 0, 0, 0, SHADE
    #define	G_CC_BLENDIA2		ENVIRONMENT, SHADE, COMBINED, SHADE, COMBINED, 0, SHADE, 0
    #define	G_CC_CHROMA_KEY2	TEXEL0, CENTER, SCALE, 0, 0, 0, 0, 0
    #define G_CC_HILITERGB2		ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, SHADE
    #define G_CC_HILITERGBA2	ENVIRONMENT, COMBINED, TEXEL0, COMBINED, ENVIRONMENT, COMBINED, TEXEL0, COMBINED
    #define G_CC_HILITERGBDECALA2	ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, TEXEL0
    #define G_CC_HILITERGBPASSA2	ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, COMBINED

    /*
     * G_SETOTHERMODE_L sft: shift count
     */
    #define	G_MDSFT_ALPHACOMPARE		0
    #define	G_MDSFT_ZSRCSEL			2
    #define	G_MDSFT_RENDERMODE		3
    #define	G_MDSFT_BLENDER			16

    /*
     * G_SETOTHERMODE_H sft: shift count
     */
    #define	G_MDSFT_BLENDMASK		0	/* unsupported */
    #define	G_MDSFT_ALPHADITHER		4
    #define	G_MDSFT_RGBDITHER		6

    #define	G_MDSFT_COMBKEY			8
    #define	G_MDSFT_TEXTCONV		9
    #define	G_MDSFT_TEXTFILT		12
    #define	G_MDSFT_TEXTLUT			14
    #define	G_MDSFT_TEXTLOD			16
    #define	G_MDSFT_TEXTDETAIL		17
    #define	G_MDSFT_TEXTPERSP		19
    #define	G_MDSFT_CYCLETYPE		20
    #define	G_MDSFT_COLORDITHER		22	/* unsupported in HW 2.0 */
    #define	G_MDSFT_PIPELINE		23

    /* G_SETOTHERMODE_H gPipelineMode */
    #define	G_PM_1PRIMITIVE		(1 << G_MDSFT_PIPELINE)
    #define	G_PM_NPRIMITIVE		(0 << G_MDSFT_PIPELINE)

    /* G_SETOTHERMODE_H gSetCycleType */
    #define	G_CYC_1CYCLE		(0 << G_MDSFT_CYCLETYPE)
    #define	G_CYC_2CYCLE		(1 << G_MDSFT_CYCLETYPE)
    #define	G_CYC_COPY		(2 << G_MDSFT_CYCLETYPE)
    #define	G_CYC_FILL		(3 << G_MDSFT_CYCLETYPE)

    /* G_SETOTHERMODE_H gSetTexturePersp */
    #define G_TP_NONE	(0 << G_MDSFT_TEXTPERSP)
    #define G_TP_PERSP	(1 << G_MDSFT_TEXTPERSP)

    /* G_SETOTHERMODE_H gSetTextureDetail */
    #define G_TD_CLAMP	(0 << G_MDSFT_TEXTDETAIL)
    #define G_TD_SHARPEN	(1 << G_MDSFT_TEXTDETAIL)
    #define G_TD_DETAIL	(2 << G_MDSFT_TEXTDETAIL)

    /* G_SETOTHERMODE_H gSetTextureLOD */
    #define G_TL_TILE	(0 << G_MDSFT_TEXTLOD)
    #define G_TL_LOD	(1 << G_MDSFT_TEXTLOD)

    /* G_SETOTHERMODE_H gSetTextureLUT */
    #define G_TT_NONE	(0 << G_MDSFT_TEXTLUT)
    #define G_TT_RGBA16	(2 << G_MDSFT_TEXTLUT)
    #define G_TT_IA16	(3 << G_MDSFT_TEXTLUT)

    /* G_SETOTHERMODE_H gSetTextureFilter */
    #define G_TF_POINT	(0 << G_MDSFT_TEXTFILT)
    #define G_TF_AVERAGE	(3 << G_MDSFT_TEXTFILT)
    #define G_TF_BILERP	(2 << G_MDSFT_TEXTFILT)

    /* G_SETOTHERMODE_H gSetTextureConvert */
    #define G_TC_CONV	(0 << G_MDSFT_TEXTCONV)
    #define G_TC_FILTCONV	(5 << G_MDSFT_TEXTCONV)
    #define G_TC_FILT	(6 << G_MDSFT_TEXTCONV)

    /* G_SETOTHERMODE_H gSetCombineKey */
    #define G_CK_NONE	(0 << G_MDSFT_COMBKEY)
    #define G_CK_KEY	(1 << G_MDSFT_COMBKEY)

    /* G_SETOTHERMODE_H gSetColorDither */
    #define	G_CD_MAGICSQ		(0 << G_MDSFT_RGBDITHER)
    #define	G_CD_BAYER		(1 << G_MDSFT_RGBDITHER)
    #define	G_CD_NOISE		(2 << G_MDSFT_RGBDITHER)

    #ifndef _HW_VERSION_1
    #define	G_CD_DISABLE		(3 << G_MDSFT_RGBDITHER)
    #define	G_CD_ENABLE		G_CD_NOISE	/* HW 1.0 compatibility mode */
    #else
    #define G_CD_ENABLE		(1 << G_MDSFT_COLORDITHER)
    #define G_CD_DISABLE		(0 << G_MDSFT_COLORDITHER)
    #endif

    /* G_SETOTHERMODE_H gSetAlphaDither */
    #define	G_AD_PATTERN		(0 << G_MDSFT_ALPHADITHER)
    #define	G_AD_NOTPATTERN		(1 << G_MDSFT_ALPHADITHER)
    #define	G_AD_NOISE		(2 << G_MDSFT_ALPHADITHER)
    #define	G_AD_DISABLE		(3 << G_MDSFT_ALPHADITHER)

    /* G_SETOTHERMODE_L gSetAlphaCompare */
    #define	G_AC_NONE		(0 << G_MDSFT_ALPHACOMPARE)
    #define	G_AC_THRESHOLD		(1 << G_MDSFT_ALPHACOMPARE)
    #define	G_AC_DITHER		(3 << G_MDSFT_ALPHACOMPARE)

    /* G_SETOTHERMODE_L gSetDepthSource */
    #define	G_ZS_PIXEL		(0 << G_MDSFT_ZSRCSEL)
    #define	G_ZS_PRIM		(1 << G_MDSFT_ZSRCSEL)

    /* G_SETOTHERMODE_L gSetRenderMode */
    #define	AA_EN		0x8
    #define	Z_CMP		0x10
    #define	Z_UPD		0x20
    #define	IM_RD		0x40
    #define	CLR_ON_CVG	0x80
    #define	CVG_DST_CLAMP	0
    #define	CVG_DST_WRAP	0x100
    #define	CVG_DST_FULL	0x200
    #define	CVG_DST_SAVE	0x300
    #define	ZMODE_OPA	0
    #define	ZMODE_INTER	0x400
    #define	ZMODE_XLU	0x800
    #define	ZMODE_DEC	0xc00
    #define	CVG_X_ALPHA	0x1000
    #define	ALPHA_CVG_SEL	0x2000
    #define	FORCE_BL	0x4000
    #define	TEX_EDGE	0x0000 /* used to be 0x8000 */

    #define	G_BL_CLR_IN	0
    #define	G_BL_CLR_MEM	1
    #define	G_BL_CLR_BL	2
    #define	G_BL_CLR_FOG	3
    #define	G_BL_1MA	0
    #define	G_BL_A_MEM	1
    #define	G_BL_A_IN	0
    #define	G_BL_A_FOG	1
    #define	G_BL_A_SHADE	2
    #define	G_BL_1		2
    #define	G_BL_0		3

    #define	GBL_c1(m1a, m1b, m2a, m2b)	\
    	(m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18
    #define	GBL_c2(m1a, m1b, m2a, m2b)	\
    	(m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16

    #define	RM_AA_ZB_OPA_SURF(clk)					\
    	AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |		\
    	ZMODE_OPA | ALPHA_CVG_SEL |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_RA_ZB_OPA_SURF(clk)					\
    	AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP |			\
    	ZMODE_OPA | ALPHA_CVG_SEL |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_AA_ZB_XLU_SURF(clk)					\
    	AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG |	\
    	FORCE_BL | ZMODE_XLU |					\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_ZB_OPA_DECAL(clk)					\
    	AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | ALPHA_CVG_SEL |	\
    	ZMODE_DEC |						\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_RA_ZB_OPA_DECAL(clk)					\
    	AA_EN | Z_CMP | CVG_DST_WRAP | ALPHA_CVG_SEL |		\
    	ZMODE_DEC |						\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_AA_ZB_XLU_DECAL(clk)					\
    	AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG |	\
    	FORCE_BL | ZMODE_DEC |					\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_ZB_OPA_INTER(clk)					\
    	AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |		\
    	ALPHA_CVG_SEL |	ZMODE_INTER |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_RA_ZB_OPA_INTER(clk)					\
    	AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP |			\
    	ALPHA_CVG_SEL |	ZMODE_INTER |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_AA_ZB_XLU_INTER(clk)					\
    	AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG |	\
    	FORCE_BL | ZMODE_INTER |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_ZB_XLU_LINE(clk)					\
    	AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA |	\
    	ALPHA_CVG_SEL | FORCE_BL | ZMODE_XLU |			\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_ZB_DEC_LINE(clk)					\
    	AA_EN | Z_CMP | IM_RD | CVG_DST_SAVE | CVG_X_ALPHA |	\
    	ALPHA_CVG_SEL | FORCE_BL | ZMODE_DEC |			\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_ZB_TEX_EDGE(clk)					\
    	AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |		\
    	CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE |	\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_AA_ZB_TEX_INTER(clk)					\
    	AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |		\
    	CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_INTER | TEX_EDGE |	\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_AA_ZB_SUB_SURF(clk)					\
    	AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL |		\
    	ZMODE_OPA | ALPHA_CVG_SEL |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_AA_ZB_PCL_SURF(clk)					\
    	AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |		\
    	ZMODE_OPA | G_AC_DITHER | 				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_ZB_OPA_TERR(clk)					\
    	AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |		\
    	ZMODE_OPA | ALPHA_CVG_SEL |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_ZB_TEX_TERR(clk)					\
    	AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP |		\
    	CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE |	\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_ZB_SUB_TERR(clk)					\
    	AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL |		\
    	ZMODE_OPA | ALPHA_CVG_SEL |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_OPA_SURF(clk)					\
    	AA_EN | IM_RD | CVG_DST_CLAMP |				\
    	ZMODE_OPA | ALPHA_CVG_SEL |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_RA_OPA_SURF(clk)					\
    	AA_EN | CVG_DST_CLAMP |				\
    	ZMODE_OPA | ALPHA_CVG_SEL |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_AA_XLU_SURF(clk)					\
    	AA_EN | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL |	\
    	ZMODE_OPA |						\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_XLU_LINE(clk)					\
    	AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA |		\
    	ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA |			\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_DEC_LINE(clk)					\
    	AA_EN | IM_RD | CVG_DST_FULL | CVG_X_ALPHA |		\
    	ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA |			\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_TEX_EDGE(clk)					\
    	AA_EN | IM_RD | CVG_DST_CLAMP |				\
    	CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE |	\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_AA_SUB_SURF(clk)					\
    	AA_EN | IM_RD | CVG_DST_FULL |				\
    	ZMODE_OPA | ALPHA_CVG_SEL |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_AA_PCL_SURF(clk)					\
    	AA_EN | IM_RD | CVG_DST_CLAMP |				\
    	ZMODE_OPA | G_AC_DITHER | 				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_OPA_TERR(clk)					\
    	AA_EN | IM_RD | CVG_DST_CLAMP |				\
    	ZMODE_OPA | ALPHA_CVG_SEL |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_TEX_TERR(clk)					\
    	AA_EN | IM_RD | CVG_DST_CLAMP |				\
    	CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE |	\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_AA_SUB_TERR(clk)					\
    	AA_EN | IM_RD | CVG_DST_FULL |				\
    	ZMODE_OPA | ALPHA_CVG_SEL |				\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_ZB_OPA_SURF(clk)					\
    	Z_CMP | Z_UPD | CVG_DST_FULL | ALPHA_CVG_SEL |		\
    	ZMODE_OPA |						\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_ZB_XLU_SURF(clk)					\
    	Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_XLU |	\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_ZB_OPA_DECAL(clk)					\
    	Z_CMP | CVG_DST_FULL | ALPHA_CVG_SEL | ZMODE_DEC |	\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM)

    #define	RM_ZB_XLU_DECAL(clk)					\
    	Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_DEC |	\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_ZB_CLD_SURF(clk)					\
    	Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_XLU |	\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_ZB_OVL_SURF(clk)					\
    	Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_DEC |	\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_ZB_PCL_SURF(clk)					\
    	Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA |		\
    	G_AC_DITHER | 						\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)

    #define	RM_OPA_SURF(clk)					\
    	CVG_DST_CLAMP | FORCE_BL | ZMODE_OPA |			\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)

    #define	RM_XLU_SURF(clk)					\
    	IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_OPA |		\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_TEX_EDGE(clk)					\
    	CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL |\
    	ZMODE_OPA | TEX_EDGE | AA_EN |					\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)

    #define	RM_CLD_SURF(clk)					\
    	IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA |		\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)

    #define	RM_PCL_SURF(clk)					\
    	CVG_DST_FULL | FORCE_BL | ZMODE_OPA | 			\
    	G_AC_DITHER | 						\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)

    #define	RM_ADD(clk)					\
    	IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA |	\
    	GBL_c##clk(G_BL_CLR_IN, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1)

    #define	RM_NOOP(clk)	\
    	GBL_c##clk(0, 0, 0, 0)

    #define RM_VISCVG(clk) \
    	IM_RD | FORCE_BL |     \
    	GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_BL, G_BL_A_MEM)

    /* for rendering to an 8-bit framebuffer */
    #define RM_OPA_CI(clk)                    \
    	CVG_DST_CLAMP | ZMODE_OPA |          \
    	GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)

    #define	G_RM_AA_ZB_OPA_SURF	RM_AA_ZB_OPA_SURF(1)
    #define	G_RM_AA_ZB_OPA_SURF2	RM_AA_ZB_OPA_SURF(2)
    #define	G_RM_AA_ZB_XLU_SURF	RM_AA_ZB_XLU_SURF(1)
    #define	G_RM_AA_ZB_XLU_SURF2	RM_AA_ZB_XLU_SURF(2)
    #define	G_RM_AA_ZB_OPA_DECAL	RM_AA_ZB_OPA_DECAL(1)
    #define	G_RM_AA_ZB_OPA_DECAL2	RM_AA_ZB_OPA_DECAL(2)
    #define	G_RM_AA_ZB_XLU_DECAL	RM_AA_ZB_XLU_DECAL(1)
    #define	G_RM_AA_ZB_XLU_DECAL2	RM_AA_ZB_XLU_DECAL(2)
    #define	G_RM_AA_ZB_OPA_INTER	RM_AA_ZB_OPA_INTER(1)
    #define	G_RM_AA_ZB_OPA_INTER2	RM_AA_ZB_OPA_INTER(2)
    #define	G_RM_AA_ZB_XLU_INTER	RM_AA_ZB_XLU_INTER(1)
    #define	G_RM_AA_ZB_XLU_INTER2	RM_AA_ZB_XLU_INTER(2)
    #define	G_RM_AA_ZB_XLU_LINE	RM_AA_ZB_XLU_LINE(1)
    #define	G_RM_AA_ZB_XLU_LINE2	RM_AA_ZB_XLU_LINE(2)
    #define	G_RM_AA_ZB_DEC_LINE	RM_AA_ZB_DEC_LINE(1)
    #define	G_RM_AA_ZB_DEC_LINE2	RM_AA_ZB_DEC_LINE(2)
    #define	G_RM_AA_ZB_TEX_EDGE	RM_AA_ZB_TEX_EDGE(1)
    #define	G_RM_AA_ZB_TEX_EDGE2	RM_AA_ZB_TEX_EDGE(2)
    #define	G_RM_AA_ZB_TEX_INTER	RM_AA_ZB_TEX_INTER(1)
    #define	G_RM_AA_ZB_TEX_INTER2	RM_AA_ZB_TEX_INTER(2)
    #define	G_RM_AA_ZB_SUB_SURF	RM_AA_ZB_SUB_SURF(1)
    #define	G_RM_AA_ZB_SUB_SURF2	RM_AA_ZB_SUB_SURF(2)
    #define	G_RM_AA_ZB_PCL_SURF	RM_AA_ZB_PCL_SURF(1)
    #define	G_RM_AA_ZB_PCL_SURF2	RM_AA_ZB_PCL_SURF(2)
    #define	G_RM_AA_ZB_OPA_TERR	RM_AA_ZB_OPA_TERR(1)
    #define	G_RM_AA_ZB_OPA_TERR2	RM_AA_ZB_OPA_TERR(2)
    #define	G_RM_AA_ZB_TEX_TERR	RM_AA_ZB_TEX_TERR(1)
    #define	G_RM_AA_ZB_TEX_TERR2	RM_AA_ZB_TEX_TERR(2)
    #define	G_RM_AA_ZB_SUB_TERR	RM_AA_ZB_SUB_TERR(1)
    #define	G_RM_AA_ZB_SUB_TERR2	RM_AA_ZB_SUB_TERR(2)

    #define	G_RM_RA_ZB_OPA_SURF	RM_RA_ZB_OPA_SURF(1)
    #define	G_RM_RA_ZB_OPA_SURF2	RM_RA_ZB_OPA_SURF(2)
    #define	G_RM_RA_ZB_OPA_DECAL	RM_RA_ZB_OPA_DECAL(1)
    #define	G_RM_RA_ZB_OPA_DECAL2	RM_RA_ZB_OPA_DECAL(2)
    #define	G_RM_RA_ZB_OPA_INTER	RM_RA_ZB_OPA_INTER(1)
    #define	G_RM_RA_ZB_OPA_INTER2	RM_RA_ZB_OPA_INTER(2)

    #define	G_RM_AA_OPA_SURF	RM_AA_OPA_SURF(1)
    #define	G_RM_AA_OPA_SURF2	RM_AA_OPA_SURF(2)
    #define	G_RM_AA_XLU_SURF	RM_AA_XLU_SURF(1)
    #define	G_RM_AA_XLU_SURF2	RM_AA_XLU_SURF(2)
    #define	G_RM_AA_XLU_LINE	RM_AA_XLU_LINE(1)
    #define	G_RM_AA_XLU_LINE2	RM_AA_XLU_LINE(2)
    #define	G_RM_AA_DEC_LINE	RM_AA_DEC_LINE(1)
    #define	G_RM_AA_DEC_LINE2	RM_AA_DEC_LINE(2)
    #define	G_RM_AA_TEX_EDGE	RM_AA_TEX_EDGE(1)
    #define	G_RM_AA_TEX_EDGE2	RM_AA_TEX_EDGE(2)
    #define	G_RM_AA_SUB_SURF	RM_AA_SUB_SURF(1)
    #define	G_RM_AA_SUB_SURF2	RM_AA_SUB_SURF(2)
    #define	G_RM_AA_PCL_SURF	RM_AA_PCL_SURF(1)
    #define	G_RM_AA_PCL_SURF2	RM_AA_PCL_SURF(2)
    #define	G_RM_AA_OPA_TERR	RM_AA_OPA_TERR(1)
    #define	G_RM_AA_OPA_TERR2	RM_AA_OPA_TERR(2)
    #define	G_RM_AA_TEX_TERR	RM_AA_TEX_TERR(1)
    #define	G_RM_AA_TEX_TERR2	RM_AA_TEX_TERR(2)
    #define	G_RM_AA_SUB_TERR	RM_AA_SUB_TERR(1)
    #define	G_RM_AA_SUB_TERR2	RM_AA_SUB_TERR(2)

    #define	G_RM_RA_OPA_SURF	RM_RA_OPA_SURF(1)
    #define	G_RM_RA_OPA_SURF2	RM_RA_OPA_SURF(2)

    #define	G_RM_ZB_OPA_SURF	RM_ZB_OPA_SURF(1)
    #define	G_RM_ZB_OPA_SURF2	RM_ZB_OPA_SURF(2)
    #define	G_RM_ZB_XLU_SURF	RM_ZB_XLU_SURF(1)
    #define	G_RM_ZB_XLU_SURF2	RM_ZB_XLU_SURF(2)
    #define	G_RM_ZB_OPA_DECAL	RM_ZB_OPA_DECAL(1)
    #define	G_RM_ZB_OPA_DECAL2	RM_ZB_OPA_DECAL(2)
    #define	G_RM_ZB_XLU_DECAL	RM_ZB_XLU_DECAL(1)
    #define	G_RM_ZB_XLU_DECAL2	RM_ZB_XLU_DECAL(2)
    #define	G_RM_ZB_CLD_SURF	RM_ZB_CLD_SURF(1)
    #define	G_RM_ZB_CLD_SURF2	RM_ZB_CLD_SURF(2)
    #define	G_RM_ZB_OVL_SURF	RM_ZB_OVL_SURF(1)
    #define	G_RM_ZB_OVL_SURF2	RM_ZB_OVL_SURF(2)
    #define	G_RM_ZB_PCL_SURF	RM_ZB_PCL_SURF(1)
    #define	G_RM_ZB_PCL_SURF2	RM_ZB_PCL_SURF(2)

    #define	G_RM_OPA_SURF		RM_OPA_SURF(1)
    #define	G_RM_OPA_SURF2		RM_OPA_SURF(2)
    #define	G_RM_XLU_SURF		RM_XLU_SURF(1)
    #define	G_RM_XLU_SURF2		RM_XLU_SURF(2)
    #define	G_RM_CLD_SURF		RM_CLD_SURF(1)
    #define	G_RM_CLD_SURF2		RM_CLD_SURF(2)
    #define	G_RM_TEX_EDGE		RM_TEX_EDGE(1)
    #define	G_RM_TEX_EDGE2		RM_TEX_EDGE(2)
    #define	G_RM_PCL_SURF		RM_PCL_SURF(1)
    #define	G_RM_PCL_SURF2		RM_PCL_SURF(2)
    #define G_RM_ADD       		RM_ADD(1)
    #define G_RM_ADD2      		RM_ADD(2)
    #define G_RM_NOOP       	RM_NOOP(1)
    #define G_RM_NOOP2      	RM_NOOP(2)
    #define G_RM_VISCVG    		RM_VISCVG(1)
    #define G_RM_VISCVG2    	RM_VISCVG(2)
    #define G_RM_OPA_CI         RM_OPA_CI(1)
    #define G_RM_OPA_CI2        RM_OPA_CI(2)

    #define	G_RM_FOG_SHADE_A	GBL_c1(G_BL_CLR_FOG, G_BL_A_SHADE, G_BL_CLR_IN, G_BL_1MA)
    #define	G_RM_FOG_PRIM_A		GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_IN, G_BL_1MA)
    #define	G_RM_PASS		GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1)

    /*
     * G_SETCONVERT: K0-5
     */
    #define	G_CV_K0		175
    #define	G_CV_K1		-43
    #define	G_CV_K2		-89
    #define	G_CV_K3		222
    #define	G_CV_K4		114
    #define	G_CV_K5		42

    /*
     * G_SETSCISSOR: interlace mode
     */
    #define	G_SC_NON_INTERLACE	0
    #define	G_SC_ODD_INTERLACE	3
    #define	G_SC_EVEN_INTERLACE	2

    /* flags to inhibit pushing of the display list (on branch) */
    #define G_DL_PUSH		0x00
    #define G_DL_NOPUSH		0x01

    /*
     * BEGIN C-specific section: (typedef's)
     */
    #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)

    /*
     * Data Structures
     *
     * NOTE:
     * The DMA transfer hardware requires 64-bit aligned, 64-bit multiple-
     * sized transfers. This important hardware optimization is unfortunately
     * reflected in the programming interface, with some structures
     * padded and alignment enforced.
     *
     * Since structures are aligned to the boundary of the "worst-case"
     * element, we can't depend on the C compiler to align things
     * properly.
     *
     * 64-bit structure alignment is enforced by wrapping structures with
     * unions that contain a dummy "long long int".  Why this works is
     * explained in the ANSI C Spec, or on page 186 of the second edition
     * of K&R, "The C Programming Language".
     *
     * The price we pay for this is a little awkwardness referencing the
     * structures through the union. There is no memory penalty, since
     * all the structures are at least 64-bits the dummy alignment field
     * does not increase the size of the union.
     *
     * Static initialization of these union structures works because
     * the ANSI C spec states that static initialization for unions
     * works by using the first union element. We put the dummy alignment
     * field last for this reason.
     *
     * (it's possible a newer 64-bit compiler from MIPS might make this
     * easier with a flag, but we can't wait for it...)
     *
     */

    /*
     * Vertex (set up for use with colors)
     */
    typedef struct {
    	short		ob[3];	/* x, y, z */
    	unsigned short	flag;
    	short		tc[2];	/* texture coord */
    	unsigned char	cn[4];	/* color & alpha */
    } Vtx_t;

    /*
     * Vertex (set up for use with normals)
     */
    typedef struct {
    	short		ob[3];	/* x, y, z */
    	unsigned short	flag;
    	short		tc[2];	/* texture coord */
    	signed char	n[3];	/* normal */
    	unsigned char   a;      /* alpha  */
    } Vtx_tn;

    typedef union {
        Vtx_t		v;  /* Use this one for colors  */
        Vtx_tn              n;  /* Use this one for normals */
        long long int	force_structure_alignment;
    } Vtx;

    /*
     * Sprite structure
     */

    typedef struct {
      void *SourceImagePointer;
      void *TlutPointer;
      short Stride;
      short SubImageWidth;
      short SubImageHeight;
      char  SourceImageType;
      char  SourceImageBitSize;
      short SourceImageOffsetS;
      short SourceImageOffsetT;
      /* 20 bytes for above */

      /* padding to bring structure size to 64 bit allignment */
      char dummy[4];

    } uSprite_t;

    typedef union {
      uSprite_t  s;

      /* Need to make sure this is 64 bit aligned */
      long long int         force_structure_allignment[3];
    } uSprite;

    /*
     * Triangle face
     */
    typedef struct {
    	unsigned char	flag;
    	unsigned char	v[3];
    } Tri;

    /*
     * 4x4 matrix, fixed point s15.16 format.
     * First 8 words are integer portion of the 4x4 matrix
     * Last 8 words are the fraction portion of the 4x4 matrix
     */
    typedef long	Mtx_t[4][4];

    typedef union {
        Mtx_t		m;
        long long int	force_structure_alignment;
    } Mtx;

    /*
     * Viewport
     */

    /*
     *
     * This magic value is the maximum INTEGER z-range of the hardware
     * (there are also 16-bits of fraction, which are introduced during
     * any transformations). This is not just a good idea, it's the law.
     * Feeding the hardware eventual z-coordinates (after any transforms
     * or scaling) bigger than this, will not work.
     *
     * This number is DIFFERENT than G_MAXFBZ, which is the maximum value
     * you want to use to initialize the z-buffer.
     *
     * The reason these are different is mildly interesting, but too long
     * to explain here. It is basically the result of optimizations in the
     * hardware. A more generic API might hide this detail from the users,
     * but we don't have the ucode to do that...
     *
     */
    #define G_MAXZ		0x03ff	/* 10 bits of integer screen-Z precision */

    /*
     * The viewport structure elements have 2 bits of fraction, necessary
     * to accomodate the sub-pixel positioning scaling for the hardware.
     * This can also be exploited to handle odd-sized viewports.
     *
     * Accounting for these fractional bits, using the default projection
     * and viewing matrices, the viewport structure is initialized thusly:
     *
     *		(SCREEN_WD/2)*4, (SCREEN_HT/2)*4, G_MAXZ, 0,
     *		(SCREEN_WD/2)*4, (SCREEN_HT/2)*4, 0, 0,
     */
    typedef struct {
    	short	vscale[4];  /* scale, 2 bits fraction */
    	short	vtrans[4];  /* translate, 2 bits fraction */
    	/* both the above arrays are padded to 64-bit boundary */
    } Vp_t;

    typedef union {
        Vp_t		vp;
        long long int	force_structure_alignment;
    } Vp;

    /*
     * MOVEMEM indices
     *
     * Each of these indexes an entry in a dmem table
     * which points to a 1-4 word block of dmem in
     * which to store a 1-4 word DMA.
     *
     */
    #ifdef	F3DEX_GBI_2
    /* 0,4 are reserved by G_MTX */
    # define G_MV_MMTX	2
    # define G_MV_PMTX	6
    # define G_MV_VIEWPORT	8
    # define G_MV_LIGHT	10
    # define G_MV_POINT	12
    # define G_MV_MATRIX	14		/* NOTE: this is in moveword table */
    # define G_MVO_LOOKATX	(0*24)
    # define G_MVO_LOOKATY	(1*24)
    # define G_MVO_L0	(2*24)
    # define G_MVO_L1	(3*24)
    # define G_MVO_L2	(4*24)
    # define G_MVO_L3	(5*24)
    # define G_MVO_L4	(6*24)
    # define G_MVO_L5	(7*24)
    # define G_MVO_L6	(8*24)
    # define G_MVO_L7	(9*24)
    #else	/* F3DEX_GBI_2 */
    # define G_MV_VIEWPORT	0x80
    # define G_MV_LOOKATY	0x82
    # define G_MV_LOOKATX	0x84
    # define G_MV_L0	0x86
    # define G_MV_L1	0x88
    # define G_MV_L2	0x8a
    # define G_MV_L3	0x8c
    # define G_MV_L4	0x8e
    # define G_MV_L5	0x90
    # define G_MV_L6	0x92
    # define G_MV_L7	0x94
    # define G_MV_TXTATT	0x96
    # define G_MV_MATRIX_1	0x9e	/* NOTE: this is in moveword table */
    # define G_MV_MATRIX_2	0x98
    # define G_MV_MATRIX_3	0x9a
    # define G_MV_MATRIX_4	0x9c
    #endif	/* F3DEX_GBI_2 */

    /*
     * MOVEWORD indices
     *
     * Each of these indexes an entry in a dmem table
     * which points to a word in dmem in dmem where
     * an immediate word will be stored.
     *
     */
    #define G_MW_MATRIX		0x00	/* NOTE: also used by movemem */
    #define G_MW_NUMLIGHT		0x02
    #define G_MW_CLIP		0x04
    #define G_MW_SEGMENT		0x06
    #define G_MW_FOG		0x08
    #define G_MW_LIGHTCOL		0x0a
    #ifdef	F3DEX_GBI_2
    # define G_MW_FORCEMTX		0x0c
    #else	/* F3DEX_GBI_2 */
    # define G_MW_POINTS		0x0c
    #endif	/* F3DEX_GBI_2 */
    #define	G_MW_PERSPNORM		0x0e

    /*
     * These are offsets from the address in the dmem table
     */
    #define G_MWO_NUMLIGHT		0x00
    #define G_MWO_CLIP_RNX		0x04
    #define G_MWO_CLIP_RNY		0x0c
    #define G_MWO_CLIP_RPX		0x14
    #define G_MWO_CLIP_RPY		0x1c
    #define G_MWO_SEGMENT_0		0x00
    #define G_MWO_SEGMENT_1		0x01
    #define G_MWO_SEGMENT_2		0x02
    #define G_MWO_SEGMENT_3		0x03
    #define G_MWO_SEGMENT_4		0x04
    #define G_MWO_SEGMENT_5		0x05
    #define G_MWO_SEGMENT_6		0x06
    #define G_MWO_SEGMENT_7		0x07
    #define G_MWO_SEGMENT_8		0x08
    #define G_MWO_SEGMENT_9		0x09
    #define G_MWO_SEGMENT_A		0x0a
    #define G_MWO_SEGMENT_B		0x0b
    #define G_MWO_SEGMENT_C		0x0c
    #define G_MWO_SEGMENT_D		0x0d
    #define G_MWO_SEGMENT_E		0x0e
    #define G_MWO_SEGMENT_F		0x0f
    #define G_MWO_FOG		0x00
    #define G_MWO_aLIGHT_1		0x00
    #define G_MWO_bLIGHT_1		0x04
    #ifdef	F3DEX_GBI_2
    #define G_MWO_aLIGHT_2		0x18
    #define G_MWO_bLIGHT_2		0x1c
    #define G_MWO_aLIGHT_3		0x30
    #define G_MWO_bLIGHT_3		0x34
    #define G_MWO_aLIGHT_4		0x48
    #define G_MWO_bLIGHT_4		0x4c
    #define G_MWO_aLIGHT_5		0x60
    #define G_MWO_bLIGHT_5		0x64
    #define G_MWO_aLIGHT_6		0x78
    #define G_MWO_bLIGHT_6		0x7c
    #define G_MWO_aLIGHT_7		0x90
    #define G_MWO_bLIGHT_7		0x94
    #define G_MWO_aLIGHT_8		0xa8
    #define G_MWO_bLIGHT_8		0xac
    #else
    #define G_MWO_aLIGHT_2		0x20
    #define G_MWO_bLIGHT_2		0x24
    #define G_MWO_aLIGHT_3		0x40
    #define G_MWO_bLIGHT_3		0x44
    #define G_MWO_aLIGHT_4		0x60
    #define G_MWO_bLIGHT_4		0x64
    #define G_MWO_aLIGHT_5		0x80
    #define G_MWO_bLIGHT_5		0x84
    #define G_MWO_aLIGHT_6		0xa0
    #define G_MWO_bLIGHT_6		0xa4
    #define G_MWO_aLIGHT_7		0xc0
    #define G_MWO_bLIGHT_7		0xc4
    #define G_MWO_aLIGHT_8		0xe0
    #define G_MWO_bLIGHT_8		0xe4
    #endif
    #define G_MWO_MATRIX_XX_XY_I	0x00
    #define G_MWO_MATRIX_XZ_XW_I	0x04
    #define G_MWO_MATRIX_YX_YY_I	0x08
    #define G_MWO_MATRIX_YZ_YW_I	0x0c
    #define G_MWO_MATRIX_ZX_ZY_I	0x10
    #define G_MWO_MATRIX_ZZ_ZW_I	0x14
    #define G_MWO_MATRIX_WX_WY_I	0x18
    #define G_MWO_MATRIX_WZ_WW_I	0x1c
    #define G_MWO_MATRIX_XX_XY_F	0x20
    #define G_MWO_MATRIX_XZ_XW_F	0x24
    #define G_MWO_MATRIX_YX_YY_F	0x28
    #define G_MWO_MATRIX_YZ_YW_F	0x2c
    #define G_MWO_MATRIX_ZX_ZY_F	0x30
    #define G_MWO_MATRIX_ZZ_ZW_F	0x34
    #define G_MWO_MATRIX_WX_WY_F	0x38
    #define G_MWO_MATRIX_WZ_WW_F	0x3c
    #define G_MWO_POINT_RGBA	0x10
    #define G_MWO_POINT_ST		0x14
    #define G_MWO_POINT_XYSCREEN	0x18
    #define G_MWO_POINT_ZSCREEN	0x1c

    /*
     * Light structure.
     *
     * Note: only directional (infinite) lights are currently supported.
     *
     * Note: the weird order is for the DMEM alignment benefit of
     * the microcode.
     *
     */

    typedef struct {
      unsigned char	col[3];		/* diffuse light value (rgba) */
      char 		pad1;
      unsigned char	colc[3];	/* copy of diffuse light value (rgba) */
      char 		pad2;
      signed char	dir[3];		/* direction of light (normalized) */
      char 		pad3;
    } Light_t;

    typedef struct {
      unsigned char	col[3];		/* ambient light value (rgba) */
      char 		pad1;
      unsigned char	colc[3];	/* copy of ambient light value (rgba) */
      char 		pad2;
    } Ambient_t;

    typedef struct {
      int		x1,y1,x2,y2;	/* texture offsets for highlight 1/2 */
    } Hilite_t;

    typedef union {
        Light_t	l;
        long long int	force_structure_alignment[2];
    } Light;

    typedef union {
        Ambient_t	l;
        long long int	force_structure_alignment[1];
    } Ambient;

    typedef struct {
        Ambient	a;
        Light	l[7];
    } Lightsn;

    typedef struct {
        Ambient	a;
        Light	l[1];
    } Lights0;

    typedef struct {
        Ambient	a;
        Light	l[1];
    } Lights1;

    typedef struct {
        Ambient	a;
        Light	l[2];
    } Lights2;

    typedef struct {
        Ambient	a;
        Light	l[3];
    } Lights3;

    typedef struct {
        Ambient	a;
        Light	l[4];
    } Lights4;

    typedef struct {
        Ambient	a;
        Light	l[5];
    } Lights5;

    typedef struct {
        Ambient	a;
        Light	l[6];
    } Lights6;

    typedef struct {
        Ambient	a;
        Light	l[7];
    } Lights7;

    typedef struct {
        Light	l[2];
    } LookAt;

    typedef union {
        Hilite_t	h;
        long int	force_structure_alignment[4];
    } Hilite;

    #define gdSPDefLights0(ar,ag,ab)					\
    		{ 	{{ {ar,ag,ab},0,{ar,ag,ab},0}},			\
    		       {{{ { 0, 0, 0},0,{ 0, 0, 0},0,{ 0, 0, 0},0}}} }
    #define gdSPDefLights1(ar,ag,ab,r1,g1,b1,x1,y1,z1)			\
    		{ 	{{ {ar,ag,ab},0,{ar,ag,ab},0}},			\
    		       {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}} }
    #define gdSPDefLights2(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2)	\
    		{ 	{{ {ar,ag,ab},0,{ar,ag,ab},0}},			\
    		       {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}},	\
    			{{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}} }
    #define gdSPDefLights3(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2,r3,g3,b3,x3,y3,z3)									\
    		{ 	{{ {ar,ag,ab},0,{ar,ag,ab},0}},			\
    		       {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}},	\
    			{{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}},	\
    			{{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}}} }
    #define gdSPDefLights4(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2,r3,g3,b3,x3,y3,z3,r4,g4,b4,x4,y4,z4)						\
    		{ 	{{ {ar,ag,ab},0,{ar,ag,ab},0}},			\
    		       {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}},	\
    			{{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}},	\
    			{{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}},	\
    			{{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}}} }
    #define gdSPDefLights5(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2,r3,g3,b3,x3,y3,z3,r4,g4,b4,x4,y4,z4,r5,g5,b5,x5,y5,z5)				\
    		{ 	{{ {ar,ag,ab},0,{ar,ag,ab},0}},			\
    		       {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}},	\
    			{{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}},	\
    			{{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}},	\
    			{{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}},	\
    			{{ {r5,g5,b5},0,{r5,g5,b5},0,{x5,y5,z5},0}}} }

    #define gdSPDefLights6(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2,r3,g3,b3,x3,y3,z3,r4,g4,b4,x4,y4,z4,r5,g5,b5,x5,y5,z5,r6,g6,b6,x6,y6,z6)		\
    		{ 	{{ {ar,ag,ab},0,{ar,ag,ab},0}},			\
    		       {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}},	\
    			{{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}},	\
    			{{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}},	\
    			{{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}},	\
    			{{ {r5,g5,b5},0,{r5,g5,b5},0,{x5,y5,z5},0}},	\
    			{{ {r6,g6,b6},0,{r6,g6,b6},0,{x6,y6,z6},0}}} }

    #define gdSPDefLights7(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2,r3,g3,b3,x3,y3,z3,r4,g4,b4,x4,y4,z4,r5,g5,b5,x5,y5,z5,r6,g6,b6,x6,y6,z6,r7,g7,b7,x7,y7,z7)	\
    		{ 	{{ {ar,ag,ab},0,{ar,ag,ab},0}},			\
    		       {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}},	\
    			{{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}},	\
    			{{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}},	\
    			{{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}},	\
    			{{ {r5,g5,b5},0,{r5,g5,b5},0,{x5,y5,z5},0}},	\
    			{{ {r6,g6,b6},0,{r6,g6,b6},0,{x6,y6,z6},0}},	\
    			{{ {r7,g7,b7},0,{r7,g7,b7},0,{x7,y7,z7},0}}} }

    #define gdSPDefLookAt(rightx,righty,rightz,upx,upy,upz)			    \
    		{	{{ {{0,0,0},0,{0,0,0},0,{rightx,righty,rightz},0}}, \
    			{ {{0,0x80,0},0,{0,0x80,0},0,{upx,upy,upz},0}}}   }

    /*
     *  Graphics DMA Packet
     */
    typedef struct {
    	int		cmd:8;
    	unsigned int	par:8;
    	unsigned int	len:16;
    	unsigned int	addr;
    } Gdma;

    /*
     * Graphics Immediate Mode Packet types
     */
    typedef struct {
    		int		cmd:8;
    		int		pad:24;
    		Tri		tri;
    } Gtri;

    typedef struct {
    		int		cmd:8;
    		int		pad1:24;
    		int             pad2:24;
    		unsigned char	param:8;
    } Gpopmtx;

    /*
     * typedef struct {
     * 		int		cmd:8;
     * 		int		pad0:24;
     * 		int		pad1:4;
     * 		int		number:4;
     * 		int		base:24;
     * } Gsegment;
     */
    typedef struct {
    		int		cmd:8;
    		int		pad0:8;
    		int		mw_index:8;
    		int		number:8;
    		int		pad1:8;
    		int		base:24;
    } Gsegment;

    typedef struct {
    		int		cmd:8;
    		int		pad0:8;
    		int		sft:8;
    		int		len:8;
    		unsigned int	data:32;
    } GsetothermodeL;

    typedef struct {
    		int		cmd:8;
    		int		pad0:8;
    		int		sft:8;
    		int		len:8;
    		unsigned int	data:32;
    } GsetothermodeH;

    typedef struct {
    		unsigned char	cmd;
    		unsigned char	lodscale;
    		unsigned char	tile;
    		unsigned char	on;
    		unsigned short	s;
    		unsigned short	t;
    } Gtexture;

    typedef struct {
    		int		cmd:8;
    		int		pad:24;
    		Tri		line;
    } Gline3D;

    typedef struct {
    		int		cmd:8;
    		int		pad1:24;
    		short int	pad2;
    		short int       scale;
    } Gperspnorm;

    /*
     * RDP Packet types
     */
    typedef struct {
                    int             cmd:8;
                    unsigned int    fmt:3;
                    unsigned int    siz:2;
                    unsigned int    pad:7;
                    unsigned int    wd:12;	/* really only 10 bits, extra	*/
                    unsigned int    dram;	/* to account for 1024		*/
    } Gsetimg;

    typedef struct {
    		int		cmd:8;
    		unsigned int	muxs0:24;
    		unsigned int	muxs1:32;
    } Gsetcombine;

    typedef struct {
    		int		cmd:8;
    		unsigned char	pad;
    		unsigned char	prim_min_level;
    		unsigned char	prim_level;
    		unsigned long	color;
    } Gsetcolor;

    typedef struct {
    		int		cmd:8;
    		int		x0:10;
    		int		x0frac:2;
    		int		y0:10;
    		int		y0frac:2;
    		unsigned int	pad:8;
    		int		x1:10;
    		int		x1frac:2;
    		int		y1:10;
    		int		y1frac:2;
    } Gfillrect;

    typedef struct {
    		int		cmd:8;
    		unsigned int	fmt:3;
    		unsigned int	siz:2;
    		unsigned int	pad0:1;
    		unsigned int	line:9;
    		unsigned int	tmem:9;
    		unsigned int	pad1:5;
    		unsigned int	tile:3;
    		unsigned int	palette:4;
    		unsigned int	ct:1;
    		unsigned int	mt:1;
    		unsigned int	maskt:4;
    		unsigned int	shiftt:4;
    		unsigned int	cs:1;
    		unsigned int	ms:1;
    		unsigned int	masks:4;
    		unsigned int	shifts:4;
    } Gsettile;

    typedef struct {
    		int		cmd:8;
    		unsigned int	sl:12;
    		unsigned int	tl:12;
    		int		pad:5;
    		unsigned int	tile:3;
    		unsigned int	sh:12;
    		unsigned int	th:12;
    } Gloadtile;

    typedef Gloadtile Gloadblock;

    typedef Gloadtile Gsettilesize;

    typedef Gloadtile Gloadtlut;

    typedef struct {
    		unsigned int	cmd:8;	/* command			*/
    		unsigned int	xl:12;	/* X coordinate of upper left	*/
    		unsigned int	yl:12;	/* Y coordinate of upper left	*/
    		unsigned int	pad1:5;	/* Padding			*/
    		unsigned int	tile:3;	/* Tile descriptor index	*/
    		unsigned int	xh:12;	/* X coordinate of lower right	*/
    		unsigned int	yh:12;	/* Y coordinate of lower right	*/
    		unsigned int	s:16;	/* S texture coord at top left	*/
    		unsigned int	t:16;	/* T texture coord at top left	*/
    		unsigned int	dsdx:16;/* Change in S per change in X	*/
    		unsigned int	dtdy:16;/* Change in T per change in Y	*/
    } Gtexrect;

    #define	MakeTexRect(xh,yh,flip,tile,xl,yl,s,t,dsdx,dtdy)		\
    	G_TEXRECT, xh, yh, 0, flip, 0, tile, xl, yl, s, t, dsdx, dtdy

    /*
     * Textured rectangles are 128 bits not 64 bits
     */
    typedef struct {
        unsigned long w0;
        unsigned long w1;
        unsigned long w2;
        unsigned long w3;
    } TexRect;

    /*
     * Generic Gfx Packet
     */
    typedef struct {
    	unsigned int w0;
    	unsigned int w1;
    } Gwords;

    /*
     * This union is the fundamental type of the display list.
     * It is, by law, exactly 64 bits in size.
     */
    typedef union {
    	Gwords		words;
    	Gdma		dma;
    	Gtri		tri;
    	Gline3D		line;
    	Gpopmtx		popmtx;
    	Gsegment	segment;
    	GsetothermodeH	setothermodeH;
    	GsetothermodeL	setothermodeL;
    	Gtexture	texture;
    	Gperspnorm	perspnorm;
    	Gsetimg		setimg;
    	Gsetcombine	setcombine;
    	Gsetcolor	setcolor;
    	Gfillrect	fillrect;	/* use for setscissor also */
    	Gsettile	settile;
    	Gloadtile	loadtile;	/* use for loadblock also, th is dxt */
    	Gsettilesize	settilesize;
    	Gloadtlut	loadtlut;
            long long int	force_structure_alignment;
    } Gfx;

    /*
     * Macros to assemble the graphics display list
     */

    /*
     * DMA macros
     */
    #define	gDma0p(pkt, c, s, l)						\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24);	\
    	_g->words.w1 = (unsigned int)(s);				\
    }

    #define	gsDma0p(c, s, l)						\
    {									\
    	_SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24), (unsigned int)(s)	\
    }

    #define	gDma1p(pkt, c, s, l, p)						\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) |	\
    			_SHIFTL((l), 0, 16));				\
    	_g->words.w1 = (unsigned int)(s);				\
    }

    #define	gsDma1p(c, s, l, p)						\
    {									\
    	(_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | 			\
    	 _SHIFTL((l), 0, 16)), 						\
            (unsigned int)(s)						\
    }

    #define	gDma2p(pkt, c, adrs, len, idx, ofs)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    	_g->words.w0 = (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)|	\
    			_SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8));	\
    	_g->words.w1 = (unsigned int)(adrs);				\
    }
    #define	gsDma2p(c, adrs, len, idx, ofs)					\
    {									\
    	(_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)|			\
    	 _SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)),			\
            (unsigned int)(adrs)						\
    }

    #define	gSPNoOp(pkt)		gDma0p(pkt, G_SPNOOP, 0, 0)
    #define	gsSPNoOp()		gsDma0p(G_SPNOOP, 0, 0)

    #ifdef	F3DEX_GBI_2
    # define	gSPMatrix(pkt, m, p)	\
    		gDma2p((pkt),G_MTX,(m),sizeof(Mtx),(p)^G_MTX_PUSH,0)
    # define	gsSPMatrix(m, p)	\
    		gsDma2p(     G_MTX,(m),sizeof(Mtx),(p)^G_MTX_PUSH,0)
    #else	/* F3DEX_GBI_2 */
    # define	gSPMatrix(pkt, m, p)	gDma1p(pkt, G_MTX, m, sizeof(Mtx), p)
    # define	gsSPMatrix(m, p)	gsDma1p(G_MTX, m, sizeof(Mtx), p)
    #endif	/* F3DEX_GBI_2 */

    #if	defined(F3DEX_GBI_2)
    /*
     * F3DEX_GBI_2: G_VTX GBI format was changed.
     *
     *        +--------+----+---+---+----+------+-+
     *  G_VTX |  cmd:8 |0000|  n:8  |0000|v0+n:7|0|
     *        +-+---+--+----+---+---+----+------+-+
     *        | |seg|         address             |
     *        +-+---+-----------------------------+
     */
    # define	gSPVertex(pkt, v, n, v0)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    	_g->words.w0 =							\
    	  _SHIFTL(G_VTX,24,8)|_SHIFTL((n),12,8)|_SHIFTL((v0)+(n),1,7);	\
    	_g->words.w1 = (unsigned int)(v);				\
    }
    # define	gsSPVertex(v, n, v0)					\
    {									\
    	(_SHIFTL(G_VTX,24,8)|_SHIFTL((n),12,8)|_SHIFTL((v0)+(n),1,7)),	\
            (unsigned int)(v)						\
    }
    #elif	(defined(F3DEX_GBI)||defined(F3DLP_GBI))
    /*
     * F3DEX_GBI: G_VTX GBI format was changed to support 64 vertice.
     *
     *        +--------+--------+------+----------+
     *  G_VTX |  cmd:8 |  v0:8  |  n:6 |length:10 |
     *        +-+---+--+--------+------+----------+
     *        | |seg|          address            |
     *        +-+---+-----------------------------+
     */
    # define	gSPVertex(pkt, v, n, v0) \
                    gDma1p((pkt),G_VTX,(v),((n)<<10)|(sizeof(Vtx)*(n)-1),(v0)*2)
    # define	gsSPVertex(v, n, v0) \
                    gsDma1p(G_VTX,(v),((n)<<10)|(sizeof(Vtx)*(n)-1),(v0)*2)
    #else
    # define	gSPVertex(pkt, v, n, v0) \
                    gDma1p(pkt, G_VTX, v, sizeof(Vtx)*(n),((n)-1)<<4|(v0))
    # define	gsSPVertex(v, n, v0) \
                    gsDma1p(G_VTX, v, sizeof(Vtx)*(n), ((n)-1)<<4|(v0))
    #endif

    #ifdef	F3DEX_GBI_2
    # define gSPViewport(pkt, v)	\
    		gDma2p((pkt), G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT, 0)
    # define gsSPViewport(v)	\
    		gsDma2p(      G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT, 0)
    #else	/* F3DEX_GBI_2 */
    # define gSPViewport(pkt,v)	\
    		gDma1p((pkt), G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT)
    # define gsSPViewport(v)	\
    		gsDma1p(      G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT)
    #endif	/* F3DEX_GBI_2 */

    #define	gSPDisplayList(pkt,dl)	gDma1p(pkt,G_DL,dl,0,G_DL_PUSH)
    #define	gsSPDisplayList(   dl)	gsDma1p(   G_DL,dl,0,G_DL_PUSH)

    #define	gSPBranchList(pkt,dl)	gDma1p(pkt,G_DL,dl,0,G_DL_NOPUSH)
    #define	gsSPBranchList(   dl)	gsDma1p(   G_DL,dl,0,G_DL_NOPUSH)

    #define	gSPSprite2DBase(pkt, s)	gDma1p(pkt, G_SPRITE2D_BASE, s, sizeof(uSprite), 0)
    #define	gsSPSprite2DBase(s)	gsDma1p(G_SPRITE2D_BASE, s, sizeof(uSprite), 0)

    /*
     * RSP short command (no DMA required) macros
     */
    #define	gImmp0(pkt, c)							\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL((c), 24, 8);				\
    }

    #define	gsImmp0(c)							\
    {									\
    	_SHIFTL((c), 24, 8)						\
    }

    #define	gImmp1(pkt, c, p0)						\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL((c), 24, 8);				\
    	_g->words.w1 = (unsigned int)(p0);				\
    }

    #define	gsImmp1(c, p0)							\
    {									\
    	_SHIFTL((c), 24, 8), (unsigned int)(p0)				\
    }

    #define	gImmp2(pkt, c, p0, p1)						\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL((c), 24, 8);				\
    	_g->words.w1 = _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8);	\
    }

    #define	gsImmp2(c, p0, p1)						\
    {									\
    	_SHIFTL((c), 24, 8),  _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8)\
    }

    #define	gImmp3(pkt, c, p0, p1, p2)					\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL((c), 24, 8);				\
    	_g->words.w1 = (_SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8) |	\
    			_SHIFTL((p2), 0, 8));				\
    }

    #define	gsImmp3(c, p0, p1, p2)						\
    {									\
    	_SHIFTL((c), 24, 8), (_SHIFTL((p0), 16, 16) | 			\
    			      _SHIFTL((p1), 8, 8) | _SHIFTL((p2), 0, 8))\
    }

    #define	gImmp21(pkt, c, p0, p1, dat)					\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL((c), 24, 8)  | _SHIFTL((p0), 8, 16) |	\
    			_SHIFTL((p1), 0, 8));				\
    	_g->words.w1 = (unsigned int) (dat);				\
    }

    #define	gsImmp21(c, p0, p1, dat)					\
    {									\
    	_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8),\
            (unsigned int) (dat)						\
    }

    #ifdef	F3DEX_GBI_2
    #define gMoveWd(pkt, index, offset, data)				\
    	gDma1p((pkt), G_MOVEWORD, data, offset, index)
    #define gsMoveWd(    index, offset, data)				\
    	gsDma1p(      G_MOVEWORD, data, offset, index)
    #else	/* F3DEX_GBI_2 */
    #define gMoveWd(pkt, index, offset, data)				\
    	gImmp21((pkt), G_MOVEWORD, offset, index, data)
    #define gsMoveWd(    index, offset, data)				\
    	gsImmp21(      G_MOVEWORD, offset, index, data)
    #endif	/* F3DEX_GBI_2 */

    /* Sprite immediate macros, there is also a sprite dma macro above */

    #define gSPSprite2DScaleFlip(pkt, sx, sy, fx, fy)                       \
    {                                                                       \
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_SPRITE2D_SCALEFLIP, 24, 8) |          \
    			_SHIFTL((fx), 8, 8) |                           \
    			_SHIFTL((fy), 0, 8));	                        \
    	_g->words.w1 = (_SHIFTL((sx), 16, 16) |                         \
    			_SHIFTL((sy),  0, 16));                         \
    }

    #define gsSPSprite2DScaleFlip(sx, sy, fx, fy)                           \
    {                                                                       \
              (_SHIFTL(G_SPRITE2D_SCALEFLIP, 24, 8) |                       \
    	   _SHIFTL((fx), 8, 8) |                                        \
    	   _SHIFTL((fy), 0, 8)),	                                \
    	  (_SHIFTL((sx), 16, 16) |                                      \
    	   _SHIFTL((sy),  0, 16))                                       \
    }

    #define gSPSprite2DDraw(pkt, px, py)                                    \
    {                                                                       \
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_SPRITE2D_DRAW, 24, 8));               \
    	_g->words.w1 = (_SHIFTL((px), 16, 16) |                         \
    			_SHIFTL((py),  0, 16));                         \
    }

    #define gsSPSprite2DDraw(px, py)                                        \
    {                                                                       \
              (_SHIFTL(G_SPRITE2D_DRAW, 24, 8)),                            \
    	  (_SHIFTL((px), 16, 16) |                                      \
    	   _SHIFTL((py),  0, 16))                                       \
    }

    /*
     * Note: the SP1Triangle() and line macros multiply the vertex indices
     * by 10, this is an optimization for the microcode.
     */
    #if	(defined(F3DLP_GBI)||defined(F3DEX_GBI))
    #  define __gsSP1Triangle_w1(v0, v1, v2)			\
         (_SHIFTL((v0)*2,16,8)|_SHIFTL((v1)*2,8,8)|_SHIFTL((v2)*2,0,8))
    #  define __gsSP1Triangle_w1f(v0, v1, v2, flag)			\
         (((flag) == 0) ? __gsSP1Triangle_w1(v0, v1, v2):		\
          ((flag) == 1) ? __gsSP1Triangle_w1(v1, v2, v0):		\
    	              __gsSP1Triangle_w1(v2, v0, v1))
    #  define __gsSPLine3D_w1(v0, v1, wd)				\
         (_SHIFTL((v0)*2,16,8)|_SHIFT((v1)*2,8,8)|_SHIFT((wd),0,8))
    #  define __gsSPLine3D_w1f(v0, v1, wd, flag)			\
         (((flag) == 0) ? __gsSPLine3D_w1(v0, v1, wd):		\
    	              __gsSPLine3D_w1(v1, v0, wd))
    #  define __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)	\
      (((flag) == 0) ? __gsSP1Triangle_w1(v0, v1, v2):      \
       ((flag) == 1) ? __gsSP1Triangle_w1(v1, v2, v3):      \
       ((flag) == 2) ? __gsSP1Triangle_w1(v2, v3, v0):      \
                       __gsSP1Triangle_w1(v3, v0, v1))
    #  define __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag)	\
      (((flag) == 0) ? __gsSP1Triangle_w1(v0, v2, v3):      \
       ((flag) == 1) ? __gsSP1Triangle_w1(v1, v3, v0):      \
       ((flag) == 2) ? __gsSP1Triangle_w1(v2, v0, v1):      \
                       __gsSP1Triangle_w1(v3, v1, v2))
    #else
    #  define __gsSP1Triangle_w1f(v0, v1, v2, flag)			\
         (_SHIFTL((flag), 24,8)|_SHIFTL((v0)*10,16,8)|		\
          _SHIFTL((v1)*10, 8,8)|_SHIFTL((v2)*10, 0,8))
    #  define __gsSPLine3D_w1f(v0, v1, wd, flag)			\
         (_SHIFTL((flag), 24,8)|_SHIFTL((v0)*10,16,8)| 		\
          _SHIFTL((v1)*10, 8,8)|_SHIFTL((wd),    0,8))
    #endif

    #ifdef	F3DEX_GBI_2
    /***
     ***  1 Triangle
     ***/
    #define gSP1Triangle(pkt, v0, v1, v2, flag)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_TRI1, 24, 8)|				\
    			__gsSP1Triangle_w1f(v0, v1, v2, flag);		\
    	_g->words.w1 = 0;						\
    }
    #define gsSP1Triangle(v0, v1, v2, flag)					\
    {									\
    	_SHIFTL(G_TRI1, 24, 8)|__gsSP1Triangle_w1f(v0, v1, v2, flag),	\
    	0								\
    }

    /***
     ***  Line
     ***/
    #define gSPLine3D(pkt, v0, v1, flag)					\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_LINE3D, 24, 8)|			\
    			__gsSPLine3D_w1f(v0, v1, 0, flag);		\
    	_g->words.w1 = 0;						\
    }
    #define gsSPLine3D(v0, v1, flag)					\
    {									\
    	_SHIFTL(G_LINE3D, 24, 8)|__gsSPLine3D_w1f(v0, v1, 0, flag),	\
    	0								\
    }

    /***
     ***  LineW
     ***/
    /* these macros are the same as SPLine3D, except they have an
     * additional parameter for width. The width is added to the "minimum"
     * thickness, which is 1.5 pixels. The units for width are in
     * half-pixel units, so a width of 1 translates to (.5 + 1.5) or
     * a 2.0 pixels wide line.
     */
    #define gSPLineW3D(pkt, v0, v1, wd, flag)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_LINE3D, 24, 8)|			\
    			__gsSPLine3D_w1f(v0, v1, wd, flag);		\
    	_g->words.w1 = 0;						\
    }
    #define gsSPLineW3D(v0, v1, wd, flag)					\
    {									\
    	_SHIFTL(G_LINE3D, 24, 8)|__gsSPLine3D_w1f(v0, v1, wd, flag),	\
    	0								\
    }

    /***
     ***  1 Quadrangle
     ***/
    #define gSP1Quadrangle(pkt, v0, v1, v2, v3, flag)                       \
    {                                                                       \
            Gfx *_g = (Gfx *)(pkt);                                         \
                                                                            \
            _g->words.w0 = (_SHIFTL(G_QUAD, 24, 8)|	                        \
                            __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag));   \
            _g->words.w1 =  __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag);    \
    }

    #define gsSP1Quadrangle(v0, v1, v2, v3, flag)                           \
    {                                                                       \
            (_SHIFTL(G_QUAD, 24, 8)|                                        \
             __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)),                  \
             __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag)                    \
    }
    #else	/* F3DEX_GBI_2 */

    /***
     ***  1 Triangle
     ***/
    #define gSP1Triangle(pkt, v0, v1, v2, flag)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_TRI1, 24, 8);				\
    	_g->words.w1 = __gsSP1Triangle_w1f(v0, v1, v2, flag);		\
    }
    #define gsSP1Triangle(v0, v1, v2, flag)					\
    {									\
    	_SHIFTL(G_TRI1, 24, 8),						\
    	__gsSP1Triangle_w1f(v0, v1, v2, flag)				\
    }

    /***
     ***  Line
     ***/
    #define gSPLine3D(pkt, v0, v1, flag)					\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_LINE3D, 24, 8);			\
    	_g->words.w1 = __gsSPLine3D_w1f(v0, v1, 0, flag);		\
    }
    #define gsSPLine3D(v0, v1, flag)					\
    {									\
    	_SHIFTL(G_LINE3D, 24, 8),					\
    	__gsSPLine3D_w1f(v0, v1, 0, flag)				\
    }

    /***
     ***  LineW
     ***/
    /* these macros are the same as SPLine3D, except they have an
     * additional parameter for width. The width is added to the "minimum"
     * thickness, which is 1.5 pixels. The units for width are in
     * half-pixel units, so a width of 1 translates to (.5 + 1.5) or
     * a 2.0 pixels wide line.
     */
    #define gSPLineW3D(pkt, v0, v1, wd, flag)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_LINE3D, 24, 8);			\
    	_g->words.w1 = __gsSPLine3D_w1f(v0, v1, wd, flag);		\
    }
    #define gsSPLineW3D(v0, v1, wd, flag)					\
    {									\
    	_SHIFTL(G_LINE3D, 24, 8),					\
    	__gsSPLine3D_w1f(v0, v1, wd, flag)				\
    }

    /***
     ***  1 Quadrangle
     ***/
    #define gSP1Quadrangle(pkt, v0, v1, v2, v3, flag)                       \
    {                                                                       \
            Gfx *_g = (Gfx *)(pkt);                                         \
                                                                            \
            _g->words.w0 = (_SHIFTL(G_TRI2, 24, 8)|	                        \
                            __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag));   \
            _g->words.w1 =  __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag);    \
    }

    #define gsSP1Quadrangle(v0, v1, v2, v3, flag)                           \
    {                                                                       \
            (_SHIFTL(G_TRI2, 24, 8)|                                        \
             __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)),                  \
             __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag)                    \
    }
    #endif	/* F3DEX_GBI_2 */

    #if	(defined(F3DLP_GBI)||defined(F3DEX_GBI))
    /***
     ***  2 Triangles
     ***/
    #define gSP2Triangles(pkt, v00, v01, v02, flag0, v10, v11, v12, flag1)	\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_TRI2, 24, 8)|				\
    			__gsSP1Triangle_w1f(v00, v01, v02, flag0));	\
            _g->words.w1 =  __gsSP1Triangle_w1f(v10, v11, v12, flag1); 	\
    }

    #define gsSP2Triangles(v00, v01, v02, flag0, v10, v11, v12, flag1)	\
    {									\
    	(_SHIFTL(G_TRI2, 24, 8)|					\
    	 __gsSP1Triangle_w1f(v00, v01, v02, flag0)),			\
    	 __gsSP1Triangle_w1f(v10, v11, v12, flag1)			\
    }

    #endif	/* F3DEX_GBI/F3DLP_GBI */

    #if	(defined(F3DEX_GBI)||defined(F3DLP_GBI))
    #define gSPCullDisplayList(pkt,vstart,vend)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | 			\
    			_SHIFTL((vstart)*2, 0, 16);			\
    	_g->words.w1 = _SHIFTL((vend)*2, 0, 16);			\
    }

    #define gsSPCullDisplayList(vstart,vend)				\
    {									\
    	_SHIFTL(G_CULLDL, 24, 8) | _SHIFTL((vstart)*2, 0, 16),		\
    	_SHIFTL((vend)*2, 0, 16)					\
    }

    #else
    #define gSPCullDisplayList(pkt,vstart,vend)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) |			\
                           ((0x0f & (vstart))*40);				\
    	_g->words.w1 = (unsigned int)((0x0f & ((vend)+1))*40);		\
    }

    #define gsSPCullDisplayList(vstart,vend)				\
    {									\
    	_SHIFTL(G_CULLDL, 24, 8) | ((0x0f & (vstart))*40), 		\
    	((0x0f & ((vend)+1))*40)					\
    }
    #endif

    #define gSPSegment(pkt, segment, base)					\
    	gMoveWd(pkt, G_MW_SEGMENT, (segment)*4, base)
    #define gsSPSegment(segment, base)					\
    	gsMoveWd(    G_MW_SEGMENT, (segment)*4, base)

    /*
     * Clipping Macros
     */
    #define FR_NEG_FRUSTRATIO_1	0x00000001
    #define FR_POS_FRUSTRATIO_1	0x0000ffff
    #define FR_NEG_FRUSTRATIO_2	0x00000002
    #define FR_POS_FRUSTRATIO_2	0x0000fffe
    #define FR_NEG_FRUSTRATIO_3	0x00000003
    #define FR_POS_FRUSTRATIO_3	0x0000fffd
    #define FR_NEG_FRUSTRATIO_4	0x00000004
    #define FR_POS_FRUSTRATIO_4	0x0000fffc
    #define FR_NEG_FRUSTRATIO_5	0x00000005
    #define FR_POS_FRUSTRATIO_5	0x0000fffb
    #define FR_NEG_FRUSTRATIO_6	0x00000006
    #define FR_POS_FRUSTRATIO_6	0x0000fffa
    /*
     * r should be one of: FRUSTRATIO_1, FRUSTRATIO_2, FRUSTRATIO_3, ... FRUSTRATIO_6
     */
    #define gSPClipRatio(pkt, r)						\
    {									\
    	gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RNX, FR_NEG_##r);		\
    	gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RNY, FR_NEG_##r);		\
    	gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RPX, FR_POS_##r);		\
    	gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RPY, FR_POS_##r);		\
    }

    #define gsSPClipRatio(r)						\
    	gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNX, FR_NEG_##r),		\
    	gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNY, FR_NEG_##r),		\
    	gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPX, FR_POS_##r),		\
    	gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPY, FR_POS_##r)

    /*
     * Insert values into Matrix
     *
     * where = element of matrix (byte offset)
     * num   = new element (32 bit value replacing 2 int or 2 frac matrix
     *                                 componants
     */
    #ifdef	F3DEX_GBI_2
    #define gSPInsertMatrix(pkt, where, num)				\
    	ERROR!! gSPInsertMatrix is no longer supported.
    #define gsSPInsertMatrix(where, num)					\
    	ERROR!! gsSPInsertMatrix is no longer supported.
    #else
    #define gSPInsertMatrix(pkt, where, num)				\
    	gMoveWd(pkt, G_MW_MATRIX, where, num)
    #define gsSPInsertMatrix(where, num)					\
    	gsMoveWd(G_MW_MATRIX, where, num)
    #endif

    /*
     * Load new matrix directly
     *
     * mptr = pointer to matrix
     */
    #ifdef	F3DEX_GBI_2
    #define	gSPForceMatrix(pkt, mptr)					\
    {	gDma2p((pkt),G_MOVEMEM,(mptr),sizeof(Mtx),G_MV_MATRIX,0);	\
    	gMoveWd((pkt), G_MW_FORCEMTX,0,0x00010000);			\
    }
    #define	gsSPForceMatrix(mptr)						\
    	gsDma2p(G_MOVEMEM,(mptr),sizeof(Mtx),G_MV_MATRIX,0),		\
    	gsMoveWd(G_MW_FORCEMTX,0,0x00010000)

    #else	/* F3DEX_GBI_2 */
    #define	gSPForceMatrix(pkt, mptr)					\
    {									\
    	gDma1p(pkt, G_MOVEMEM, mptr,              16, G_MV_MATRIX_1);	\
    	gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+16, 16, G_MV_MATRIX_2);	\
    	gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+32, 16, G_MV_MATRIX_3);	\
    	gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+48, 16, G_MV_MATRIX_4);	\
    }
    #define	gsSPForceMatrix(mptr)						\
    	gsDma1p(    G_MOVEMEM, mptr,              16, G_MV_MATRIX_1),	\
    	gsDma1p(    G_MOVEMEM, (char *)(mptr)+16, 16, G_MV_MATRIX_2),	\
    	gsDma1p(    G_MOVEMEM, (char *)(mptr)+32, 16, G_MV_MATRIX_3),	\
    	gsDma1p(    G_MOVEMEM, (char *)(mptr)+48, 16, G_MV_MATRIX_4)
    #endif	/* F3DEX_GBI_2 */

    /*
     * Insert values into Points
     *
     * point = point number 0-15
     * where = which element of point to modify (byte offset into point)
     * num   = new value (32 bit)
     */
    #if	(defined(F3DEX_GBI)||defined(F3DLP_GBI))
    # define gSPModifyVertex(pkt, vtx, where, val)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    	_g->words.w0 = (_SHIFTL(G_MODIFYVTX,24,8)|			\
    		        _SHIFTL((where),16,8)|_SHIFTL((vtx)*2,0,16));	\
    	_g->words.w1 = (unsigned int)(val);				\
    }
    # define gsSPModifyVertex(vtx, where, val)				\
    {									\
    	_SHIFTL(G_MODIFYVTX,24,8)|					\
    	_SHIFTL((where),16,8)|_SHIFTL((vtx)*2,0,16),			\
    	(unsigned int)(val)						\
    }
    #else
    # define gSPModifyVertex(pkt, vtx, where, val)				\
    	 gMoveWd(pkt, G_MW_POINTS, (vtx)*40+(where), val)
    # define gsSPModifyVertex(vtx, where, val)				\
    	 gsMoveWd(G_MW_POINTS, (vtx)*40+(where), val)
    #endif

    #if	(defined(F3DEX_GBI)||defined(F3DLP_GBI))
    /*
     *  gSPBranchLessZ   Branch DL if (vtx.z) less than or equal (zval).
     *
     *  dl	 = DL branch to
     *  vtx  = Vertex
     *  zval = Screen depth
     *  near = Near plane
     *  far  = Far  plane
     *  flag = G_BZ_PERSP or G_BZ_ORTHO
     */

    #define	G_BZ_PERSP	0
    #define	G_BZ_ORTHO	1

    #define	G_DEPTOZSrg(zval, near, far, flag, zmin, zmax)			\
    (((unsigned int)FTOFIX32(((flag) == G_BZ_PERSP ? 			\
    			  (1.0f-(float)(near)/(float)(zval)) / 		\
    			  (1.0f-(float)(near)/(float)(far )) :		\
    			  ((float)(zval) - (float)(near)) /		\
    			  ((float)(far ) - (float)(near))))) *		\
     (((int)((zmax) - (zmin)))&~1) + (int)FTOFIX32(zmin))

    #define	G_DEPTOZS(zval, near, far, flag) \
    	G_DEPTOZSrg(zval, near, far, flag, 0, G_MAXZ)

    #define	gSPBranchLessZrg(pkt, dl, vtx, zval, near, far, flag, zmin, zmax) \
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    	_g->words.w0 = _SHIFTL(G_RDPHALF_1,24,8);			\
    	_g->words.w1 = (unsigned int)(dl);				\
    	_g = (Gfx *)(pkt);						\
    	_g->words.w0 = (_SHIFTL(G_BRANCH_Z,24,8)|			\
    		        _SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12));	\
    	_g->words.w1 = G_DEPTOZSrg(zval, near, far, flag, zmin, zmax);	\
    }

    #define	gsSPBranchLessZrg(dl, vtx, zval, near, far, flag, zmin, zmax)	      \
    {	_SHIFTL(G_RDPHALF_1,24,8),					      \
    	(unsigned int)(dl),						},    \
    {	_SHIFTL(G_BRANCH_Z,24,8)|_SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12),\
    	G_DEPTOZSrg(zval, near, far, flag, zmin, zmax),			}

    #define	gSPBranchLessZ(pkt, dl, vtx, zval, near, far, flag)		\
    	gSPBranchLessZrg(pkt, dl, vtx, zval, near, far, flag, 0, G_MAXZ)
    #define	gsSPBranchLessZ(dl, vtx, zval, near, far, flag)			\
    	gsSPBranchLessZrg(dl, vtx, zval, near, far, flag, 0, G_MAXZ)

    /*
     *  gSPBranchLessZraw   Branch DL if (vtx.z) less than or equal (raw zval).
     *
     *  dl	 = DL branch to
     *  vtx  = Vertex
     *  zval = Raw value of screen depth
     */
    #define	gSPBranchLessZraw(pkt, dl, vtx, zval)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    	_g->words.w0 = _SHIFTL(G_RDPHALF_1,24,8);			\
    	_g->words.w1 = (unsigned int)(dl);				\
    	_g = (Gfx *)(pkt);						\
    	_g->words.w0 = (_SHIFTL(G_BRANCH_Z,24,8)|			\
    		        _SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12));	\
    	_g->words.w1 = (unsigned int)(zval);				\
    }

    #define	gsSPBranchLessZraw(dl, vtx, zval)				\
    {	_SHIFTL(G_RDPHALF_1,24,8),					      \
    	(unsigned int)(dl),						},    \
    {	_SHIFTL(G_BRANCH_Z,24,8)|_SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12),\
    	(unsigned int)(zval),						}

    /*
     * gSPLoadUcode   RSP loads specified ucode.
     *
     * uc_start  = ucode text section start
     * uc_dstart = ucode data section start
     */
    #define	gSPLoadUcodeEx(pkt, uc_start, uc_dstart, uc_dsize)		\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    	_g->words.w0 = _SHIFTL(G_RDPHALF_1,24,8);			\
    	_g->words.w1 = (unsigned int)(uc_dstart);			\
    	_g = (Gfx *)(pkt);						\
    	_g->words.w0 = (_SHIFTL(G_LOAD_UCODE,24,8)|			\
    			_SHIFTL((int)(uc_dsize)-1,0,16));		\
    	_g->words.w1 = (unsigned int)(uc_start);			\
    }

    #define	gsSPLoadUcodeEx(uc_start, uc_dstart, uc_dsize)			\
    {	_SHIFTL(G_RDPHALF_1,24,8),					\
    	(unsigned int)(uc_dstart),				},	\
    {	_SHIFTL(G_LOAD_UCODE,24,8)|					\
    	  _SHIFTL((int)(uc_dsize)-1,0,16),				\
    	(unsigned int)(uc_start),				}

    #define	gSPLoadUcode(pkt, uc_start, uc_dstart)				\
            gSPLoadUcodeEx((pkt), (uc_start), (uc_dstart), SP_UCODE_DATA_SIZE)
    #define	gsSPLoadUcode(uc_start, uc_dstart)				\
            gsSPLoadUcodeEx((uc_start), (uc_dstart), SP_UCODE_DATA_SIZE)

    #define	gSPLoadUcodeL(pkt, ucode)					\
            gSPLoadUcode((pkt), OS_K0_TO_PHYSICAL(&##ucode##TextStart),	\
    		            OS_K0_TO_PHYSICAL(&##ucode##DataStart))
    #define	gsSPLoadUcodeL(ucode)						\
            gsSPLoadUcode(OS_K0_TO_PHYSICAL(&##ucode##TextStart),		\
    		      OS_K0_TO_PHYSICAL(&##ucode##DataStart))
    #endif

    #ifdef	F3DEX_GBI_2
    /*
     * gSPDma_io  DMA to/from DMEM/IMEM for DEBUG.
     */
    #define	gSPDma_io(pkt, flag, dmem, dram, size)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    	_g->words.w0 = _SHIFTL(G_DMA_IO,24,8)|_SHIFTL((flag),23,1)|	\
    	  _SHIFTL((dmem)/8,13,10)|_SHIFTL((size)-1,0,12);		\
    	_g->words.w1 = (unsigned int)(dram);				\
    }

    #define	gsSPDma_io(flag, dmem, dram, size)				\
    {									\
    	_SHIFTL(G_DMA_IO,24,8)|_SHIFTL((flag),23,1)|			\
    	_SHIFTL((dmem)/8,13,10)|_SHIFTL((size)-1,0,12),			\
    	(unsigned int)(dram)						\
    }

    #define	gSPDmaRead(pkt,dmem,dram,size)	gSPDma_io((pkt),0,(dmem),(dram),(size))
    #define	gsSPDmaRead(dmem,dram,size)	gsSPDma_io(0,(dmem),(dram),(size))
    #define	gSPDmaWrite(pkt,dmem,dram,size)	gSPDma_io((pkt),1,(dmem),(dram),(size))
    #define	gsSPDmaWrite(dmem,dram,size)	gsSPDma_io(1,(dmem),(dram),(size))
    #endif

    /*
     * Lighting Macros
     */
    #ifdef	F3DEX_GBI_2
    # define NUML(n)	((n)*24)
    #else
    # define NUML(n)	(((n)+1)*32 + 0x80000000)
    #endif
    #define NUMLIGHTS_0	1
    #define NUMLIGHTS_1	1
    #define NUMLIGHTS_2	2
    #define NUMLIGHTS_3	3
    #define NUMLIGHTS_4	4
    #define NUMLIGHTS_5	5
    #define NUMLIGHTS_6	6
    #define NUMLIGHTS_7	7
    /*
     * n should be one of: NUMLIGHTS_0, NUMLIGHTS_1, ..., NUMLIGHTS_7
     * NOTE: in addition to the number of directional lights specified,
     *       there is always 1 ambient light
     */
    #define gSPNumLights(pkt, n)						\
    	gMoveWd(pkt, G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n))
    #define gsSPNumLights(n)						\
    	gsMoveWd(    G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n))

    #define LIGHT_1		1
    #define LIGHT_2		2
    #define LIGHT_3		3
    #define LIGHT_4		4
    #define LIGHT_5		5
    #define LIGHT_6		6
    #define LIGHT_7		7
    #define LIGHT_8		8
    /*
     * l should point to a Light struct
     * n should be one of: LIGHT_1, LIGHT_2, ..., LIGHT_8
     * NOTE: the highest numbered light is always the ambient light (eg if there are
     *       3 directional lights defined: gsSPNumLights(NUMLIGHTS_3), then lights
     *       LIGHT_1 through LIGHT_3 will be the directional lights and light
     *       LIGHT_4 will be the ambient light.
     */
    #ifdef	F3DEX_GBI_2
    # define gSPLight(pkt, l, n)	\
    	  gDma2p((pkt),G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,(n)*24+24)
    # define gsSPLight(l, n)	\
    	 gsDma2p(      G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,(n)*24+24)
    #else	/* F3DEX_GBI_2 */
    # define gSPLight(pkt, l, n)	\
    	 gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),((n)-1)*2+G_MV_L0)
    # define gsSPLight(l, n)	\
    	 gsDma1p(    G_MOVEMEM, l, sizeof(Light),((n)-1)*2+G_MV_L0)
    #endif	/* F3DEX_GBI_2 */

    /*
     * gSPLightColor changes color of light without recalculating light direction
     * col is a 32 bit word with r,g,b,a (alpha is ignored)
     * n should be one of LIGHT_1, LIGHT_2, ..., LIGHT_8
     */
    #define gSPLightColor(pkt, n, col)					\
    {									\
    	gMoveWd(pkt, G_MW_LIGHTCOL, G_MWO_a##n, col);			\
    	gMoveWd(pkt, G_MW_LIGHTCOL, G_MWO_b##n, col);			\
    }
    #define gsSPLightColor(n, col)						\
    	gsMoveWd(G_MW_LIGHTCOL, G_MWO_a##n, col),			\
    	gsMoveWd(G_MW_LIGHTCOL, G_MWO_b##n, col)

    /* These macros use a structure "name" which is init'd with the gdSPDefLights macros*/

    #define gSPSetLights0(pkt,name)						\
    {									\
    	gSPNumLights(pkt,NUMLIGHTS_0);					\
    	gSPLight(pkt,&name.l[0],1);					\
    	gSPLight(pkt,&name.a,2);					\
    }
    #define gsSPSetLights0(name)						\
    	gsSPNumLights(NUMLIGHTS_0),					\
    	gsSPLight(&name.l[0],1),					\
    	gsSPLight(&name.a,2)

    #define gSPSetLights1(pkt,name)						\
    {									\
    	gSPNumLights(pkt,NUMLIGHTS_1);					\
    	gSPLight(pkt,&name.l[0],1);					\
    	gSPLight(pkt,&name.a,2);					\
    }
    #define gsSPSetLights1(name)						\
    	gsSPNumLights(NUMLIGHTS_1),					\
    	gsSPLight(&name.l[0],1),					\
    	gsSPLight(&name.a,2)

    #define gSPSetLights2(pkt,name)						\
    {									\
    	gSPNumLights(pkt,NUMLIGHTS_2);					\
    	gSPLight(pkt,&name.l[0],1);					\
    	gSPLight(pkt,&name.l[1],2);					\
    	gSPLight(pkt,&name.a,3);					\
    }
    #define gsSPSetLights2(name)						\
    	gsSPNumLights(NUMLIGHTS_2),					\
    	gsSPLight(&name.l[0],1),					\
    	gsSPLight(&name.l[1],2),					\
    	gsSPLight(&name.a,3)

    #define gSPSetLights3(pkt,name)						\
    {									\
    	gSPNumLights(pkt,NUMLIGHTS_3);					\
    	gSPLight(pkt,&name.l[0],1);					\
    	gSPLight(pkt,&name.l[1],2);					\
    	gSPLight(pkt,&name.l[2],3);					\
    	gSPLight(pkt,&name.a,4);					\
    }
    #define gsSPSetLights3(name)						\
    	gsSPNumLights(NUMLIGHTS_3),					\
    	gsSPLight(&name.l[0],1),					\
    	gsSPLight(&name.l[1],2),					\
    	gsSPLight(&name.l[2],3),					\
    	gsSPLight(&name.a,4)

    #define gSPSetLights4(pkt,name)						\
    {									\
    	gSPNumLights(pkt,NUMLIGHTS_4);					\
    	gSPLight(pkt,&name.l[0],1);					\
    	gSPLight(pkt,&name.l[1],2);					\
    	gSPLight(pkt,&name.l[2],3);					\
    	gSPLight(pkt,&name.l[3],4);					\
    	gSPLight(pkt,&name.a,5);					\
    }
    #define gsSPSetLights4(name)						\
    	gsSPNumLights(NUMLIGHTS_4),					\
    	gsSPLight(&name.l[0],1),					\
    	gsSPLight(&name.l[1],2),					\
    	gsSPLight(&name.l[2],3),					\
    	gsSPLight(&name.l[3],4),					\
    	gsSPLight(&name.a,5)

    #define gSPSetLights5(pkt,name)						\
    {									\
    	gSPNumLights(pkt,NUMLIGHTS_5);					\
    	gSPLight(pkt,&name.l[0],1);					\
    	gSPLight(pkt,&name.l[1],2);					\
    	gSPLight(pkt,&name.l[2],3);					\
    	gSPLight(pkt,&name.l[3],4);					\
    	gSPLight(pkt,&name.l[4],5);					\
    	gSPLight(pkt,&name.a,6);					\
    }

    #define gsSPSetLights5(name)						\
    	gsSPNumLights(NUMLIGHTS_5),					\
    	gsSPLight(&name.l[0],1),					\
    	gsSPLight(&name.l[1],2),					\
    	gsSPLight(&name.l[2],3),					\
    	gsSPLight(&name.l[3],4),					\
    	gsSPLight(&name.l[4],5),					\
    	gsSPLight(&name.a,6)

    #define gSPSetLights6(pkt,name)						\
    {									\
    	gSPNumLights(pkt,NUMLIGHTS_6);					\
    	gSPLight(pkt,&name.l[0],1);					\
    	gSPLight(pkt,&name.l[1],2);					\
    	gSPLight(pkt,&name.l[2],3);					\
    	gSPLight(pkt,&name.l[3],4);					\
    	gSPLight(pkt,&name.l[4],5);					\
    	gSPLight(pkt,&name.l[5],6);					\
    	gSPLight(pkt,&name.a,7);					\
    }

    #define gsSPSetLights6(name)						\
    	gsSPNumLights(NUMLIGHTS_6),					\
    	gsSPLight(&name.l[0],1),					\
    	gsSPLight(&name.l[1],2),					\
    	gsSPLight(&name.l[2],3),					\
    	gsSPLight(&name.l[3],4),					\
    	gsSPLight(&name.l[4],5),					\
    	gsSPLight(&name.l[5],6),					\
    	gsSPLight(&name.a,7)

    #define gSPSetLights7(pkt,name)						\
    {									\
    	gSPNumLights(pkt,NUMLIGHTS_7);					\
    	gSPLight(pkt,&name.l[0],1);					\
    	gSPLight(pkt,&name.l[1],2);					\
    	gSPLight(pkt,&name.l[2],3);					\
    	gSPLight(pkt,&name.l[3],4);					\
    	gSPLight(pkt,&name.l[4],5);					\
    	gSPLight(pkt,&name.l[5],6);					\
    	gSPLight(pkt,&name.l[6],7);					\
    	gSPLight(pkt,&name.a,8);					\
    }

    #define gsSPSetLights7(name)						\
    	gsSPNumLights(NUMLIGHTS_7),					\
    	gsSPLight(&name.l[0],1),					\
    	gsSPLight(&name.l[1],2),					\
    	gsSPLight(&name.l[2],3),					\
    	gsSPLight(&name.l[3],4),					\
    	gsSPLight(&name.l[4],5),					\
    	gsSPLight(&name.l[5],6),					\
    	gsSPLight(&name.l[6],7),					\
    	gsSPLight(&name.a,8)

    /*
     * Reflection/Hiliting Macros
     */
    #ifdef	F3DEX_GBI_2
    # define gSPLookAtX(pkt, l)	\
    	 gDma2p((pkt),G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATX)
    # define gsSPLookAtX(l)		\
    	 gsDma2p(     G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATX)
    # define gSPLookAtY(pkt, l)	\
    	 gDma2p((pkt),G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATY)
    # define gsSPLookAtY(l)		\
    	 gsDma2p(     G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATY)
    #else	/* F3DEX_GBI_2 */
    # define gSPLookAtX(pkt, l)	\
    	 gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATX)
    # define gsSPLookAtX(l)		\
    	 gsDma1p(    G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATX)
    # define gSPLookAtY(pkt, l)	\
    	 gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATY)
    # define gsSPLookAtY(l)		\
    	 gsDma1p(    G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATY)
    #endif	/* F3DEX_GBI_2 */

    #define gSPLookAt(pkt, la)						\
    {									\
    	gSPLookAtX(pkt,la)						\
    	gSPLookAtY(pkt,(char *)(la)+16)					\
    }
    #define gsSPLookAt(la)							\
    	gsSPLookAtX(la),						\
    	gsSPLookAtY((char *)(la)+16)

    #define gDPSetHilite1Tile(pkt, tile, hilite, width, height)		\
    	gDPSetTileSize(pkt, tile, (hilite)->h.x1 & 0xfff, (hilite)->h.y1 & 0xfff, 	\
    		((((width)-1)*4)+(hilite)->h.x1) & 0xfff, ((((height)-1)*4)+(hilite)->h.y1) & 0xfff)
    #define gsDPSetHilite1Tile(tile, hilite, width, height)			\
    	gsDPSetTileSize(tile, (hilite)->h.x1 & 0xfff, (hilite)->h.y1 & 0xfff, 		\
    		((((width)-1)*4)+(hilite)->h.x1) & 0xfff, ((((height)-1)*4)+(hilite)->h.y1) & 0xfff)

    #define gDPSetHilite2Tile(pkt, tile, hilite, width, height)		\
    	gDPSetTileSize(pkt, tile, (hilite)->h.x2 & 0xfff, (hilite)->h.y2 & 0xfff, 	\
    		((((width)-1)*4)+(hilite)->h.x2) & 0xfff, ((((height)-1)*4)+(hilite)->h.y2) & 0xfff)
    #define gsDPSetHilite2Tile(tile, hilite, width, height)			\
    	gsDPSetTileSize(tile, (hilite)->h.x2 & 0xfff, (hilite)->h.y2 & 0xfff, 		\
    		((((width)-1)*4)+(hilite)->h.x2) & 0xfff, ((((height)-1)*4)+(hilite)->h.y2) & 0xfff)

    /*
     * FOG macros
     * fm = z multiplier
     * fo = z offset
     * FOG FORMULA:    alpha(fog) = (eyespace z) * fm  + fo  CLAMPED 0 to 255
     *   note: (eyespace z) ranges -1 to 1
     *
     * Alternate method of setting fog:
     * min, max: range 0 to 1000: 0=nearplane, 1000=farplane
     * min is where fog begins (usually less than max and often 0)
     * max is where fog is thickest (usually 1000)
     *
     */
    #define gSPFogFactor(pkt, fm, fo)				\
            gMoveWd(pkt, G_MW_FOG, G_MWO_FOG, 			\
    		(_SHIFTL(fm,16,16) | _SHIFTL(fo,0,16)))

    #define gsSPFogFactor(fm, fo)					\
            gsMoveWd(G_MW_FOG, G_MWO_FOG, 				\
    		(_SHIFTL(fm,16,16) | _SHIFTL(fo,0,16)))

    #define gSPFogPosition(pkt, min, max)				\
    	gMoveWd(pkt, G_MW_FOG, G_MWO_FOG, 			\
    		(_SHIFTL((128000/((max)-(min))),16,16) |		\
    		_SHIFTL(((500-(min))*256/((max)-(min))),0,16)))

    #define gsSPFogPosition(min, max)				\
    	gsMoveWd(G_MW_FOG, G_MWO_FOG, 				\
    		(_SHIFTL((128000/((max)-(min))),16,16) |		\
    		_SHIFTL(((500-(min))*256/((max)-(min))),0,16)))

    #ifdef	F3DEX_GBI_2
    /*
     * Macros to turn texture on/off
     */
    # define gSPTexture(pkt, s, t, level, tile, on)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_TEXTURE,24,8) | 			\
    			_SHIFTL(BOWTIE_VAL,16,8) |			\
    			_SHIFTL((level),11,3) | _SHIFTL((tile),8,3) |	\
    			_SHIFTL((on),1,7));				\
    	_g->words.w1 = (_SHIFTL((s),16,16) | _SHIFTL((t),0,16));	\
    }
    # define gsSPTexture(s, t, level, tile, on)				\
    {									\
    	(_SHIFTL(G_TEXTURE,24,8) | _SHIFTL(BOWTIE_VAL,16,8) |		\
    	 _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | _SHIFTL((on),1,7)),\
            (_SHIFTL((s),16,16) | _SHIFTL((t),0,16))			\
    }
    /*
     * Different version of SPTexture macro, has an additional parameter
     * which is currently reserved in the microcode.
     */
    # define gSPTextureL(pkt, s, t, level, xparam, tile, on)		\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_TEXTURE,24,8) | 			\
    			_SHIFTL((xparam),16,8) | 			\
    			_SHIFTL((level),11,3) | _SHIFTL((tile),8,3) |	\
    			_SHIFTL((on),1,7));				\
    	_g->words.w1 = (_SHIFTL((s),16,16) | _SHIFTL((t),0,16));	\
    }
    # define gsSPTextureL(s, t, level, xparam, tile, on)			\
    {									\
    	(_SHIFTL(G_TEXTURE,24,8) | _SHIFTL((xparam),16,8) |		\
    	 _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | _SHIFTL((on),1,7)),\
            (_SHIFTL((s),16,16) | _SHIFTL((t),0,16))			\
    }
    #else
    /*
     * Macros to turn texture on/off
     */
    # define gSPTexture(pkt, s, t, level, tile, on)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL(BOWTIE_VAL,16,8)|\
    			_SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|	\
    			_SHIFTL((on),0,8));				\
    	_g->words.w1 = (_SHIFTL((s),16,16)|_SHIFTL((t),0,16));		\
    }
    # define gsSPTexture(s, t, level, tile, on)				\
    {									\
    	(_SHIFTL(G_TEXTURE,24,8)|_SHIFTL(BOWTIE_VAL,16,8)|		\
    	 _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|_SHIFTL((on),0,8)),	\
            (_SHIFTL((s),16,16)|_SHIFTL((t),0,16))				\
    }
    /*
     * Different version of SPTexture macro, has an additional parameter
     * which is currently reserved in the microcode.
     */
    # define gSPTextureL(pkt, s, t, level, xparam, tile, on)		\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL((xparam),16,8)|	\
    			_SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|	\
    			_SHIFTL((on),0,8));				\
    	_g->words.w1 = (_SHIFTL((s),16,16)|_SHIFTL((t),0,16));		\
    }
    # define gsSPTextureL(s, t, level, xparam, tile, on)			\
    {									\
    	(_SHIFTL(G_TEXTURE,24,8)|_SHIFTL((xparam),16,8)|		\
    	 _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|_SHIFTL((on),0,8)),	\
            (_SHIFTL((s),16,16)|_SHIFTL((t),0,16))				\
    }
    #endif

    #define gSPPerspNormalize(pkt, s)	gMoveWd(pkt, G_MW_PERSPNORM, 0, (s))
    #define gsSPPerspNormalize(s)		gsMoveWd(    G_MW_PERSPNORM, 0, (s))

    #ifdef	F3DEX_GBI_2
    # define gSPPopMatrixN(pkt, n, num)	gDma2p((pkt),G_POPMTX,(num)*64,64,2,0)
    # define gsSPPopMatrixN(n, num)		gsDma2p(     G_POPMTX,(num)*64,64,2,0)
    # define gSPPopMatrix(pkt, n)		gSPPopMatrixN((pkt), (n), 1)
    # define gsSPPopMatrix(n)		gsSPPopMatrixN(      (n), 1)
    #else	/* F3DEX_GBI_2 */
    # define gSPPopMatrix(pkt, n)		gImmp1(pkt, G_POPMTX, n)
    # define gsSPPopMatrix(n)		gsImmp1(    G_POPMTX, n)
    #endif	/* F3DEX_GBI_2 */

    #define gSPEndDisplayList(pkt)						\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_ENDDL, 24, 8);				\
    	_g->words.w1 = 0;						\
    }

    #define gsSPEndDisplayList()						\
    {									\
    	_SHIFTL(G_ENDDL, 24, 8), 0					\
    }

    #ifdef	F3DEX_GBI_2
    /*
     *	One gSPGeometryMode(pkt,c,s) GBI is equal to these two GBIs.
     *
     *		gSPClearGeometryMode(pkt,c)
     *		gSPSetGeometryMode(pkt,s)
     *
     *	gSPLoadGeometryMode(pkt, word) sets GeometryMode directly.
     */
    #define	gSPGeometryMode(pkt, c, s)					\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    	_g->words.w0 = _SHIFTL(G_GEOMETRYMODE,24,8)|_SHIFTL(~(u32)(c),0,24);\
    	_g->words.w1 = (u32)(s);					\
    }

    #define	gsSPGeometryMode(c, s)						\
    {									\
    	(_SHIFTL(G_GEOMETRYMODE,24,8)|_SHIFTL(~(u32)(c),0,24)),(u32)(s)	\
    }
    #define	gSPSetGeometryMode(pkt, word)	gSPGeometryMode((pkt),0,(word))
    #define	gsSPSetGeometryMode(word)	gsSPGeometryMode(0,(word))
    #define	gSPClearGeometryMode(pkt, word)	gSPGeometryMode((pkt),(word),0)
    #define	gsSPClearGeometryMode(word)	gsSPGeometryMode((word),0)
    #define	gSPLoadGeometryMode(pkt, word)	gSPGeometryMode((pkt),-1,(word))
    #define	gsSPLoadGeometryMode(pkt, word)	gsSPGeometryMode(-1,(word))

    #else	/* F3DEX_GBI_2 */
    #define	gSPSetGeometryMode(pkt, word)					\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_SETGEOMETRYMODE, 24, 8);		\
    	_g->words.w1 = (unsigned int)(word);				\
    }

    #define	gsSPSetGeometryMode(word)					\
    {									\
    	_SHIFTL(G_SETGEOMETRYMODE, 24, 8), (unsigned int)(word)		\
    }

    #define	gSPClearGeometryMode(pkt, word)					\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8);		\
    	_g->words.w1 = (unsigned int)(word);				\
    }

    #define	gsSPClearGeometryMode(word)					\
    {									\
    	_SHIFTL(G_CLEARGEOMETRYMODE, 24, 8), (unsigned int)(word)	\
    }
    #endif	/* F3DEX_GBI_2 */

    #ifdef	F3DEX_GBI_2
    #define	gSPSetOtherMode(pkt, cmd, sft, len, data)			\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    	_g->words.w0 = (_SHIFTL(cmd,24,8)|_SHIFTL(32-(sft)-(len),8,8)|	\
    			_SHIFTL((len)-1,0,8));				\
    	_g->words.w1 = (unsigned int)(data);				\
    }

    #define	gsSPSetOtherMode(cmd, sft, len, data)				\
    {									\
    	_SHIFTL(cmd,24,8)|_SHIFTL(32-(sft)-(len),8,8)|_SHIFTL((len)-1,0,8), \
    	(unsigned int)(data)						\
    }
    #else
    #define	gSPSetOtherMode(pkt, cmd, sft, len, data)			\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) |	\
    			_SHIFTL(len, 0, 8));				\
    	_g->words.w1 = (unsigned int)(data);				\
    }

    #define	gsSPSetOtherMode(cmd, sft, len, data)				\
    {									\
    	_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(len, 0, 8),	\
    	(unsigned int)(data)						\
    }
    #endif

    /*
     * RDP setothermode register commands - register shadowed in RSP
     */
    #define	gDPPipelineMode(pkt, mode)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode)
    #define	gsDPPipelineMode(mode)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode)

    #define	gDPSetCycleType(pkt, type)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_CYCLETYPE, 2, type)
    #define	gsDPSetCycleType(type)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_CYCLETYPE, 2, type)

    #define	gDPSetTexturePersp(pkt, type)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTPERSP, 1, type)
    #define	gsDPSetTexturePersp(type)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTPERSP, 1, type)

    #define	gDPSetTextureDetail(pkt, type)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTDETAIL, 2, type)
    #define	gsDPSetTextureDetail(type)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTDETAIL, 2, type)

    #define	gDPSetTextureLOD(pkt, type)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTLOD, 1, type)
    #define	gsDPSetTextureLOD(type)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTLOD, 1, type)

    #define	gDPSetTextureLUT(pkt, type)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTLUT, 2, type)
    #define	gsDPSetTextureLUT(type)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTLUT, 2, type)

    #define	gDPSetTextureFilter(pkt, type)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTFILT, 2, type)
    #define	gsDPSetTextureFilter(type)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTFILT, 2, type)

    #define	gDPSetTextureConvert(pkt, type)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTCONV, 3, type)
    #define	gsDPSetTextureConvert(type)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTCONV, 3, type)

    #define	gDPSetCombineKey(pkt, type)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_COMBKEY, 1, type)
    #define	gsDPSetCombineKey(type)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_COMBKEY, 1, type)

    #ifndef _HW_VERSION_1
    #define	gDPSetColorDither(pkt, mode)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_RGBDITHER, 2, mode)
    #define	gsDPSetColorDither(mode)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_RGBDITHER, 2, mode)
    #else
    #define gDPSetColorDither(pkt, mode)    \
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_COLORDITHER, 1, mode)
    #define gsDPSetColorDither(mode)                \
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_COLORDITHER, 1, mode)
    #endif

    #ifndef _HW_VERSION_1
    #define	gDPSetAlphaDither(pkt, mode)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode)
    #define	gsDPSetAlphaDither(mode)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode)
    #endif

    /* 'blendmask' is not supported anymore.
     * The bits are reserved for future use.
     * Fri May 26 13:45:55 PDT 1995
     */
    #define	gDPSetBlendMask(pkt, mask)      gDPNoOp(pkt)
    #define	gsDPSetBlendMask(mask)		gsDPNoOp()

    #define	gDPSetAlphaCompare(pkt, type)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_ALPHACOMPARE, 2, type)
    #define	gsDPSetAlphaCompare(type)		\
    	gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_ALPHACOMPARE, 2, type)

    #define	gDPSetDepthSource(pkt, src)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_ZSRCSEL, 1, src)
    #define	gsDPSetDepthSource(src)	\
    	gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_ZSRCSEL, 1, src)

    #define	gDPSetRenderMode(pkt, c0, c1)	\
    	gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_RENDERMODE, 29, 	\
    			(c0) | (c1))
    #define	gsDPSetRenderMode(c0, c1)	\
    	gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_RENDERMODE, 29, 	\
    			 (c0) | (c1))

    #define	gSetImage(pkt, cmd, fmt, siz, width, i)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) |	\
    		       _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12);	\
    	_g->words.w1 = (unsigned int)(i);				\
    }

    #define	gsSetImage(cmd, fmt, siz, width, i)				\
    {									\
    	_SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) |			\
    	_SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12),		\
    	(unsigned int)(i)						\
    }

    #define	gDPSetColorImage(pkt, f, s, w, i)	gSetImage(pkt, G_SETCIMG, f, s, w, i)
    #define	gsDPSetColorImage(f, s, w, i)		gsSetImage(G_SETCIMG, f, s, w, i)

    /* use these for new code */
    #define	gDPSetDepthImage(pkt, i)	gSetImage(pkt, G_SETZIMG, 0, 0, 1, i)
    #define	gsDPSetDepthImage(i)		gsSetImage(G_SETZIMG, 0, 0, 1, i)
    /* kept for compatibility */
    #define	gDPSetMaskImage(pkt, i)		gDPSetDepthImage(pkt, i)
    #define	gsDPSetMaskImage(i)			gsDPSetDepthImage(i)

    #define	gDPSetTextureImage(pkt, f, s, w, i)	gSetImage(pkt, G_SETTIMG, f, s, w, i)
    #define	gsDPSetTextureImage(f, s, w, i)	gsSetImage(G_SETTIMG, f, s, w, i)

    /*
     * RDP macros
     */

    #define	gDPSetCombine(pkt, muxs0, muxs1)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24);\
    	_g->words.w1 = (unsigned int)(muxs1);				\
    }

    #define	gsDPSetCombine(muxs0, muxs1)					\
    {									\
    	_SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24),		\
    	(unsigned int)(muxs1)						\
    }

    #define	GCCc0w0(saRGB0, mRGB0, saA0, mA0)				\
    		(_SHIFTL((saRGB0), 20, 4) | _SHIFTL((mRGB0), 15, 5) | 	\
    		 _SHIFTL((saA0), 12, 3) | _SHIFTL((mA0), 9, 3))

    #define	GCCc1w0(saRGB1, mRGB1)						\
    		(_SHIFTL((saRGB1), 5, 4) | _SHIFTL((mRGB1), 0, 5))

    #define GCCc0w1(sbRGB0, aRGB0, sbA0, aA0)				\
                    (_SHIFTL((sbRGB0), 28, 4) | _SHIFTL((aRGB0), 15, 3) |	\
    		 _SHIFTL((sbA0), 12, 3) | _SHIFTL((aA0), 9, 3))

    #define	GCCc1w1(sbRGB1, saA1, mA1, aRGB1, sbA1, aA1)			\
    		(_SHIFTL((sbRGB1), 24, 4) | _SHIFTL((saA1), 21, 3) |	\
    		 _SHIFTL((mA1), 18, 3) | _SHIFTL((aRGB1), 6, 3) |	\
    		 _SHIFTL((sbA1), 3, 3) | _SHIFTL((aA1), 0, 3))

    #define	gDPSetCombineLERP(pkt, a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0,	\
    		a1, b1, c1, d1,	Aa1, Ab1, Ac1, Ad1)			\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 =	_SHIFTL(G_SETCOMBINE, 24, 8) |			\
    			_SHIFTL(GCCc0w0(G_CCMUX_##a0, G_CCMUX_##c0,	\
    				       G_ACMUX_##Aa0, G_ACMUX_##Ac0) |	\
    			       GCCc1w0(G_CCMUX_##a1, G_CCMUX_##c1), 	\
    			       0, 24);					\
    	_g->words.w1 =	(unsigned int)(GCCc0w1(G_CCMUX_##b0, 		\
    					       G_CCMUX_##d0,		\
    					       G_ACMUX_##Ab0, 		\
    					       G_ACMUX_##Ad0) |		\
    				       GCCc1w1(G_CCMUX_##b1, 		\
    					       G_ACMUX_##Aa1,		\
    					       G_ACMUX_##Ac1, 		\
    					       G_CCMUX_##d1,		\
    					       G_ACMUX_##Ab1, 		\
    					       G_ACMUX_##Ad1));		\
    }

    #define	gsDPSetCombineLERP(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0,		\
    		a1, b1, c1, d1,	Aa1, Ab1, Ac1, Ad1)			\
    {									\
    	_SHIFTL(G_SETCOMBINE, 24, 8) |					\
    	_SHIFTL(GCCc0w0(G_CCMUX_##a0, G_CCMUX_##c0,			\
    		       G_ACMUX_##Aa0, G_ACMUX_##Ac0) |			\
    	       GCCc1w0(G_CCMUX_##a1, G_CCMUX_##c1), 0, 24),		\
    	(unsigned int)(GCCc0w1(G_CCMUX_##b0, G_CCMUX_##d0,		\
    			       G_ACMUX_##Ab0, G_ACMUX_##Ad0) |		\
    		       GCCc1w1(G_CCMUX_##b1, G_ACMUX_##Aa1,		\
    			       G_ACMUX_##Ac1, G_CCMUX_##d1,		\
    			       G_ACMUX_##Ab1, G_ACMUX_##Ad1))		\
    }

    /*
     * SetCombineMode macros are NOT redunant. It allow the C preprocessor
     * to substitute single parameter which includes commas in the token and
     * rescan for higher parameter count macro substitution.
     *
     * eg.	gsDPSetCombineMode(G_CC_MODULATE, G_CC_MODULATE) turns into
     *	gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0,
     *		TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0)
     */

    #define gDPSetCombineMode(pkt, a, b)	gDPSetCombineLERP(pkt, a, b)
    #define	gsDPSetCombineMode(a, b)	gsDPSetCombineLERP(a, b)

    #define	gDPSetColor(pkt, c, d)						\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(c, 24, 8);				\
    	_g->words.w1 = (unsigned int)(d);				\
    }

    #define	gsDPSetColor(c, d)						\
    {									\
    	_SHIFTL(c, 24, 8), (unsigned int)(d)				\
    }

    #define	DPRGBColor(pkt, cmd, r, g, b, a)				\
                gDPSetColor(pkt, cmd,					\
    			(_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | 	\
    			 _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8)))
    #define	sDPRGBColor(cmd, r, g, b, a)					\
    	    gsDPSetColor(cmd,						\
    			 (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | 	\
    			  _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8)))

    #define	gDPSetEnvColor(pkt, r, g, b, a)					\
                DPRGBColor(pkt, G_SETENVCOLOR, r,g,b,a)
    #define	gsDPSetEnvColor(r, g, b, a)					\
                sDPRGBColor(G_SETENVCOLOR, r,g,b,a)
    #define	gDPSetBlendColor(pkt, r, g, b, a)				\
                DPRGBColor(pkt, G_SETBLENDCOLOR, r,g,b,a)
    #define	gsDPSetBlendColor(r, g, b, a)					\
                sDPRGBColor(G_SETBLENDCOLOR, r,g,b,a)
    #define	gDPSetFogColor(pkt, r, g, b, a)					\
                DPRGBColor(pkt, G_SETFOGCOLOR, r,g,b,a)
    #define	gsDPSetFogColor(r, g, b, a)					\
                sDPRGBColor(G_SETFOGCOLOR, r,g,b,a)
    #define	gDPSetFillColor(pkt, d)						\
                gDPSetColor(pkt, G_SETFILLCOLOR, (d))
    #define	gsDPSetFillColor(d)						\
                gsDPSetColor(G_SETFILLCOLOR, (d))

    #define	gDPSetPrimDepth(pkt, z, dz)					\
    		gDPSetColor(pkt, G_SETPRIMDEPTH, 			\
    			    _SHIFTL(z, 16, 16) | _SHIFTL(dz, 0, 16))
    #define	gsDPSetPrimDepth(z, dz)						\
    		gsDPSetColor(G_SETPRIMDEPTH, _SHIFTL(z, 16, 16) | 	\
    			     _SHIFTL(dz, 0, 16))

    #define	gDPSetPrimColor(pkt, m, l, r, g, b, a)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 =	(_SHIFTL(G_SETPRIMCOLOR, 24, 8) | 		\
    			 _SHIFTL(m, 8, 8) | _SHIFTL(l, 0, 8));		\
    	_g->words.w1 =  (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | 	\
    			 _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8));		\
    }

    #define	gsDPSetPrimColor(m, l, r, g, b, a)				\
    {									\
    	(_SHIFTL(G_SETPRIMCOLOR, 24, 8) | _SHIFTL(m, 8, 8) |		\
    	 _SHIFTL(l, 0, 8)),						\
    	(_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) |	\
    	 _SHIFTL(a, 0, 8))						\
    }

    /*
     * gDPSetOtherMode (This is for expert user.)
     *
     * This command makes all othermode parameters set.
     * Do not use this command in the same DL with another g*SPSetOtherMode DLs.
     *
     * [Usage]
     *	gDPSetOtherMode(pkt, modeA, modeB)
     *
     *      'modeA' is described all parameters of GroupA GBI command.
     *      'modeB' is also described all parameters of GroupB GBI command.
     *
     *	GroupA:
     *	  gDPPipelineMode, gDPSetCycleType, gSPSetTexturePersp,
     *	  gDPSetTextureDetail, gDPSetTextureLOD, gDPSetTextureLUT,
     *	  gDPSetTextureFilter, gDPSetTextureConvert, gDPSetCombineKey,
     *	  gDPSetColorDither, gDPSetAlphaDither
     *
     *	GroupB:
     *	  gDPSetAlphaCompare, gDPSetDepthSource, gDPSetRenderMode
     *
     *	Use 'OR' operation to get modeA and modeB.
     *
     *	modeA = G_PM_* | G_CYC_* | G_TP_* | G_TD_* | G_TL_* | G_TT_* | G_TF_*
     *		G_TC_* | G_CK_*  | G_CD_* | G_AD_*;
     *
     *	modeB = G_AC_* | G_ZS_*  | G_RM_* | G_RM_*2;
     */
    #define	gDPSetOtherMode(pkt, mode0, mode1)				\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24);\
    	_g->words.w1 = (unsigned int)(mode1);				\
    }

    #define	gsDPSetOtherMode(mode0, mode1)					\
    {									\
    	_SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24),		\
    	(unsigned int)(mode1)						\
    }

    /*
     * Texturing macros
     */

    /* These are also defined defined above for Sprite Microcode */

    #define	G_TX_LOADTILE	7
    #define	G_TX_RENDERTILE	0

    #define	G_TX_NOMIRROR	0
    #define	G_TX_WRAP	0
    #define	G_TX_MIRROR	0x1
    #define	G_TX_CLAMP	0x2
    #define	G_TX_NOMASK	0
    #define	G_TX_NOLOD	0

    #ifndef MAX
    #define MAX(a, b)				((a) > (b) ? (a) : (b))
    #endif

    #ifndef MIN
    #define MIN(a, b)				((a) < (b) ? (a) : (b))
    #endif
    /*
     *  Dxt is the inverse of the number of 64-bit words in a line of
     *  the texture being loaded using the load_block command.  If
     *  there are any 1's to the right of the 11th fractional bit,
     *  dxt should be rounded up.  The following macros accomplish
     *  this.  The 4b macros are a special case since 4-bit textures
     *  are loaded as 8-bit textures.  Dxt is fixed point 1.11. RJM
     */
    #define	G_TX_DXT_FRAC	11

    /*
     *  For RCP 2.0, the maximum number of texels that can be loaded
     *  using a load_block command is 2048.  In order to load the total
     *  4kB of Tmem, change the texel size when loading to be G_IM_SIZ_16b,
     *  then change the tile to the proper texel size after the load.
     *  The g*DPLoadTextureBlock macros already do this, so this change
     *  will be transparent if you use these macros.  If you use
     *  the g*DPLoadBlock macros directly, you will need to handle this
     *  tile manipulation yourself.  RJM.
     */
    #ifdef _HW_VERSION_1
    #define G_TX_LDBLK_MAX_TXL	4095
    #else
    #define G_TX_LDBLK_MAX_TXL	2047
    #endif /* _HW_VERSION_1 */

    #define TXL2WORDS(txls, b_txl)	MAX(1, ((txls)*(b_txl)/8))
    #define CALC_DXT(width, b_txl)	\
    		(((1 << G_TX_DXT_FRAC) + TXL2WORDS(width, b_txl) - 1) / \
    					TXL2WORDS(width, b_txl))

    #define TXL2WORDS_4b(txls)	MAX(1, ((txls)/16))
    #define CALC_DXT_4b(width)	\
    		(((1 << G_TX_DXT_FRAC) + TXL2WORDS_4b(width) - 1) / \
    					TXL2WORDS_4b(width))

    #define gDPLoadTileGeneric(pkt, c, tile, uls, ult, lrs, lrt)		\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) |	\
    		      _SHIFTL(ult, 0, 12);				\
    	_g->words.w1 = _SHIFTL(tile, 24, 3) | _SHIFTL(lrs, 12, 12) |	\
    		      _SHIFTL(lrt, 0, 12);				\
    }

    #define gsDPLoadTileGeneric(c, tile, uls, ult, lrs, lrt)		\
    {									\
    	_SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12),	\
    	_SHIFTL(tile, 24, 3) | _SHIFTL(lrs, 12, 12) | _SHIFTL(lrt, 0, 12)\
    }

    #define	gDPSetTileSize(pkt, t, uls, ult, lrs, lrt)			\
    		gDPLoadTileGeneric(pkt, G_SETTILESIZE, t, uls, ult, lrs, lrt)
    #define	gsDPSetTileSize(t, uls, ult, lrs, lrt)				\
    		gsDPLoadTileGeneric(G_SETTILESIZE, t, uls, ult, lrs, lrt)
    #define	gDPLoadTile(pkt, t, uls, ult, lrs, lrt)				\
    		gDPLoadTileGeneric(pkt, G_LOADTILE, t, uls, ult, lrs, lrt)
    #define	gsDPLoadTile(t, uls, ult, lrs, lrt)				\
    		gsDPLoadTileGeneric(G_LOADTILE, t, uls, ult, lrs, lrt)

    #define	gDPSetTile(pkt, fmt, siz, line, tmem, tile, palette, cmt,	\
    		maskt, shiftt, cms, masks, shifts)			\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_SETTILE, 24, 8) | _SHIFTL(fmt, 21, 3) |\
    		       _SHIFTL(siz, 19, 2) | _SHIFTL(line, 9, 9) |	\
    		       _SHIFTL(tmem, 0, 9);				\
    	_g->words.w1 = _SHIFTL(tile, 24, 3) | _SHIFTL(palette, 20, 4) |	\
    		       _SHIFTL(cmt, 18, 2) | _SHIFTL(maskt, 14, 4) |	\
    		       _SHIFTL(shiftt, 10, 4) |_SHIFTL(cms, 8, 2) |	\
    		       _SHIFTL(masks, 4, 4) | _SHIFTL(shifts, 0, 4);	\
    }

    #define	gsDPSetTile(fmt, siz, line, tmem, tile, palette, cmt,		\
    		maskt, shiftt, cms, masks, shifts)			\
    {									\
    	(_SHIFTL(G_SETTILE, 24, 8) | _SHIFTL(fmt, 21, 3) | 		\
    	 _SHIFTL(siz, 19, 2) | _SHIFTL(line, 9, 9) | _SHIFTL(tmem, 0, 9)),\
            (_SHIFTL(tile, 24, 3) | _SHIFTL(palette, 20, 4) | 		\
    	 _SHIFTL(cmt, 18, 2) | _SHIFTL(maskt, 14, 4) | 			\
    	 _SHIFTL(shiftt, 10, 4) | _SHIFTL(cms, 8, 2) | 			\
    	 _SHIFTL(masks, 4, 4) | _SHIFTL(shifts, 0, 4))			\
    }

    /*
     *  For RCP 2.0, the maximum number of texels that can be loaded
     *  using a load_block command is 2048.  In order to load the total
     *  4kB of Tmem, change the texel size when loading to be G_IM_SIZ_16b,
     *  then change the tile to the proper texel size after the load.
     *  The g*DPLoadTextureBlock macros already do this, so this change
     *  will be transparent if you use these macros.  If you use
     *  the g*DPLoadBlock macros directly, you will need to handle this
     *  tile manipulation yourself.  RJM.
     */
    #define gDPLoadBlock(pkt, tile, uls, ult, lrs, dxt)			\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_LOADBLOCK, 24, 8) | 			\
    			_SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12));	\
    	_g->words.w1 = (_SHIFTL(tile, 24, 3) |				\
    			_SHIFTL((MIN(lrs,G_TX_LDBLK_MAX_TXL)), 12, 12) |\
    			_SHIFTL(dxt, 0, 12));				\
    }

    #define gsDPLoadBlock(tile, uls, ult, lrs, dxt)				\
    {									\
    	(_SHIFTL(G_LOADBLOCK, 24, 8) | _SHIFTL(uls, 12, 12) | 		\
    	 _SHIFTL(ult, 0, 12)),						\
    	(_SHIFTL(tile, 24, 3) | 					\
    	 _SHIFTL((MIN(lrs,G_TX_LDBLK_MAX_TXL)), 12, 12) |		\
    	 _SHIFTL(dxt, 0, 12))						\
    }

    #define	gDPLoadTLUTCmd(pkt, tile, count)				\
    {									\
    	Gfx *_g = (Gfx *)pkt;						\
    									\
    	_g->words.w0 = _SHIFTL(G_LOADTLUT, 24, 8);			\
    	_g->words.w1 = _SHIFTL((tile), 24, 3) | _SHIFTL((count), 14, 10);\
    }

    #define	gsDPLoadTLUTCmd(tile, count)					\
    {									\
    	_SHIFTL(G_LOADTLUT, 24, 8),					\
    	_SHIFTL((tile), 24, 3) | _SHIFTL((count), 14, 10)		\
    }

    #define	gDPLoadTextureBlock(pkt, timg, fmt, siz, width, height,		\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    {									\
    	gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);	\
    	gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 	\
    		0 , cmt, maskt, shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1,	\
    		CALC_DXT(width, siz##_BYTES)); 				\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, siz,					\
    		(((width) * siz##_LINE_BYTES)+7)>>3, 0,			\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts);						\
    	gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,			\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    #define	gDPLoadTextureBlockYuv(pkt, timg, fmt, siz, width, height,	\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    {									\
    	gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);	\
    	gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 	\
    		0 , cmt, maskt, shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1,	\
    		CALC_DXT(width, siz##_BYTES)); 				\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, siz,					\
    		(((width) * 1)+7)>>3, 0,				\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts);						\
    	gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,			\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    /* Load fix rww 27jun95 */
    /* The S at the end means odd lines are already word Swapped */

    #define	gDPLoadTextureBlockS(pkt, timg, fmt, siz, width, height,	\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    {									\
    	gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);	\
    	gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 	\
    		0 , cmt, maskt,	shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0);	\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, siz,					\
    		(((width) * siz##_LINE_BYTES)+7)>>3, 0,			\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts);						\
    	gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,			\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    /*
     *  Allow tmem address and render tile to be specified.
     *  The S at the end means odd lines are already word Swapped
     */
    #define	gDPLoadMultiBlockS(pkt, timg, tmem, rtile, fmt, siz, width, 	\
    		   height, pal, cms, cmt, masks, maskt, shifts, shiftt)	\
    {									\
    	gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);	\
    	gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 	\
    		0 , cmt, maskt,	shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0);	\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, siz,					\
    		(((width) * siz##_LINE_BYTES)+7)>>3, tmem,		\
    		rtile, pal, cmt, maskt, shiftt, cms, masks,		\
    		shifts);						\
    	gDPSetTileSize(pkt, rtile, 0, 0,				\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    #define	gDPLoadTextureBlockYuvS(pkt, timg, fmt, siz, width, height,	\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    {									\
    	gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);	\
    	gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 	\
    		0 , cmt, maskt,	shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0);	\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, siz,					\
    		(((width) * 1)+7)>>3, 0,				\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts);						\
    	gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,			\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    /*
     *  allows tmem address to be specified
     */
    #define	_gDPLoadTextureBlock(pkt, timg, tmem, fmt, siz, width, height,	\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    {									\
    	gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);	\
    	gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE,  \
    		0, cmt, maskt, shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,	\
    		CALC_DXT(width, siz##_BYTES)); 				\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3,	\
    		tmem, G_TX_RENDERTILE, pal, cmt,			\
    		maskt, shiftt, cms, masks, shifts);			\
    	gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,			\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    /*
     *  allows tmem address and render tile to be specified
     */
    #define	_gDPLoadTextureBlockTile(pkt, timg, tmem, rtile, fmt, siz, width,  \
    		height, pal, cms, cmt, masks, maskt, shifts, shiftt)	\
    {									\
    	gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);	\
    	gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0,\
    		cmt, maskt, shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,	\
    		CALC_DXT(width, siz##_BYTES)); 				\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3,	\
    		tmem, rtile, pal, cmt,					\
    		maskt, shiftt, cms, masks, shifts);			\
    	gDPSetTileSize(pkt, rtile, 0, 0,				\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    /*
     *  allows tmem address and render tile to be specified
     */
    #define	gDPLoadMultiBlock(pkt, timg, tmem, rtile, fmt, siz, width,  	\
    		height, pal, cms, cmt, masks, maskt, shifts, shiftt)	\
    {									\
    	gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);	\
    	gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0,\
    		cmt, maskt, shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,	\
    		CALC_DXT(width, siz##_BYTES)); 				\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3,	\
    		tmem, rtile, pal, cmt,					\
    		maskt, shiftt, cms, masks, shifts);			\
    	gDPSetTileSize(pkt, rtile, 0, 0,				\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    #define	gsDPLoadTextureBlock(timg, fmt, siz, width, height,		\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    									\
    	gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),		\
    	gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, 0, 			\
    		G_TX_LOADTILE, 	0 , cmt, maskt,	shiftt, cms, 		\
    		masks, shifts),						\
    	gsDPLoadSync(),							\
    	gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,	\
    		CALC_DXT(width, siz##_BYTES)), 				\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), 0,	\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts),						\
    	gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,				\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)

    /* Here is the static form of the pre-swapped texture block loading */
    /* See gDPLoadTextureBlockS() for reference.  Basically, just don't
       calculate DxT, use 0 */

    #define	gsDPLoadTextureBlockS(timg, fmt, siz, width, height,		\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    									\
    	gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),		\
    	gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0 , 	\
    		cmt, maskt,shiftt, cms, masks, shifts),			\
    	gsDPLoadSync(),							\
    	gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, 0 ),\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), 0,	\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts),						\
    	gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,				\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)

    /*
     *  Allow tmem address to be specified
     */
    #define	_gsDPLoadTextureBlock(timg, tmem, fmt, siz, width, height,	\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    									\
    	gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),		\
    	gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 	\
    		0 , cmt, maskt,	shiftt, cms, masks, shifts),		\
    	gsDPLoadSync(),							\
    	gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,	\
    		CALC_DXT(width, siz##_BYTES)), 				\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, siz,						\
    		((((width) * siz##_LINE_BYTES)+7)>>3), tmem,		\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts),						\
    	gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,				\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)

    /*
     *  Allow tmem address and render_tile to be specified
     */
    #define	_gsDPLoadTextureBlockTile(timg, tmem, rtile, fmt, siz, width,	\
    		height, pal, cms, cmt, masks, maskt, shifts, shiftt)	\
    									\
    	gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),		\
    	gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 	\
    		0 , cmt, maskt,	shiftt, cms, masks, shifts),		\
    	gsDPLoadSync(),							\
    	gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,	\
    		CALC_DXT(width, siz##_BYTES)), 				\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, siz,						\
    		((((width) * siz##_LINE_BYTES)+7)>>3), tmem,		\
    		rtile, pal, cmt, maskt, shiftt, cms, masks,		\
    		shifts),						\
    	gsDPSetTileSize(rtile, 0, 0,					\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)

    /*
     *  Allow tmem address and render_tile to be specified, useful when loading
     *  mutilple tiles at a time.
     */
    #define	gsDPLoadMultiBlock(timg, tmem, rtile, fmt, siz, width,		\
    		height, pal, cms, cmt, masks, maskt, shifts, shiftt)	\
    									\
    	gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),		\
    	gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 	\
    		0 , cmt, maskt,	shiftt, cms, masks, shifts),		\
    	gsDPLoadSync(),							\
    	gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,	\
    		CALC_DXT(width, siz##_BYTES)), 				\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, siz,						\
    		((((width) * siz##_LINE_BYTES)+7)>>3), tmem,		\
    		rtile, pal, cmt, maskt, shiftt, cms, masks,		\
    		shifts),						\
    	gsDPSetTileSize(rtile, 0, 0,					\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)

    /*
     *  Allows tmem and render tile to be specified.  Useful when loading
     *  several tiles at a time.
     *
     *  Here is the static form of the pre-swapped texture block loading
     *  See gDPLoadTextureBlockS() for reference.  Basically, just don't
     *  calculate DxT, use 0
     */

    #define	gsDPLoadMultiBlockS(timg, tmem, rtile, fmt, siz, width, height,	\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    									\
    	gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg),		\
    	gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0 , 	\
    		cmt, maskt,shiftt, cms, masks, shifts),			\
    	gsDPLoadSync(),							\
    	gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 				\
    		(((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, 0 ),\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), tmem,\
    		rtile, pal, cmt, maskt, shiftt, cms, masks,		\
    		shifts),						\
    	gsDPSetTileSize(rtile, 0, 0,					\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)

    #define	gDPLoadTextureBlock_4b(pkt, timg, fmt, width, height,		\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    {									\
    	gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg);		\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0,	\
    		cmt, maskt, shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,				\
    		(((width)*(height)+3)>>2)-1,				\
    		CALC_DXT_4b(width)); 					\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0,	\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts);						\
    	gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,			\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    /* Load fix rww 27jun95 */
    /* The S at the end means odd lines are already word Swapped */

    #define	gDPLoadTextureBlock_4bS(pkt, timg, fmt, width, height,		\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    {									\
    	gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg);		\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0,	\
    		cmt, maskt, shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,				\
    		(((width)*(height)+3)>>2)-1, 0 );			\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0,	\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts);						\
    	gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,			\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    /*
     *  4-bit load block.  Useful when loading multiple tiles
     */
    #define	gDPLoadMultiBlock_4b(pkt, timg, tmem, rtile, fmt, width, height,\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    {									\
    	gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg);		\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0,	\
    		cmt, maskt, shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,				\
    		(((width)*(height)+3)>>2)-1,				\
    		CALC_DXT_4b(width));					\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem,	\
    		rtile, pal, cmt, maskt, shiftt, cms, masks,		\
    		shifts);						\
    	gDPSetTileSize(pkt, rtile, 0, 0,				\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    /*
     *  4-bit load block.  Allows tmem and render tile to be specified.  Useful when
     *  loading multiple tiles.  The S means odd lines are already word swapped.
     */
    #define	gDPLoadMultiBlock_4bS(pkt, timg, tmem, rtile, fmt, width, height,\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    {									\
    	gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg);		\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0,	\
    		cmt, maskt, shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,				\
    		(((width)*(height)+3)>>2)-1, 0 );			\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem,	\
    		rtile, pal, cmt, maskt, shiftt, cms, masks,		\
    		shifts);						\
    	gDPSetTileSize(pkt, rtile, 0, 0,				\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    #define	_gDPLoadTextureBlock_4b(pkt, timg, tmem, fmt, width, height,	\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    {									\
    	gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg);		\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0,	\
    		cmt, maskt, shiftt, cms, masks, shifts);		\
    	gDPLoadSync(pkt);						\
    	gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,				\
    		(((width)*(height)+3)>>2)-1,				\
    		CALC_DXT_4b(width));					\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem,	\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts);						\
    	gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,			\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)			\
    }

    #define	gsDPLoadTextureBlock_4b(timg, fmt, width, height,		\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    									\
    	gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg),		\
    	gsDPSetTile(fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0 , cmt,	\
    		maskt, shiftt, cms, masks, shifts),			\
    	gsDPLoadSync(),							\
    	gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,	\
    		CALC_DXT_4b(width)),					\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0,		\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts),						\
    	gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,				\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)

    #define	gsDPLoadTextureBlock_4bS(timg, fmt, width, height,		\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    									\
    	gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg),		\
    	gsDPSetTile(fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0 , cmt,	\
    		maskt, shiftt, cms, masks, shifts),			\
    	gsDPLoadSync(),							\
    	gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,0),\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0,		\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts),						\
    	gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,				\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)

    /*
     *  4-bit load block.  Allows tmem address and render tile to be specified.
     *  Useful when loading multiple tiles.
     */
    #define	gsDPLoadMultiBlock_4b(timg, tmem, rtile, fmt, width, height,	\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    									\
    	gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg),		\
    	gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt,	\
    		maskt, shiftt, cms, masks, shifts),			\
    	gsDPLoadSync(),							\
    	gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,	\
    		CALC_DXT_4b(width)), 					\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem,	\
    		rtile, pal, cmt, maskt, shiftt, cms, masks,		\
    		shifts),						\
    	gsDPSetTileSize(rtile, 0, 0,					\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)

    /*
     *  4-bit load block.  Allows tmem address and render tile to be specified.
     *  Useful when loading multiple tiles.  S means odd lines are already swapped.
     */
    #define	gsDPLoadMultiBlock_4bS(timg, tmem, rtile, fmt, width, height,	\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    									\
    	gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg),		\
    	gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt,	\
    		maskt, shiftt, cms, masks, shifts),			\
    	gsDPLoadSync(),							\
    	gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,0),\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem,	\
    		rtile, pal, cmt, maskt, shiftt, cms, masks,		\
    		shifts),						\
    	gsDPSetTileSize(rtile, 0, 0,					\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)

    /*
     *  Allows tmem address to be specified
     */
    #define	_gsDPLoadTextureBlock_4b(timg, tmem, fmt, width, height,	\
    		pal, cms, cmt, masks, maskt, shifts, shiftt)		\
    									\
    	gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg),		\
    	gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt,	\
    		maskt, shiftt, cms, masks, shifts),			\
    	gsDPLoadSync(),							\
    	gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,	\
    		CALC_DXT_4b(width)), 					\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem,	\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts),						\
    	gsDPSetTileSize(G_TX_RENDERTILE, 0, 0,				\
    		((width)-1) << G_TEXTURE_IMAGE_FRAC,			\
    		((height)-1) << G_TEXTURE_IMAGE_FRAC)

    #ifndef _HW_VERSION_1

    #define	gDPLoadTextureTile(pkt, timg, fmt, siz, width, height,		\
    		uls, ult, lrs, lrt, pal,				\
    		cms, cmt, masks, maskt, shifts, shiftt)			\
    {									\
    	gDPSetTextureImage(pkt, fmt, siz, width, timg);			\
    	gDPSetTile(pkt, fmt, siz,					\
    		(((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), 0,	\
    		G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,	\
    		shifts);						\
    	gDPLoadSync(pkt);						\
    	gDPLoadTile(	pkt, G_TX_LOADTILE,				\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC);			\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, siz,					\
    		(((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), 0,	\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts);						\
    	gDPSetTileSize(pkt, G_TX_RENDERTILE,				\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC)			\
    }

    #else /******** WORKAROUND hw 1 load tile bug ********/

    #define	gDPLoadTextureTile(pkt, timg, fmt, siz, width, height,		\
    		uls, ult, lrs, lrt, pal,				\
    		cms, cmt, masks, maskt, shifts, shiftt)			\
    									\
    {									\
    	int _loadtile_i, _loadtile_nw; Gfx *_loadtile_temp = pkt; 	\
    	guDPLoadTextureTile(_loadtile_temp, timg, fmt, siz, 		\
    		width, height,        					\
                    uls, ult, lrs, lrt, pal,                                \
                    cms, cmt, masks, maskt, shifts, shiftt);		\
    	_loadtile_nw = guGetDPLoadTextureTileSz(ult, lrt) - 1;		\
    	for(_loadtile_i = 0; _loadtile_i < _loadtile_nw; _loadtile_i++)	\
    	  pkt;								\
    }

    #endif /* HW_VERSION_1 */

    /*
     *  Load texture tile.  Allows tmem address and render tile to be specified.
     *  Useful for loading multiple tiles.
     */
    #define	gDPLoadMultiTile(pkt, timg, tmem, rtile, fmt, siz, width, height,\
    		uls, ult, lrs, lrt, pal,				\
    		cms, cmt, masks, maskt, shifts, shiftt)			\
    {									\
    	gDPSetTextureImage(pkt, fmt, siz, width, timg);			\
    	gDPSetTile(pkt, fmt, siz,					\
    		(((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), tmem,	\
    		G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,	\
    		shifts);						\
    	gDPLoadSync(pkt);						\
    	gDPLoadTile(	pkt, G_TX_LOADTILE,				\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC);			\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, siz,					\
    		(((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), tmem,	\
    		rtile, pal, cmt, maskt, shiftt, cms, masks,		\
    		shifts);						\
    	gDPSetTileSize(pkt, rtile,					\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC)			\
    }

    #define	gsDPLoadTextureTile(timg, fmt, siz, width, height,		\
    		uls, ult, lrs, lrt, pal,				\
    		cms, cmt, masks, maskt, shifts, shiftt)			\
    									\
    	gsDPSetTextureImage(fmt, siz, width, timg),			\
    	gsDPSetTile(fmt, siz, 						\
    		    (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), 0,	\
    		    G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,	\
    		    shifts),						\
    	gsDPLoadSync(),							\
    	gsDPLoadTile(	G_TX_LOADTILE,					\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC),			\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, siz, 						\
    		    (((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), 0,	\
    		    G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,\
    		    shifts),						\
    	gsDPSetTileSize(G_TX_RENDERTILE,				\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC)

    /*
     *  Load texture tile.  Allows tmem address and render tile to be specified.
     *  Useful for loading multiple tiles.
     */
    #define	gsDPLoadMultiTile(timg, tmem, rtile, fmt, siz, width, height,	\
    		uls, ult, lrs, lrt, pal,				\
    		cms, cmt, masks, maskt, shifts, shiftt)			\
    									\
    	gsDPSetTextureImage(fmt, siz, width, timg),			\
    	gsDPSetTile(fmt, siz, 						\
    		    (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), 	\
    		    tmem, G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, 	\
    		    masks, shifts),					\
    	gsDPLoadSync(),							\
    	gsDPLoadTile(	G_TX_LOADTILE,					\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC),			\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, siz, 						\
    		    (((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), 	\
    		    tmem, rtile, pal, cmt, maskt, shiftt, cms, masks,	\
    		    shifts),						\
    	gsDPSetTileSize(rtile,						\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC)

    #define	gDPLoadTextureTile_4b(pkt, timg, fmt, width, height,		\
    		uls, ult, lrs, lrt, pal,				\
    		cms, cmt, masks, maskt, shifts, shiftt)			\
    {									\
    	gDPSetTextureImage(pkt, fmt, G_IM_SIZ_8b, ((width)>>1), timg);	\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_8b, 				\
    		   (((((lrs)-(uls)+1)>>1)+7)>>3), 0,			\
    		   G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,	\
    		   shifts);						\
    	gDPLoadSync(pkt);						\
    	gDPLoadTile(	pkt, G_TX_LOADTILE,				\
    			(uls)<<(G_TEXTURE_IMAGE_FRAC-1),		\
    			(ult)<<(G_TEXTURE_IMAGE_FRAC),			\
    			(lrs)<<(G_TEXTURE_IMAGE_FRAC-1),		\
    			(lrt)<<(G_TEXTURE_IMAGE_FRAC));			\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_4b, 				\
    		   (((((lrs)-(uls)+1)>>1)+7)>>3), 0,			\
    		   G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, 	\
    		   masks, shifts);					\
    	gDPSetTileSize(pkt, G_TX_RENDERTILE,				\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC)			\
    }

    /*
     *  Load texture tile.  Allows tmem address and render tile to be specified.
     *  Useful for loading multiple tiles.
     */
    #define	gDPLoadMultiTile_4b(pkt, timg, tmem, rtile, fmt, width, height,	\
    		uls, ult, lrs, lrt, pal,				\
    		cms, cmt, masks, maskt, shifts, shiftt)			\
    {									\
    	gDPSetTextureImage(pkt, fmt, G_IM_SIZ_8b, ((width)>>1), timg);	\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_8b, 			        \
    		   (((((lrs)-(uls)+1)>>1)+7)>>3), tmem,			\
    		   G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,	\
    		   shifts);						\
    	gDPLoadSync(pkt);						\
    	gDPLoadTile(	pkt, G_TX_LOADTILE,				\
    			(uls)<<(G_TEXTURE_IMAGE_FRAC-1),		\
    			(ult)<<(G_TEXTURE_IMAGE_FRAC),			\
    			(lrs)<<(G_TEXTURE_IMAGE_FRAC-1),		\
    			(lrt)<<(G_TEXTURE_IMAGE_FRAC));			\
    	gDPPipeSync(pkt);						\
    	gDPSetTile(pkt, fmt, G_IM_SIZ_4b, 				\
    		   (((((lrs)-(uls)+1)>>1)+7)>>3), tmem,			\
    		   rtile, pal, cmt, maskt, shiftt, cms, masks,		\
    		   shifts);						\
    	gDPSetTileSize(pkt, rtile,					\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC)			\
    }

    #define	gsDPLoadTextureTile_4b(timg, fmt, width, height,		\
    		uls, ult, lrs, lrt, pal,				\
    		cms, cmt, masks, maskt, shifts, shiftt)			\
    									\
    	gsDPSetTextureImage(fmt, G_IM_SIZ_8b, ((width)>>1), timg),	\
    	gsDPSetTile(fmt, G_IM_SIZ_8b, (((((lrs)-(uls)+1)>>1)+7)>>3), 0,	\
    		G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,	\
    		shifts),						\
    	gsDPLoadSync(),							\
    	gsDPLoadTile(	G_TX_LOADTILE,					\
    			(uls)<<(G_TEXTURE_IMAGE_FRAC-1),		\
    			(ult)<<(G_TEXTURE_IMAGE_FRAC),			\
    			(lrs)<<(G_TEXTURE_IMAGE_FRAC-1),		\
    			(lrt)<<(G_TEXTURE_IMAGE_FRAC)),			\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, G_IM_SIZ_4b, (((((lrs)-(uls)+1)>>1)+7)>>3), 0,	\
    		G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,	\
    		shifts),						\
    	gsDPSetTileSize(G_TX_RENDERTILE,				\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC)

    /*
     *  Load texture tile.  Allows tmem address and render tile to be specified.
     *  Useful for loading multiple tiles.
     */
    #define	gsDPLoadMultiTile_4b(timg, tmem, rtile, fmt, width, height,	\
    		uls, ult, lrs, lrt, pal,				\
    		cms, cmt, masks, maskt, shifts, shiftt)			\
    									\
    	gsDPSetTextureImage(fmt, G_IM_SIZ_8b, ((width)>>1), timg),	\
    	gsDPSetTile(fmt, G_IM_SIZ_8b, (((((lrs)-(uls)+1)>>1)+7)>>3), 	\
    		    tmem, G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, 	\
    		    masks, shifts),					\
    	gsDPLoadSync(),							\
    	gsDPLoadTile(	G_TX_LOADTILE,					\
    			(uls)<<(G_TEXTURE_IMAGE_FRAC-1),		\
    			(ult)<<(G_TEXTURE_IMAGE_FRAC),			\
    			(lrs)<<(G_TEXTURE_IMAGE_FRAC-1),		\
    			(lrt)<<(G_TEXTURE_IMAGE_FRAC)),			\
    	gsDPPipeSync(),							\
    	gsDPSetTile(fmt, G_IM_SIZ_4b, (((((lrs)-(uls)+1)>>1)+7)>>3), 	\
    		    tmem, rtile, pal, cmt, maskt, shiftt, cms, masks,	\
    		    shifts),						\
    	gsDPSetTileSize(rtile,						\
    			(uls)<<G_TEXTURE_IMAGE_FRAC,			\
    			(ult)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrs)<<G_TEXTURE_IMAGE_FRAC,			\
    			(lrt)<<G_TEXTURE_IMAGE_FRAC)

    /*
     *  Load a 16-entry palette (for 4-bit CI textures)
     *  Assumes a 16 entry tlut is being loaded, palette # is 0-15
     */
    #ifndef _HW_VERSION_1

    #define gDPLoadTLUT_pal16(pkt, pal, dram)				\
    {									\
    	gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram);	\
    	gDPTileSync(pkt);						\
    	gDPSetTile(pkt, 0, 0, 0, (256+(((pal)&0xf)*16)),		\
    		G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0);			\
    	gDPLoadSync(pkt);						\
    	gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, 15);				\
    	gDPPipeSync(pkt)						\
    }

    #else /* **** WORKAROUND hardware 1 load_tlut bug ****** */

    #define gDPLoadTLUT_pal16(pkt, pal, dram)				\
    									\
            _gDPLoadTextureBlock(pkt, dram, (256+(((pal)&0xf)*16)),		\
    		G_IM_FMT_RGBA, G_IM_SIZ_16b, 4*16, 1,			\
    		pal, 0, 0, 0, 0, 0, 0)

    #endif /* _HW_VERSION_1 */

    /*
     *  Load a 16-entry palette (for 4-bit CI textures)
     *  Assumes a 16 entry tlut is being loaded, palette # is 0-15
     */
    #ifndef _HW_VERSION_1

    #define gsDPLoadTLUT_pal16(pal, dram)					\
     									\
    	gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram),	\
    	gsDPTileSync(),							\
    	gsDPSetTile(0, 0, 0, (256+(((pal)&0xf)*16)),			\
    		G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0),			\
    	gsDPLoadSync(),							\
    	gsDPLoadTLUTCmd(G_TX_LOADTILE, 15),				\
    	gsDPPipeSync()

    #else /* **** WORKAROUND hardware 1 load_tlut bug ****** */

    #define gsDPLoadTLUT_pal16(pal, dram)                                   \
    									\
    	_gsDPLoadTextureBlock(dram, (256+(((pal)&0xf)*16)),           	\
                    G_IM_FMT_RGBA, G_IM_SIZ_16b, 4*16, 1,                   \
                    pal, 0, 0, 0, 0, 0, 0)

    #endif /* _HW_VERSION_1 */

    /*
     *  Load a 256-entry palette (for 8-bit CI textures)
     *  Assumes a 256 entry tlut is being loaded, palette # is not used
     */
    #ifndef _HW_VERSION_1

    #define gDPLoadTLUT_pal256(pkt, dram)					\
    {									\
    	gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram);	\
    	gDPTileSync(pkt);						\
    	gDPSetTile(pkt, 0, 0, 0, 256,					\
    		G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0);			\
    	gDPLoadSync(pkt);						\
    	gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, 255);			\
    	gDPPipeSync(pkt)						\
    }

    #else /* **** WORKAROUND hardware 1 load_tlut bug ****** */

    #define gDPLoadTLUT_pal256(pkt, dram)                                   \
    	                                                                \
    	_gDPLoadTextureBlock(pkt, dram, 256,           			\
                    G_IM_FMT_RGBA, G_IM_SIZ_16b, 4*256, 1,			\
                    0, 0, 0, 0, 0, 0, 0)

    #endif /* _HW_VERSION_1 */

    #ifndef _HW_VERSION_1

    #define gsDPLoadTLUT_pal256(dram)					\
     									\
    	gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram),	\
    	gsDPTileSync(),							\
    	gsDPSetTile(0, 0, 0, 256,					\
    		G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0),			\
    	gsDPLoadSync(),							\
    	gsDPLoadTLUTCmd(G_TX_LOADTILE, 255),				\
    	gsDPPipeSync()

    #else /* **** WORKAROUND hardware 1 load_tlut bug ****** */

    #define gsDPLoadTLUT_pal256(dram)                                       \
                                                                            \
    	_gsDPLoadTextureBlock(dram, 256,                            	\
                    G_IM_FMT_RGBA, G_IM_SIZ_16b, 4*256, 1,                  \
                    0, 0, 0, 0, 0, 0, 0)

    #endif /* _HW_VERSION_1 */

    #ifndef _HW_VERSION_1

    #define gDPLoadTLUT(pkt, count, tmemaddr, dram)				\
    {									\
    	gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram);	\
    	gDPTileSync(pkt);						\
    	gDPSetTile(pkt, 0, 0, 0, tmemaddr,				\
    		G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0);			\
    	gDPLoadSync(pkt);						\
    	gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, ((count)-1));		\
    	gDPPipeSync(pkt);						\
    }

    #else /* **** WORKAROUND hardware 1 load_tlut bug ****** */

    #define gDPLoadTLUT(pkt, count, tmemaddr, dram)                         \
    									\
            _gDPLoadTextureBlock(pkt, dram, tmemaddr,                       \
                    G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, count,                  \
                    0, 0, 0, 0, 0, 0, 0)

    #endif /* _HW_VERSION_1 */

    #ifndef _HW_VERSION_1

    #define gsDPLoadTLUT(count, tmemaddr, dram)				\
     									\
    	gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram),	\
    	gsDPTileSync(),							\
    	gsDPSetTile(0, 0, 0, tmemaddr,					\
    		G_TX_LOADTILE, 0 , 0, 0, 0, 0, 0, 0),			\
    	gsDPLoadSync(),							\
    	gsDPLoadTLUTCmd(G_TX_LOADTILE, ((count)-1)),			\
    	gsDPPipeSync()

    #else /* **** WORKAROUND hardware 1 load_tlut bug ****** */
    #define gsDPLoadTLUT(count, tmemaddr, dram)                             \
                                                                            \
            _gsDPLoadTextureBlock(dram, tmemaddr,                       	\
                    G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, count,                  \
                    0, 0, 0, 0, 0, 0, 0)

    #endif /* _HW_VERSION_1 */

    #define gDPSetScissor(pkt, mode, ulx, uly, lrx, lry)			\
    {									\
    	Gfx *_g = (Gfx *)pkt;						\
    									\
    	_g->words.w0 = _SHIFTL(G_SETSCISSOR, 24, 8) |			\
    		       _SHIFTL((int)((float)(ulx)*4.0F), 12, 12) |	\
                           _SHIFTL((int)((float)(uly)*4.0F), 0, 12);	\
    	_g->words.w1 = _SHIFTL(mode, 24, 2) |				\
    		       _SHIFTL((int)((float)(lrx)*4.0F), 12, 12) |	\
                           _SHIFTL((int)((float)(lry)*4.0F), 0, 12);	\
    }

    #define gDPSetScissorFrac(pkt, mode, ulx, uly, lrx, lry)		\
    {									\
    	Gfx *_g = (Gfx *)pkt;						\
    									\
    	_g->words.w0 = _SHIFTL(G_SETSCISSOR, 24, 8) |			\
    		       _SHIFTL((int)((ulx)), 12, 12) |			\
                           _SHIFTL((int)((uly)), 0, 12);			\
    	_g->words.w1 = _SHIFTL(mode, 24, 2) |				\
    		       _SHIFTL((int)((lrx)), 12, 12) | 			\
                           _SHIFTL((int)((lry)), 0, 12);			\
    }

    #define gsDPSetScissor(mode, ulx, uly, lrx, lry)			\
    {									\
    	_SHIFTL(G_SETSCISSOR, 24, 8) |					\
    	_SHIFTL((int)((float)(ulx)*4.0F), 12, 12) |			\
    	_SHIFTL((int)((float)(uly)*4.0F), 0, 12),			\
    	_SHIFTL(mode, 24, 2) |						\
    	_SHIFTL((int)((float)(lrx)*4.0F), 12, 12) |			\
    	_SHIFTL((int)((float)(lry)*4.0F), 0, 12)			\
    }

    #define gsDPSetScissorFrac(mode, ulx, uly, lrx, lry)			\
    {									\
    	_SHIFTL(G_SETSCISSOR, 24, 8) |					\
    	_SHIFTL((int)((ulx)), 12, 12) |					\
    	_SHIFTL((int)((uly)), 0, 12),					\
    	_SHIFTL(mode, 24, 2) |						\
    	_SHIFTL((int)(lrx), 12, 12) |					\
    	_SHIFTL((int)(lry), 0, 12)					\
    }

    /* Fraction never used in fill */
    #define	gDPFillRectangle(pkt, ulx, uly, lrx, lry)			\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_FILLRECT, 24, 8) | 			\
    			_SHIFTL((lrx), 14, 10) | _SHIFTL((lry), 2, 10));\
    	_g->words.w1 = (_SHIFTL((ulx), 14, 10) | _SHIFTL((uly), 2, 10));\
    }

    #define	gsDPFillRectangle(ulx, uly, lrx, lry)				\
    {									\
    	(_SHIFTL(G_FILLRECT, 24, 8) | _SHIFTL((lrx), 14, 10) | 		\
    	 _SHIFTL((lry), 2, 10)),					\
    	(_SHIFTL((ulx), 14, 10) | _SHIFTL((uly), 2, 10))		\
    }

    /* like gDPFillRectangle but accepts negative arguments */
    #define	gDPScisFillRectangle(pkt, ulx, uly, lrx, lry)			\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_FILLRECT, 24, 8) | 			\
    			_SHIFTL(MAX((lrx),0), 14, 10) | 		\
    			_SHIFTL(MAX((lry),0), 2, 10));			\
    	_g->words.w1 = (_SHIFTL(MAX((ulx),0), 14, 10) | 		\
    			_SHIFTL(MAX((uly),0), 2, 10));			\
    }

    #define	gDPSetConvert(pkt, k0, k1, k2, k3, k4, k5)			\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_SETCONVERT, 24, 8) |			\
    			_SHIFTL(k0, 13, 9) | _SHIFTL(k1, 4, 9) | 	\
    			_SHIFTR(k2, 5, 4));				\
    	_g->words.w1 = (_SHIFTL(k2, 27, 5) | _SHIFTL(k3, 18, 9) |	\
    			_SHIFTL(k4, 9, 9) | _SHIFTL(k5, 0, 9));		\
    }

    #define gsDPSetConvert(k0, k1, k2, k3, k4, k5)				\
    {									\
    	(_SHIFTL(G_SETCONVERT, 24, 8) |					\
    	 _SHIFTL(k0, 13, 9) | _SHIFTL(k1, 4, 9) | _SHIFTL(k2, 5, 4)),	\
    	(_SHIFTL(k2, 27, 5) | _SHIFTL(k3, 18, 9) | _SHIFTL(k4, 9, 9) | 	\
    	 _SHIFTL(k5, 0, 9))						\
    }

    #define	gDPSetKeyR(pkt, cR, sR, wR)					\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(G_SETKEYR, 24, 8);			\
    	_g->words.w1 = (_SHIFTL(wR, 16, 12) | _SHIFTL(cR, 8, 8) | 	\
    			_SHIFTL(sR, 0, 8));				\
    }

    #define	gsDPSetKeyR(cR, sR, wR)						\
    {									\
    	_SHIFTL(G_SETKEYR, 24, 8),					\
    	_SHIFTL(wR, 16, 12) | _SHIFTL(cR, 8, 8) | _SHIFTL(sR, 0, 8)	\
    }

    #define	gDPSetKeyGB(pkt, cG, sG, wG, cB, sB, wB)			\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = (_SHIFTL(G_SETKEYGB, 24, 8) |			\
    			_SHIFTL(wG, 12, 12) | _SHIFTL(wB, 0, 12));	\
    	_g->words.w1 = (_SHIFTL(cG, 24, 8) | _SHIFTL(sG, 16, 8) |	\
    			 _SHIFTL(cB, 8, 8) | _SHIFTL(sB, 0, 8));	\
    }

    #define	gsDPSetKeyGB(cG, sG, wG, cB, sB, wB)				\
    {									\
    	(_SHIFTL(G_SETKEYGB, 24, 8) | _SHIFTL(wG, 12, 12) |		\
    	 _SHIFTL(wB, 0, 12)),						\
    	(_SHIFTL(cG, 24, 8) | _SHIFTL(sG, 16, 8) | _SHIFTL(cB, 8, 8) |	\
    	 _SHIFTL(sB, 0, 8))						\
    }

    #define gDPNoParam(pkt, cmd)						\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(cmd, 24, 8);				\
    	_g->words.w1 = 0;						\
    }

    #define gsDPNoParam(cmd)						\
    {									\
    	_SHIFTL(cmd, 24, 8), 0						\
    }

    #define gDPParam(pkt, cmd, param)					\
    {									\
    	Gfx *_g = (Gfx *)(pkt);						\
    									\
    	_g->words.w0 = _SHIFTL(cmd, 24, 8);				\
    	_g->words.w1 = (param);						\
    }

    #define gsDPParam(cmd, param)						\
    {									\
    	_SHIFTL(cmd, 24, 8), (param)					\
    }

    /* Notice that textured rectangles are 128-bit commands, therefore
     * gsDPTextureRectangle() should not be used in display lists
     * under normal circumstances (use gsSPTextureRectangle()).
     * That is also why there is no gDPTextureRectangle() macros.
     */
    #define gsDPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy)	\
    {									\
        (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | 			\
         _SHIFTL(yh, 0, 12)),						\
        (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)),	\
    },									\
    {									\
        _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16),				\
        _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)			\
    }

    #define gDPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\
    {									\
        Gfx *_g = (Gfx *)(pkt);						\
        if (pkt);								\
        _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) |	\
    		    _SHIFTL(yh, 0, 12));    				\
        _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) |	\
    		    _SHIFTL(yl, 0, 12));				\
        _g ++;								\
        _g->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16));		\
        _g->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16));	\
    }

    #define gsDPTextureRectangleFlip(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
    {									\
        (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) |		\
         _SHIFTL(yh, 0, 12)),						\
        (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)),	\
    },									\
    {									\
        _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16),				\
        _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)			\
    }

    #define gDPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\
    {									\
        Gfx *_g = (Gfx *)(pkt);						\
        if (pkt);								\
        _g->words.w0 = (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | \
    		    _SHIFTL(yh, 0, 12));    				\
        _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) |	\
    		    _SHIFTL(yl, 0, 12));				\
        _g ++;								\
        _g->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16));		\
        _g->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16));	\
    }

    #define gsSPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy)	\
        (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)),\
        (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)),	\
        gsImmp1(G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))),	\
        gsImmp1(G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)))

    #define gSPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\
    {									\
        Gfx *_g = (Gfx *)(pkt);						\
    									\
        _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) |	\
    		    _SHIFTL(yh, 0, 12));    				\
        _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) |	\
    		    _SHIFTL(yl, 0, 12));				\
        gImmp1(pkt, G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)));	\
        gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)));\
    }

    /* like gSPTextureRectangle but accepts negative position arguments */
    #define gSPScisTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
    {                                                                            \
        Gfx *_g = (Gfx *)(pkt);                                                  \
                                                                                 \
        _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) |                              \
                        _SHIFTL(MAX((s16)(xh),0), 12, 12) |                      \
                        _SHIFTL(MAX((s16)(yh),0), 0, 12));                       \
        _g->words.w1 = (_SHIFTL((tile), 24, 3) |                                 \
                        _SHIFTL(MAX((s16)(xl),0), 12, 12) |                      \
                        _SHIFTL(MAX((s16)(yl),0), 0, 12));                       \
        gImmp1(pkt, G_RDPHALF_1,                                                 \
                    (_SHIFTL(((s) -                                              \
                              (((s16)(xl) < 0) ?                                 \
                               (((s16)(dsdx) < 0) ?                              \
                                (MAX((((s16)(xl)*(s16)(dsdx))>>7),0)) :          \
    			    (MIN((((s16)(xl)*(s16)(dsdx))>>7),0))) : 0)),    \
    			 16, 16) |                                           \
                     _SHIFTL(((t) -                                              \
                              (((yl) < 0) ?                                      \
                               (((s16)(dtdy) < 0) ?                              \
                                (MAX((((s16)(yl)*(s16)(dtdy))>>7),0)) :          \
                                (MIN((((s16)(yl)*(s16)(dtdy))>>7),0))) : 0)),    \
    			 0, 16)));                                           \
        gImmp1(pkt, G_RDPHALF_2, (_SHIFTL((dsdx), 16, 16) |                      \
                                  _SHIFTL((dtdy), 0, 16)));                      \
    }

    #define gsSPTextureRectangleFlip(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
        (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) |		\
         _SHIFTL(yh, 0, 12)),						\
        (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)),	\
        gsImmp1(G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))),	\
        gsImmp1(G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)))

    #define gSPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
    {								       	\
        Gfx *_g = (Gfx *)(pkt);					       	\
    									 \
        _g->words.w0 = (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) |\
    		    _SHIFTL(yh, 0, 12)); 				\
        _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) |	\
    		    _SHIFTL(yl, 0, 12));				\
        gImmp1(pkt, G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)));	\
        gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))); \
    }

    #define gsDPWord(wordhi, wordlo)			\
        gsImmp1(G_RDPHALF_1, (unsigned int)(wordhi)),	\
        gsImmp1(G_RDPHALF_2, (unsigned int)(wordlo))

    #define gDPWord(pkt, wordhi, wordlo)      		\
    {							\
        Gfx *_g = (Gfx *)(pkt);				\
    							\
        gImmp1(pkt, G_RDPHALF_1, (unsigned int)(wordhi));	\
        gImmp1(pkt, G_RDPHALF_2, (unsigned int)(wordlo));	\
    }

    #define	gDPFullSync(pkt)	gDPNoParam(pkt, G_RDPFULLSYNC)
    #define	gsDPFullSync()		gsDPNoParam(G_RDPFULLSYNC)
    #define	gDPTileSync(pkt)	gDPNoParam(pkt, G_RDPTILESYNC)
    #define	gsDPTileSync()		gsDPNoParam(G_RDPTILESYNC)
    #define	gDPPipeSync(pkt)	gDPNoParam(pkt, G_RDPPIPESYNC)
    #define	gsDPPipeSync()		gsDPNoParam(G_RDPPIPESYNC)
    #define	gDPLoadSync(pkt)	gDPNoParam(pkt, G_RDPLOADSYNC)
    #define	gsDPLoadSync()		gsDPNoParam(G_RDPLOADSYNC)
    #define	gDPNoOp(pkt)		gDPNoParam(pkt, G_NOOP)
    #define	gsDPNoOp()		gsDPNoParam(G_NOOP)
    #define	gDPNoOpTag(pkt, tag)	gDPParam(pkt, G_NOOP, tag)
    #define	gsDPNoOpTag(tag)	gsDPParam(G_NOOP, tag)

    #endif /* _LANGUAGE_C */

    #endif /* _GBI_H_ */