Compare commits
No commits in common. "c8ae311e60f0a92dceeba978176b712e705fd941" and "f3f1969f4a9b336536f5fb23d246f7103c41e20d" have entirely different histories.
c8ae311e60
...
f3f1969f4a
@ -1,4 +0,0 @@
|
||||
OUT TEX_SEM_WAIT
|
||||
:
|
||||
out[0].a = MAX src0.1 src0.1 ,
|
||||
out[0].rgb = MAX src0.000 src0.000 ;
|
||||
@ -1,7 +0,0 @@
|
||||
0x00078005,
|
||||
0x08020080,
|
||||
0x08020080,
|
||||
0x00920490,
|
||||
0x00c18003,
|
||||
0x00000005,
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
-- 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 ;
|
||||
@ -1,13 +0,0 @@
|
||||
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
1177
drm/pumpkin_man.c
File diff suppressed because it is too large
Load Diff
@ -1,67 +0,0 @@
|
||||
-- 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 ;
|
||||
@ -1,16 +0,0 @@
|
||||
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,
|
||||
@ -50,3 +50,4 @@ src0.a = temp[0] ,
|
||||
src0.rgb = temp[0] :
|
||||
out[0].a = MAX src0.1 src0.1 ,
|
||||
out[0].rgb = MAX src0.rgb src0.rgb ;
|
||||
,
|
||||
|
||||
@ -20,11 +20,11 @@
|
||||
0x00000000,
|
||||
|
||||
0x00004000,
|
||||
0x10320080,
|
||||
0x08020080,
|
||||
0x0802f400,
|
||||
0x00000000,
|
||||
0x0068c000,
|
||||
0x04000000,
|
||||
0x20000000,
|
||||
|
||||
0x00004000,
|
||||
0x08020080,
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
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 ;
|
||||
@ -1,14 +0,0 @@
|
||||
0x00007807,
|
||||
0x02400000,
|
||||
0xe400f400,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
|
||||
0x00078005,
|
||||
0x08020000,
|
||||
0x08020000,
|
||||
0x00440220,
|
||||
0x0060c003,
|
||||
0x00000005,
|
||||
|
||||
@ -121,13 +121,43 @@ const face faces[] = {
|
||||
static const int faces_length = (sizeof (faces)) / (sizeof (faces[0]));
|
||||
|
||||
static const uint32_t fragment_shader[] = {
|
||||
#include "texture_cube.fs.inc"
|
||||
#include "clear.fs.inc"
|
||||
#include "../shader_examples/mesa/texture_cube.fs.txt"
|
||||
// clear shader
|
||||
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_instructions = (fragment_shader_length / 6) - 1;
|
||||
|
||||
static const uint32_t vertex_shader[] = {
|
||||
//#include "../shader_examples/mesa/texture_cube.vs.txt"
|
||||
#include "cube_rotate.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
@ -347,26 +347,30 @@ int indirect_buffer()
|
||||
// );
|
||||
|
||||
T0V(VAP_PROG_STREAM_CNTL_0
|
||||
, VAP_PROG_STREAM_CNTL__DATA_TYPE_0__FLOAT_3
|
||||
, VAP_PROG_STREAM_CNTL__DATA_TYPE_0(2)
|
||||
| VAP_PROG_STREAM_CNTL__SKIP_DWORDS_0(0)
|
||||
| VAP_PROG_STREAM_CNTL__DST_VEC_LOC_0(0)
|
||||
| VAP_PROG_STREAM_CNTL__LAST_VEC_0(0)
|
||||
| VAP_PROG_STREAM_CNTL__DATA_TYPE_1__FLOAT_3
|
||||
| VAP_PROG_STREAM_CNTL__SIGNED_0(0)
|
||||
| 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__DST_VEC_LOC_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
|
||||
, VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_X_0__SELECT_X
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Y_0__SELECT_Y
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Z_0__SELECT_Z
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_W_0__SELECT_FP_ONE
|
||||
| VAP_PROG_STREAM_CNTL_EXT__WRITE_ENA_0(0b1111)
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_X_1__SELECT_X
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Y_1__SELECT_Y
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Z_1__SELECT_Z
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_W_1__SELECT_FP_ONE
|
||||
| VAP_PROG_STREAM_CNTL_EXT__WRITE_ENA_1(0b1111)
|
||||
, VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_X_0(0)
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Y_0(1)
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Z_0(2)
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_W_0(5)
|
||||
| VAP_PROG_STREAM_CNTL_EXT__WRITE_ENA_0(15)
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_X_1(0)
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Y_1(1)
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_Z_1(2)
|
||||
| VAP_PROG_STREAM_CNTL_EXT__SWIZZLE_SELECT_W_1(5)
|
||||
| VAP_PROG_STREAM_CNTL_EXT__WRITE_ENA_1(15)
|
||||
);
|
||||
|
||||
T0V(VAP_VSM_VTX_ASSM, 0x00000005); // undocumented
|
||||
|
||||
@ -1,66 +0,0 @@
|
||||
#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
79552
model/pumpkin/pumpkin.h
File diff suppressed because it is too large
Load Diff
@ -1,115 +0,0 @@
|
||||
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)
|
||||
@ -1,490 +0,0 @@
|
||||
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
|
||||
@ -1,69 +0,0 @@
|
||||
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")
|
||||
@ -1,43 +0,0 @@
|
||||
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]
|
||||
@ -1,12 +1,180 @@
|
||||
from assembler.fs import alu_emitter
|
||||
from assembler.fs import tex_emitter
|
||||
from assembler.fs import alu_validator
|
||||
from assembler.fs import tex_validator
|
||||
from os import path
|
||||
from pprint import pprint
|
||||
from functools import partial
|
||||
|
||||
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):
|
||||
if type(ins) is alu_validator.Instruction:
|
||||
return alu_emitter.emit_instruction(code, ins)
|
||||
elif type(ins) is tex_validator.Instruction:
|
||||
return tex_emitter.emit_instruction(code, ins)
|
||||
else:
|
||||
assert False, type(ins)
|
||||
US_CMN_INST.TYPE(code, ins.type.value)
|
||||
US_CMN_INST.TEX_SEM_WAIT(code, int(ins.tex_sem_wait))
|
||||
US_CMN_INST.NOP(code, int(ins.nop))
|
||||
|
||||
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)
|
||||
|
||||
@ -41,18 +41,6 @@ class KW(Enum):
|
||||
# modifiers
|
||||
NOP = 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 = {
|
||||
b"CMP": KW.CMP,
|
||||
@ -88,16 +76,6 @@ _string_to_keyword = {
|
||||
b"NEG": KW.NEG,
|
||||
b"NOP": KW.NOP,
|
||||
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()}
|
||||
|
||||
|
||||
@ -7,14 +7,14 @@ from assembler.lexer import TT, Token
|
||||
from assembler.fs.keywords import KW, find_keyword
|
||||
from assembler.error import print_error
|
||||
|
||||
class ALUMod(IntEnum):
|
||||
class Mod(IntEnum):
|
||||
nop = 0
|
||||
neg = 1
|
||||
abs = 2
|
||||
nab = 3
|
||||
|
||||
@dataclass
|
||||
class ALULetExpression:
|
||||
class LetExpression:
|
||||
src_keyword: Token
|
||||
src_swizzle_identifier: Token
|
||||
addr_keyword: Token
|
||||
@ -27,39 +27,27 @@ class DestAddrSwizzle:
|
||||
swizzle_identifier: Token
|
||||
|
||||
@dataclass
|
||||
class ALUSwizzleSel:
|
||||
class SwizzleSel:
|
||||
sel_keyword: Token
|
||||
swizzle_identifier: Token
|
||||
mod: ALUMod
|
||||
mod: Mod
|
||||
|
||||
@dataclass
|
||||
class ALUOperation:
|
||||
class Operation:
|
||||
dest_addr_swizzles: list[DestAddrSwizzle]
|
||||
opcode_keyword: Token
|
||||
swizzle_sels: list[ALUSwizzleSel]
|
||||
swizzle_sels: list[SwizzleSel]
|
||||
|
||||
@dataclass
|
||||
class ALUInstruction:
|
||||
tags: set[Token]
|
||||
let_expressions: list[ALULetExpression]
|
||||
operations: list[ALUOperation]
|
||||
|
||||
@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 Instruction:
|
||||
out: bool
|
||||
tex_sem_wait: bool
|
||||
nop: bool
|
||||
let_expressions: list[LetExpression]
|
||||
operations: list[Operation]
|
||||
|
||||
class Parser(BaseParser):
|
||||
def alu_let_expression(self):
|
||||
def let_expression(self):
|
||||
src_keyword = self.consume(TT.keyword, "expected src keyword")
|
||||
self.consume(TT.dot, "expected dot")
|
||||
src_swizzle_identifier = self.consume(TT.identifier, "expected src swizzle identifier")
|
||||
@ -81,7 +69,7 @@ class Parser(BaseParser):
|
||||
else:
|
||||
self.consume(TT.right_square, "expected right square")
|
||||
|
||||
return ALULetExpression(
|
||||
return LetExpression(
|
||||
src_keyword,
|
||||
src_swizzle_identifier,
|
||||
addr_keyword,
|
||||
@ -102,7 +90,7 @@ class Parser(BaseParser):
|
||||
swizzle_identifier,
|
||||
)
|
||||
|
||||
def alu_is_opcode(self):
|
||||
def is_opcode(self):
|
||||
opcode_keywords = {
|
||||
KW.CMP, KW.CND, KW.COS, KW.D2A,
|
||||
KW.DP , KW.DP3, KW.DP4, KW.EX2,
|
||||
@ -115,21 +103,21 @@ class Parser(BaseParser):
|
||||
return token.keyword in opcode_keywords
|
||||
return False
|
||||
|
||||
def alu_is_neg(self):
|
||||
def is_neg(self):
|
||||
result = self.match(TT.minus)
|
||||
if result:
|
||||
self.advance()
|
||||
return result
|
||||
|
||||
def alu_is_abs(self):
|
||||
def is_abs(self):
|
||||
result = self.match(TT.bar)
|
||||
if result:
|
||||
self.advance()
|
||||
return result
|
||||
|
||||
def alu_swizzle_sel(self):
|
||||
neg = self.alu_is_neg()
|
||||
abs = self.alu_is_abs()
|
||||
def swizzle_sel(self):
|
||||
neg = self.is_neg()
|
||||
abs = self.is_abs()
|
||||
|
||||
sel_keyword = self.consume(TT.keyword, "expected sel keyword")
|
||||
self.consume(TT.dot, "expected dot")
|
||||
@ -140,51 +128,52 @@ class Parser(BaseParser):
|
||||
|
||||
mod_table = {
|
||||
# (neg, abs)
|
||||
(False, False): ALUMod.nop,
|
||||
(False, True): ALUMod.abs,
|
||||
(True, False): ALUMod.neg,
|
||||
(True, True): ALUMod.nab,
|
||||
(False, False): Mod.nop,
|
||||
(False, True): Mod.abs,
|
||||
(True, False): Mod.neg,
|
||||
(True, True): Mod.nab,
|
||||
}
|
||||
mod = mod_table[(neg, abs)]
|
||||
return ALUSwizzleSel(
|
||||
return SwizzleSel(
|
||||
sel_keyword,
|
||||
swizzle_identifier,
|
||||
mod,
|
||||
)
|
||||
|
||||
def alu_operation(self):
|
||||
def operation(self):
|
||||
dest_addr_swizzles = []
|
||||
while not self.alu_is_opcode():
|
||||
while not self.is_opcode():
|
||||
dest_addr_swizzles.append(self.dest_addr_swizzle())
|
||||
|
||||
opcode_keyword = self.consume(TT.keyword, "expected opcode keyword")
|
||||
|
||||
swizzle_sels = []
|
||||
while not (self.match(TT.comma) or self.match(TT.semicolon)):
|
||||
swizzle_sels.append(self.alu_swizzle_sel())
|
||||
swizzle_sels.append(self.swizzle_sel())
|
||||
|
||||
return ALUOperation(
|
||||
return Operation(
|
||||
dest_addr_swizzles,
|
||||
opcode_keyword,
|
||||
swizzle_sels
|
||||
)
|
||||
|
||||
def alu_instruction(self, out: bool):
|
||||
tags = list()
|
||||
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:
|
||||
def instruction(self):
|
||||
out = False
|
||||
if self.match_keyword(KW.OUT):
|
||||
self.advance()
|
||||
tag_keywords.remove(token.keyword)
|
||||
tags.append(token)
|
||||
continue
|
||||
break
|
||||
out = True
|
||||
tex_sem_wait = False
|
||||
if self.match_keyword(KW.TEX_SEM_WAIT):
|
||||
self.advance()
|
||||
tex_sem_wait = True
|
||||
nop = False
|
||||
if self.match_keyword(KW.NOP):
|
||||
self.advance()
|
||||
nop = True
|
||||
|
||||
let_expressions = []
|
||||
while not self.match(TT.colon):
|
||||
let_expressions.append(self.alu_let_expression())
|
||||
let_expressions.append(self.let_expression())
|
||||
if not self.match(TT.colon):
|
||||
self.consume(TT.comma, "expected comma")
|
||||
|
||||
@ -192,87 +181,20 @@ class Parser(BaseParser):
|
||||
|
||||
operations = []
|
||||
while not self.match(TT.semicolon):
|
||||
operations.append(self.alu_operation())
|
||||
operations.append(self.operation())
|
||||
if not self.match(TT.semicolon):
|
||||
self.consume(TT.comma, "expected comma")
|
||||
|
||||
self.consume(TT.semicolon, "expected semicolon")
|
||||
|
||||
return ALUInstruction(
|
||||
tags,
|
||||
return Instruction(
|
||||
out,
|
||||
tex_sem_wait,
|
||||
nop,
|
||||
let_expressions,
|
||||
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):
|
||||
while not self.match(TT.eof):
|
||||
yield self.instruction()
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
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)
|
||||
@ -1,159 +0,0 @@
|
||||
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
|
||||
)
|
||||
@ -1,11 +1,530 @@
|
||||
from assembler.fs import alu_validator
|
||||
from assembler.fs import tex_validator
|
||||
from assembler.fs.parser import TEXInstruction, ALUInstruction
|
||||
from pprint import pprint
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum, IntEnum, auto
|
||||
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):
|
||||
if type(ins) is TEXInstruction:
|
||||
return tex_validator.validate_instruction(ins)
|
||||
elif type(ins) is ALUInstruction:
|
||||
return alu_validator.validate_instruction(ins)
|
||||
addr_rgb_alpha = validate_instruction_let_expressions(ins.let_expressions)
|
||||
|
||||
instruction_type = InstructionType.OUT if ins.out else InstructionType.ALU
|
||||
tex_sem_wait = ins.tex_sem_wait
|
||||
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:
|
||||
assert False, type(ins)
|
||||
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
|
||||
|
||||
@ -44,11 +44,3 @@ class BaseParser:
|
||||
if token.type != token_type1 and token.type != token_type2:
|
||||
raise ParserError(message, 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)
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import sys
|
||||
|
||||
from assembler.lexer import Lexer, LexerError
|
||||
from assembler.validator import ValidatorError
|
||||
from assembler.vs.keywords import find_keyword
|
||||
from assembler.vs.parser import Parser, ParserError
|
||||
from assembler.vs.emitter import emit_instruction, emit_dual_math_instruction
|
||||
@ -43,9 +42,6 @@ def frontend(filename, buf):
|
||||
except LexerError as e:
|
||||
print_error(input_filename, buf, e)
|
||||
raise
|
||||
except ValidatorError as e:
|
||||
print_error(filename, buf, e)
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
input_filename = sys.argv[1]
|
||||
|
||||
@ -131,7 +131,6 @@ def disassemble(code, ix):
|
||||
print('\n'.join(inner2(i, register_name)))
|
||||
|
||||
inner = inner_rows
|
||||
#inner = inner_columns
|
||||
|
||||
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"}:
|
||||
|
||||
@ -88,8 +88,8 @@ def disassemble_addr_inner(register_const, address, const, rel):
|
||||
assert False, const
|
||||
|
||||
|
||||
alu_swizzle_strs = ['r', 'g', 'b', 'a', '0', 'h', '1', '_']
|
||||
alu_sel_strs = ['0', '1', '2', 'p']
|
||||
swizzle_strs = ['r', 'g', 'b', 'a', '0', 'h', '1', '_']
|
||||
sel_strs = ['0', '1', '2', 'p']
|
||||
|
||||
def disassemble_addr(register, code, suffix):
|
||||
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)
|
||||
sp = srcp_op.lower()
|
||||
return [
|
||||
f"src{alu_sel_strs[i]}.{suffix} = {s}"
|
||||
f"src{sel_strs[i]}.{suffix} = {s}"
|
||||
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)
|
||||
rgb_mod_c = US_ALU_RGBA_INST.RGB_MOD_C(code)
|
||||
|
||||
rgb_swiz_a = ''.join(alu_swizzle_strs[n] for n in [red_swiz_a, green_swiz_a, blue_swiz_a])
|
||||
rgb_swiz_b = ''.join(alu_swizzle_strs[n] for n in [red_swiz_b, green_swiz_b, blue_swiz_b])
|
||||
rgb_swiz_c = ''.join(alu_swizzle_strs[n] for n in [red_swiz_c, green_swiz_c, blue_swiz_c])
|
||||
rgb_swiz_a = ''.join(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_c = ''.join(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_sels = [rgb_sel_a, rgb_sel_b, rgb_sel_c]
|
||||
rgb_mods = [rgb_mod_a, rgb_mod_b, rgb_mod_c]
|
||||
|
||||
return [mod_str(f"src{alu_sel_strs[sel]}.{swiz}", mod)
|
||||
return [mod_str(f"src{sel_strs[sel]}.{swiz}", mod)
|
||||
for swiz, sel, mod in zip(rgb_swiz, rgb_sels, rgb_mods)], rgb_sels
|
||||
|
||||
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_mod_c = US_ALU_RGBA_INST.ALPHA_MOD_C(code)
|
||||
|
||||
a_swiz = [alu_swizzle_strs[n] for n in [alpha_swiz_a, alpha_swiz_b, alpha_swiz_c]]
|
||||
a_swiz = [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_mods = [alpha_mod_a, alpha_mod_b, alpha_mod_c]
|
||||
|
||||
return [mod_str(f"src{alu_sel_strs[sel]}.{swiz}", mod)
|
||||
return [mod_str(f"src{sel_strs[sel]}.{swiz}", mod)
|
||||
for swiz, sel, mod in zip(a_swiz, a_sels, a_mods)], a_sels
|
||||
|
||||
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)
|
||||
assert rgb_addrd_rel == 0
|
||||
|
||||
rgb_wmask, rgb_wmask_str, _ = US_CMN_INST._RGB_WMASK(code)
|
||||
a_wmask, a_wmask_str, _ = US_CMN_INST._ALPHA_WMASK(code)
|
||||
_, rgb_wmask, _ = US_CMN_INST._RGB_WMASK(code)
|
||||
_, a_wmask, _ = US_CMN_INST._ALPHA_WMASK(code)
|
||||
|
||||
rgb_omask, rgb_omask_str, _ = US_CMN_INST._RGB_OMASK(code)
|
||||
a_omask, a_omask_str, _ = US_CMN_INST._ALPHA_OMASK(code)
|
||||
_, rgb_omask, _ = US_CMN_INST._RGB_OMASK(code)
|
||||
_, a_omask, _ = US_CMN_INST._ALPHA_OMASK(code)
|
||||
|
||||
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_str.lower().ljust(4)} = " if a_wmask != 0 else ""
|
||||
a_out_str = f"out[{a_addrd}].{a_omask.lower().ljust(4)}"
|
||||
a_temp_str = f"temp[{a_addrd}].{a_wmask.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_str.lower().ljust(4)} = " if rgb_wmask != 0 else ""
|
||||
rgb_out_str = f"out[{rgb_addrd}].{rgb_omask.lower().ljust(4)}"
|
||||
rgb_temp_str = f"temp[{rgb_addrd}].{rgb_wmask.lower().ljust(4)}"
|
||||
|
||||
return (a_out_str, a_temp_str), (rgb_out_str, rgb_temp_str)
|
||||
|
||||
def assert_zeros_common(code):
|
||||
def assert_zeros(code):
|
||||
rgb_pred_sel = US_CMN_INST.RGB_PRED_SEL(code)
|
||||
assert rgb_pred_sel == 0
|
||||
rgb_pred_inv = US_CMN_INST.RGB_PRED_INV(code)
|
||||
@ -237,7 +237,6 @@ def assert_zeros_common(code):
|
||||
stat_we = US_CMN_INST.STAT_WE(code)
|
||||
assert stat_we == 0
|
||||
|
||||
def assert_zeros_alu(code):
|
||||
rgb_omod = US_ALU_RGB_INST.OMOD(code)
|
||||
rgb_target = US_ALU_RGB_INST.TARGET(code)
|
||||
alu_wmask = US_ALU_RGB_INST.ALU_WMASK(code)
|
||||
@ -252,47 +251,6 @@ def assert_zeros_alu(code):
|
||||
assert a_target == 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 = {
|
||||
"OP_MAD": 3,
|
||||
"OP_DP3": 2,
|
||||
@ -326,8 +284,7 @@ _a_op_operands = {
|
||||
}
|
||||
|
||||
def disassemble_alu(code, is_output):
|
||||
assert_zeros_common(code)
|
||||
assert_zeros_alu(code)
|
||||
assert_zeros(code)
|
||||
|
||||
a_addr_strs = disassemble_addr(US_ALU_ALPHA_ADDR, code, "a")
|
||||
rgb_addr_strs = disassemble_addr(US_ALU_RGB_ADDR, code, "rgb")
|
||||
@ -376,80 +333,15 @@ def disassemble_alu(code, is_output):
|
||||
|
||||
rgb_clamp = US_CMN_INST.RGB_CLAMP(code)
|
||||
alpha_clamp = US_CMN_INST.ALPHA_CLAMP(code)
|
||||
rgb_clamp_str = ".SAT" if rgb_clamp != 0 else ""
|
||||
a_clamp_str = ".SAT" if alpha_clamp != 0 else ""
|
||||
rgb_clamp_str = ".CLAMP" if rgb_clamp != 0 else ""
|
||||
a_clamp_str = ".CLAMP" if alpha_clamp != 0 else ""
|
||||
|
||||
print(", ".join([*a_addr_strs, *rgb_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(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} ;")
|
||||
print(f" {rgb_out_str} = {rgb_temp_str} = {rgb_op.removeprefix('OP_').ljust(3)}{rgb_clamp_str} {' '.join(rgb_swizzle_sel)}", ";")
|
||||
|
||||
def disassemble(code):
|
||||
assert len(code) == 6, len(code)
|
||||
@ -458,8 +350,6 @@ def disassemble(code):
|
||||
disassemble_alu(code, is_output=True)
|
||||
elif type == US_CMN_INST.TYPE.US_INST_TYPE_ALU:
|
||||
disassemble_alu(code, is_output=False)
|
||||
elif type == US_CMN_INST.TYPE.US_INST_TYPE_TEX:
|
||||
disassemble_tex(code)
|
||||
else:
|
||||
print("[TYPE]", type)
|
||||
#assert False, US_CMN_INST._TYPE(code)
|
||||
|
||||
@ -4,14 +4,12 @@
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
|
||||
0x00007807,
|
||||
0x02410000,
|
||||
0xe402f400,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
|
||||
0x00078005,
|
||||
0x40000801,
|
||||
0x48000801,
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
0x00003807,
|
||||
0x02400000,
|
||||
0xe400f400,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00078005,
|
||||
0x08020000,
|
||||
0x08020080,
|
||||
0x1c280140,
|
||||
0x1c204003,
|
||||
0x00000005,
|
||||
Loading…
x
Reference in New Issue
Block a user