Compare commits

...

3 Commits

Author SHA1 Message Date
06f4c14181 regs: add pvs_disassemble 2025-10-11 17:55:04 -05:00
18772f0976 add triangle.c 2025-10-11 17:55:04 -05:00
66dca90a98 3d_registers: generate address-to-string lookup table 2025-10-11 17:54:52 -05:00
16 changed files with 643 additions and 60 deletions

View File

@ -170,12 +170,12 @@
#define VAP_VF_CNTL 0x2084 #define VAP_VF_CNTL 0x2084
#define VAP_VF_MAX_VTX_INDX 0x2134 #define VAP_VF_MAX_VTX_INDX 0x2134
#define VAP_VF_MIN_VTX_INDX 0x2138 #define VAP_VF_MIN_VTX_INDX 0x2138
#define VAP_VPORT_XOFFSET 0x1d9c, #define VAP_VPORT_XOFFSET 0x1d9c
#define VAP_VPORT_XSCALE 0x1d98, #define VAP_VPORT_XSCALE 0x1d98
#define VAP_VPORT_YOFFSET 0x1da4, #define VAP_VPORT_YOFFSET 0x1da4
#define VAP_VPORT_YSCALE 0x1da0, #define VAP_VPORT_YSCALE 0x1da0
#define VAP_VPORT_ZOFFSET 0x1dac, #define VAP_VPORT_ZOFFSET 0x1dac
#define VAP_VPORT_ZSCALE 0x1da8, #define VAP_VPORT_ZSCALE 0x1da8
#define VAP_VTE_CNTL 0x20b0 #define VAP_VTE_CNTL 0x20b0
#define VAP_VTX_NUM_ARRAYS 0x20c0 #define VAP_VTX_NUM_ARRAYS 0x20c0
#define VAP_VTX_SIZE 0x204b #define VAP_VTX_SIZE 0x204b

21
pci/3d_registers2.h Normal file
View File

@ -0,0 +1,21 @@
#define VAP_PVS_FLOW_CNTL_ADDRS_LW_0 0x2500
#define VAP_PVS_FLOW_CNTL_ADDRS_UW_0 0x2504
#define VAP_PVS_FLOW_CNTL_LOOP_INDEX_0 0x2290
#define RS_IP_0 0x4074
#define RS_INST_0 0x4320
#define VAP_OUTPUT_VTX_FMT_0 0x2090
#define VAP_OUTPUT_VTX_FMT_1 0x2094
#define VAP_PROG_STREAM_CNTL_0 0x2150
#define VAP_PROG_STREAM_CNTL_EXT_0 0x21e0
#define US_OUT_FMT_0 0x46a4
#define US_OUT_FMT_1 0x46a8
#define US_OUT_FMT_2 0x46ac
#define US_OUT_FMT_3 0x46b0
#define RB3D_COLOROFFSET0 0x4e28
#define RB3D_COLORPITCH0 0x4e38

View File

