GPU/Shader Instruction Set
Overview
A compiled shader binary is comprised of two parts : the main instruction sequence and the operand descriptor table. These are both sent to the GPU around the same time but using separate GPU Commands. Instructions (such as format 1 instruction) may reference operand descriptors. When such is the case, the operand descriptor ID is the offset, in words, of the descriptor within the table. Both instructions and descriptors are coded in little endian. [1] includes a basic implementation of the following specification.
Instruction formats
Format 1 : (used for register instructions)
Offset | Size | Description |
---|---|---|
0x0 | 0x6 | Operand descriptor ID (DESC) |
0x6 | 0x6 | Source 1 register (SRC2) |
0xC | 0x6 | Source 2 register (SRC1) |
0x12 | 0x2 | Flags |
0x24 | 0x2 | Destination register (DST) |
0x1A | 0x6 | Opcode |
Format 2 : (used for flow control instructions)
Offset | Size | Description |
---|---|---|
0x0 | 0x8 | Number of instructions ? (NUM) |
0x8 | 0x10? | Destination offset (DST) |
0x1A | 0x6 | Opcode |
Instructions
Opcode | Format | Name | Description |
---|---|---|---|
0x01 | 1 | DP3 | Computes dot product on 3-component vectors; DST = SRC1.SRC2 |
0x02 | 1 | DP4 | Computes dot product on 4-component vectors; DST = SRC1.SRC2 |
0x13 | 1 | MOV | Moves value from one register to another; DST = SRC1 |
0x24 | 2 | CALL | Jumps to DST and executes NUM instructions |
0x21 | 1 | END2 | ? |
0x22 | 1 | END1 | ? |
Operand descriptors
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | Destination component mask. Bit 3 = x, 2 = y, 1 = z, 0 = w. |
0x5 | 0x8 | Source 1 component selector |
0x14 | 0x8 | Source 2 component selector |
0x1F | 0x1 | Flag |
Component selector :
Offset | Size | Description |
---|---|---|
0x0 | 0x2 | Component 3 value |
0x2 | 0x2 | Component 2 value |
0x4 | 0x2 | Component 1 value |
0x6 | 0x2 | Component 0 value |
Value | Component |
---|---|
0x0 | x |
0x1 | y |
0x2 | z |
0x3 | w |
The component selector enables swizzling. For example, component selector 0x1B is equivalent to .xyzw, while 0x55 is equivalent to .yyyy.
Registers
It is not yet fully understood how registers are organized. It does however seem that registers are separated into various banks, some RO, some WO and some RW. Because of this separation, a given register ID may not refer to the same register value when it is used as SRC or as DST. Since the PICA200 does not support fragment shaders, WO registers are fixed function.
RO registers :
Register ID | Description |
---|---|
0x0 | vertex.position |
0x1 | vertex.texcoord ? |
0x4 | vertex.color ? |
0x6 | vertex.color ? |
WO registers :
Register ID | Description |
---|---|
0x0 | result.position |
0x2 | result.texcoord ? |
0x4 | result.color ? |
0x6 | result.texcoord ? |
(these are mostly guesses aside from vertex.position and result.position)
Registers within the 0x20-0x40 ranges seem to be RW. They are often used to access matrix data.