#!/usr/bin/env tclsh

set input ""
set header_file "registers.h"
set code_file "packet.c"
foreach arg $argv {
	switch -glob $arg {
		"--help"     {
			puts stderr "Usage: pretty_print_command_stream.tcl  [options] [input_file]"
			exit
			}
		"--header=*" {
			regexp {--header=(.*)$} $arg {} header_file
			}
		"--code=*" {
			regexp {--code=(.*)$} $arg {} code_file
			}
		default {
			set input $arg
			}
		}
	}

if { $input != "" } {
	set FILE [open $input "r"]
	} {
	set FILE stdin
	}

global HEADER CODE
set HEADER [open $header_file "w"]
set CODE [open $code_file "w"]

puts -nonewline $CODE {
#include "radeon_reg.h"
#include "registers.h"
#include "pixel_shader.h"

#define CP_PACKET0(reg, n)	(RADEON_CP_PACKET0 | ((n)<<16) | ((reg)>>2))

extern unsigned int display_base, depth_offset, zmask_offset;
extern int display_width;

void e32(unsigned int);
void efloat(float);

void output_packet(void)
}

puts $CODE "{\n"

#
# Registers with name starting with X are those
# that were not described in the documentation, the name is made up.
#
# Some registers not beginning with X were also guessed (or taken from R200
# documentation) before I started using X convention
#
# Registers that end with FL take 32bit floats as values.
# Remember - they are just guesses, sometimes just because they happen to be
# close to something with seemingly floating point value and have 0 written in them.
#