@ -5,6 +5,7 @@
#include <linux/aperture.h> #include <linux/aperture.h>
#include "3d_registers.h" #include "3d_registers.h"
#include "3d_registers2.h"
#include "undocumented_3d_registers.h" #include "undocumented_3d_registers.h"
#define R500 "r500" #define R500 "r500"
@ -64,6 +65,8 @@ static inline uint32_t rreg(void __iomem * rmmio, uint32_t reg)
#define bswap32 __builtin_bswap32 #define bswap32 __builtin_bswap32
#include "triangle.c"
static const uint8_t _cp_data[] __attribute__((aligned (4))) = { static const uint8_t _cp_data[] __attribute__((aligned (4))) = {
0x00,0x00,0x00,0x00,0x42,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0xe0,0x00, 0x00,0x00,0x00,0x00,0x42,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0xe0,0x00,
0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x99,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x9d, 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x99,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x9d,
@ -370,11 +373,28 @@ static int r500_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mb(); mb();
wreg(rmmio, 0x1000, 0xdeadbeef); wreg(rmmio, 0x1000, 0xdeadbeef);
mb(); mb();
for (int i = 0; i < 3; i++) {
wreg(rmmio, 0x1000, 0xc0001000); // NOP
mb();
wreg(rmmio, 0x1000, 0);
mb();
}
mdelay(1); mdelay(1);
scratch = rreg(rmmio, SCRATCH_REG0); scratch = rreg(rmmio, SCRATCH_REG0);
printk(KERN_INFO "[r500] SCRATCH_REG0 2 %08x\n", scratch); printk(KERN_INFO "[r500] SCRATCH_REG0 2 %08x\n", scratch);
mdelay(100);
triangle(rmmio);
mdelay(100);
RM(GA_IDLE);
RM(VAP_CNTL_STATUS);
RM(CP_STAT);
if (0) { if (0) {
wreg(rmmio, CP_CSQ_CNTL, 1); // Primary PIO, Indirect Disabled wreg(rmmio, CP_CSQ_CNTL, 1); // Primary PIO, Indirect Disabled
wreg(rmmio, CP_CSQ_MODE, (1 << 30) | (1 << 31)); // Primary PIO, Indirect Disabled wreg(rmmio, CP_CSQ_MODE, (1 << 30) | (1 << 31)); // Primary PIO, Indirect Disabled
@ -403,12 +423,12 @@ static int r500_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
(void)rreg(rmmio, CP_RB_WPTR); (void)rreg(rmmio, CP_RB_WPTR);
udelay(500); udelay(500);
uint32_t scratch_reg0_2 = rreg(rmmio, SCRATCH_REG0);
printk(KERN_INFO "[r500] SCRATCH_REG0 2 %08x\n", scratch_reg0_2);
} }
uint32_t scratch_reg0_2 = rreg(rmmio, SCRATCH_REG0); if (0) {
printk(KERN_INFO "[r500] SCRATCH_REG0 2 %08x\n", scratch_reg0_2);
if (1) {
// GB_PIPE_SELECT // GB_PIPE_SELECT
// GB_TILE_CONFIG // GB_TILE_CONFIG
// GA_SOFT_RESET // GA_SOFT_RESET
@ -455,7 +475,7 @@ static int r500_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
printk(KERN_INFO "[r500] SCRATCH_REG0 3 %08x\n", scratch_reg03); printk(KERN_INFO "[r500] SCRATCH_REG0 3 %08x\n", scratch_reg03);
} }
if (0) { if (1) {
uint32_t tmp; uint32_t tmp;
tmp = rreg(rmmio, 0xf8); tmp = rreg(rmmio, 0xf8);
printk(KERN_INFO "CONFIG_MEMSIZE 0x%08x\n", tmp); printk(KERN_INFO "CONFIG_MEMSIZE 0x%08x\n", tmp);

275
pci/triangle.c Normal file
View File

@ -0,0 +1,275 @@
#define WM(offset, value) \
do { \
wreg(rmmio, offset, value); \
mb(); \
mdelay(1); \
printk(KERN_INFO "[r500] %s %08x\n", #offset, value); \
} while (0);
#define RM(offset) \
do { \
printk(KERN_INFO "[r500] %s %08x\n", #offset, rreg(rmmio, offset)); \
} while (0);
static void triangle(void __iomem * rmmio)
{
// r300_emit_gpu_flush
WM(SC_SCISSOR0, 0);
uint32_t sc_scissor1 = ((1600 - 1) << 13) | ((1600 - 1) << 0);
WM(SC_SCISSOR1, sc_scissor1);
WM(RB3D_DSTCACHE_CTLSTAT, 0xa); // DC_FLUSH | DC_FREE
WM(ZB_ZCACHE_CTLSTAT, 0x3); // ZC_FLUSH | ZC_FREE
mb();
mdelay(100);
// r300_emit_aa_state
WM(GB_AA_CONFIG, 0);
WM(RB3D_AARESOLVE_CTL, 0);
// r300_emit_fb_state
WM(RB3D_CCTL, 0x4000); // INDEPENDENT_COLORFORMAT_ENABLE
WM(RB3D_COLOROFFSET0, 0);
mb();
uint32_t rb3d_colorpitch0
= (1600 << 0) // COLORPITCH
| (1 << 16) // COLORTILE (is macrotiled)
| (6 << 21) // COLORFORMAT (ARGB8888)
;
WM(RB3D_COLORPITCH0, rb3d_colorpitch0);
mb();
WM(ZB_FORMAT, 2); // 24-bit integer, 8 bit stencil
WM(ZB_DEPTHOFFSET, 0);
mb();
uint32_t zb_depthpitch
= (1600 << 0)
| (1 << 16) // DEPTHMACROTILE
| (0b01 << 17) // DEPTHMICROTILE (32 byte cache line is tiled)
;
WM(ZB_DEPTHPITCH, zb_depthpitch);
mb();
// r300_emit_hyperz_state
WM(ZB_BW_CNTL, 0);
WM(ZB_DEPTHCLEARVALUE, 0);
WM(SC_HYPERZ_EN, 0x1c); // HZ_ADJ (add or subtract 1/2)
WM(GB_Z_PEQ_CONFIG, 0);
// r300_emit_ztop_state
WM(ZB_ZTOP, 1); // Z is at top of pipe, after the scan unit
// r300_emit_dsa_state
WM(FG_ALPHA_FUNC, 0);
WM(ZB_CNTL, 0);
WM(ZB_ZSTENCILCNTL, 0);
WM(ZB_STENCILREFMASK, 0);
WM(ZB_STENCILREFMASK_BF, 0);
WM(FG_ALPHA_VALUE, 0);
// r300_emit_blend_state
WM(RB3D_ROPCNTL, 0);
WM(RB3D_BLENDCNTL, 0);
WM(RB3D_ABLENDCNTL, 0);
WM(RB3D_COLOR_CHANNEL_MASK, 0xf); // BLUE_MASK | GREEN_MASK | RED_MASK | ALPHA_MASK
WM(RB3D_DITHER_CTL, 0);
// r300_emit_blend_color_state
WM(RB3D_CONSTANT_COLOR_AR, 0);
WM(RB3D_CONSTANT_COLOR_GB, 0);
// r300_emit_scissor_state
WM(SC_CLIP_0_A, 0);
WM(SC_CLIP_0_B, 0x3ffffff);
// r300_emit_sample_mask
WM(SC_SCREENDOOR, 0xffffff);
// r300_emit_invariant_state
WM(GB_SELECT, 0);
WM(FG_FOG_BLEND, 0);
WM(GA_OFFSET, 0);
WM(SU_TEX_WRAP, 0);
WM(SU_DEPTH_SCALE, 0x4b7fffff); // 16777215.0f
WM(SU_DEPTH_OFFSET, 0);
WM(SC_EDGERULE, 0x2da49525);
WM(RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD, 0x1010101);
WM(RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD, 0xfefefefe);
WM(GA_COLOR_CONTROL_PS3, 0);
WM(SU_TEX_WRAP_PS3, 0);
// r300_emit_viewport_state
WM(VAP_VPORT_XSCALE, 0x44160000); // 600.0f
WM(VAP_VPORT_XOFFSET, 0x44480000); // 800.0f
WM(VAP_VPORT_YSCALE, 0xc4160000); // -600.0f
WM(VAP_VPORT_YOFFSET, 0x44160000); // 600.0f
WM(VAP_VPORT_ZSCALE, 0x3f000000); // 0.5f
WM(VAP_VPORT_ZOFFSET, 0x3f000000); // 0.5f
// r300_emit_pvs_flush
WM(VAP_PVS_STATE_FLUSH_REG, 0);
// r300_emit_vap_invariant_state
WM(VAP_PVS_VTX_TIMEOUT_REG, 0xffff);
WM(VAP_GB_VERT_CLIP_ADJ, 0x3f800000); // 1.0f
WM(VAP_GB_VERT_DISC_ADJ, 0x3f800000); // 1.0f
WM(VAP_GB_HORZ_CLIP_ADJ, 0x3f800000); // 1.0f
WM(VAP_GB_HORZ_DISC_ADJ, 0x3f800000); // 1.0f
WM(VAP_PSC_SGN_NORM_CNTL, 0xaaaaaaaa); // SGN_NORM_NO_ZERO
WM(VAP_TEX_TO_COLOR_CNTL, 0);
// r300_emit_vertex_stream_state
WM(VAP_PROG_STREAM_CNTL_0, 0x2002); // DATA_TYPE_0(FLOAT_3) | LAST_VEC_0
/*
= SWIZZLE_SELECT_X_0(SELECT_X)
| SWIZZLE_SELECT_Y_0(SELECT_Y)
| SWIZZLE_SELECT_Z_0(SELECT_Z)
| SWIZZLE_SELECT_W_0(SELECT_FP_ONE)
| WRITE_ENA_0(XYZW)
*/
WM(VAP_PROG_STREAM_CNTL_EXT_0, 0xfa88);
// r300_emit_vs_state
WM(VAP_PVS_CODE_CNTL_0, 0);
WM(VAP_PVS_CODE_CNTL_1, 0);
WM(VAP_PVS_VECTOR_INDX_REG, 0);
const uint32_t vertex_program[] = {0xf00203, 0xd10001, 0x1248001, 0x1248001};
for (int i = 0; i < (sizeof (vertex_program)) / (sizeof (vertex_program[0])); i++) {
wreg(rmmio, VAP_PVS_VECTOR_DATA_REG_128, vertex_program[i]);
mb();
}
/*
= PVS_NUM_SLOTS(10)
| PVS_NUM_CNTLRS(5)
| PVS_NUM_FPUS(5)
| VF_MAX_VTX_NUM(12)
| TCL_STATE_OPTIMIZATION
*/
WM(VAP_CNTL, 0xb0055a);
WM(VAP_PVS_FLOW_CNTL_OPC, 0);
for (int i = 0; i < 16; i++) {
wreg(rmmio, VAP_PVS_FLOW_CNTL_ADDRS_LW_0 + i * 8, 0);
wreg(rmmio, VAP_PVS_FLOW_CNTL_ADDRS_UW_0 + i * 8, 0);
mb();
}
for (int i = 0; i < 16; i++) {
wreg(rmmio, VAP_PVS_FLOW_CNTL_LOOP_INDEX_0 + i * 4, 0);
mb();
}
// r300_emit_clip_state
WM(VAP_PVS_VECTOR_INDX_REG, 0x600);
for (int i = 0; i < 128; i++) {
wreg(rmmio, VAP_PVS_VECTOR_DATA_REG_128, 0);
mb();
}
// r300_emit_rs_block_stat
WM(VAP_VTX_STATE_CNTL, 0x5555); // Select User Color 0
WM(VAP_VSM_VTX_ASSM, 0x1);
WM(VAP_OUTPUT_VTX_FMT_0, 0x1); // output position vector
WM(VAP_OUTPUT_VTX_FMT_1, 0x4); // TEX_0_COMP_CNT(4)
WM(GB_ENABLE, 0);
WM(RS_IP_0, 0x30000000); // Zero components (0,0,0,1)
WM(RS_COUNT, 0x40080); // IC_COUNT(1) | HIRES_EN
WM(RS_INST_COUNT, 0);
WM(RS_INST_0, 0);
// r300_emit_rs_state
WM(VAP_CNTL_STATUS, 0);
WM(VAP_CLIP_CNTL, 0xc000); // PS_UCP_MODE(3)
WM(GA_POINT_SIZE, 0x60006);
WM(GA_POINT_MINMAX, 0x60006);
WM(GA_LINE_CNTL, 0x20006);
WM(SU_POLY_OFFSET_ENABLE, 0);
WM(SU_CULL_MODE, 0);
WM(GA_LINE_STIPPLE_CONFIG, 0);
WM(GA_LINE_STIPPLE_VALUE, 0);
WM(GA_POLY_MODE, 0);
WM(GA_ROUND_MODE, 0x31); // round to nearest | RGB_CLAMP | ALPHA_CLAMP
WM(SC_CLIP_RULE, 0xffff);
WM(GA_POINT_S0, 0); // 0.0f
WM(GA_POINT_T0, 0x3f800000); // 1.0f
WM(GA_POINT_S1, 0x3f800000); // 1.0f
WM(GA_POINT_T1, 0); // 0.0f
// r300_emit_fb_state_pipelined
//
WM(US_OUT_FMT_0, 0x1b00); // C4_8 | C0_SEL(Blue) | C1_SEL(Green) | C2_SEL(Red) | C3_SEL(Alpha)
WM(US_OUT_FMT_1, 0xf); // unused
WM(US_OUT_FMT_2, 0xf); // unused
WM(US_OUT_FMT_3, 0xf); // unused
WM(GB_MSPOS0, 0x66666666);
WM(GB_MSPOS0, 0x6666666);
// r500_emit_fs
WM(US_CONFIG, 0x2); // Legacy behavior for shader model 1
WM(US_PIXSIZE, 1);
WM(US_FC_CTRL, 0);
WM(US_CODE_RANGE, 0);
WM(US_CODE_OFFSET, 0);
WM(US_CODE_ADDR, 0);
WM(GA_US_VECTOR_INDEX, 0);
const uint32_t fragment_program[] = {0x78005, 0x8020080, 0x8020080, 0x1c9b04d8, 0x1c810003, 0x5};
for (int i = 0; i < (sizeof (fragment_program)) / (sizeof (fragment_program[0])); i++) {
wreg(rmmio, GA_US_VECTOR_DATA, fragment_program[i]);
mb();
}
WM(FG_DEPTH_SRC, 0);
WM(US_W_FMT, 0);
// r300_emit_vs_constants
WM(VAP_PVS_CONST_CNTL, 0);
// r300_emit_texture_cache_inval
WM(TX_INVALTAGS, 0);
// r300_emit_textures_state
WM(TX_ENABLE, 0);
// r500_emit_index_bias
WM(VAP_INDEX_OFFSET, 0);
// r300_emit_draw_init
WM(GA_COLOR_CONTROL, 0x3aaaa); // gouraud shading | provoking is always last vertex
WM(VAP_VF_MAX_VTX_INDX, 2);
WM(VAP_VF_MIN_VTX_INDX, 0);
// r300_draw_arrays_immediate
WM(VAP_VTX_SIZE, 3);
const float vertices[] = {
0.5, -0.5, 0,
-0.5, -0.5, 0,
0, 0.5, 0,
};
#define _3D_DRAW_IMMD_2 (0x35)
#define NOP (0x10)
#define TYPE_3_PACKET(opcode, count) \
((3 << 30) | ((count) << 16) | (opcode << 8))
printk(KERN_INFO "[r500] draw start\n");
wreg(rmmio, 0x1000, TYPE_3_PACKET(_3D_DRAW_IMMD_2, (3 * 3)));
mb();
mdelay(1);
wreg(rmmio, 0x1000, 0x30034); // VAP_VF_CNTL
mb();
mdelay(1);
const uint32_t * vertices_u32 = (const uint32_t *)vertices;
for (int i = 0; i < 9; i++) {
wreg(rmmio, 0x1000, vertices_u32[i]);
mb();
mdelay(1);
}
wreg(rmmio, 0x1000, TYPE_3_PACKET(NOP, 4 - 1));
mb();
mdelay(1);
for (int i = 0; i < 4; i++) {
wreg(rmmio, 0x1000, 0);
mb();
mdelay(1);
}
printk(KERN_INFO "[r500] draw end\n");
WM(0x6110, 0xe0000000);
}

View File

@ -16,3 +16,5 @@
#define RBBM_SOFT_RESET_IDCT (1 << 14) #define RBBM_SOFT_RESET_IDCT (1 << 14)
#define SCRATCH_REG0 0x15e0 #define SCRATCH_REG0 0x15e0
#define VAP_VSM_VTX_ASSM 0x2184

3
regs/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
pvs_dst.py
pvs_src.py
pvs_dst_bits.py

View File

@ -1,9 +1,91 @@
with open('3d_registers.txt') as f: with open('3d_registers.txt') as f:
lines = f.read().split('\n') lines = f.read().split('\n')
for line in lines: def parse_reg_value(value):
if not line.strip(): if '-' in value:
continue start, end = value.split('-')
reg_name = line.split(':')[1].split(' ')[0] return int(start, 16), int(end, 16)
reg_value = line.split('MMReg:')[1] else:
print("#define", reg_name, reg_value) return int(value, 16)
def reg_name_value(lines):
for line in lines:
if not line.strip():
continue
reg_name = line.split(':')[1].split(' ')[0]
reg_value = line.split(' MMReg:')[1:]
for value in reg_value:
yield reg_name, parse_reg_value(value.removesuffix(','))
#for reg_name, reg_value in reg_name_value(lines):
# print("#define", reg_name, reg_value)
aos_order_table = [
"VTX_AOS_ATTR01",
"VTX_AOS_ADDR0",
"VTX_AOS_ADDR1",
"VTX_AOS_ATTR23",
"VTX_AOS_ADDR2",
"VTX_AOS_ADDR3",
"VTX_AOS_ATTR45",
"VTX_AOS_ADDR4",
"VTX_AOS_ADDR5",
"VTX_AOS_ATTR67",
"VTX_AOS_ADDR6",
"VTX_AOS_ADDR7",
"VTX_AOS_ATTR89",
"VTX_AOS_ADDR8",
"VTX_AOS_ADDR8",
"VTX_AOS_ATTR1011",
"VTX_AOS_ADDR10",
"VTX_AOS_ADDR11",
"VTX_AOS_ATTR1213",
"VTX_AOS_ADDR12",
"VTX_AOS_ADDR13",
"VTX_AOS_ATTR1415",
"VTX_AOS_ADDR14",
"VTX_AOS_ADDR15",
]
print("registers_lookup = {")
for reg_name, reg_value in reg_name_value(lines):
if type(reg_value) is int:
print(f' 0x{reg_value:04x}: "{reg_name}",')
else:
start, end = reg_value
if '[' not in reg_name:
offset = start
while offset <= end:
ix = (offset - start) // 4
print(f' 0x{offset:04x}: "{reg_name}[{ix}]",')
offset += 4
else:
reg_basename = reg_name.split('[')[0]
index_range = reg_name.split('[')[1].split(']')[0]
start_ix, end_ix = map(int, index_range.split('-'))
offset_increment = 4
if (end - start) // 4 != end_ix - start_ix:
# guess the offset increment
if start + end_ix * 8 == end:
offset_increment = 8
elif start + end_ix * 16 == end:
offset_increment = 16
elif reg_basename == 'VAP_VTX_AOS_ADDR':
pass
elif reg_basename == 'VAP_VTX_AOS_ATTR':
for i, name in enumerate(aos_order_table):
print(f' 0x{i * 4 + start}: "{name}",')
continue
else:
print(reg_name, reg_value)
assert False
offset = start
while offset <= end:
ix = (offset - start) // offset_increment
print(f' 0x{offset:04x}: "{reg_basename}{ix}",')
offset += offset_increment
print('}')

View File

@ -214,7 +214,7 @@ VAP:VAP_VTE_CNTL · [R/W] · 32 bits · Access: 32 · MMReg:0x20b0
VAP:VAP_VTX_AOS_ADDR[0-15] · [R/W] · 32 bits · Access: 32 · MMReg:0x20c8-0x2120 VAP:VAP_VTX_AOS_ADDR[0-15] · [R/W] · 32 bits · Access: 32 · MMReg:0x20c8-0x2120
VAP:VAP_VTX_AOS_ATTR[01-1415] · [R/W] · 32 bits · Access: 32 · MMReg:0x20c4-0x2118 VAP:VAP_VTX_AOS_ATTR[01-1415] · [R/W] · 32 bits · Access: 32 · MMReg:0x20c4-0x2118
VAP:VAP_VTX_NUM_ARRAYS · [R/W] · 32 bits · Access: 32 · MMReg:0x20c0 VAP:VAP_VTX_NUM_ARRAYS · [R/W] · 32 bits · Access: 32 · MMReg:0x20c0
VAP:VAP_VTX_SIZE · [R/W] · 32 bits · Access: 32 · MMReg:0x204b VAP:VAP_VTX_SIZE · [R/W] · 32 bits · Access: 32 · MMReg:0x20b4
VAP:VAP_VTX_STATE_CNTL · [R/W] · 32 bits · Access: 32 · MMReg:0x2180 VAP:VAP_VTX_STATE_CNTL · [R/W] · 32 bits · Access: 32 · MMReg:0x2180
VAP:VAP_VTX_ST_BLND_WT_[0-3] · [R/W] · 32 bits · Access: 32 · MMReg:0x2430-0x243c VAP:VAP_VTX_ST_BLND_WT_[0-3] · [R/W] · 32 bits · Access: 32 · MMReg:0x2430-0x243c
VAP:VAP_VTX_ST_CLR_[0-7]_A · [R/W] · 32 bits · Access: 32 · MMReg:0x232c-0x239c VAP:VAP_VTX_ST_CLR_[0-7]_A · [R/W] · 32 bits · Access: 32 · MMReg:0x232c-0x239c

5
regs/build.sh Normal file
View File

@ -0,0 +1,5 @@
set -eux
python parse_pvs.py PVS_DST pvs_opcode_and_destination_operand.txt > pvs_dst.py
python parse_pvs.py PVS_SRC pvs_source_operand.txt > pvs_src.py
python parse_pvs_bits.py regs/pvs_opcode_and_destination_operand_bits.txt > pvs_dst_bits.py

85
regs/parse_pvs.py Normal file
View File

@ -0,0 +1,85 @@
import sys
from typing import Union
import re
from dataclasses import dataclass
from pprint import pprint
def split_line_fields(line):
fields = [0, 22, 30]
a = line[fields[0]:fields[1]]
b = line[fields[1]:fields[2]]
c = line[fields[2]:]
return a, b, c
def parse_file_fields(filename):
with open(filename) as f:
lines = f.read().split('\n')
first, *rest = lines
a, b, c = split_line_fields(first)
assert a.rstrip() == 'Field Name', a
assert b.rstrip() == 'Bits', b
assert c.rstrip() == 'Description', c
for line in rest:
if not line.strip():
continue
a, b, c = split_line_fields(line)
yield a.strip(), b.strip(), c.strip()
def parse_bits(s):
if ':' in s:
a, b = s.split(':')
h = int(a, 10)
l = int(b, 10)
assert h > l
return h, l
else:
b = int(s, 10)
return b
def parse_file_fields2(filename):
for line in parse_file_fields(filename):
field_name, bits, description = line
bits = parse_bits(bits)
if not field_name.startswith(prefix + '_'):
assert field_name.startswith("SPARE_")
continue
field_name = field_name.removeprefix(prefix + '_')
yield field_name, bits, description
def out(level, *args):
sys.stdout.write(" " * level + " ".join(args) + '\n')
def mask_from_bits(bits):
if type(bits) is tuple:
high, low = bits
assert high > low, (high, low)
else:
high = bits
low = bits
length = (high - low) + 1
return (1 << length) - 1
def low_from_bits(bits):
if type(bits) is tuple:
return bits[1]
else:
return bits
def generate_python(prefix, fields):
#out(0, f"class {prefix}:")
fields = list(fields)
for field_name, bits, description in fields:
#out(1, f"@staticmethod")
out(0, f"def {field_name}(n):")
out(1, f"return (n >> {low_from_bits(bits)}) & {mask_from_bits(bits)}")
out(0, "")
out(0, "table = [")
for field_name, bits, description in fields:
out(1, f'("{field_name}", {field_name}),')
out(0, "]")
prefix = sys.argv[1]
filename = sys.argv[2]
generate_python(prefix, parse_file_fields2(filename))

30
regs/parse_pvs_bits.py Normal file
View File

@ -0,0 +1,30 @@
import sys
with open(sys.argv[1]) as f:
lines = f.read().strip().split('\n')
ix = 0
def next_ix():
global ix
while not lines[ix].strip():
ix += 1
return ix
while ix < len(lines):
name = lines[next_ix()]
assert name.strip().endswith(":")
name = name.strip().removesuffix(":")
ix += 1
print(f"{name} = {{")
while ix < len(lines) and not lines[next_ix()].strip().endswith(":"):
key, value = lines[next_ix()].split("=")
if key.startswith("PVS_DST_REG_"):
key = key.removeprefix("PVS_DST_REG_")
print(f' {value.strip()}: "{key.strip()}",')
ix += 1
print("}")
print()

55
regs/pvs_disassemble.py Normal file
View File

@ -0,0 +1,55 @@
import pvs_src
import pvs_dst
import pvs_dst_bits
from pprint import pprint
code = [
0xf00203,
0xd10001,
0x1248001,
0x1248001
]
def out(level, *args):
sys.stdout.write(" " * level + " ".join(args))
def parse_code(code):
ix = 0
pvs_dst_maxlen = max(len(k) for k, _ in pvs_dst.table)
print(pvs_dst_maxlen)
while ix < len(code):
print(f"ix: {ix // 4}")
dst_op = code[ix + 0]
src_op0 = code[ix + 1]
src_op1 = code[ix + 2]
src_op2 = code[ix + 3]
print(f" dst: {dst_op:08x}")
for name, parse in pvs_dst.table:
namepad = name.ljust(pvs_dst_maxlen + 1)
value = parse(dst_op)
if name == "OPCODE":
if pvs_dst.MATH_INST(dst_op):
print(" ", namepad, pvs_dst_bits.MATH_OPCODE[value])
else:
print(" ", namepad, pvs_dst_bits.VECTOR_OPCODE[value])
elif name == "REG_TYPE":
print(" ", namepad, pvs_dst_bits.PVS_DST_REG[value])
else:
print(" ", namepad, value)
print(f" src0: {src_op0:08x}")
for name, parse in pvs_src.table:
print(" ", name, parse(src_op0))
print(f" src1: {src_op1:08x}")
for name, parse in pvs_src.table:
print(" ", name, parse(src_op1))
print(f" src2: {src_op2:08x}")
for name, parse in pvs_src.table:
print(" ", name, parse(src_op2))
ix += 4
parse_code(code)

View File

@ -2,10 +2,7 @@ Field Name Bit(s) Description
PVS_SRC_REG_TYPE 1:0 Defines the Memory Select (Register Type) for the Source Operand. See Below. PVS_SRC_REG_TYPE 1:0 Defines the Memory Select (Register Type) for the Source Operand. See Below.
PVS_DST_OPCODE_MSB 2 Math Opcode MSB for Dual Math Inst. PVS_DST_OPCODE_MSB 2 Math Opcode MSB for Dual Math Inst.
PVS_SRC_ABS_XYZW 3 If set, Take absolute value of both components of Dual Math input vector. PVS_SRC_ABS_XYZW 3 If set, Take absolute value of both components of Dual Math input vector.
PVS_SRC_ADDR_MODE_0 4 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE as follows: PVS_SRC_ADDR_MODE_0 4 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE
0 = Absolute addressing
1 = Relative addressing using A0 register
2 = Relative addressing using I0 register (loop index)
PVS_SRC_OFFSET 12:5 Vector Offset into selected memory (Register Type) PVS_SRC_OFFSET 12:5 Vector Offset into selected memory (Register Type)
PVS_SRC_SWIZZLE_X 15:13 X-Component Swizzle Select. See Below PVS_SRC_SWIZZLE_X 15:13 X-Component Swizzle Select. See Below
PVS_SRC_SWIZZLE_Y 18:16 Y-Component Swizzle Select. See Below PVS_SRC_SWIZZLE_Y 18:16 Y-Component Swizzle Select. See Below
@ -15,7 +12,4 @@ PVS_SRC_MODIFIER_X 25 If set, Negate X Component of input vector.
PVS_SRC_MODIFIER_Y 26 If set, Negate Y Component of input vector. PVS_SRC_MODIFIER_Y 26 If set, Negate Y Component of input vector.
PVS_DST_WE_SEL 28:27 Encoded Write Enable for Dual Math Op Inst (0 = X, 1 = Y, 2 = Z, 3 = W) PVS_DST_WE_SEL 28:27 Encoded Write Enable for Dual Math Op Inst (0 = X, 1 = Y, 2 = Z, 3 = W)
PVS_SRC_ADDR_SEL 30:29 When PVS_SRC_ADDR_MODE is set, this selects which component of the 4-component address register to use. PVS_SRC_ADDR_SEL 30:29 When PVS_SRC_ADDR_MODE is set, this selects which component of the 4-component address register to use.
PVS_SRC_ADDR_MODE_1 31 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE as follows: PVS_SRC_ADDR_MODE_1 31 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE
0 = Absolute addressing
1 = Relative addressing using A0 register
2 = Relative addressing using I0 register (loop index)

View File

@ -1,18 +1,18 @@
Field Name Bits Description Field Name Bits Description
PVS_DST_OPCODE 5:0 Selects the Operation which is to be performed. PVS_DST_OPCODE 5:0 Selects the Operation which is to be performed.
PVS_DST_MATH_INST 6 Specifies a Math Engine Operation PVS_DST_MATH_INST 6 Specifies a Math Engine Operation
PVS_DST_MACRO_INST 7 Specifies a Macro Operation PVS_DST_MACRO_INST 7 Specifies a Macro Operation
PVS_DST_REG_TYPE 11:8 Defines the Memory Select (Register Type) for the Dest Operand. PVS_DST_REG_TYPE 11:8 Defines the Memory Select (Register Type) for the Dest Operand.
PVS_DST_ADDR_MODE_1 12 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE PVS_DST_ADDR_MODE_1 12 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE
PVS_DST_OFFSET 20 Vector Offset into the Selected Memory PVS_DST_OFFSET 19:13 Vector Offset into the Selected Memory
PVS_DST_WE_X 21 Write Enable for X Component PVS_DST_WE_X 20 Write Enable for X Component
PVS_DST_WE_Y 22 Write Enable for Y Component PVS_DST_WE_Y 21 Write Enable for Y Component
PVS_DST_WE_Z 23 Write Enable for Z Component PVS_DST_WE_Z 22 Write Enable for Z Component
PVS_DST_WE_W 24 Write Enable for W Component PVS_DST_WE_W 23 Write Enable for W Component
PVS_DST_VE_SAT 19:13 Vector engine operation is saturate clamped between 0 and 1 (all components) PVS_DST_VE_SAT 24 Vector engine operation is saturate clamped between 0 and 1 (all components)
PVS_DST_ME_SAT 25 Math engine operation is saturate clamped between 0 and 1 (all components) PVS_DST_ME_SAT 25 Math engine operation is saturate clamped between 0 and 1 (all components)
PVS_DST_PRED_ENABLE 26 Operation is predicated – Operation writes if predicate bit matches predicate sense. PVS_DST_PRED_ENABLE 26 Operation is predicated – Operation writes if predicate bit matches predicate sense.
PVS_DST_PRED_SENSE 27 Operation predication sense – If set, operation writes if predicate bit is set. If reset, operation writes if predicate bit is reset. PVS_DST_PRED_SENSE 27 Operation predication sense – If set, operation writes if predicate bit is set. If reset, operation writes if predicate bit is reset.
PVS_DST_DUAL_MATH_OP 28 Set to describe a dual-math op. PVS_DST_DUAL_MATH_OP 28 Set to describe a dual-math op.
PVS_DST_ADDR_SEL 30:29 When PVS_DST_ADDR_MODE is set, this selects which component of the 4-component address register to use. PVS_DST_ADDR_SEL 30:29 When PVS_DST_ADDR_MODE is set, this selects which component of the 4-component address register to use.
PVS_DST_ADDR_MODE_0 31 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE PVS_DST_ADDR_MODE_0 31 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE

View File

@ -58,3 +58,14 @@ ME_PRED_SET_CLR = 25
ME_PRED_SET_INV = 26 ME_PRED_SET_INV = 26
ME_PRED_SET_POP = 27 ME_PRED_SET_POP = 27
ME_PRED_SET_RESTORE = 28 ME_PRED_SET_RESTORE = 28
PVS_DST_REG:
PVS_DST_REG_TEMPORARY = 0
PVS_DST_REG_A0 = 1
PVS_DST_REG_OUT = 2
PVS_DST_REG_OUT_REPL_X = 3
PVS_DST_REG_ALT_TEMPORARY = 4
PVS_DST_REG_INPUT = 5
ADDR_MODE:
ABSOLUTE = 0
RELATIVE_A0 = 1
RELATIVE_I0 = 2

View File

@ -1,16 +1,16 @@
Field Name Bit(s) Description Field Name Bits Description
PVS_SRC_REG_TYPE 1:0 Defines the Memory Select (Register Type) for the Source Operand. See Below. PVS_SRC_REG_TYPE 1:0 Defines the Memory Select (Register Type) for the Source Operand. See Below.
SPARE_0 2 SPARE_0 2
PVS_SRC_ABS_XYZW 3 If set, Take absolute value of all 4 components of input vector. PVS_SRC_ABS_XYZW 3 If set, Take absolute value of all 4 components of input vector.
PVS_SRC_ADDR_MODE_0 4 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE PVS_SRC_ADDR_MODE_0 4 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE
PVS_SRC_OFFSET 12:5 Vector Offset into selected memory (Register Type) PVS_SRC_OFFSET 12:5 Vector Offset into selected memory (Register Type)
PVS_SRC_SWIZZLE_X 15:13 X-Component Swizzle Select. See Below PVS_SRC_SWIZZLE_X 15:13 X-Component Swizzle Select. See Below
PVS_SRC_SWIZZLE_Y 18:16 Y-Component Swizzle Select. See Below PVS_SRC_SWIZZLE_Y 18:16 Y-Component Swizzle Select. See Below
PVS_SRC_SWIZZLE_Z 21:19 Z-Component Swizzle Select. See Below PVS_SRC_SWIZZLE_Z 21:19 Z-Component Swizzle Select. See Below
PVS_SRC_SWIZZLE_W 24:22 W-Component Swizzle Select. See Below PVS_SRC_SWIZZLE_W 24:22 W-Component Swizzle Select. See Below
PVS_SRC_MODIFIER_X 25 If set, Negate X Component of input vector. PVS_SRC_MODIFIER_X 25 If set, Negate X Component of input vector.
PVS_SRC_MODIFIER_Y 26 If set, Negate Y Component of input vector. PVS_SRC_MODIFIER_Y 26 If set, Negate Y Component of input vector.
PVS_SRC_MODIFIER_Z 27 If set, Negate Z Component of input vector. PVS_SRC_MODIFIER_Z 27 If set, Negate Z Component of input vector.
PVS_SRC_MODIFIER_W 28 If set, Negate W Component of input vector. PVS_SRC_MODIFIER_W 28 If set, Negate W Component of input vector.
PVS_SRC_ADDR_SEL 30:29 When PVS_SRC_ADDR_MODE is set, this selects which component of the 4-component address register to use. PVS_SRC_ADDR_SEL 30:29 When PVS_SRC_ADDR_MODE is set, this selects which component of the 4-component address register to use.
PVS_SRC_ADDR_MODE_1 31 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE PVS_SRC_ADDR_MODE_1 31 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE