Compare commits

..

8 Commits

33 changed files with 84593 additions and 828 deletions

4
drm/clear.fs.asm Normal file
View File

@ -0,0 +1,4 @@
OUT TEX_SEM_WAIT
:
out[0].a = MAX src0.1 src0.1 ,
out[0].rgb = MAX src0.000 src0.000 ;

7
drm/clear.fs.inc Normal file
View File

@ -0,0 +1,7 @@
0x00078005,
0x08020080,
0x08020080,
0x00920490,
0x00c18003,
0x00000005,

View File

@ -0,0 +1,58 @@
-- CONST[0] = {theta1, theta2, 0.159155, 0.5}
-- CONST[1] = {6.283185, -3.141593, 0.2, 0.5}
-- ME_SIN and ME_COS clamp their inputs to [-π,+π] prior to the sin/cos
-- calculation.
--
-- This 3-instruction sequence remaps the range [-,+] to [-π,+π]
temp[0].xy = VE_MAD const[0].xy__ const[0].zz__ const[0].ww__ ;
temp[0].xy = VE_FRC temp[0].xy__ ;
temp[0].xy = VE_MAD temp[0].xy__ const[1].xx__ const[1].yy__ ;
-- sin and cos
temp[3].x = ME_SIN temp[0].___x ;
temp[3].y = ME_COS temp[0].___x ;
alt_temp[3].z = ME_SIN temp[0].___y ;
-- temp[3] now contains:
-- temp[3] = {sin(theta1), cos(theta1), sin(theta2), cos(theta2)}
-------------------------------------------------------------------------
-- first rotation: X-axis rotation:
-------------------------------------------------------------------------
-- y_ = (-z0 * st1)
-- z_ = ( z0 * ct1)
temp[1].yz = VE_MUL input[0]._-zz_ temp[3]._xy_ ,
alt_temp[3].w = ME_COS temp[0].y_ ;
-- x1 = (x0 * 1 + 0)
-- y1 = (y0 * ct1 + nz0st1)
-- z1 = (y0 * st1 + z0ct1)
temp[1].xyz = VE_MAD input[0].xyy_ temp[3].1yx_ temp[1].0yz_ ;
-------------------------------------------------------------------------
-- second rotation: Y-axis rotation:
-------------------------------------------------------------------------
-- x_ = (-z1 * st2)
-- z_ = ( z1 * ct2)
temp[2].xz = VE_MUL temp[1].-z_z_ alt_temp[3].z_w_ ;
-- x2 = (x1 * ct2 + nz1st2)
-- y2 = (y1 * 1 + 0)
-- z2 = (x1 * st2 + z1ct2)
temp[2].xyz = VE_MAD temp[1].xyx_ alt_temp[3].w1z_ temp[2].x0z_ ;
-------------------------------------------------------------------------
-- scale
-------------------------------------------------------------------------
temp[3].xyz = VE_MAD temp[2].xyz_ const[1].zzz_ const[1].00w_ ;
-------------------------------------------------------------------------
-- output
-------------------------------------------------------------------------
out[0].xyzw = VE_MUL temp[3].xyzz temp[3].11-z1 ;
out[1].xyzw = VE_ADD input[1].xyzw input[1].0000 ;

View File

@ -0,0 +1,13 @@
0x00300004, 0x01f90002, 0x01fa4002, 0x01fb6002,
0x00300006, 0x01f90000, 0x01ffe000, 0x01ffe000,
0x00300004, 0x01f90000, 0x01f80022, 0x01f92022,
0x00106050, 0x003fe000, 0x01ffe000, 0x01ffe000,
0x00206051, 0x003fe000, 0x01ffe000, 0x01ffe000,
0x00806451, 0x007fe000, 0x01ffe000, 0x01ffe000,
0x10602002, 0x05d2e001, 0x01c8e060, 0x10192004,
0x00702004, 0x01c90001, 0x01c1a060, 0x01d18020,
0x00504002, 0x03d74020, 0x01df4063, 0x01ffe063,
0x00704080, 0x01c10020, 0x01d56060, 0x01d40040,
0x00706004, 0x01d10040, 0x01d24022, 0x01dc8022,
0x00f00202, 0x00910060, 0x0955a060, 0x01ffe060,
0x00f02203, 0x00d10021, 0x01248021, 0x01ffe021,

1177
drm/pumpkin_man.c Normal file

File diff suppressed because it is too large Load Diff

67
drm/pumpkin_man.vs.asm Normal file
View File

@ -0,0 +1,67 @@
-- CONST[0] = {0.159155, 0.5, 6.283185, -3.141593}
-- CONST[1] = {theta1, theta2, 0.2, 0.5}
-- CONST[2] = {1.33333, 0, 0, 0}
-- each instruction is only allowed to use a single unique `const` address
--
-- instructions may use multiple `temp` addresses, so const[1] is moved to
-- temp[0]:
--
temp[0].xy = VE_ADD const[1].xy__ const[1].00__ ;
-- ME_SIN and ME_COS clamp their inputs to [-π,+π] prior to the sin/cos
-- calculation.
--
-- This 3-instruction sequence remaps the range [-,+] to [-π,+π]
temp[0].xy = VE_MAD temp[0].xy__ const[0].xx__ const[0].yy__ ;
temp[0].xy = VE_FRC temp[0].xy__ ;
temp[0].xy = VE_MAD temp[0].xy__ const[0].zz__ const[0].ww__ ;
-- sin and cos
temp[3].x = ME_SIN temp[0].___x ;
temp[3].y = ME_COS temp[0].___x ;
temp[3].z = ME_SIN temp[0].___y ;
temp[3].w = ME_COS temp[0].___y ;
-- temp[3] now contains:
-- temp[3] = {sin(theta1), cos(theta1), sin(theta2), cos(theta2)}
-------------------------------------------------------------------------
-- first rotation: X-axis rotation:
-------------------------------------------------------------------------
-- y_ = (-z0 * st1)
-- z_ = ( z0 * ct1)
temp[1].yz = VE_MUL input[0]._-zz_ temp[3]._xy_ ;
-- x1 = (x0 * 1 + 0)
-- y1 = (y0 * ct1 + nz0st1)
-- z1 = (y0 * st1 + z0ct1)
temp[1].xyz = VE_MAD input[0].xyy_ temp[3].1yx_ temp[1].0yz_ ;
-------------------------------------------------------------------------
-- second rotation: Y-axis rotation:
-------------------------------------------------------------------------
-- x_ = (-z1 * st2)
-- z_ = ( z1 * ct2)
temp[2].xz = VE_MUL temp[1].-z_z_ temp[3].z_w_ ;
-- x2 = (x1 * ct2 + nz1st2)
-- y2 = (y1 * 1 + 0)
-- z2 = (x1 * st2 + z1ct2)
temp[2].xyz = VE_MAD temp[1].xyx_ temp[3].w1z_ temp[2].x0z_ ;
-------------------------------------------------------------------------
-- scale
-------------------------------------------------------------------------
temp[3].xyz = VE_MAD temp[2].xyz_ const[1].zzz_ const[1].00w_ ;
temp[3].x = VE_MUL temp[3].x___ const[2].x___;
-------------------------------------------------------------------------
-- output
-------------------------------------------------------------------------
out[0].xyzw = VE_MUL temp[3].xyzz temp[3].11-z1 ;
out[1].xyzw = VE_ADD input[1].xyzw input[1].0000 ;

16
drm/pumpkin_man.vs.inc Normal file
View File

@ -0,0 +1,16 @@
0x00300003, 0x01f90022, 0x01fc8022, 0x01ffe022,
0x00300004, 0x01f90000, 0x01f80002, 0x01f92002,
0x00300006, 0x01f90000, 0x01ffe000, 0x01ffe000,
0x00300004, 0x01f90000, 0x01fa4002, 0x01fb6002,
0x00106050, 0x003fe000, 0x01ffe000, 0x01ffe000,
0x00206051, 0x003fe000, 0x01ffe000, 0x01ffe000,
0x00406050, 0x007fe000, 0x01ffe000, 0x01ffe000,
0x00806051, 0x007fe000, 0x01ffe000, 0x01ffe000,
0x00602002, 0x05d2e001, 0x01c8e060, 0x01ffe060,
0x00702004, 0x01c90001, 0x01c1a060, 0x01d18020,
0x00504002, 0x03d74020, 0x01df4060, 0x01ffe060,
0x00704080, 0x01c10020, 0x01d56060, 0x01d40040,
0x00706004, 0x01d10040, 0x01d24022, 0x01dc8022,
0x00106002, 0x01ff0060, 0x01ff0042, 0x01ffe042,
0x00f02203, 0x00d10021, 0x01248021, 0x01ffe021,
0x00f00202, 0x00910060, 0x0955a060, 0x01ffe060,

View File

@ -50,4 +50,3 @@ src0.a = temp[0] ,
src0.rgb = temp[0] : src0.rgb = temp[0] :
out[0].a = MAX src0.1 src0.1 , out[0].a = MAX src0.1 src0.1 ,
out[0].rgb = MAX src0.rgb src0.rgb ; out[0].rgb = MAX src0.rgb src0.rgb ;
,

View File

@ -20,11 +20,11 @@
0x00000000, 0x00000000,
0x00004000, 0x00004000,
0x08020080, 0x10320080,
0x0802f400, 0x0802f400,
0x00000000, 0x00000000,
0x0068c000, 0x0068c000,
0x20000000, 0x04000000,
0x00004000, 0x00004000,
0x08020080, 0x08020080,

7
drm/texture_cube.fs.asm Normal file
View File

@ -0,0 +1,7 @@
TEX TEX_SEM_WAIT TEX_SEM_ACQUIRE
temp[0].argb = LD tex[0].rgba temp[0].rgaa ;
OUT TEX_SEM_WAIT
src0.a = temp[0], src0.rgb = temp[0] :
out[0].a = MAX src0.a src0.a ,
out[0].rgb = MAX src0.rgb src0.rgb ;

14
drm/texture_cube.fs.inc Normal file
View File

@ -0,0 +1,14 @@
0x00007807,
0x02400000,
0xe400f400,
0x00000000,
0x00000000,
0x00000000,
0x00078005,
0x08020000,
0x08020000,
0x00440220,
0x0060c003,
0x00000005,

View File