global REG_NAMES
foreach {name addr} {
	 "R300_CRTC_GUI_TRIG_VLINE"	218
	 "R300_CP_IB_BASE {expr indirect buffer address}" 	738
	 "R300_CP_IB_BUF_SIZE {expr starts indirect buffer}"	73c

	 "R300_DST_OFFSET {expr display_base}"	1404
	 "R300_DST_PITCH {expr display_width*4}"	1408
	 "R300_DST_Y_X"			1438
	 "R300_SRC_Y_X"			1434
	 "R300_DST_HEIGHT_WIDTH"		143c
	 "R300_DP_GUI_MASTER_CNTL"		146c
	 "R300_BRUSH_Y_X"			1474
	 "R300_DP_BRUSH_BKGD_CLR"		1478
	 "R300_DP_BRUSH_FRGD_CLR"		147c

	 "R300_SRC_OFFSET {expr display_base}"	15ac
	 "R300_SRC_PITCH {expr display_width*4}"	15b0

	 "R300_DST_WIDTH_HEIGHT"		1598
	 "R300_DP_CNTL"			16c0
	 "R300_DP_WRITE_MASK"		16cc

	 "RB3D_DEPTHOFFSET {expr depth_offset}"		1c24
	 "RB3D_ZSTENCIL_CNTL"		1c2c
	 "RB3D_ZMASKOFFSET {expr zmask_offset}"		1c34
	 "RB3D_CNTL"			1c3c
	 
	 "R300_SE_VPORT_XSCALE"         1D98
	 "R300_SE_VPORT_XOFFSET"        1D9C
	 "R300_SE_VPORT_YSCALE"         1DA0
	 "R300_SE_VPORT_YOFFSET"        1DA4
	 "R300_SE_VPORT_ZSCALE"         1DA8
	 "R300_SE_VPORT_ZOFFSET"        1DAC

	 "R300_VAP_OUTPUT_VTX_FMT_0"    2090
	 "R300_VAP_OUTPUT_VTX_FMT_1"    2094
	 "R300_VAP_INPUT_CNTL_0"        2180
	 "R300_VAP_INPUT_CNTL_1"        2184
	 "R300_VAP_PVS_UPLOAD_ADDRESS"  2200
	 "R300_VAP_PVS_UPLOAD_DATA"     2208
	 "R300_VAP_PVS_CNTL_1"          22D0
	 "R300_VAP_PVS_CNTL_2"          22D4
	 "R300_VAP_PVS_CNTL_3"	        22D8

	 "R300_RE_POINTSIZE"            421C
	 "R300_RE_CULL_CNTL"            42B8

	 "R300_RB2D_DSTCACHE_MODE"		3428
	 "R300_RB2D_DSTCACHE_CTLSTAT"	342c
	 "R300_PLANE_3D_MASK_C"		1d44
	 "R300_PLANEMASK"			1d84
	 "R300_STENCILREFMASK"		1d7c
	 "R300_ZCACHE_MODE"			3250
	 "R300_ZCACHE_CTLSTAT"		3254

	 "R300_SE_VAP_CNTL"			2080
	 "R300_VAP_VF_CNTL" 	      		2084
	 "R300_GB_VAP_RASTER_VTX_FMT_0"	4000
	 "R300_GB_VAP_RASTER_VTX_FMT_1"	4004
	 "R300_GB_MSPOS0"			4010
	 "R300_GB_MSPOS1"			4014
	 "R300_GB_ENABLE"			4008
	 "R300_GB_TILE_CONFIG"		4018
	 "R300_GB_SELECT"			401c
	 "R300_GB_AA_CONFIG"			4020
	 "R300_GB_FIFO_SIZE"			4024

	 "R300_VAP_PVS_CNTL_0"		22d0
	 "R300_VAP_PVS_CNTL_1"		22d4
	 "R300_VAP_PVS_CNTL"		22d8

	 "X_QUAD0_1_FL"			2220
	 "X_QUAD0_2_FL"			2224
	 "X_QUAD0_3_FL"			2228
	 "X_QUAD0_4_FL"			222c

	 "R300_VAP_PVS_WAITIDLE"	2284

	 "X_2310_FL"			2310
	 "X_2314_FL"			2314
	 "X_2318_FL"			2318

	 "R300_UPLOAD_TEXTURE_X_FL"			23a0
	 "R300_UPLOAD_TEXTURE_Y_FL"			23a4
	 "X_23a8_FL"			23a8
	 "X_23ac_FL"			23ac

	 "X_23b0_FL"			23b0
	 "X_23b4_FL"			23b4
	 "X_23b8_FL"			23b8
	 "X_23bc_FL"			23bc

	 "X_23c0_FL"			23c0
	 "X_23c4_FL"			23c4
	 "X_23c8_FL"			23c8
	 "X_23cc_FL"			23cc

	 "X_23d0_FL"			23d0
	 "X_23d4_FL"			23d4
	 "X_23d8_FL"			23d8
	 "X_23dc_FL"			23dc

	 "X_23e0_FL"			23e0
	 "X_23e4_FL"			23e4
	 "X_23e8_FL"			23e8
	 "X_23ec_FL"			23ec

	 "X_23f0_FL"			23f0
	 "X_23f4_FL"			23f4
	 "X_23f8_FL"			23f8
	 "X_23fc_FL"			23fc

	 "X_2400_FL"			2400
	 "X_2404_FL"			2404
	 "X_2408_FL"			2408
	 "X_240c_FL"			240c

	 "X_2410_FL"			2410
	 "X_2414_FL"			2414
	 "X_2418_FL"			2418
	 "X_241c_FL"			241c

	 "X_2450_FL"			2450
	 "X_2454_FL"			2454
	 "X_2458_FL"			2458

	 "X_UPLOAD_R_FL"			2460
	 "X_UPLOAD_G_FL"			2464
	 "X_UPLOAD_B_FL"			2468
	 "X_246c_FL"			246c

	 "X_UPLOAD_X_FL"			24a0
	 "X_UPLOAD_Y_FL"			24a4
	 "X_UPLOAD_Z_FL"			24a8

	 "R300_VAP_VTX_END_OF_PKT"	24ac

	 "X_3430_FL"			3430
	 "X_3434_FL"			3434
	 "X_3438_FL"			3438
	 "X_343c_FL"			343c

	 "X_4200_FL"			4200
	 "X_4204_FL"			4204
	 "X_4208_FL"			4208
	 "X_420c_FL"			420c

	 "X_INIT0"			4290
	 "R300_RB3D_DSTCACHE_CTLSTAT"	4e4c
	 "X_INIT2"			4f18

	 "R300_RB3D_CBLEND"		4e04
	 "R300_RB3D_ABLEND"		4e08
	 "R300_RB3D_COLORMASK"	4e0c

	 "R300_RB3D_COLOROFFSET0 {expr display_base}"		4e28
	 "X_INIT3_1"			4e2c
	 "X_INIT3_2"			4e30
	 "X_INIT3_3"			4e34

	 "R300_RB3D_COLORPITCH0 {expr display_width | (0xc0 <<16)}"		4e38
	 "X_INIT4_1"			4e3c
	 "X_INIT4_2"			4e40
	 "X_INIT4_3"			4e44

	 "X_INIT5_0"			4e54
	 "X_INIT5_1"			4e58
	 "X_INIT5_2"			4e5c
	 "X_INIT5_3"			4e60

	 "X_INIT6_0"			4e64
	 "X_INIT6_1"			4e68
	 "X_INIT6_2"			4e6c
	 "X_INIT6_3"			4e70

	 "R300_DEPTHBUFFER_OFFSET {expr depth_offset}"		4f20
	 "R300_DEPTHPITCH {expr display_width | (3<<16)}"			4f24
	 "X_INIT9"			4f44
	 "X_INIT10"			4f54
	 "X_INIT11"			4f30
	 "X_INIT12"			4f34
	 "X_INIT13"			4e00
	 "X_INIT14"			4e50

	 "X_INIT15_0"			42b4
	 "X_INIT15_1"			42b8

	 "X_INIT16_0"			4288
	 "X_INIT16_1"			428c

	 "X_INIT17"			4234
	 "X_INIT18"			4214
	 "X_INIT19"			4238
	 "X_INIT20"			4260

	 "X_INIT_21_0_FL"		4264
	 "X_INIT_21_1_FL"		4268

	 "R300_RE_CLIPRECT_TL_0"        43B0
	 "R300_RE_CLIPRECT_BR_0"        43B4
	 "R300_RE_CLIPRECT_TL_1"        43B8
	 "R300_RE_CLIPRECT_BR_1"        43BC
	 "R300_RE_CLIPRECT_TL_2"        43C0
	 "R300_RE_CLIPRECT_BR_2"        43C4
	 "R300_RE_CLIPRECT_TL_3"        43C8
	 "R300_RE_CLIPRECT_BR_3"        43CC
	 "R300_RE_CLIPRECT_CNTL"        43D0
	 "R300_RE_SCISSORS_TL"          43E0
         "R300_RE_SCISSORS_BR"          43E4

	 "R300_PFS_CNTL_0"		4600
	 "R300_PFS_CNTL_1"		4604
	 "R300_PFS_CNTL_2"		4608

	 "R300_PFS_NODE_0"		4610
	 "R300_PFS_NODE_1"		4614
	 "R300_PFS_NODE_2"		4618
	 "R300_PFS_NODE_3"		461c

	 "R300_PP_ALPHA_TEST"           4BD4
	 "R300_RB3D_CBLEND"             4E04
	 "R300_RB3D_ABLEND"             4E08

	 "R300_RB3D_COLORMASK"          4E0C

	 "R300_RB3D_ZCNTL_0"            4F00
	 "R300_RB3D_ZCNTL_1"            4F04

	 "R300_RB3D_DEPTHOFFSET"        4F20
	 "R300_RB3D_DEPTHPITCH"         4F24

	 "R300_SE_VAP_CNTL_STATUS"		2140
	 "R300_SE_VPORT_XSCALE_FL"		1d98
	 "R300_SE_VPORT_XOFFSET_FL"		1d9c
	 "R300_SE_VPORT_YSCALE_FL"		1da0
	 "R300_SE_VPORT_YOFFSET_FL"		1da4
	 "R300_SE_VPORT_ZSCALE_FL"		1da8
	 "R300_SE_VPORT_ZOFFSET_FL"		1dac

	 "R300_VAP_PORT_DATA_0"		2000
	 "R300_VAP_VTX_NUM_ARRAYS"		20C0
	 "R300_SRC_CLUT_DATA"		1784
	 "R300_WAIT_UNTIL"			1720

	 "R300_TX_ENABLE"			4104
	 "R300_RS_COUNT"			4300
	 "R300_RS_INST_COUNT"		4304
	 "R300_HOST_DATA_LAST"		17e0

	 "R300_TX_OFFSET_0 {expr texture_offset}"	4540

	} {
	if { [info exists REG_NAMES($addr)] } {
		puts "duplicate register: $REG_NAMES($addr) $name"
		exit
		}
	set REG_NAMES($addr) $name
	}

foreach { fmt start init count step} {
	"R300_BRUSH_DATA%d"   	1480 0 64 4
	"R300_GUI_SCRATCH_REG%d"  	15e0 0  6 4
	"R300_GUI_DEBUG%d"		16a0 0  7 4
	"R300_FLUSH_%d"		1704 1  7 4
	"R300_VAP_INPUT_ROUTE_0_%d"     2150 0  4 4
	"R300_VAP_INPUT_ROUTE_1_%d"     21E0 0  4 4

        "R200_PS_C0_I%d"                2f00 0  32 16
        "R200_PS_C1_I%d"                2f04 0  32 16
        "R200_PS_A0_I%d"                2f08 0  32 16
        "R200_PS_A1_I%d"                2f0c 0  32 16

	"R300_X_MEM0_%d"  		4310 0  8 4
	
	"R300_RS_ROUTE_%d"		4330 0  8 4

	"R300_TX_FILTER_%d"		4400 0 16 4
	"R300_TX_UNK1_%d"		4440 0 16 4
	"R300_TX_SIZE_%d"		4480 0 16 4
	"R300_TX_FORMAT_%d"		44C0 0 16 4
	"R300_TX_OFFSET_%d"             4544 1 15 4
	"R300_TX_UNK4_%d"		4580 0 16 4
	"R300_TX_UNK5_%d"		45C0 0 16 4
	
	"R300_PFS_PARAM_%d_X"  	4c00 0 32 16
	"R300_PFS_PARAM_%d_Y"  	4c04 0 32 16
	"R300_PFS_PARAM_%d_Z"  	4c08 0 32 16
	"R300_PFS_PARAM_%d_W"  	4c0c 0 32 16
	"R300_PFS_TEXI_%d"	4620 0 32 4
	"R300_PFS_INSTR1_%d"	46c0 0 64 4
	"R300_PFS_INSTR3_%d"	47c0 0 64 4
	"R300_PFS_INSTR0_%d"	48c0 0 64 4
	"R300_PFS_INSTR2_%d"	49c0 0 64 4
	"X_MEM2_%d_FL"  	2320 0 32 4
	"R300_HOST_DATA%d"  		17c0 0  8 4
	} {
	for { set i 0 } { $i < $count } {incr i } {
		set addr [format %x [expr 0x$start+$i*$step]]
		set name [format $fmt [expr $i+$init]]
		if { [info exists REG_NAMES($addr)] } {
			puts "duplicate register: $REG_NAMES($addr) $name"
			exit
			}
		set REG_NAMES($addr) $name
		}
	}


proc name_register { address } {
global REG_NAMES
set addr2 [format %x $address]
if { ! [info exists REG_NAMES($addr2) ] } {
	set REG_NAMES($addr2) "XG_$addr2"
	}
set name "[set REG_NAMES($addr2)]($addr2)"
return $name
}

global PFS_INSTR0_ARG_TABLE PFS_INSTR0_OP_TABLE
set PFS_INSTR0_ARG_TABLE {
	SRC0C_XYZ          0
	SRC0C_XXX          1
	SRC0C_YYY          2
	SRC0C_ZZZ          3
	SRC1C_XYZ          4
	SRC1C_XXX          5
	SRC1C_YYY          6
	SRC1C_ZZZ          7
	SRC2C_XYZ          8
	SRC2C_XXX          9
	SRC2C_YYY          10
	SRC2C_ZZZ          11
	SRC0A              12
	SRC1A              13
	SRC2A              14
	SRC1C_LRP          15
	???		   16
	???		   17
	???		   18
	???		   19
	ZERO               20
	ONE                21
	HALF               22 
	SRC0C_YZX          23
	SRC1C_YZX          24
	SRC2C_YZX          25
	SRC0C_ZXY          26
	SRC1C_ZXY          27
	SRC2C_ZXY          28
	SRC0CA_WZY         29
	SRC1CA_WZY         30
	SRC2CA_WZY         31
	}

set PFS_INSTR0_OP_TABLE {
	MAD	0
	DP3	1
	DP4	2
	???	3
	MIN	4
	MAX	5
	???	6
	???	7
	CMP	8
	FRC	9
	OUTC_REPL_ALPHA	10
	}

proc lookup_table { table val } {
if { $val < 0 } { return "??" }
if { 2*$val >= [llength $table] } { return "??" }
return [lindex $table [expr $val*2] ]
}

proc pretty_print_value_R300_PFS_INSTR0 {reg_name value} {
global CODE PFS_INSTR0_ARG_TABLE PFS_INSTR0_OP_TABLE
set num 0x$value
set op [expr ($num >> 23) & 0xf ]
set arg0 [expr ($num) & 0x1f]
set arg1 [expr ($num>>7) & 0x1f]
set arg2 [expr ($num>>14) & 0x1f]

set op_name [lookup_table $PFS_INSTR0_OP_TABLE $op]
set arg0_name [lookup_table $PFS_INSTR0_ARG_TABLE $arg0]
set arg1_name [lookup_table $PFS_INSTR0_ARG_TABLE $arg1]
set arg2_name [lookup_table $PFS_INSTR0_ARG_TABLE $arg2]


switch -exact [expr ($num >> 30) ] {
	0    { set flags 0 }
	1    { set flags "R300_FPI0_OUTC_SAT" } 
	2    { set flags "R300_FPI0_UNKNOWN_31" } 
	3    { set flags "R300_FPI0_OUTC_SAT | R300_FPI0_UNKNOWN_31" } 
	}

# cheat - just or the remaining bits
set remainder [expr $num & (~((0xf<<23) | (0x1f) | (0x1f<<7) | (0x1f<<14) | (3<<30)))]

if { $remainder==0 } {
	set value2 "EASY_PFS_INSTR0($op_name, $arg0_name, $arg1_name, $arg2_name)" 
	} {
	set value2 "EASY_PFS_INSTR0($op_name, $arg0_name, $arg1_name, $arg2_name) | [format 0x%08x $remainder]" 
	}

if { $flags != 0 } {
	set value2 "$value2 | $flags"
	}

puts $CODE "\te32($value2); /* 0x$value */"

return "$value2=$value"
}