@ -121,43 +121,13 @@ const face faces[] = {
static const int faces_length = (sizeof (faces)) / (sizeof (faces[0])); static const int faces_length = (sizeof (faces)) / (sizeof (faces[0]));
static const uint32_t fragment_shader[] = { static const uint32_t fragment_shader[] = {
#include "../shader_examples/mesa/texture_cube.fs.txt" #include "texture_cube.fs.inc"
// clear shader #include "clear.fs.inc"
US_CMN_INST__TYPE__US_INST_TYPE_OUT
| US_CMN_INST__TEX_SEM_WAIT(1)
| US_CMN_INST__RGB_OMASK__RGB
| US_CMN_INST__ALPHA_OMASK__A
, US_ALU_RGB_ADDR__ADDR0(128)
| US_ALU_RGB_ADDR__ADDR1(128)
| US_ALU_RGB_ADDR__ADDR2(128)
, US_ALU_ALPHA_ADDR__ADDR0(128)
| US_ALU_ALPHA_ADDR__ADDR1(128)
| US_ALU_ALPHA_ADDR__ADDR2(128)
, US_ALU_RGB_INST__RED_SWIZ_A__ZERO
| US_ALU_RGB_INST__GREEN_SWIZ_A__ZERO
| US_ALU_RGB_INST__BLUE_SWIZ_A__ZERO
| US_ALU_RGB_INST__RED_SWIZ_B__ZERO
| US_ALU_RGB_INST__GREEN_SWIZ_B__ZERO
| US_ALU_RGB_INST__BLUE_SWIZ_B__ZERO
| US_ALU_RGB_INST__OMOD(7)
| US_ALU_RGB_INST__TARGET__A
, US_ALU_ALPHA_INST__ALPHA_OP__OP_MAX
| US_ALU_ALPHA_INST__ALPHA_SWIZ_A__ONE
| US_ALU_ALPHA_INST__ALPHA_SWIZ_B__ONE
| US_ALU_ALPHA_INST__OMOD(7)
| US_ALU_ALPHA_INST__TARGET__A
, US_ALU_RGBA_INST__RGB_OP__OP_MAX
}; };
static const int fragment_shader_length = (sizeof (fragment_shader)) / (sizeof (fragment_shader[0])); static const int fragment_shader_length = (sizeof (fragment_shader)) / (sizeof (fragment_shader[0]));
static const int fragment_shader_instructions = (fragment_shader_length / 6) - 1; static const int fragment_shader_instructions = (fragment_shader_length / 6) - 1;
static const uint32_t vertex_shader[] = { static const uint32_t vertex_shader[] = {
//#include "../shader_examples/mesa/texture_cube.vs.txt"
#include "cube_rotate.vs.inc" #include "cube_rotate.vs.inc"
#include "clear_nop.vs.inc" #include "clear_nop.vs.inc"
}; };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -347,30 +347,26 @@ int indirect_buffer()
// ); // );
T0V(VAP_PROG_STREAM_CNTL_0 T0V(VAP_PROG_STREAM_CNTL_0
, VAP_PROG_STREAM_CNTL__DATA_TYPE_0(2) , VAP_PROG_STREAM_CNTL__DATA_TYPE_0__FLOAT_3
| VAP_PROG_STREAM_CNTL__SKIP_DWORDS_0(0) | VAP_PROG_STREAM_CNTL__SKIP_DWORDS_0(0)
| VAP_PROG_STREAM_CNTL__DST_VEC_LOC_0(0) | VAP_PROG_STREAM_CNTL__DST_VEC_LOC_0(0)
| VAP_PROG_STREAM_CNTL__LAST_VEC_0(0) | VAP_PROG_STREAM_CNTL__LAST_VEC_0(0)
| VAP_PROG_STREAM_CNTL__SIGNED_0(0) | VAP_PROG_STREAM_CNTL__DATA_TYPE_1__FLOAT_3
| VAP_PROG_STREAM_CNTL__NORMALIZE_0(0)
| VAP_PROG_STREAM_CNTL__DATA_TYPE_1(2)
| VAP_PROG_STREAM_CNTL__SKIP_DWORDS_1(0) | VAP_PROG_STREAM_CNTL__SKIP_DWORDS_1(0)
| VAP_PROG_STREAM_CNTL__DST_VEC_LOC_1(1) | VAP_PROG_STREAM_CNTL__DST_VEC_LOC_1(1)
| VAP_PROG_STREAM_CNTL__LAST_VEC_1(1) | VAP_PROG_STREAM_CNTL__LAST_VEC_1(1)
| VAP_PROG_STREAM_CNTL__SIGNED_1(0)
| VAP_PROG_STREAM_CNTL__NORMALIZE_1(0)
); );
T0V(VAP_PROG_STREAM_CNTL_EXT_0 T0V(VAP_PROG_STREAM_CNTL_EXT_0
, VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_X_0(0) , VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_X_0__SELECT_X
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Y_0(1) | VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Y_0__SELECT_Y
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Z_0(2) | VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Z_0__SELECT_Z
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_W_0(5) | VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_W_0__SELECT_FP_ONE
| VAP_PROG_STREAM_CNTL_EXT__WRITE_ENA_0(15) | VAP_PROG_STREAM_CNTL_EXT__WRITE_ENA_0(0b1111)
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_X_1(0) | VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_X_1__SELECT_X
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Y_1(1) | VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Y_1__SELECT_Y
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Z_1(2) | VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Z_1__SELECT_Z
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_W_1(5) | VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_W_1__SELECT_FP_ONE
| VAP_PROG_STREAM_CNTL_EXT__WRITE_ENA_1(15) | VAP_PROG_STREAM_CNTL_EXT__WRITE_ENA_1(0b1111)
); );
T0V(VAP_VSM_VTX_ASSM, 0x00000005); // undocumented T0V(VAP_VSM_VTX_ASSM, 0x00000005); // undocumented

66
model/model.h Normal file
View File

@ -0,0 +1,66 @@
#pragma once
struct vec3 {
float x;
float y;
float z;
};
struct vec2 {
float x;
float y;
};
typedef struct vec3 vertex_position;
typedef struct vec2 vertex_texture;
typedef struct vec3 vertex_normal;
struct index_ptn {
uint16_t position;
uint16_t texture;
uint16_t normal;
};
union triangle {
struct {
struct index_ptn a;
struct index_ptn b;
struct index_ptn c;
};
struct index_ptn v[3];
};
union quadrilateral {
struct {
struct index_ptn a;
struct index_ptn b;
struct index_ptn c;
struct index_ptn d;
};
struct index_ptn v[4];
};
union line {
struct {
int a;
int b;
};
int v[2];
};
struct object {
const union triangle * triangle;
const union quadrilateral * quadrilateral;
const union line * line;
const int triangle_count;
const int quadrilateral_count;
const int line_count;
const int material;
};
struct model {
const vertex_position * position;
const vertex_texture * texture;
const vertex_normal * normal;
const struct object ** object;
const int object_count;
};

79552
model/pumpkin/pumpkin.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,115 @@
from assembler.fs.keywords import KW
from assembler.fs.alu_validator import SrcAddrType, InstructionType
from assembler.fs.common_emitter import US_CMN_INST, US_ALU_RGB_ADDR, US_ALU_ALPHA_ADDR
from assembler.fs.common_emitter import US_ALU_RGB_INST, US_ALU_ALPHA_INST, US_ALU_RGBA_INST
def emit_alpha_op(code, alpha_op):
# dest
if alpha_op.dest.wmask is not None:
US_CMN_INST.ALPHA_WMASK(code, alpha_op.dest.wmask.value)
if alpha_op.dest.omask is not None:
US_CMN_INST.ALPHA_OMASK(code, alpha_op.dest.omask.value)
assert type(alpha_op.dest.addrd) is int
US_ALU_ALPHA_INST.ALPHA_ADDRD(code, alpha_op.dest.addrd)
# opcode
US_ALU_ALPHA_INST.ALPHA_OP(code, alpha_op.opcode.value)
# sels
srcs = [
US_ALU_ALPHA_INST.ALPHA_SEL_A,
US_ALU_ALPHA_INST.ALPHA_SEL_B,
US_ALU_RGBA_INST.ALPHA_SEL_C,
]
swizzles = [
[US_ALU_ALPHA_INST.ALPHA_SWIZ_A],
[US_ALU_ALPHA_INST.ALPHA_SWIZ_B],
[US_ALU_RGBA_INST.ALPHA_SWIZ_C],
]
mods = [
US_ALU_ALPHA_INST.ALPHA_MOD_A,
US_ALU_ALPHA_INST.ALPHA_MOD_B,
US_ALU_RGBA_INST.ALPHA_MOD_C,
]
for sel, src_func, swizzle_funcs, mod_func in zip(alpha_op.sels,
srcs, swizzles, mods):
src_func(code, sel.src.value)
assert len(sel.swizzle) == 1
assert len(swizzle_funcs) == 1
for swizzle_func, swizzle in zip(swizzle_funcs, sel.swizzle):
swizzle_func(code, swizzle.value)
mod_func(code, sel.mod.value)
def emit_rgb_op(code, rgb_op):
# dest
if rgb_op.dest.wmask is not None:
US_CMN_INST.RGB_WMASK(code, rgb_op.dest.wmask.value)
if rgb_op.dest.omask is not None:
US_CMN_INST.RGB_OMASK(code, rgb_op.dest.omask.value)
assert type(rgb_op.dest.addrd) is int
US_ALU_RGBA_INST.RGB_ADDRD(code, rgb_op.dest.addrd)
# opcode
US_ALU_RGBA_INST.RGB_OP(code, rgb_op.opcode.value)
# sels
srcs = [
US_ALU_RGB_INST.RGB_SEL_A,
US_ALU_RGB_INST.RGB_SEL_B,
US_ALU_RGBA_INST.RGB_SEL_C,
]
swizzles = [
[US_ALU_RGB_INST.RED_SWIZ_A, US_ALU_RGB_INST.GREEN_SWIZ_A, US_ALU_RGB_INST.BLUE_SWIZ_A],
[US_ALU_RGB_INST.RED_SWIZ_B, US_ALU_RGB_INST.GREEN_SWIZ_B, US_ALU_RGB_INST.BLUE_SWIZ_B],
[US_ALU_RGBA_INST.RED_SWIZ_C, US_ALU_RGBA_INST.GREEN_SWIZ_C, US_ALU_RGBA_INST.BLUE_SWIZ_C],
]
mods = [
US_ALU_RGB_INST.RGB_MOD_A,
US_ALU_RGB_INST.RGB_MOD_B,
US_ALU_RGBA_INST.RGB_MOD_C,
]
for sel, src_func, swizzle_funcs, mod_func in zip(rgb_op.sels,
srcs, swizzles, mods):
src_func(code, sel.src.value)
assert len(sel.swizzle) == 3
assert len(swizzle_funcs) == 3
for swizzle_func, swizzle in zip(swizzle_funcs, sel.swizzle):
swizzle_func(code, swizzle.value)
mod_func(code, sel.mod)
def emit_addr(code, addr):
srcs = [
(addr.alpha.src0 , US_ALU_ALPHA_ADDR.ADDR0 , US_ALU_ALPHA_ADDR.ADDR0_CONST),
(addr.alpha.src1 , US_ALU_ALPHA_ADDR.ADDR1 , US_ALU_ALPHA_ADDR.ADDR1_CONST),
(addr.alpha.src2 , US_ALU_ALPHA_ADDR.ADDR2 , US_ALU_ALPHA_ADDR.ADDR2_CONST),
(addr.rgb.src0 , US_ALU_RGB_ADDR.ADDR0 , US_ALU_RGB_ADDR.ADDR0_CONST),
(addr.rgb.src1 , US_ALU_RGB_ADDR.ADDR1 , US_ALU_RGB_ADDR.ADDR1_CONST),
(addr.rgb.src2 , US_ALU_RGB_ADDR.ADDR2 , US_ALU_RGB_ADDR.ADDR2_CONST),
]
for src, ADDR, ADDR_CONST in srcs:
if src is not None:
is_const = int(src.type is SrcAddrType.const)
is_float = int(src.type is SrcAddrType.float)
ADDR(code, (is_float << 7) | src.value)
ADDR_CONST(code, is_const)
else:
ADDR(code, (1 << 7) | 0)
if addr.alpha.srcp is not None:
US_ALU_ALPHA_ADDR.SRCP_OP(code, addr.alpha.srcp.value)
if addr.rgb.srcp is not None:
US_ALU_RGB_ADDR.SRCP_OP(code, addr.rgb.srcp.value)
def emit_instruction(code, ins):
US_CMN_INST.TYPE(code, InstructionType.OUT if KW.OUT in ins.tags else InstructionType.ALU)
US_CMN_INST.TEX_SEM_WAIT(code, int(KW.TEX_SEM_WAIT in ins.tags))
US_CMN_INST.LAST(code, int(KW.LAST in ins.tags))
US_CMN_INST.NOP(code, int(KW.NOP in ins.tags))
US_CMN_INST.ALU_WAIT(code, int(KW.ALU_WAIT in ins.tags))
emit_addr(code, ins.addr)
if ins.alpha_op is not None:
emit_alpha_op(code, ins.alpha_op)
if ins.rgb_op is not None:
emit_rgb_op(code, ins.rgb_op)

View File

@ -0,0 +1,490 @@
from pprint import pprint
from dataclasses import dataclass
from enum import Enum, IntEnum, auto
from collections import OrderedDict
from typing import Union
from assembler.fs.parser import ALUMod
from assembler.fs.keywords import _keyword_to_string, KW
from assembler.error import print_error
from assembler.validator import ValidatorError
from assembler.fs.common_validator import RGBMask, AlphaMask, InstructionType
from assembler.fs.common_validator import validate_identifier_number, validate_dest_keyword, keywords_to_string
class SrcAddrType(Enum):
temp = auto()
const = auto()
float = auto()
@dataclass
class SrcAddr:
type: SrcAddrType
value: int
class SrcMod(IntEnum):
nop = 0
neg = 1
abs = 2
nab = 3
class SrcpOp(IntEnum):
neg2 = 0
sub = 1
add = 2
neg = 3
@dataclass
class Addr:
src0: SrcAddr = None
src1: SrcAddr = None
src2: SrcAddr = None
srcp: SrcpOp = None
@dataclass
class AddrRGBAlpha:
alpha: Addr
rgb: Addr
class Unit(Enum):
alpha = auto()
rgb = auto()
class RGBOp(IntEnum):
MAD = 0
DP3 = 1
DP4 = 2
D2A = 3
MIN = 4
MAX = 5
CND = 7
CMP = 8
FRC = 9
SOP = 10
MDH = 11
MDV = 12
class AlphaOp(IntEnum):
MAD = 0
DP = 1
MIN = 2
MAX = 3
CND = 5
CMP = 6
FRC = 7
EX2 = 8
LN2 = 9
RCP = 10
RSQ = 11
SIN = 12
COS = 13
MDH = 14
MDV = 15
@dataclass
class RGBDest:
addrd: int
wmask: RGBMask
omask: RGBMask
@dataclass
class AlphaDest:
addrd: int
wmask: AlphaMask
omask: AlphaMask
class SwizzleSelSrc(IntEnum):
src0 = 0
src1 = 1
src2 = 2
srcp = 3
class Swizzle(IntEnum):
r = 0
g = 1
b = 2
a = 3
zero = 4
half = 5
one = 6
unused = 7
@dataclass
class SwizzleSel:
src: SwizzleSelSrc
swizzle: list[Swizzle]
mod: ALUMod
@dataclass
class AlphaOperation:
dest: AlphaDest
opcode: AlphaOp
sels: list[SwizzleSel]
@dataclass
class RGBOperation:
dest: RGBDest
opcode: RGBOp
sels: list[SwizzleSel]
@dataclass
class Instruction:
tags: set[Union[KW.OUT, KW.TEX_SEM_WAIT, KW.NOP]]
addr: Addr
alpha_op: AlphaOperation
rgb_op: RGBOperation
def validate_instruction_let_expressions(let_expressions):
src_keywords = [KW.SRC0, KW.SRC1, KW.SRC2, KW.SRCP]
src_keyword_strs = keywords_to_string(src_keywords)
rgb_alpha_swizzles = [b"rgb", b"a"]
addr_rgb_alpha = AddrRGBAlpha(Addr(), Addr())
def set_src_by_keyword(addr, keyword, value):
if keyword == KW.SRC0:
addr.src0 = value
elif keyword == KW.SRC1:
addr.src1 = value
elif keyword == KW.SRC2:
addr.src2 = value
elif keyword == KW.SRCP:
addr.srcp = value
else:
assert False, keyword
def src_value(expr, src):
if src in {KW.SRC0, KW.SRC1, KW.SRC2}:
keyword_to_src_addr_type = OrderedDict([
(KW.TEMP, SrcAddrType.temp),
(KW.CONST, SrcAddrType.const),
(KW.FLOAT, SrcAddrType.float),
])
src_addr_type_strs = keywords_to_string(keyword_to_src_addr_type.keys())
type_kw = expr.addr_keyword.keyword
if type_kw not in keyword_to_src_addr_type:
raise ValidatorError(f"invalid src addr type, expected one of {src_addr_type_strs}", expr.addr_keyword)
type = keyword_to_src_addr_type[type_kw]
value = validate_identifier_number(expr.addr_value_identifier)
if type is SrcAddrType.float:
if value >= 128:
raise ValidatorError(f"invalid float value", expr.addr_value_identifier)
elif type is SrcAddrType.temp:
if value >= 128:
raise ValidatorError(f"invalid temp value", expr.addr_value_identifier)
elif type is SrcAddrType.const:
if value >= 256:
raise ValidatorError(f"invalid const value", expr.addr_value_identifier)
else:
assert False, (id(type), id(SrcAddrType.float))
return SrcAddr(
type,
value,
)
elif src == KW.SRCP:
keyword_to_srcp_op = OrderedDict([
(KW.NEG2, SrcpOp.neg2),
(KW.SUB, SrcpOp.sub),
(KW.ADD, SrcpOp.add),
(KW.NEG, SrcpOp.neg),
])
srcp_op_strs = keywords_to_string(keyword_to_srcp_op.keys())
op = expr.addr_keyword.keyword
if op not in keyword_to_srcp_op:
raise ValidatorError(f"invalid srcp op, expected one of {srcp_op_strs}", expr.addr_keyword)
return keyword_to_srcp_op[op]
else:
assert False, src
sources = set()
for expr in let_expressions:
src = expr.src_keyword.keyword
if src not in src_keywords:
raise ValidatorError(f"invalid src keyword, expected one of {src_keyword_strs}", expr.src_keyword)
src_swizzle = expr.src_swizzle_identifier.lexeme.lower()
if src_swizzle not in rgb_alpha_swizzles:
raise ValidatorError(f"invalid src swizzle, expected one of {rgb_alpha_swizzles}", expr.src_swizzle_identifier)
source = (_keyword_to_string[src].lower(), src_swizzle)
if source in sources:
raise ValidatorError(f"duplicate source/swizzle in let expressions", expr.src_swizzle_identifier)
sources.add(source)
value = src_value(expr, src)
if src_swizzle == b"a":
set_src_by_keyword(addr_rgb_alpha.alpha, src, value)
elif src_swizzle == b"rgb":
set_src_by_keyword(addr_rgb_alpha.rgb, src, value)
else:
assert False, src_swizzle
return addr_rgb_alpha
def prevalidate_mask(dest_addr_swizzle, valid_masks):
# we don't know yet whether this is an Alpha operation or an RGB operation
swizzle_str = dest_addr_swizzle.swizzle_identifier.lexeme
if swizzle_str.lower() not in valid_masks:
raise ValidatorError(f"invalid write mask, expected one of {valid_masks}", dest_addr_swizzle.swizzle_identifier)
mask = swizzle_str.lower()
return mask
rgb_op_kws = OrderedDict([
(KW.MAD, RGBOp.MAD),
(KW.DP3, RGBOp.DP3),
(KW.DP4, RGBOp.DP4),
(KW.D2A, RGBOp.D2A),
(KW.MIN, RGBOp.MIN),
(KW.MAX, RGBOp.MAX),
(KW.CND, RGBOp.CND),
(KW.CMP, RGBOp.CMP),
(KW.FRC, RGBOp.FRC),
(KW.SOP, RGBOp.SOP),
(KW.MDH, RGBOp.MDH),
(KW.MDV, RGBOp.MDV)
])
alpha_op_kws = OrderedDict([
(KW.MAD, AlphaOp.MAD),
(KW.DP, AlphaOp.DP),
(KW.MIN, AlphaOp.MIN),
(KW.MAX, AlphaOp.MAX),
(KW.CND, AlphaOp.CND),
(KW.CMP, AlphaOp.CMP),
(KW.FRC, AlphaOp.FRC),
(KW.EX2, AlphaOp.EX2),
(KW.LN2, AlphaOp.LN2),
(KW.RCP, AlphaOp.RCP),
(KW.RSQ, AlphaOp.RSQ),
(KW.SIN, AlphaOp.SIN),
(KW.COS, AlphaOp.COS),
(KW.MDH, AlphaOp.MDH),
(KW.MDV, AlphaOp.MDV)
])
rgb_masks = OrderedDict([
(b"none" , RGBMask.NONE),
(b"r" , RGBMask.R),
(b"g" , RGBMask.G),
(b"rg" , RGBMask.RG),
(b"b" , RGBMask.B),
(b"rb" , RGBMask.RB),
(b"gb" , RGBMask.GB),
(b"rgb" , RGBMask.RGB),
])
alpha_masks = OrderedDict([
(b"none" , AlphaMask.NONE),
(b"a" , AlphaMask.A),
])
alpha_only_ops = set(alpha_op_kws.keys()) - set(rgb_op_kws.keys())
rgb_only_ops = set(rgb_op_kws.keys()) - set(alpha_op_kws.keys())
all_ops = set(rgb_op_kws.keys()) | set(alpha_op_kws.keys())
alpha_only_masks = set(alpha_masks.keys()) - set(rgb_masks.keys())
rgb_only_masks = set(rgb_masks.keys()) - set(alpha_masks.keys())
all_masks = set(rgb_masks.keys()) | set(alpha_masks.keys())
def infer_operation_units(operations):
if len(operations) > 2:
raise ValidatorError("too many operations in instruction", operations[-1].opcode_keyword)
units = [None, None]
for i, operation in enumerate(operations):
opcode = operation.opcode_keyword.keyword
if opcode not in all_ops:
raise ValidatorError(f"invalid opcode keyword, expected one of {all_ops}", operation.opcode_keyword)
if len(operation.dest_addr_swizzles) > 2:
raise ValidationError("too many destinations in instruction", operation.dest_addr_swizzles[-1])
masks = set(prevalidate_mask(dest_addr_swizzle, all_masks) for dest_addr_swizzle in operation.dest_addr_swizzles)
def infer_opcode_unit():
if opcode in alpha_only_ops:
return Unit.alpha
if opcode in rgb_only_ops:
return Unit.rgb
return None
def infer_mask_unit():
if any(mask in alpha_only_masks for mask in masks):
return Unit.alpha
if any(mask in rgb_only_masks for mask in masks):
return Unit.rgb
return None
opcode_unit = infer_opcode_unit()
mask_unit = infer_mask_unit()
if opcode_unit is not None and mask_unit is not None and opcode_unit != mask_unit:
raise ValidatorError(f"contradictory {mask_unit.name} write mask for {opcode_unit.name} opcode", operation.opcode_keyword)
units[i] = opcode_unit or mask_unit
if units[0] == units[1]:
raise ValidatorError(f"invalid duplicate use of {units[1].name} unit", operations[1].opcode_keyword)
other_unit = {
Unit.alpha: Unit.rgb,
Unit.rgb: Unit.alpha,
}
if units[0] is None:
units[0] = other_unit[units[1]]
if units[1] is None:
units[1] = other_unit[units[0]]
assert units[0] is not None
assert units[1] is not None
assert units[0] != units[1]
for i, operation in enumerate(operations):
yield units[i], operation
def validate_instruction_operation_dest(dest_addr_swizzles, mask_lookup, type_cls):
addrs = set()
wmask = None
omask = None
for dest_addr_swizzle in dest_addr_swizzles:
dest = validate_dest_keyword(dest_addr_swizzle.dest_keyword)
addr = validate_identifier_number(dest_addr_swizzle.addr_identifier)
mask = mask_lookup[dest_addr_swizzle.swizzle_identifier.lexeme.lower()]
addrs.add(addr)
if dest == KW.OUT:
omask = mask
elif dest == KW.TEMP:
wmask = mask
else:
assert False, dest
if len(addrs) > 1:
raise ValidatorError(f"too many destination addresses", operation.dest_addr_swizzles[-1].addr_identifier)
addrd, = addrs if addrs else [0]
return type_cls(
addrd=addrd,
wmask=wmask,
omask=omask
)
swizzle_sel_src_kws = OrderedDict([
(KW.SRC0, SwizzleSelSrc.src0),
(KW.SRC1, SwizzleSelSrc.src1),
(KW.SRC2, SwizzleSelSrc.src2),
(KW.SRCP, SwizzleSelSrc.srcp),
])
swizzle_kws = OrderedDict([
(ord("r"), Swizzle.r),
(ord("g"), Swizzle.g),
(ord("b"), Swizzle.b),
(ord("a"), Swizzle.a),
(ord("0"), Swizzle.zero),
(ord("h"), Swizzle.half),
(ord("1"), Swizzle.one),
(ord("_"), Swizzle.unused),
])
def validate_instruction_operation_sels(swizzle_sels, is_alpha):
if len(swizzle_sels) > 3:
raise ValidatorError("too many swizzle sels", swizzle_sels[-1].sel_keyword)
sels = []
for swizzle_sel in swizzle_sels:
if swizzle_sel.sel_keyword.keyword not in swizzle_sel_src_kws:
raise ValidatorError("invalid swizzle src", swizzle_sel.sel_keyword.keyword)
src = swizzle_sel_src_kws[swizzle_sel.sel_keyword.keyword]
swizzle_lexeme = swizzle_sel.swizzle_identifier.lexeme.lower()
swizzles_length = 1 if is_alpha else 3
if len(swizzle_lexeme) != swizzles_length:
raise ValidatorError("invalid swizzle length", swizzle_sel.swizzle_identifier)
if not all(c in swizzle_kws for c in swizzle_lexeme):
raise ValidatorError("invalid swizzle characters", swizzle_sel.swizzle_identifier)
swizzle = [
swizzle_kws[c] for c in swizzle_lexeme
]
mod = swizzle_sel.mod
sels.append(SwizzleSel(src, swizzle, mod))
return sels
def validate_alpha_instruction_operation(operation):
dest = validate_instruction_operation_dest(operation.dest_addr_swizzles,
mask_lookup=alpha_masks,
type_cls=AlphaDest)
opcode = alpha_op_kws[operation.opcode_keyword.keyword]
sels = validate_instruction_operation_sels(operation.swizzle_sels, is_alpha=True)
return AlphaOperation(
dest,
opcode,
sels
)
def validate_rgb_instruction_operation(operation):
dest = validate_instruction_operation_dest(operation.dest_addr_swizzles,
mask_lookup=rgb_masks,
type_cls=RGBDest)
opcode = rgb_op_kws[operation.opcode_keyword.keyword]
sels = validate_instruction_operation_sels(operation.swizzle_sels, is_alpha=False)
return RGBOperation(
dest,
opcode,
sels
)
def validate_instruction_operations(operations):
for unit, operation in infer_operation_units(operations):
if unit is Unit.alpha:
yield validate_alpha_instruction_operation(operation)
elif unit is Unit.rgb:
yield validate_rgb_instruction_operation(operation)
else:
assert False, unit
def validate_instruction(ins):
addr_rgb_alpha = validate_instruction_let_expressions(ins.let_expressions)
tags = set([tag.keyword for tag in ins.tags])
instruction = Instruction(
tags,
addr_rgb_alpha,
None,
None
)
for op in validate_instruction_operations(ins.operations):
if type(op) is RGBOperation:
instruction.rgb_op = op
elif type(op) is AlphaOperation:
instruction.alpha_op = op
else:
assert False, op
return instruction
if __name__ == "__main__":
from assembler.lexer import Lexer, LexerError
from assembler.fs.parser import Parser, ParserError
from assembler.fs.keywords import find_keyword
buf = b"""
src0.a = float(0), src0.rgb = temp[0] , srcp.a = neg :
out[0].none = temp[0].none = MAD src0.r src0.r src0.r ,
out[0].none = temp[0].r = DP3 src0.rg0 src0.rg0 ;
"""
lexer = Lexer(buf, find_keyword, emit_newlines=False, minus_is_token=True)
tokens = list(lexer.lex_tokens())
parser = Parser(tokens)
try:
ins_ast = parser.instruction()
pprint(validate_instruction(ins_ast))
except LexerError as e:
print_error(None, buf, e)
raise
except ParserError as e:
print_error(None, buf, e)
raise
except ValidatorError as e:
print_error(None, buf, e)
raise

View File

@ -0,0 +1,69 @@
from os import path
from functools import partial
import parse_bits
class BaseRegister:
def set(self, code, value, *, code_ix, descriptor):
if type(descriptor.bits) is int:
mask = 1
low = descriptor.bits
else:
high, low = descriptor.bits
assert high > low
mask_length = (high - low) + 1
mask = (1 << mask_length) - 1
code_value = code[code_ix]
assert (code_value >> low) & mask == 0
assert value & mask == value
code[code_ix] |= (value & mask) << low
_descriptor_indicies = {
"US_CMN_INST": 0,
"US_ALU_RGB_ADDR": 1,
"US_ALU_ALPHA_ADDR": 2,
"US_ALU_RGB_INST": 3,
"US_ALU_ALPHA_INST": 4,
"US_ALU_RGBA_INST": 5,
"US_TEX_INST": 1,
"US_TEX_ADDR": 2,
"US_TEX_ADDR_DXDY": 3,
"US_FC_INST": 2,
"US_FC_ADDR": 3,
}
def parse_register(register_name):
base = path.dirname(__file__)
filename = path.join(base, "..", "..", "bits", register_name.lower() + ".txt")
l = list(parse_bits.parse_file_fields(filename))
cls = type(register_name, (BaseRegister,), {})
instance = cls()
descriptors = list(parse_bits.aggregate(l))
code_ix = _descriptor_indicies[register_name]
for descriptor in descriptors:
setattr(instance, descriptor.field_name,
partial(instance.set, code_ix=code_ix, descriptor=descriptor))
func = getattr(instance, descriptor.field_name)
for pv_value, (pv_name, _) in descriptor.possible_values.items():
if pv_name is not None:
setattr(func, pv_name, pv_value)
assert getattr(instance, "descriptors", None) is None
instance.descriptors = descriptors
return instance
US_CMN_INST = parse_register("US_CMN_INST")
US_ALU_RGB_ADDR = parse_register("US_ALU_RGB_ADDR")
US_ALU_ALPHA_ADDR = parse_register("US_ALU_ALPHA_ADDR")
US_ALU_RGB_INST = parse_register("US_ALU_RGB_INST")
US_ALU_ALPHA_INST = parse_register("US_ALU_ALPHA_INST")
US_ALU_RGBA_INST = parse_register("US_ALU_RGBA_INST")
US_TEX_INST = parse_register("US_TEX_INST")
US_TEX_ADDR = parse_register("US_TEX_ADDR")
US_TEX_ADDR_DXDY = parse_register("US_TEX_ADDR_DXDY")
US_FC_INST = parse_register("US_FC_INST")
US_FC_ADDR = parse_register("US_FC_ADDR")

View File

@ -0,0 +1,43 @@
from enum import IntEnum
from collections import OrderedDict
from assembler.fs.keywords import _keyword_to_string
from assembler.fs.keywords import KW
from assembler.validator import ValidatorError
class InstructionType(IntEnum):
ALU = 0
OUT = 1
FC = 2
TEX = 3
class RGBMask(IntEnum):
NONE = 0
R = 1
G = 2
RG = 3
B = 4
RB = 5
GB = 6
RGB = 7
class AlphaMask(IntEnum):
NONE = 0
A = 1
def validate_identifier_number(token):
try:
return int(token.lexeme, 10)
except ValueError:
raise ValidatorError("invalid number", token)
def validate_dest_keyword(dest_keyword):
dest_keywords = [KW.OUT, KW.TEMP]
dest_keyword_strs = keywords_to_string(dest_keywords)
dest = dest_keyword.keyword
if dest not in dest_keywords:
raise ValidatorError(f"invalid dest keyword, expected one of {dest_keyword_strs}", dest_addr_swizzle.dest_keyword)
return dest
def keywords_to_string(keywords):
return [_keyword_to_string[s].decode("utf-8") for s in keywords]

View File

@ -1,180 +1,12 @@
from os import path from assembler.fs import alu_emitter
from pprint import pprint from assembler.fs import tex_emitter
from functools import partial from assembler.fs import alu_validator
from assembler.fs import tex_validator
import parse_bits
from assembler.fs.validator import SrcAddrType
class BaseRegister:
def set(self, code, value, *, code_ix, descriptor):
if type(descriptor.bits) is int:
mask = 1
low = descriptor.bits
else:
high, low = descriptor.bits
assert high > low
mask_length = (high - low) + 1
mask = (1 << mask_length) - 1
code_value = code[code_ix]
assert (code_value >> low) & mask == 0
assert value & mask == value
code[code_ix] |= (value & mask) << low
_descriptor_indicies = {
"US_CMN_INST": 0,
"US_ALU_RGB_ADDR": 1,
"US_ALU_ALPHA_ADDR": 2,
"US_ALU_RGB_INST": 3,
"US_ALU_ALPHA_INST": 4,
"US_ALU_RGBA_INST": 5,
"US_TEX_INST": 1,
"US_TEX_ADDR": 2,
"US_TEX_ADDR_DXDY": 3,
"US_FC_INST": 2,
"US_FC_ADDR": 3,
}
def parse_register(register_name):
base = path.dirname(__file__)
filename = path.join(base, "..", "..", "bits", register_name.lower() + ".txt")
l = list(parse_bits.parse_file_fields(filename))
cls = type(register_name, (BaseRegister,), {})
instance = cls()
descriptors = list(parse_bits.aggregate(l))
code_ix = _descriptor_indicies[register_name]
for descriptor in descriptors:
setattr(instance, descriptor.field_name,
partial(instance.set, code_ix=code_ix, descriptor=descriptor))
func = getattr(instance, descriptor.field_name)
for pv_value, (pv_name, _) in descriptor.possible_values.items():
if pv_name is not None:
setattr(func, pv_name, pv_value)
assert getattr(instance, "descriptors", None) is None
instance.descriptors = descriptors
return instance
US_CMN_INST = parse_register("US_CMN_INST")
US_ALU_RGB_ADDR = parse_register("US_ALU_RGB_ADDR")
US_ALU_ALPHA_ADDR = parse_register("US_ALU_ALPHA_ADDR")
US_ALU_RGB_INST = parse_register("US_ALU_RGB_INST")
US_ALU_ALPHA_INST = parse_register("US_ALU_ALPHA_INST")
US_ALU_RGBA_INST = parse_register("US_ALU_RGBA_INST")
US_TEX_INST = parse_register("US_TEX_INST")
US_TEX_ADDR = parse_register("US_TEX_ADDR")
US_TEX_ADDR_DXDY = parse_register("US_TEX_ADDR_DXDY")
US_FC_INST = parse_register("US_FC_INST")
US_FC_ADDR = parse_register("US_FC_ADDR")
def emit_alpha_op(code, alpha_op):
# dest
if alpha_op.dest.wmask is not None:
US_CMN_INST.ALPHA_WMASK(code, alpha_op.dest.wmask.value)
if alpha_op.dest.omask is not None:
US_CMN_INST.ALPHA_OMASK(code, alpha_op.dest.omask.value)
assert type(alpha_op.dest.addrd) is int
US_ALU_ALPHA_INST.ALPHA_ADDRD(code, alpha_op.dest.addrd)
# opcode
US_ALU_ALPHA_INST.ALPHA_OP(code, alpha_op.opcode.value)
# sels
srcs = [
US_ALU_ALPHA_INST.ALPHA_SEL_A,
US_ALU_ALPHA_INST.ALPHA_SEL_B,
US_ALU_RGBA_INST.ALPHA_SEL_C,
]
swizzles = [
[US_ALU_ALPHA_INST.ALPHA_SWIZ_A],
[US_ALU_ALPHA_INST.ALPHA_SWIZ_B],
[US_ALU_RGBA_INST.ALPHA_SWIZ_C],
]
mods = [
US_ALU_ALPHA_INST.ALPHA_MOD_A,
US_ALU_ALPHA_INST.ALPHA_MOD_B,
US_ALU_RGBA_INST.ALPHA_MOD_C,
]
for sel, src_func, swizzle_funcs, mod_func in zip(alpha_op.sels,
srcs, swizzles, mods):
src_func(code, sel.src.value)
assert len(sel.swizzle) == 1
assert len(swizzle_funcs) == 1
for swizzle_func, swizzle in zip(swizzle_funcs, sel.swizzle):
swizzle_func(code, swizzle.value)
mod_func(code, sel.mod.value)
def emit_rgb_op(code, rgb_op):
# dest
if rgb_op.dest.wmask is not None:
US_CMN_INST.RGB_WMASK(code, rgb_op.dest.wmask.value)
if rgb_op.dest.omask is not None:
US_CMN_INST.RGB_OMASK(code, rgb_op.dest.omask.value)
assert type(rgb_op.dest.addrd) is int
US_ALU_RGBA_INST.RGB_ADDRD(code, rgb_op.dest.addrd)
# opcode
US_ALU_RGBA_INST.RGB_OP(code, rgb_op.opcode.value)
# sels
srcs = [
US_ALU_RGB_INST.RGB_SEL_A,
US_ALU_RGB_INST.RGB_SEL_B,
US_ALU_RGBA_INST.RGB_SEL_C,
]
swizzles = [
[US_ALU_RGB_INST.RED_SWIZ_A, US_ALU_RGB_INST.GREEN_SWIZ_A, US_ALU_RGB_INST.BLUE_SWIZ_A],
[US_ALU_RGB_INST.RED_SWIZ_B, US_ALU_RGB_INST.GREEN_SWIZ_B, US_ALU_RGB_INST.BLUE_SWIZ_B],
[US_ALU_RGBA_INST.RED_SWIZ_C, US_ALU_RGBA_INST.GREEN_SWIZ_C, US_ALU_RGBA_INST.BLUE_SWIZ_C],
]
mods = [
US_ALU_RGB_INST.RGB_MOD_A,
US_ALU_RGB_INST.RGB_MOD_B,
US_ALU_RGBA_INST.RGB_MOD_C,
]
for sel, src_func, swizzle_funcs, mod_func in zip(rgb_op.sels,
srcs, swizzles, mods):
src_func(code, sel.src.value)
assert len(sel.swizzle) == 3
assert len(swizzle_funcs) == 3
for swizzle_func, swizzle in zip(swizzle_funcs, sel.swizzle):
swizzle_func(code, swizzle.value)
mod_func(code, sel.mod)
def emit_addr(code, addr):
srcs = [
(addr.alpha.src0 , US_ALU_ALPHA_ADDR.ADDR0 , US_ALU_ALPHA_ADDR.ADDR0_CONST),
(addr.alpha.src1 , US_ALU_ALPHA_ADDR.ADDR1 , US_ALU_ALPHA_ADDR.ADDR1_CONST),
(addr.alpha.src2 , US_ALU_ALPHA_ADDR.ADDR2 , US_ALU_ALPHA_ADDR.ADDR2_CONST),
(addr.rgb.src0 , US_ALU_RGB_ADDR.ADDR0 , US_ALU_RGB_ADDR.ADDR0_CONST),
(addr.rgb.src1 , US_ALU_RGB_ADDR.ADDR1 , US_ALU_RGB_ADDR.ADDR1_CONST),
(addr.rgb.src2 , US_ALU_RGB_ADDR.ADDR2 , US_ALU_RGB_ADDR.ADDR2_CONST),
]
for src, ADDR, ADDR_CONST in srcs:
if src is not None:
is_const = int(src.type is SrcAddrType.const)
is_float = int(src.type is SrcAddrType.float)
ADDR(code, (is_float << 7) | src.value)
ADDR_CONST(code, is_const)
else:
ADDR(code, (1 << 7) | 0)
if addr.alpha.srcp is not None:
US_ALU_ALPHA_ADDR.SRCP_OP(code, addr.alpha.srcp.value)
if addr.rgb.srcp is not None:
US_ALU_RGB_ADDR.SRCP_OP(code, addr.rgb.srcp.value)
def emit_instruction(code, ins): def emit_instruction(code, ins):
US_CMN_INST.TYPE(code, ins.type.value) if type(ins) is alu_validator.Instruction:
US_CMN_INST.TEX_SEM_WAIT(code, int(ins.tex_sem_wait)) return alu_emitter.emit_instruction(code, ins)
US_CMN_INST.NOP(code, int(ins.nop)) elif type(ins) is tex_validator.Instruction:
return tex_emitter.emit_instruction(code, ins)
emit_addr(code, ins.addr) else:
if ins.alpha_op is not None: assert False, type(ins)
emit_alpha_op(code, ins.alpha_op)
if ins.rgb_op is not None:
emit_rgb_op(code, ins.rgb_op)

View File

@ -41,6 +41,18 @@ class KW(Enum):
# modifiers # modifiers
NOP = auto() NOP = auto()
TEX_SEM_WAIT = auto() TEX_SEM_WAIT = auto()
TEX = auto()
TEX_SEM_ACQUIRE = auto()
ALU_WAIT = auto()
LAST = auto()
# tex opcodes
LD = auto()
TEXKILL = auto()
PROJ = auto()
LODBIAS = auto()
LOD = auto()
DXDY = auto()
_string_to_keyword = { _string_to_keyword = {
b"CMP": KW.CMP, b"CMP": KW.CMP,
@ -76,6 +88,16 @@ _string_to_keyword = {
b"NEG": KW.NEG, b"NEG": KW.NEG,
b"NOP": KW.NOP, b"NOP": KW.NOP,
b"TEX_SEM_WAIT": KW.TEX_SEM_WAIT, b"TEX_SEM_WAIT": KW.TEX_SEM_WAIT,
b"TEX": KW.TEX,
b"TEX_SEM_ACQUIRE": KW.TEX_SEM_ACQUIRE,
b"ALU_WAIT": KW.ALU_WAIT,
b"LAST": KW.LAST,
b"LD": KW.LD,
b"TEXKILL": KW.TEXKILL,
b"PROJ": KW.PROJ,
b"LODBIAS": KW.LODBIAS,
b"LOD": KW.LOD,
b"DXDY": KW.DXDY,
} }
_keyword_to_string = {v:k for k,v in _string_to_keyword.items()} _keyword_to_string = {v:k for k,v in _string_to_keyword.items()}

View File

@ -7,14 +7,14 @@ from assembler.lexer import TT, Token
from assembler.fs.keywords import KW, find_keyword from assembler.fs.keywords import KW, find_keyword
from assembler.error import print_error from assembler.error import print_error
class Mod(IntEnum): class ALUMod(IntEnum):
nop = 0 nop = 0
neg = 1 neg = 1
abs = 2 abs = 2
nab = 3 nab = 3
@dataclass @dataclass
class LetExpression: class ALULetExpression:
src_keyword: Token src_keyword: Token
src_swizzle_identifier: Token src_swizzle_identifier: Token
addr_keyword: Token addr_keyword: Token
@ -27,27 +27,39 @@ class DestAddrSwizzle:
swizzle_identifier: Token swizzle_identifier: Token
@dataclass @dataclass
class SwizzleSel: class ALUSwizzleSel:
sel_keyword: Token sel_keyword: Token
swizzle_identifier: Token swizzle_identifier: Token
mod: Mod mod: ALUMod
@dataclass @dataclass
class Operation: class ALUOperation:
dest_addr_swizzles: list[DestAddrSwizzle] dest_addr_swizzles: list[DestAddrSwizzle]
opcode_keyword: Token opcode_keyword: Token
swizzle_sels: list[SwizzleSel] swizzle_sels: list[ALUSwizzleSel]
@dataclass @dataclass
class Instruction: class ALUInstruction:
out: bool tags: set[Token]
tex_sem_wait: bool let_expressions: list[ALULetExpression]
nop: bool operations: list[ALUOperation]
let_expressions: list[LetExpression]
operations: list[Operation] @dataclass
class TEXOperation:
dest_addr_swizzles: list[DestAddrSwizzle]
opcode_keyword: Token
tex_id_identifier: Token
tex_dst_swizzle_identifier: Token
tex_src_address_identifier: Token
tex_src_swizzle_identifier: Token
@dataclass
class TEXInstruction:
tags: set[Token]
operation: TEXOperation
class Parser(BaseParser): class Parser(BaseParser):
def let_expression(self): def alu_let_expression(self):
src_keyword = self.consume(TT.keyword, "expected src keyword") src_keyword = self.consume(TT.keyword, "expected src keyword")
self.consume(TT.dot, "expected dot") self.consume(TT.dot, "expected dot")
src_swizzle_identifier = self.consume(TT.identifier, "expected src swizzle identifier") src_swizzle_identifier = self.consume(TT.identifier, "expected src swizzle identifier")
@ -69,7 +81,7 @@ class Parser(BaseParser):
else: else:
self.consume(TT.right_square, "expected right square") self.consume(TT.right_square, "expected right square")
return LetExpression( return ALULetExpression(
src_keyword, src_keyword,
src_swizzle_identifier, src_swizzle_identifier,
addr_keyword, addr_keyword,
@ -90,7 +102,7 @@ class Parser(BaseParser):
swizzle_identifier, swizzle_identifier,
) )
def is_opcode(self): def alu_is_opcode(self):
opcode_keywords = { opcode_keywords = {
KW.CMP, KW.CND, KW.COS, KW.D2A, KW.CMP, KW.CND, KW.COS, KW.D2A,
KW.DP , KW.DP3, KW.DP4, KW.EX2, KW.DP , KW.DP3, KW.DP4, KW.EX2,
@ -103,21 +115,21 @@ class Parser(BaseParser):
return token.keyword in opcode_keywords return token.keyword in opcode_keywords
return False return False
def is_neg(self): def alu_is_neg(self):
result = self.match(TT.minus) result = self.match(TT.minus)
if result: if result:
self.advance() self.advance()
return result return result
def is_abs(self): def alu_is_abs(self):
result = self.match(TT.bar) result = self.match(TT.bar)
if result: if result:
self.advance() self.advance()
return result return result
def swizzle_sel(self): def alu_swizzle_sel(self):
neg = self.is_neg() neg = self.alu_is_neg()
abs = self.is_abs() abs = self.alu_is_abs()
sel_keyword = self.consume(TT.keyword, "expected sel keyword") sel_keyword = self.consume(TT.keyword, "expected sel keyword")
self.consume(TT.dot, "expected dot") self.consume(TT.dot, "expected dot")
@ -128,52 +140,51 @@ class Parser(BaseParser):
mod_table = { mod_table = {
# (neg, abs) # (neg, abs)
(False, False): Mod.nop, (False, False): ALUMod.nop,
(False, True): Mod.abs, (False, True): ALUMod.abs,
(True, False): Mod.neg, (True, False): ALUMod.neg,
(True, True): Mod.nab, (True, True): ALUMod.nab,
} }
mod = mod_table[(neg, abs)] mod = mod_table[(neg, abs)]
return SwizzleSel( return ALUSwizzleSel(
sel_keyword, sel_keyword,
swizzle_identifier, swizzle_identifier,
mod, mod,
) )
def operation(self): def alu_operation(self):
dest_addr_swizzles = [] dest_addr_swizzles = []
while not self.is_opcode(): while not self.alu_is_opcode():
dest_addr_swizzles.append(self.dest_addr_swizzle()) dest_addr_swizzles.append(self.dest_addr_swizzle())
opcode_keyword = self.consume(TT.keyword, "expected opcode keyword") opcode_keyword = self.consume(TT.keyword, "expected opcode keyword")
swizzle_sels = [] swizzle_sels = []
while not (self.match(TT.comma) or self.match(TT.semicolon)): while not (self.match(TT.comma) or self.match(TT.semicolon)):
swizzle_sels.append(self.swizzle_sel()) swizzle_sels.append(self.alu_swizzle_sel())
return Operation( return ALUOperation(
dest_addr_swizzles, dest_addr_swizzles,
opcode_keyword, opcode_keyword,
swizzle_sels swizzle_sels
) )
def instruction(self): def alu_instruction(self, out: bool):
out = False tags = list()
if self.match_keyword(KW.OUT): tag_keywords = set([KW.OUT, KW.TEX_SEM_WAIT, KW.NOP, KW.LAST, KW.ALU_WAIT])
while True:
if self.match(TT.keyword):
token = self.peek()
if token.keyword in tag_keywords:
self.advance() self.advance()
out = True tag_keywords.remove(token.keyword)
tex_sem_wait = False tags.append(token)
if self.match_keyword(KW.TEX_SEM_WAIT): continue
self.advance() break
tex_sem_wait = True
nop = False
if self.match_keyword(KW.NOP):
self.advance()
nop = True
let_expressions = [] let_expressions = []
while not self.match(TT.colon): while not self.match(TT.colon):
let_expressions.append(self.let_expression()) let_expressions.append(self.alu_let_expression())
if not self.match(TT.colon): if not self.match(TT.colon):
self.consume(TT.comma, "expected comma") self.consume(TT.comma, "expected comma")
@ -181,20 +192,87 @@ class Parser(BaseParser):
operations = [] operations = []
while not self.match(TT.semicolon): while not self.match(TT.semicolon):
operations.append(self.operation()) operations.append(self.alu_operation())
if not self.match(TT.semicolon): if not self.match(TT.semicolon):
self.consume(TT.comma, "expected comma") self.consume(TT.comma, "expected comma")
self.consume(TT.semicolon, "expected semicolon") self.consume(TT.semicolon, "expected semicolon")
return Instruction( return ALUInstruction(
out, tags,
tex_sem_wait,
nop,
let_expressions, let_expressions,
operations, operations,
) )
def tex_is_opcode(self):
opcode_keywords = {
KW.NOP, KW.LD, KW.TEXKILL, KW.PROJ,
KW.LODBIAS, KW.LOD, KW.DXDY,
}
if self.match(TT.keyword):
token = self.peek()
return token.keyword in opcode_keywords
return False
def tex_operation(self):
dest_addr_swizzles = []
while not self.tex_is_opcode():
dest_addr_swizzles.append(self.dest_addr_swizzle())
opcode_keyword = self.consume(TT.keyword, "expected tex opcode keyword")
self.consume_keyword(KW.TEX, "expected tex keyword")
self.consume(TT.left_square, "expected left square")
tex_id_identifier = self.consume(TT.identifier, "expected tex ID identifier")
self.consume(TT.right_square, "expected left square")
self.consume(TT.dot, "expected dot")
tex_dst_swizzle_identifier = self.consume(TT.identifier, "expected src swizzle")
self.consume_keyword(KW.TEMP, "expected temp keyword")
self.consume(TT.left_square, "expected left square")
tex_src_address_identifier = self.consume(TT.identifier, "expected tex address identifier")
self.consume(TT.right_square, "expected left square")
self.consume(TT.dot, "expected dot")
tex_src_swizzle_identifier = self.consume(TT.identifier, "expected dst swizzle")
return TEXOperation(
dest_addr_swizzles,
opcode_keyword,
tex_id_identifier,
tex_dst_swizzle_identifier,
tex_src_address_identifier,
tex_src_swizzle_identifier,
)
def tex_instruction(self):
tags = list()
tag_keywords = set([KW.OUT, KW.TEX_SEM_WAIT, KW.TEX_SEM_ACQUIRE, KW.NOP, KW.ALU_WAIT, KW.LAST])
while True:
if self.match(TT.keyword):
token = self.peek()
if token.keyword in tag_keywords:
self.advance()
tag_keywords.remove(token.keyword)
tags.append(token)
continue
break
operation = self.tex_operation()
self.consume(TT.semicolon, "expected semicolon")
return TEXInstruction(
tags,
operation,
)
def instruction(self):
out = False
if self.match_keyword(KW.TEX):
self.advance()
return self.tex_instruction()
else:
return self.alu_instruction(out=False)
def instructions(self): def instructions(self):
while not self.match(TT.eof): while not self.match(TT.eof):
yield self.instruction() yield self.instruction()

View File

@ -0,0 +1,36 @@
from assembler.fs.common_validator import InstructionType
from assembler.fs.keywords import KW
from assembler.fs.common_emitter import US_CMN_INST
from assembler.fs.common_emitter import US_TEX_INST
from assembler.fs.common_emitter import US_TEX_ADDR
from assembler.fs.common_emitter import US_TEX_ADDR_DXDY
def emit_instruction(code, ins):
US_CMN_INST.TYPE(code, InstructionType.TEX)
US_CMN_INST.TEX_SEM_WAIT(code, int(KW.TEX_SEM_WAIT in ins.tags))
US_CMN_INST.LAST(code, int(KW.LAST in ins.tags))
US_CMN_INST.NOP(code, int(KW.NOP in ins.tags))
US_CMN_INST.ALU_WAIT(code, int(KW.ALU_WAIT in ins.tags))
US_CMN_INST.RGB_WMASK(code, ins.masks.rgb_wmask.value)
US_CMN_INST.ALPHA_WMASK(code, ins.masks.alpha_wmask.value)
US_CMN_INST.RGB_OMASK(code, ins.masks.rgb_omask.value)
US_CMN_INST.ALPHA_OMASK(code, ins.masks.alpha_omask.value)
US_TEX_INST.TEX_ID(code, ins.tex_id)
US_TEX_INST.INST(code, ins.opcode.value)
US_TEX_INST.TEX_SEM_ACQUIRE(code, int(KW.TEX_SEM_ACQUIRE in ins.tags))
US_TEX_INST.IGNORE_UNCOVERED(code, 0)
US_TEX_INST.UNSCALED(code, 0)
US_TEX_ADDR.SRC_ADDR(code, ins.src_addr)
US_TEX_ADDR.SRC_S_SWIZ(code, ins.src_swizzle[0].value)
US_TEX_ADDR.SRC_T_SWIZ(code, ins.src_swizzle[1].value)
US_TEX_ADDR.SRC_R_SWIZ(code, ins.src_swizzle[2].value)
US_TEX_ADDR.SRC_Q_SWIZ(code, ins.src_swizzle[3].value)
US_TEX_ADDR.DST_ADDR(code, ins.dst_addr)
US_TEX_ADDR.DST_R_SWIZ(code, ins.dst_swizzle[0].value)
US_TEX_ADDR.DST_G_SWIZ(code, ins.dst_swizzle[1].value)
US_TEX_ADDR.DST_B_SWIZ(code, ins.dst_swizzle[2].value)
US_TEX_ADDR.DST_A_SWIZ(code, ins.dst_swizzle[3].value)

View File

@ -0,0 +1,159 @@
from dataclasses import dataclass
from typing import Union
from collections import OrderedDict
from enum import IntEnum
from assembler.validator import ValidatorError
from assembler.fs import parser
from assembler.fs.keywords import KW
from assembler.fs.common_validator import RGBMask, AlphaMask
from assembler.fs.common_validator import validate_identifier_number, validate_dest_keyword
from assembler.fs.common_validator import keywords_to_string
@dataclass
class Masks:
alpha_wmask: AlphaMask
rgb_wmask: RGBMask
alpha_omask: AlphaMask
rgb_omask: RGBMask
class TEXOp(IntEnum):
NOP = 0
LD = 1
TEXKILL = 2
PROJ = 3
LODBIAS = 4
LOD = 5
DXDY = 6
class Swizzle(IntEnum):
R = 0
G = 1
B = 2
A = 3
@dataclass
class Instruction:
tags: set[Union[KW.TEX_SEM_WAIT, KW.TEX_SEM_ACQUIRE, KW.OUT]]
masks: Masks
opcode: TEXOp
tex_id: int
src_addr: int
src_swizzle: tuple[Swizzle, Swizzle, Swizzle, Swizzle]
dst_addr: int
dst_swizzle: tuple[Swizzle, Swizzle, Swizzle, Swizzle]
def validate_swizzle(token):
if len(token.lexeme) != 4:
raise ValidatorError("invalid swizzle identifier", token)
swizzles = OrderedDict([
(ord(b"r"), Swizzle.R),
(ord(b"g"), Swizzle.G),
(ord(b"b"), Swizzle.B),
(ord(b"a"), Swizzle.A),
])
if not all(c in swizzles for c in token.lexeme):
raise ValidatorError("invalid swizzle identifier", token)
return tuple(swizzles[c] for c in token.lexeme)
def validate_mask_swizzle(token) -> tuple[AlphaMask, RGBMask]:
argb_masks = OrderedDict([
(b"none" , (AlphaMask.NONE, RGBMask.NONE)),
(b"r" , (AlphaMask.NONE, RGBMask.R)),
(b"g" , (AlphaMask.NONE, RGBMask.G)),
(b"rg" , (AlphaMask.NONE, RGBMask.RG)),
(b"b" , (AlphaMask.NONE, RGBMask.B)),
(b"rb" , (AlphaMask.NONE, RGBMask.RB)),
(b"gb" , (AlphaMask.NONE, RGBMask.GB)),
(b"rgb" , (AlphaMask.NONE, RGBMask.RGB)),
(b"ar" , (AlphaMask.A, RGBMask.R)),
(b"ag" , (AlphaMask.A, RGBMask.G)),
(b"arg" , (AlphaMask.A, RGBMask.RG)),
(b"ab" , (AlphaMask.A, RGBMask.B)),
(b"arb" , (AlphaMask.A, RGBMask.RB)),
(b"agb" , (AlphaMask.A, RGBMask.GB)),
(b"argb" , (AlphaMask.A, RGBMask.RGB)),
])
if token.lexeme not in argb_masks:
raise ValidatorError("invalid destination mask", token)
return argb_masks[token.lexeme]
def validate_masks(ins_ast: parser.TEXInstruction):
addresses = set()
dests = set()
masks = Masks(
alpha_wmask = AlphaMask.NONE,
rgb_wmask = RGBMask.NONE,
alpha_omask = AlphaMask.NONE,
rgb_omask = RGBMask.NONE,
)
for dest_addr_swizzle in ins_ast.operation.dest_addr_swizzles:
dest_keyword = dest_addr_swizzle.dest_keyword
dest = validate_dest_keyword(dest_keyword)
if dest in dests:
raise ValidatorError(f"duplicate destination keyword {dest}", dest_keyword)
dests.add(dest)
addr_identifier = dest_addr_swizzle.addr_identifier
addr = validate_identifier_number(addr_identifier)
addresses.add(addr)
swizzle_identifier = dest_addr_swizzle.swizzle_identifier
alpha_mask, rgb_mask = validate_mask_swizzle(swizzle_identifier)
if dest is KW.OUT:
masks.alpha_omask = alpha_mask
masks.rgb_omask = rgb_mask
elif dest is KW.TEMP:
masks.alpha_wmask = alpha_mask
masks.rgb_wmask = rgb_mask
else:
assert False, type(dest)
if len(addresses) > 1:
raise ValidatorError("contradictory destination address", ins_ast.operation.dest_addr_swizzles[-1].addr_identifier)
address, = addresses
return masks, address
op_kws = OrderedDict([
(KW.NOP, TEXOp.NOP),
(KW.LD, TEXOp.LD),
(KW.TEXKILL, TEXOp.TEXKILL),
(KW.PROJ, TEXOp.PROJ),
(KW.LODBIAS, TEXOp.LODBIAS),
(KW.LOD, TEXOp.LOD),
(KW.DXDY, TEXOp.DXDY),
])
def validate_opcode(token):
if token.keyword not in op_kws:
raise ValidatorError("invalid tex opcode keyword", token)
return op_kws[token.keyword]
def validate_instruction(ins_ast: parser.TEXInstruction):
tags = set([tag.keyword for tag in ins_ast.tags])
masks, dst_addr = validate_masks(ins_ast)
opcode = validate_opcode(ins_ast.operation.opcode_keyword)
tex_id = validate_identifier_number(ins_ast.operation.tex_id_identifier)
dst_swizzle = validate_swizzle(ins_ast.operation.tex_dst_swizzle_identifier)
src_address = validate_identifier_number(ins_ast.operation.tex_src_address_identifier)
src_swizzle = validate_swizzle(ins_ast.operation.tex_src_swizzle_identifier)
return Instruction(
tags = tags,
masks = masks,
opcode = opcode,
tex_id = tex_id,
src_addr = src_address, # texture coordinate address
src_swizzle = src_swizzle, # texture coordinate swizzle
dst_addr = dst_addr, # temp address
dst_swizzle = dst_swizzle, # texture value swizzle
)

View File

@ -1,530 +1,11 @@
from pprint import pprint from assembler.fs import alu_validator
from dataclasses import dataclass from assembler.fs import tex_validator
from enum import Enum, IntEnum, auto from assembler.fs.parser import TEXInstruction, ALUInstruction
from collections import OrderedDict
from assembler.fs.parser import Mod
from assembler.fs.keywords import _keyword_to_string, KW
from assembler.error import print_error
from assembler.validator import ValidatorError
class SrcAddrType(Enum):
temp = auto()
const = auto()
float = auto()
@dataclass
class SrcAddr:
type: SrcAddrType
value: int
class SrcMod(IntEnum):
nop = 0
neg = 1
abs = 2
nab = 3
class SrcpOp(IntEnum):
neg2 = 0
sub = 1
add = 2
neg = 3
@dataclass
class Addr:
src0: SrcAddr = None
src1: SrcAddr = None
src2: SrcAddr = None
srcp: SrcpOp = None
@dataclass
class AddrRGBAlpha:
alpha: Addr
rgb: Addr
class RGBMask(IntEnum):
NONE = 0
R = 1
G = 2
RG = 3
B = 4
RB = 5
GB = 6
RGB = 7
class AlphaMask(IntEnum):
NONE = 0
A = 1
class Unit(Enum):
alpha = auto()
rgb = auto()
class RGBOp(IntEnum):
MAD = 0
DP3 = 1
DP4 = 2
D2A = 3
MIN = 4
MAX = 5
CND = 7
CMP = 8
FRC = 9
SOP = 10
MDH = 11
MDV = 12
class AlphaOp(IntEnum):
MAD = 0
DP = 1
MIN = 2
MAX = 3
CND = 5
CMP = 6
FRC = 7
EX2 = 8
LN2 = 9
RCP = 10
RSQ = 11
SIN = 12
COS = 13
MDH = 14
MDV = 15
@dataclass
class RGBDest:
addrd: int
wmask: RGBMask
omask: RGBMask
@dataclass
class AlphaDest:
addrd: int
wmask: AlphaMask
omask: AlphaMask
class SwizzleSelSrc(IntEnum):
src0 = 0
src1 = 1
src2 = 2
srcp = 3
class Swizzle(IntEnum):
r = 0
g = 1
b = 2
a = 3
zero = 4
half = 5
one = 6
unused = 7
@dataclass
class SwizzleSel:
src: SwizzleSelSrc
swizzle: list[Swizzle]
mod: Mod
@dataclass
class AlphaOperation:
dest: AlphaDest
opcode: AlphaOp
sels: list[SwizzleSel]
@dataclass
class RGBOperation:
dest: RGBDest
opcode: RGBOp
sels: list[SwizzleSel]
class InstructionType(IntEnum):
ALU = 0
OUT = 1
FC = 2
TEX = 3
@dataclass
class Instruction:
type: InstructionType
tex_sem_wait: bool
nop: bool
addr: Addr
alpha_op: AlphaOperation
rgb_op: RGBOperation
def validate_identifier_number(token):
try:
return int(token.lexeme, 10)
except ValueError:
raise ValidatorError("invalid number", token)
def keywords_to_string(keywords):
return [_keyword_to_string[s].decode("utf-8") for s in keywords]
def validate_instruction_let_expressions(let_expressions):
src_keywords = [KW.SRC0, KW.SRC1, KW.SRC2, KW.SRCP]
src_keyword_strs = keywords_to_string(src_keywords)
rgb_alpha_swizzles = [b"rgb", b"a"]
addr_rgb_alpha = AddrRGBAlpha(Addr(), Addr())
def set_src_by_keyword(addr, keyword, value):
if keyword == KW.SRC0:
addr.src0 = value
elif keyword == KW.SRC1:
addr.src1 = value
elif keyword == KW.SRC2:
addr.src2 = value
elif keyword == KW.SRCP:
addr.srcp = value
else:
assert False, keyword
def src_value(expr, src):
if src in {KW.SRC0, KW.SRC1, KW.SRC2}:
keyword_to_src_addr_type = OrderedDict([
(KW.TEMP, SrcAddrType.temp),
(KW.CONST, SrcAddrType.const),
(KW.FLOAT, SrcAddrType.float),
])
src_addr_type_strs = keywords_to_string(keyword_to_src_addr_type.keys())
type_kw = expr.addr_keyword.keyword
if type_kw not in keyword_to_src_addr_type:
raise ValidatorError(f"invalid src addr type, expected one of {src_addr_type_strs}", expr.addr_keyword)
type = keyword_to_src_addr_type[type_kw]
value = validate_identifier_number(expr.addr_value_identifier)
if type is SrcAddrType.float:
if value >= 128:
raise ValidatorError(f"invalid float value", expr.addr_value_identifier)
elif type is SrcAddrType.temp:
if value >= 128:
raise ValidatorError(f"invalid temp value", expr.addr_value_identifier)
elif type is SrcAddrType.const:
if value >= 256:
raise ValidatorError(f"invalid const value", expr.addr_value_identifier)
else:
assert False, (id(type), id(SrcAddrType.float))
return SrcAddr(
type,
value,
)
elif src == KW.SRCP:
keyword_to_srcp_op = OrderedDict([
(KW.NEG2, SrcpOp.neg2),
(KW.SUB, SrcpOp.sub),
(KW.ADD, SrcpOp.add),
(KW.NEG, SrcpOp.neg),
])
srcp_op_strs = keywords_to_string(keyword_to_srcp_op.keys())
op = expr.addr_keyword.keyword
if op not in keyword_to_srcp_op:
raise ValidatorError(f"invalid srcp op, expected one of {srcp_op_strs}", expr.addr_keyword)
return keyword_to_srcp_op[op]
else:
assert False, src
sources = set()
for expr in let_expressions:
src = expr.src_keyword.keyword
if src not in src_keywords:
raise ValidatorError(f"invalid src keyword, expected one of {src_keyword_strs}", expr.src_keyword)
src_swizzle = expr.src_swizzle_identifier.lexeme.lower()
if src_swizzle not in rgb_alpha_swizzles:
raise ValidatorError(f"invalid src swizzle, expected one of {rgb_alpha_swizzles}", expr.src_swizzle_identifier)
source = (_keyword_to_string[src].lower(), src_swizzle)
if source in sources:
raise ValidatorError(f"duplicate source/swizzle in let expressions", expr.src_swizzle_identifier)
sources.add(source)
value = src_value(expr, src)
if src_swizzle == b"a":
set_src_by_keyword(addr_rgb_alpha.alpha, src, value)
elif src_swizzle == b"rgb":
set_src_by_keyword(addr_rgb_alpha.rgb, src, value)
else:
assert False, src_swizzle
return addr_rgb_alpha
def prevalidate_mask(dest_addr_swizzle, valid_masks):
# we don't know yet whether this is an Alpha operation or an RGB operation
swizzle_str = dest_addr_swizzle.swizzle_identifier.lexeme
if swizzle_str.lower() not in valid_masks:
raise ValidatorError(f"invalid write mask, expected one of {valid_masks}", dest_addr_swizzle.swizzle_identifier)
mask = swizzle_str.lower()
return mask
rgb_op_kws = OrderedDict([
(KW.MAD, RGBOp.MAD),
(KW.DP3, RGBOp.DP3),
(KW.DP4, RGBOp.DP4),
(KW.D2A, RGBOp.D2A),
(KW.MIN, RGBOp.MIN),
(KW.MAX, RGBOp.MAX),
(KW.CND, RGBOp.CND),
(KW.CMP, RGBOp.CMP),
(KW.FRC, RGBOp.FRC),
(KW.SOP, RGBOp.SOP),
(KW.MDH, RGBOp.MDH),
(KW.MDV, RGBOp.MDV)
])
alpha_op_kws = OrderedDict([
(KW.MAD, AlphaOp.MAD),
(KW.DP, AlphaOp.DP),
(KW.MIN, AlphaOp.MIN),
(KW.MAX, AlphaOp.MAX),
(KW.CND, AlphaOp.CND),
(KW.CMP, AlphaOp.CMP),
(KW.FRC, AlphaOp.FRC),
(KW.EX2, AlphaOp.EX2),
(KW.LN2, AlphaOp.LN2),
(KW.RCP, AlphaOp.RCP),
(KW.RSQ, AlphaOp.RSQ),
(KW.SIN, AlphaOp.SIN),
(KW.COS, AlphaOp.COS),
(KW.MDH, AlphaOp.MDH),
(KW.MDV, AlphaOp.MDV)
])
rgb_masks = OrderedDict([
(b"none" , RGBMask.NONE),
(b"r" , RGBMask.R),
(b"g" , RGBMask.G),
(b"rg" , RGBMask.RG),
(b"b" , RGBMask.B),
(b"rb" , RGBMask.RB),
(b"gb" , RGBMask.GB),
(b"rgb" , RGBMask.RGB),
])
alpha_masks = OrderedDict([
(b"none" , AlphaMask.NONE),
(b"a" , AlphaMask.A),
])
alpha_only_ops = set(alpha_op_kws.keys()) - set(rgb_op_kws.keys())
rgb_only_ops = set(rgb_op_kws.keys()) - set(alpha_op_kws.keys())
all_ops = set(rgb_op_kws.keys()) | set(alpha_op_kws.keys())
alpha_only_masks = set(alpha_masks.keys()) - set(rgb_masks.keys())
rgb_only_masks = set(rgb_masks.keys()) - set(alpha_masks.keys())
all_masks = set(rgb_masks.keys()) | set(alpha_masks.keys())
def infer_operation_units(operations):
if len(operations) > 2:
raise ValidatorError("too many operations in instruction", operations[-1].opcode_keyword)
units = [None, None]
for i, operation in enumerate(operations):
opcode = operation.opcode_keyword.keyword
if opcode not in all_ops:
raise ValidatorError(f"invalid opcode keyword, expected one of {all_ops}", operation.opcode_keyword)
if len(operation.dest_addr_swizzles) > 2:
raise ValidationError("too many destinations in instruction", operation.dest_addr_swizzles[-1])
masks = set(prevalidate_mask(dest_addr_swizzle, all_masks) for dest_addr_swizzle in operation.dest_addr_swizzles)
def infer_opcode_unit():
if opcode in alpha_only_ops:
return Unit.alpha
if opcode in rgb_only_ops:
return Unit.rgb
return None
def infer_mask_unit():
if any(mask in alpha_only_masks for mask in masks):
return Unit.alpha
if any(mask in rgb_only_masks for mask in masks):
return Unit.rgb
return None
opcode_unit = infer_opcode_unit()
mask_unit = infer_mask_unit()
if opcode_unit is not None and mask_unit is not None and opcode_unit != mask_unit:
raise ValidatorError(f"contradictory {mask_unit.name} write mask for {opcode_unit.name} opcode", operation.opcode_keyword)
units[i] = opcode_unit or mask_unit
if units[0] == units[1]:
raise ValidatorError(f"invalid duplicate use of {units[1].name} unit", operations[1].opcode_keyword)
other_unit = {
Unit.alpha: Unit.rgb,
Unit.rgb: Unit.alpha,
}
if units[0] is None:
units[0] = other_unit[units[1]]
if units[1] is None:
units[1] = other_unit[units[0]]
assert units[0] is not None
assert units[1] is not None
assert units[0] != units[1]
for i, operation in enumerate(operations):
yield units[i], operation
def validate_dest_keyword(dest_keyword):
dest_keywords = [KW.OUT, KW.TEMP]
dest_keyword_strs = keywords_to_string(dest_keywords)
dest = dest_keyword.keyword
if dest not in dest_keywords:
raise ValidatorError(f"invalid dest keyword, expected one of {dest_keyword_strs}", dest_addr_swizzle.dest_keyword)
return dest
def validate_instruction_operation_dest(dest_addr_swizzles, mask_lookup, type_cls):
addrs = set()
wmask = None
omask = None
for dest_addr_swizzle in dest_addr_swizzles:
dest = validate_dest_keyword(dest_addr_swizzle.dest_keyword)
addr = validate_identifier_number(dest_addr_swizzle.addr_identifier)
mask = mask_lookup[dest_addr_swizzle.swizzle_identifier.lexeme.lower()]
addrs.add(addr)
if dest == KW.OUT:
omask = mask
elif dest == KW.TEMP:
wmask = mask
else:
assert False, dest
if len(addrs) > 1:
raise ValidatorError(f"too many destination addresses", operation.dest_addr_swizzles[-1].addr_identifier)
addrd, = addrs if addrs else [0]
return type_cls(
addrd=addrd,
wmask=wmask,
omask=omask
)
swizzle_sel_src_kws = OrderedDict([
(KW.SRC0, SwizzleSelSrc.src0),
(KW.SRC1, SwizzleSelSrc.src1),
(KW.SRC2, SwizzleSelSrc.src2),
(KW.SRCP, SwizzleSelSrc.srcp),
])
swizzle_kws = OrderedDict([
(ord("r"), Swizzle.r),
(ord("g"), Swizzle.g),
(ord("b"), Swizzle.b),
(ord("a"), Swizzle.a),
(ord("0"), Swizzle.zero),
(ord("h"), Swizzle.half),
(ord("1"), Swizzle.one),
(ord("_"), Swizzle.unused),
])
def validate_instruction_operation_sels(swizzle_sels, is_alpha):
if len(swizzle_sels) > 3:
raise ValidatorError("too many swizzle sels", swizzle_sels[-1].sel_keyword)
sels = []
for swizzle_sel in swizzle_sels:
if swizzle_sel.sel_keyword.keyword not in swizzle_sel_src_kws:
raise ValidatorError("invalid swizzle src", swizzle_sel.sel_keyword.keyword)
src = swizzle_sel_src_kws[swizzle_sel.sel_keyword.keyword]
swizzle_lexeme = swizzle_sel.swizzle_identifier.lexeme.lower()
swizzles_length = 1 if is_alpha else 3
if len(swizzle_lexeme) != swizzles_length:
raise ValidatorError("invalid swizzle length", swizzle_sel.swizzle_identifier)
if not all(c in swizzle_kws for c in swizzle_lexeme):
raise ValidatorError("invalid swizzle characters", swizzle_sel.swizzle_identifier)
swizzle = [
swizzle_kws[c] for c in swizzle_lexeme
]
mod = swizzle_sel.mod
sels.append(SwizzleSel(src, swizzle, mod))
return sels
def validate_alpha_instruction_operation(operation):
dest = validate_instruction_operation_dest(operation.dest_addr_swizzles,
mask_lookup=alpha_masks,
type_cls=AlphaDest)
opcode = alpha_op_kws[operation.opcode_keyword.keyword]
sels = validate_instruction_operation_sels(operation.swizzle_sels, is_alpha=True)
return AlphaOperation(
dest,
opcode,
sels
)
def validate_rgb_instruction_operation(operation):
dest = validate_instruction_operation_dest(operation.dest_addr_swizzles,
mask_lookup=rgb_masks,
type_cls=RGBDest)
opcode = rgb_op_kws[operation.opcode_keyword.keyword]
sels = validate_instruction_operation_sels(operation.swizzle_sels, is_alpha=False)
return RGBOperation(
dest,
opcode,
sels
)
def validate_instruction_operations(operations):
for unit, operation in infer_operation_units(operations):
if unit is Unit.alpha:
yield validate_alpha_instruction_operation(operation)
elif unit is Unit.rgb:
yield validate_rgb_instruction_operation(operation)
else:
assert False, unit
def validate_instruction(ins): def validate_instruction(ins):
addr_rgb_alpha = validate_instruction_let_expressions(ins.let_expressions) if type(ins) is TEXInstruction:
return tex_validator.validate_instruction(ins)
instruction_type = InstructionType.OUT if ins.out else InstructionType.ALU elif type(ins) is ALUInstruction:
tex_sem_wait = ins.tex_sem_wait return alu_validator.validate_instruction(ins)
nop = ins.nop
instruction = Instruction(
instruction_type,
tex_sem_wait,
nop,
addr_rgb_alpha,
None,
None
)
for op in validate_instruction_operations(ins.operations):
if type(op) is RGBOperation:
instruction.rgb_op = op
elif type(op) is AlphaOperation:
instruction.alpha_op = op
else: else:
assert False, op assert False, type(ins)
return instruction
if __name__ == "__main__":
from assembler.lexer import Lexer, LexerError
from assembler.fs.parser import Parser, ParserError
from assembler.fs.keywords import find_keyword
buf = b"""
src0.a = float(0), src0.rgb = temp[0] , srcp.a = neg :
out[0].none = temp[0].none = MAD src0.r src0.r src0.r ,
out[0].none = temp[0].r = DP3 src0.rg0 src0.rg0 ;
"""
lexer = Lexer(buf, find_keyword, emit_newlines=False, minus_is_token=True)
tokens = list(lexer.lex_tokens())
parser = Parser(tokens)
try:
ins_ast = parser.instruction()
pprint(validate_instruction(ins_ast))
except LexerError as e:
print_error(None, buf, e)
raise
except ParserError as e:
print_error(None, buf, e)
raise
except ValidatorError as e:
print_error(None, buf, e)
raise

View File

@ -44,3 +44,11 @@ class BaseParser:
if token.type != token_type1 and token.type != token_type2: if token.type != token_type1 and token.type != token_type2:
raise ParserError(message, token) raise ParserError(message, token)
return token return token
def consume_keyword(self, keyword, message):
if self.match_keyword(keyword):
token = self.advance()
return token
else:
token = self.advance()
raise ParserError(message, token)

View File

@ -1,6 +1,7 @@
import sys import sys
from assembler.lexer import Lexer, LexerError from assembler.lexer import Lexer, LexerError
from assembler.validator import ValidatorError
from assembler.vs.keywords import find_keyword from assembler.vs.keywords import find_keyword
from assembler.vs.parser import Parser, ParserError from assembler.vs.parser import Parser, ParserError
from assembler.vs.emitter import emit_instruction, emit_dual_math_instruction from assembler.vs.emitter import emit_instruction, emit_dual_math_instruction
@ -42,6 +43,9 @@ def frontend(filename, buf):
except LexerError as e: except LexerError as e:
print_error(input_filename, buf, e) print_error(input_filename, buf, e)
raise raise
except ValidatorError as e:
print_error(filename, buf, e)
raise
if __name__ == "__main__": if __name__ == "__main__":
input_filename = sys.argv[1] input_filename = sys.argv[1]

View File

@ -131,6 +131,7 @@ def disassemble(code, ix):
print('\n'.join(inner2(i, register_name))) print('\n'.join(inner2(i, register_name)))
inner = inner_rows inner = inner_rows
#inner = inner_columns
inst_type = get_field_pv_name(us_cmn_inst, US_CMN_INST["TYPE"]) inst_type = get_field_pv_name(us_cmn_inst, US_CMN_INST["TYPE"])
if inst_type in {"US_INST_TYPE_OUT", "US_INST_TYPE_ALU"}: if inst_type in {"US_INST_TYPE_OUT", "US_INST_TYPE_ALU"}:

View File

@ -88,8 +88,8 @@ def disassemble_addr_inner(register_const, address, const, rel):
assert False, const assert False, const
swizzle_strs = ['r', 'g', 'b', 'a', '0', 'h', '1', '_'] alu_swizzle_strs = ['r', 'g', 'b', 'a', '0', 'h', '1', '_']
sel_strs = ['0', '1', '2', 'p'] alu_sel_strs = ['0', '1', '2', 'p']
def disassemble_addr(register, code, suffix): def disassemble_addr(register, code, suffix):
addr0 = register.ADDR0(code) addr0 = register.ADDR0(code)
@ -108,7 +108,7 @@ def disassemble_addr(register, code, suffix):
s2 = disassemble_addr_inner(register.ADDR2_CONST, addr2, addr2_const, addr2_rel) s2 = disassemble_addr_inner(register.ADDR2_CONST, addr2, addr2_const, addr2_rel)
sp = srcp_op.lower() sp = srcp_op.lower()
return [ return [
f"src{sel_strs[i]}.{suffix} = {s}" f"src{alu_sel_strs[i]}.{suffix} = {s}"
for i, s in enumerate([s0, s1, s2, sp]) for i, s in enumerate([s0, s1, s2, sp])
] ]
@ -143,15 +143,15 @@ def disassemble_rgb_swizzle_sel(code):
blue_swiz_c = US_ALU_RGBA_INST.BLUE_SWIZ_C(code) blue_swiz_c = US_ALU_RGBA_INST.BLUE_SWIZ_C(code)
rgb_mod_c = US_ALU_RGBA_INST.RGB_MOD_C(code) rgb_mod_c = US_ALU_RGBA_INST.RGB_MOD_C(code)
rgb_swiz_a = ''.join(swizzle_strs[n] for n in [red_swiz_a, green_swiz_a, blue_swiz_a]) rgb_swiz_a = ''.join(alu_swizzle_strs[n] for n in [red_swiz_a, green_swiz_a, blue_swiz_a])
rgb_swiz_b = ''.join(swizzle_strs[n] for n in [red_swiz_b, green_swiz_b, blue_swiz_b]) rgb_swiz_b = ''.join(alu_swizzle_strs[n] for n in [red_swiz_b, green_swiz_b, blue_swiz_b])
rgb_swiz_c = ''.join(swizzle_strs[n] for n in [red_swiz_c, green_swiz_c, blue_swiz_c]) rgb_swiz_c = ''.join(alu_swizzle_strs[n] for n in [red_swiz_c, green_swiz_c, blue_swiz_c])
rgb_swiz = [rgb_swiz_a, rgb_swiz_b, rgb_swiz_c] rgb_swiz = [rgb_swiz_a, rgb_swiz_b, rgb_swiz_c]
rgb_sels = [rgb_sel_a, rgb_sel_b, rgb_sel_c] rgb_sels = [rgb_sel_a, rgb_sel_b, rgb_sel_c]
rgb_mods = [rgb_mod_a, rgb_mod_b, rgb_mod_c] rgb_mods = [rgb_mod_a, rgb_mod_b, rgb_mod_c]
return [mod_str(f"src{sel_strs[sel]}.{swiz}", mod) return [mod_str(f"src{alu_sel_strs[sel]}.{swiz}", mod)
for swiz, sel, mod in zip(rgb_swiz, rgb_sels, rgb_mods)], rgb_sels for swiz, sel, mod in zip(rgb_swiz, rgb_sels, rgb_mods)], rgb_sels
def disassemble_a_swizzle_sel(code): def disassemble_a_swizzle_sel(code):
@ -167,11 +167,11 @@ def disassemble_a_swizzle_sel(code):
alpha_swiz_c = US_ALU_RGBA_INST.ALPHA_SWIZ_C(code) alpha_swiz_c = US_ALU_RGBA_INST.ALPHA_SWIZ_C(code)
alpha_mod_c = US_ALU_RGBA_INST.ALPHA_MOD_C(code) alpha_mod_c = US_ALU_RGBA_INST.ALPHA_MOD_C(code)
a_swiz = [swizzle_strs[n] for n in [alpha_swiz_a, alpha_swiz_b, alpha_swiz_c]] a_swiz = [alu_swizzle_strs[n] for n in [alpha_swiz_a, alpha_swiz_b, alpha_swiz_c]]
a_sels = [alpha_sel_a, alpha_sel_b, alpha_sel_c] a_sels = [alpha_sel_a, alpha_sel_b, alpha_sel_c]
a_mods = [alpha_mod_a, alpha_mod_b, alpha_mod_c] a_mods = [alpha_mod_a, alpha_mod_b, alpha_mod_c]
return [mod_str(f"src{sel_strs[sel]}.{swiz}", mod) return [mod_str(f"src{alu_sel_strs[sel]}.{swiz}", mod)
for swiz, sel, mod in zip(a_swiz, a_sels, a_mods)], a_sels for swiz, sel, mod in zip(a_swiz, a_sels, a_mods)], a_sels
def omod_str(s, mod): def omod_str(s, mod):
@ -201,21 +201,21 @@ def disassemble_alu_dest(code):
rgb_addrd_rel = US_ALU_RGBA_INST.RGB_ADDRD_REL(code) rgb_addrd_rel = US_ALU_RGBA_INST.RGB_ADDRD_REL(code)
assert rgb_addrd_rel == 0 assert rgb_addrd_rel == 0
_, rgb_wmask, _ = US_CMN_INST._RGB_WMASK(code) rgb_wmask, rgb_wmask_str, _ = US_CMN_INST._RGB_WMASK(code)
_, a_wmask, _ = US_CMN_INST._ALPHA_WMASK(code) a_wmask, a_wmask_str, _ = US_CMN_INST._ALPHA_WMASK(code)
_, rgb_omask, _ = US_CMN_INST._RGB_OMASK(code) rgb_omask, rgb_omask_str, _ = US_CMN_INST._RGB_OMASK(code)
_, a_omask, _ = US_CMN_INST._ALPHA_OMASK(code) a_omask, a_omask_str, _ = US_CMN_INST._ALPHA_OMASK(code)
a_out_str = f"out[{a_addrd}].{a_omask.lower().ljust(4)}" a_out_str = f"out[{a_addrd}].{a_omask_str.lower().ljust(4)} = " if a_omask != 0 else ""
a_temp_str = f"temp[{a_addrd}].{a_wmask.lower().ljust(4)}" a_temp_str = f"temp[{a_addrd}].{a_wmask_str.lower().ljust(4)} = " if a_wmask != 0 else ""
rgb_out_str = f"out[{rgb_addrd}].{rgb_omask.lower().ljust(4)}" rgb_out_str = f"out[{rgb_addrd}].{rgb_omask_str.lower().ljust(4)} = " if rgb_omask != 0 else ""
rgb_temp_str = f"temp[{rgb_addrd}].{rgb_wmask.lower().ljust(4)}" rgb_temp_str = f"temp[{rgb_addrd}].{rgb_wmask_str.lower().ljust(4)} = " if rgb_wmask != 0 else ""
return (a_out_str, a_temp_str), (rgb_out_str, rgb_temp_str) return (a_out_str, a_temp_str), (rgb_out_str, rgb_temp_str)
def assert_zeros(code): def assert_zeros_common(code):
rgb_pred_sel = US_CMN_INST.RGB_PRED_SEL(code) rgb_pred_sel = US_CMN_INST.RGB_PRED_SEL(code)
assert rgb_pred_sel == 0 assert rgb_pred_sel == 0
rgb_pred_inv = US_CMN_INST.RGB_PRED_INV(code) rgb_pred_inv = US_CMN_INST.RGB_PRED_INV(code)
@ -237,6 +237,7 @@ def assert_zeros(code):
stat_we = US_CMN_INST.STAT_WE(code) stat_we = US_CMN_INST.STAT_WE(code)
assert stat_we == 0 assert stat_we == 0
def assert_zeros_alu(code):
rgb_omod = US_ALU_RGB_INST.OMOD(code) rgb_omod = US_ALU_RGB_INST.OMOD(code)
rgb_target = US_ALU_RGB_INST.TARGET(code) rgb_target = US_ALU_RGB_INST.TARGET(code)
alu_wmask = US_ALU_RGB_INST.ALU_WMASK(code) alu_wmask = US_ALU_RGB_INST.ALU_WMASK(code)
@ -251,6 +252,47 @@ def assert_zeros(code):
assert a_target == 0 assert a_target == 0
assert w_omask == 0 assert w_omask == 0
def assert_zeros_tex(code):
dx_addr = US_TEX_ADDR_DXDY.DX_ADDR(code)
dx_addr_rel = US_TEX_ADDR_DXDY.DX_ADDR_REL(code)
dx_s_swiz = US_TEX_ADDR_DXDY.DX_S_SWIZ(code)
dx_t_swiz = US_TEX_ADDR_DXDY.DX_T_SWIZ(code)
dx_r_swiz = US_TEX_ADDR_DXDY.DX_R_SWIZ(code)
dx_q_swiz = US_TEX_ADDR_DXDY.DX_Q_SWIZ(code)
assert dx_addr == 0, dx_addr
assert dx_addr_rel == 0, dx_addr_rel
assert dx_s_swiz == 0, dx_s_swiz
assert dx_t_swiz == 0, dx_t_swiz
assert dx_r_swiz == 0, dx_r_swiz
assert dx_q_swiz == 0, dx_q_swiz
dy_addr = US_TEX_ADDR_DXDY.DY_ADDR(code)
dy_addr_rel = US_TEX_ADDR_DXDY.DY_ADDR_REL(code)
dy_s_swiz = US_TEX_ADDR_DXDY.DY_S_SWIZ(code)
dy_t_swiz = US_TEX_ADDR_DXDY.DY_T_SWIZ(code)
dy_r_swiz = US_TEX_ADDR_DXDY.DY_R_SWIZ(code)
dy_q_swiz = US_TEX_ADDR_DXDY.DY_Q_SWIZ(code)
assert dy_addr == 0, dy_addr
assert dy_addr_rel == 0, dy_addr_rel
assert dy_s_swiz == 0, dy_s_swiz
assert dy_t_swiz == 0, dy_t_swiz
assert dy_r_swiz == 0, dy_r_swiz
assert dy_q_swiz == 0, dy_q_swiz
src_addr_rel = US_TEX_ADDR.SRC_ADDR_REL(code)
assert src_addr_rel == 0, src_addr_rel
dst_addr_rel = US_TEX_ADDR.DST_ADDR_REL(code)
assert dst_addr_rel == 0, dst_addr_rel
ignore_uncovered = US_TEX_INST.IGNORE_UNCOVERED(code)
assert ignore_uncovered == 0, ignore_uncovered
unscaled = US_TEX_INST.UNSCALED(code)
assert unscaled == 0, unscaled
_rgb_op_operands = { _rgb_op_operands = {
"OP_MAD": 3, "OP_MAD": 3,
"OP_DP3": 2, "OP_DP3": 2,
@ -284,7 +326,8 @@ _a_op_operands = {
} }
def disassemble_alu(code, is_output): def disassemble_alu(code, is_output):
assert_zeros(code) assert_zeros_common(code)
assert_zeros_alu(code)
a_addr_strs = disassemble_addr(US_ALU_ALPHA_ADDR, code, "a") a_addr_strs = disassemble_addr(US_ALU_ALPHA_ADDR, code, "a")
rgb_addr_strs = disassemble_addr(US_ALU_RGB_ADDR, code, "rgb") rgb_addr_strs = disassemble_addr(US_ALU_RGB_ADDR, code, "rgb")
@ -333,15 +376,80 @@ def disassemble_alu(code, is_output):
rgb_clamp = US_CMN_INST.RGB_CLAMP(code) rgb_clamp = US_CMN_INST.RGB_CLAMP(code)
alpha_clamp = US_CMN_INST.ALPHA_CLAMP(code) alpha_clamp = US_CMN_INST.ALPHA_CLAMP(code)
rgb_clamp_str = ".CLAMP" if rgb_clamp != 0 else "" rgb_clamp_str = ".SAT" if rgb_clamp != 0 else ""
a_clamp_str = ".CLAMP" if alpha_clamp != 0 else "" a_clamp_str = ".SAT" if alpha_clamp != 0 else ""
print(", ".join([*a_addr_strs, *rgb_addr_strs]), ":") print(", ".join([*a_addr_strs, *rgb_addr_strs]), ":")
#print(", ".join(a_addr_strs), ":") #print(", ".join(a_addr_strs), ":")
print(f" {a_out_str} = {a_temp_str} = {a_op.removeprefix('OP_').ljust(3)}{a_clamp_str} {' '.join(a_swizzle_sel)}", ",") print(f" {a_out_str}{a_temp_str}{a_op.removeprefix('OP_').ljust(3)}{a_clamp_str} {' '.join(a_swizzle_sel)}", ",")
#print(", ".join(rgb_addr_strs), ":") #print(", ".join(rgb_addr_strs), ":")
print(f" {rgb_out_str} = {rgb_temp_str} = {rgb_op.removeprefix('OP_').ljust(3)}{rgb_clamp_str} {' '.join(rgb_swizzle_sel)}", ";") print(f" {rgb_out_str}{rgb_temp_str}{rgb_op.removeprefix('OP_').ljust(3)}{rgb_clamp_str} {' '.join(rgb_swizzle_sel)}", ";")
def disassemble_tex_swizzle_str(code):
tex_swiz_strs = ["r", "g", "b", "a"]
src_s_swiz = US_TEX_ADDR.SRC_S_SWIZ(code)
src_t_swiz = US_TEX_ADDR.SRC_T_SWIZ(code)
src_r_swiz = US_TEX_ADDR.SRC_R_SWIZ(code)
src_q_swiz = US_TEX_ADDR.SRC_Q_SWIZ(code)
src_swiz = ''.join(tex_swiz_strs[n] for n in [src_s_swiz, src_t_swiz, src_r_swiz, src_q_swiz])
dst_r_swiz = US_TEX_ADDR.DST_R_SWIZ(code)
dst_g_swiz = US_TEX_ADDR.DST_G_SWIZ(code)
dst_b_swiz = US_TEX_ADDR.DST_B_SWIZ(code)
dst_a_swiz = US_TEX_ADDR.DST_A_SWIZ(code)
dst_swiz = ''.join(tex_swiz_strs[n] for n in [dst_r_swiz, dst_g_swiz, dst_b_swiz, dst_a_swiz])
return src_swiz, dst_swiz
def disassemble_tex_dest(code):
dst_addr = US_TEX_ADDR.DST_ADDR(code)
rgb_wmask, rgb_wmask_str, _ = US_CMN_INST._RGB_WMASK(code)
a_wmask, a_wmask_str, _ = US_CMN_INST._ALPHA_WMASK(code)
wmask_bool = rgb_wmask != 0 or a_wmask != 0
rgba_wmask = (a_wmask_str if a_wmask else "") + (rgb_wmask_str if rgb_wmask else "")
temp_str = f"temp[{dst_addr}].{rgba_wmask.lower().ljust(4)} = " if wmask_bool else ""
rgb_omask, rgb_omask_str, _ = US_CMN_INST._RGB_OMASK(code)
a_omask, a_omask_str, _ = US_CMN_INST._ALPHA_OMASK(code)
omask_bool = rgb_omask != 0 or a_omask != 0
rgba_omask = (a_omask_str if a_omask else "") + (rgb_omask_str if rgb_omask else "")
out_str = f"out[{dst_addr}].{rgba_omask.lower().ljust(4)} = " if omask_bool else ""
return out_str, temp_str
def disassemble_tex(code):
assert_zeros_common(code)
assert_zeros_tex(code)
_, inst, _ = US_TEX_INST._INST(code)
tex_id = US_TEX_INST.TEX_ID(code)
src_addr = US_TEX_ADDR.SRC_ADDR(code)
src_swiz, dst_swiz = disassemble_tex_swizzle_str(code)
out_str, temp_str = disassemble_tex_dest(code)
temp_out_str = ''.join([out_str, temp_str])
tags = ["TEX"]
if US_CMN_INST.TEX_SEM_WAIT(code):
tags.append("TEX_SEM_WAIT")
if US_TEX_INST.TEX_SEM_ACQUIRE(code):
tags.append("TEX_SEM_ACQUIRE")
if US_CMN_INST.ALU_WAIT(code):
tags.append("ALU_WAIT")
print(" ".join(tags))
print(f" {temp_out_str}{inst} tex[{tex_id}].{dst_swiz} temp[{src_addr}].{src_swiz} ;")
def disassemble(code): def disassemble(code):
assert len(code) == 6, len(code) assert len(code) == 6, len(code)
@ -350,6 +458,8 @@ def disassemble(code):
disassemble_alu(code, is_output=True) disassemble_alu(code, is_output=True)
elif type == US_CMN_INST.TYPE.US_INST_TYPE_ALU: elif type == US_CMN_INST.TYPE.US_INST_TYPE_ALU:
disassemble_alu(code, is_output=False) disassemble_alu(code, is_output=False)
elif type == US_CMN_INST.TYPE.US_INST_TYPE_TEX:
disassemble_tex(code)
else: else:
print("[TYPE]", type) print("[TYPE]", type)
#assert False, US_CMN_INST._TYPE(code) #assert False, US_CMN_INST._TYPE(code)

View File

@ -4,12 +4,14 @@
0x00000000, 0x00000000,
0x00000000, 0x00000000,
0x00000000, 0x00000000,
0x00007807, 0x00007807,
0x02410000, 0x02410000,
0xe402f400, 0xe402f400,
0x00000000, 0x00000000,
0x00000000, 0x00000000,
0x00000000, 0x00000000,
0x00078005, 0x00078005,
0x40000801, 0x40000801,
0x48000801, 0x48000801,

View File

@ -0,0 +1,12 @@
0x00003807,
0x02400000,
0xe400f400,
0x00000000,
0x00000000,
0x00000000,
0x00078005,
0x08020000,
0x08020080,
0x1c280140,
0x1c204003,
0x00000005,