proc pretty_print_value_R300_PFS_INSTR1 {reg_name value} {
global CODE
set num 0x$value
set src0 [expr $num & 0x1f]
set src1 [expr ($num>>6) & 0x1f]
set src2 [expr ($num>>12) & 0x1f]
set dstc [expr ($num>>18) & 0x1f]
set reg [expr ($num >> 23 ) & 7]
set output [expr ($num >> 26) & 7]

set remainder [expr ($num & (~(0x3f | (0x3f<<6) | (0x3f<<12) | (0x1f<<18) | (0x7<<23)| (7<<26))))]

switch -exact $reg {
	0 	{ set reg_name "NONE" }
	1 	{ set reg_name "X" }
	2 	{ set reg_name "Y" }
	3 	{ set reg_name "XY" }
	4 	{ set reg_name "Z" }
	5 	{ set reg_name "XZ" }
	6 	{ set reg_name "YZ" }
	7 	{ set reg_name "ALL" }
	}

switch -exact $output {
	0 	{ set output_name "NONE" }
	1 	{ set output_name "X" }
	2 	{ set output_name "Y" }
	3 	{ set reg_name "XY" }
	4 	{ set output_name "Z" }
	5 	{ set reg_name "XZ" }
	6 	{ set reg_name "YZ" }
	7 	{ set output_name "ALL" }
	}

if { ($num >> 5) & 1 } {
	set src0 "$src0 | PFS_FLAG_CONST"
	}

if { ($num >> 11) & 1 } {
	set src1 "$src1 | PFS_FLAG_CONST"
	}

if { ($num >> 17) & 1 } {
	set src2 "$src2 | PFS_FLAG_CONST"
	}

if { $remainder == 0 } {
	set value2 "EASY_PFS_INSTR1($dstc, $src0, $src1, $src2, $reg_name, $output_name)"
	} {
	set value2 "EASY_PFS_INSTR1($dstc, $src0, $src1, $src2, $reg_name, $output_name) | [format 0x%08x $remainder]"
	}

puts $CODE "\te32($value2); /* 0x$value */"
return "$value2=$value"
}


global PFS_INSTR0_ARG_TABLE PFS_INSTR0_OP_TABLE
set PFS_INSTR2_ARG_TABLE {
	SRC0C_X            0
	SRC0C_Y            1
	SRC0C_Z            2
	SRC1C_X            3
	SRC1C_Y            4
	SRC1C_Z            5
	SRC2C_X            6
	SRC2C_Y            7
	SRC2C_Z            8
	SRC0A              9
	SRC1A              10
	SRC2A              11
	???		   12
	???		   13
	???		   14
	SRC1A_LRP          15
	ZERO               16
	ONE                17
	HALF               18
	}

set PFS_INSTR2_OP_TABLE {
	MAD                0
	DP4                1
	MIN                2
	MAX                3
	CMP                6
	FRC                7
	EX2                8
	LG2                9
	RCP                10
	RSQ                11
	}

proc pretty_print_value_R300_PFS_INSTR2 {reg_name value} {
global CODE PFS_INSTR2_ARG_TABLE PFS_INSTR2_OP_TABLE
set num 0x$value
set op [expr ($num >> 23) & 0xf ]
set arg0 [expr ($num) & 0x1f]
set arg1 [expr ($num>>7) & 0x1f]
set arg2 [expr ($num>>14) & 0x1f]

set op_name [lookup_table $PFS_INSTR2_OP_TABLE $op]
set arg0_name [lookup_table $PFS_INSTR2_ARG_TABLE $arg0]
set arg1_name [lookup_table $PFS_INSTR2_ARG_TABLE $arg1]
set arg2_name [lookup_table $PFS_INSTR2_ARG_TABLE $arg2]


switch -exact [expr ($num >> 30) ] {
	0    { set flags 0 }
	1    { set flags "R300_FPI2_OUTA_SAT" } 
	2    { set flags "R300_FPI2_UNKNOWN_31" } 
	3    { set flags "R300_FPI2_OUTA_SAT | R300_FPI2_UNKNOWN_31" } 
	}

# cheat - just or the remaining bits
set remainder [expr $num & (~((0xf<<23) | (0x1f) | (0x1f<<7) | (0x1f<<14) | (3<<30)))]


if { $remainder==0 } {
	set value2 "EASY_PFS_INSTR2($op_name, $arg0_name, $arg1_name, $arg2_name)" 
	} {
	set value2 "EASY_PFS_INSTR2($op_name, $arg0_name, $arg1_name, $arg2_name) | [format 0x%08x $remainder]" 
	}

if { $flags != 0 } {
	set value2 "$value2 | $flags"
	}

puts $CODE "\te32($value2); /* 0x$value */"

return "$value2=$value"
}

proc pretty_print_value_R300_PFS_INSTR3 {reg_name value} {
global CODE
set num 0x$value
set src0 [expr $num & 0x1f]
set src1 [expr ($num>>6) & 0x1f]
set src2 [expr ($num>>12) & 0x1f]
set dstc [expr ($num>>18) & 0x1f]
set flags [expr ($num >> 23 ) & 3]

set remainder [expr ($num & (~(0x3f | (0x3f<<6) | (0x3f<<12) | (0x1f<<18) | (0x3<<23))))]

switch -exact $flags {
	0 	{ set flags_name "NONE" }
	1 	{ set flags_name "REG" }
	2 	{ set flags_name "OUTPUT" }
	3 	{ set flags_name "BOTH" }
	}

if { ($num >> 5) & 1 } {
	set src0 "$src0 | PFS_FLAG_CONST"
	}

if { ($num >> 11) & 1 } {
	set src1 "$src1 | PFS_FLAG_CONST"
	}

if { ($num >> 17) & 1 } {
	set src2 "$src2 | PFS_FLAG_CONST"
	}

if { $remainder == 0 } {
	set value2 "EASY_PFS_INSTR3($dstc, $src0, $src1, $src2, $flags_name)"
	} {
	set value2 "EASY_PFS_INSTR3($dstc, $src0, $src1, $src2, $flags_name) | [format 0x%08x $remainder]"
	}

puts $CODE "\te32($value2); /* 0x$value */"
return "$value2=$value"
}

global PS_INSTR_ARG_TABLE PS_OP_ARG_TABLE
set PS_INSTR_ARG_TABLE {
    ZERO            0
    ???             1
    CURRENT_COLOR   2
    CURRENT_ALPHA   3
    DIFFUSE_COLOR   4
    DIFFUSE_ALPHA   5
    SPECULAR_COLOR  6
    SPECULAR_ALPHA  7
    TFACTOR0_COLOR   8
    TFACTOR0_ALPHA   9
    R0_COLOR       10
    R0_ALPHA       11
    R1_COLOR       12
    R1_ALPHA       13
    R2_COLOR       14
    R2_ALPHA       15
    R3_COLOR       16
    R3_ALPHA       17
    R4_COLOR       18
    R4_ALPHA       19
    R5_COLOR       20
    R5_ALPHA       21
    ???            22
    ???            23
    ???            24
    ???            25
    TFACTOR1_COLOR  26
    TFACTOR1_ALPHA  27
}

set PS_OP_ARG_TABLE {
    MADD  0
    ???   1
    CND0  2
    LERP  3
    DOT3  4
    DOT4  5
    COND  6
    DOT2  7
}    

global PS_DST_ARG_TABLE
set PS_DST_ARG_TABLE {
    NONE 0
    R0   1
    R1   2
    R2   3
    R3   4
    R4   5
    R5   6
}
    
proc pretty_print_value_R200_PS_C0_ { reg_name value } {
global CODE PS_INSTR_ARG_TABLE PS_OP_ARG_TABLE
set num 0x$value
    set src0 [expr $num & 0x1f]
    set src1 [expr ($num>>5) & 0x1f]
    set src2 [expr ($num>>10) & 0x1f]
    set opr  [expr ($num>>28) & 0x7]

    set src0_name [lookup_table $PS_INSTR_ARG_TABLE $src0]
    set src1_name [lookup_table $PS_INSTR_ARG_TABLE $src1]
    set src2_name [lookup_table $PS_INSTR_ARG_TABLE $src2]
    set opr_name  [lookup_table $PS_OP_ARG_TABLE $opr]
    
    set value2 "COLOR_OP($src0_name, $src1_name, $src2_name, $opr_name)"
    return "$value2=$value"
}

proc pretty_print_value_R200_PS_A0_ { reg_name value } {
global CODE PS_INSTR_ARG_TABLE PS_OP_ARG_TABLE
set num 0x$value
    set src0 [expr $num & 0x1f]
    set src1 [expr ($num>>5) & 0x1f]
    set src2 [expr ($num>>10) & 0x1f]
    set opr  [expr ($num>>28) & 0x7]

    set src0_name [lookup_table $PS_INSTR_ARG_TABLE $src0]
    set src1_name [lookup_table $PS_INSTR_ARG_TABLE $src1]
    set src2_name [lookup_table $PS_INSTR_ARG_TABLE $src2]
    set opr_name  [lookup_table $PS_OP_ARG_TABLE $opr]
    
    set value2 "ALPHA_OP($src0_name, $src1_name, $src2_name, $opr_name)"
    return "$value2=$value"
}

proc pretty_print_value_R200_PS_C1_ { reg_name value } {
global PS_DST_ARG_TABLE
set num 0x$value
    set dst [expr ($num>>16) & 0x7]

    set dst_name [lookup_table $PS_DST_ARG_TABLE $dst]
    set value2 "COLOR_OP($dst_name)"
    return "$value2=$value"
}

proc pretty_print_value_R200_PS_A1_ { reg_name value } {
global PS_DST_ARG_TABLE
set num 0x$value
    set dst [expr ($num>>16) & 0x7]

    set dst_name [lookup_table $PS_DST_ARG_TABLE $dst]
    set value2 "ALPHA_OP($dst_name)"
    return "$value2=$value"
}


proc pretty_print_value { reg_name value } {
global CODE
    if { [ regexp {^(R200_PS_C0.)} $reg_name {} prefix] } {
	return [pretty_print_value_$prefix $reg_name $value]
    }

    if { [ regexp {^(R200_PS_A0.)} $reg_name {} prefix] } {
	return [pretty_print_value_$prefix $reg_name $value]
    }

    if { [ regexp {^(R200_PS_C1.)} $reg_name {} prefix] } {
	return [pretty_print_value_$prefix $reg_name $value]
    }

    if { [ regexp {^(R200_PS_A1.)} $reg_name {} prefix] } {
	return [pretty_print_value_$prefix $reg_name $value]
    }
	
if { [regexp {^(R300_PFS_INSTR.)} $reg_name {} prefix] } {
	# Call special procedure to pretty print instructions with this prefix
	return [pretty_print_value_$prefix $reg_name $value]
	}
if { [regexp {\{expr (.*)\}} $reg_name {} expression ] } {
	if { [regexp {_FL(.*)$} $reg_name ] } {
		binary scan [binary format i 0x$value] f f
		set valuef [format %f $f]
		puts $CODE "\tefloat($expression);  /* $valuef = 0x$value */"
		return $valuef
		}
	puts $CODE "\te32($expression);  /* 0x$value */"
	return $value
	}
if { [regexp {_FL(.*)$} $reg_name ] } {
	binary scan [binary format i 0x$value] f f
	set valuef [format %f $f]
	puts $CODE "\tefloat($valuef);  /* $valuef = 0x$value */"
	return $valuef
	}
puts $CODE "\te32(0x$value);"
return $value
}

proc pretty_print_packet0 { addr same count values } {
global CODE
if { $count == 0 } {
	set reg_name [name_register $addr]
	regexp {^([^( ]*)($| |\()} $reg_name {} short_name
	puts $CODE "e32(CP_PACKET0($short_name,0));"
	puts "packet0 $reg_name=[pretty_print_value $reg_name $values]"
	} {
	puts "packet0 $same"
	if { $same } {
		set reg_name [name_register $addr]
		regexp {^([^( ]*)($| |\()} $reg_name {} short_name
		puts $CODE "e32(CP_PACKET0($short_name,$count) | ($same << 15));"
		} {
		puts $CODE "e32(CP_PACKET0(0x[format %x $addr],$count));"
		}
	for { set i 0 } { $i <= $count } { incr i } {
		 set name [name_register [expr $addr+(1-$same)*$i*4]]
		 if { ! $same } {
			 puts $CODE "\t/* $name */"
			 }
		 puts "\t$name=[pretty_print_value $name [lindex $values $i]]"
		 }
	}
puts $CODE ""
}

proc pretty_print_packet3 { opcode body } {
global CODE
# More of these can be obtained from radeon_reg.h from DRM/XFree86 driver
set reg 0
set off 0
switch -exact $opcode {
	10 { set name "NOP"}
	28 { set name "CONTEXT_CONTROL"}
	2d { set name "DRAW_INDEX_AUTO"}
	2f { set name "DRAW_NUM_INSTANCES"}
	32 { set name "INDIRECT_BUFFER_PRIV"}
	3c { set name "WAIT_REG_MEM"}
	43 { set name "SURFACE_SYNC"}
	46 { set name "EVENT_WRITE"}
	47 { set name "EVENT_WRITE_EOP"}
	62 { set name "LOAD_ALU_CONST" }
	63 { set name "LOAD_BOOL_CONST" }
	64 { set name "LOAD_LOOP_CONST" }
	68 { set name "CONFIG" 
		set reg [lrange $body 0 0]
		set off 0x8000}
	69 { set name "CONTEXT" 
		set reg [lrange $body 0 0] 
		set off 0x28000 }
	6a { set name "SET_ALU_CONST" }
	6d { set name "SET_RESOURCE" }
	6e { set name "SAMPLER" }
	6f { set name "CTL_CONST" }
	default { set name $opcode }
	}

if { $reg != "00000000" } { 
	set rreg [expr (0x$reg << 2) + $off]
	set rest [lrange $body 1 end]
	puts "packet3 $name [format %x $rreg] {$rest}"
	foreach value $rest {
		puts "[format %x $rreg] = 0x$value"
		set rreg [expr $rreg + 4]
	} } { puts "packet3 $name {$body}" }
regexp {^([^ ]*)($| )} $name {} short_name
puts $CODE "e32(RADEON_CP_PACKET3_$short_name | ([expr [llength $body]-1]<<16));"
foreach value $body {
	puts $CODE "\te32(0x$value);"
	}
puts $CODE ""
#if { $name == "NOP" } { wrap_up }
}

proc wrap_up {} {
global REG_NAMES HEADER CODE

puts $HEADER {#ifndef __REGISTERS_H__
#define __REGISTERS_H__

/*

#
# Registers with name starting with X are those
# that were not described in the documentation, the name is made up.
#
# Some registers not beginning with X were also guessed (or taken from R200
# documentation) before I started using X convention
#
#
# Registers that end with FL take 32bit floats as values.
# Remember - they are just guesses, sometimes just because they happen to be
# close to something with seemingly floating point value and have 0 written in them.
#
#
# Registers with names starting with XG were generated automatically
#
#

*/

}

set L {}
foreach {addr name} [array get REG_NAMES] {
	lappend L [list $name 0x$addr]
	}

foreach pair [lsort -integer -index 1 $L] {
	set name [lindex $pair 0]
	set addr [lindex $pair 1]
	regexp {^([^ ]*)( |$)} $name {} short_name
	puts $HEADER "#define $short_name\t\t$addr"
	}
puts $HEADER {

#endif /* __REGISTERS_H__ */
}
close $HEADER
# {
puts $CODE "}"
close $CODE
exit
}

while { ! [eof $FILE] } {
	gets $FILE s
	set header [expr 0x$s]
	set type [expr $header >> 30]
	set count [expr ($header >> 16) & 0x3ff]
	if { $s == "00000000" } { wrap_up }
	if { $type == 0 } {
		set reg [expr ($header & 0x1fff) *4]
		set same [expr ($header >> 15) & 1]
		set values {}
		for { set i 0 } { $i <= $count } { incr i } {
			gets $FILE s
			lappend values $s
			}
		pretty_print_packet0 $reg $same $count $values
		} \
	elseif { $type ==1 } {
		set reg1 [expr ($header & 0x7ff) *4 ]
		set reg2 [expr (($header>>11) & 0x7ff) *4 ]
		gets $FILE val1
		gets $FILE val2
		set name1 [name_register $reg1]
		set name2 [name_register $reg2]
		regexp {^([^( ]*)($| |\()} $name1 {} short_name1
		regexp {^([^( ]*)($| |\()} $name2 {} short_name2
		puts "packet$type $name1=$val1 $name2=$val2"
		puts $CODE "e32(CP_PACKET1($short_name1, $short_name2));"
		puts $CODE "\te32(0x$val1);"
		puts $CODE "\te32(0x$val2);\n"
		} \
	elseif { $type ==2 } {
		puts "filler (packet2)"
		puts $CODE "e32(RADEON_CP_PACKET2);\n"
		} {
		set opcode [format %02x [expr ($header >> 8) & 0xff]]
		set body {}
		for { set i 0 } { $i <= $count } { incr i } {
			gets $FILE s
			lappend body $s
			}
		pretty_print_packet3 $opcode $body
		}

	}

close $FILE

