diff --git a/regs/assembler/vs/__main__.py b/regs/assembler/vs/__main__.py index 3847b51..99351e2 100644 --- a/regs/assembler/vs/__main__.py +++ b/regs/assembler/vs/__main__.py @@ -3,8 +3,8 @@ import sys from assembler.lexer import Lexer, LexerError from assembler.vs.keywords import find_keyword from assembler.vs.parser import Parser, ParserError -from assembler.vs.emitter import emit_instruction -from assembler.vs.validator import validate_instruction +from assembler.vs.emitter import emit_instruction, emit_dual_math_instruction +from assembler.vs.validator import validate_instruction, Instruction, DualMathInstruction from assembler.error import print_error sample = b""" @@ -26,7 +26,12 @@ def frontend_inner(buf): parser = Parser(tokens) for ins in parser.instructions(): ins = validate_instruction(ins) - yield list(emit_instruction(ins)) + if type(ins) is Instruction: + yield list(emit_instruction(ins)) + elif type(ins) is DualMathInstruction: + yield list(emit_dual_math_instruction(ins)) + else: + assert False, type(ins) def frontend(filename, buf): try: diff --git a/regs/assembler/vs/emitter.py b/regs/assembler/vs/emitter.py index ea251b8..289fd42 100644 --- a/regs/assembler/vs/emitter.py +++ b/regs/assembler/vs/emitter.py @@ -2,9 +2,11 @@ from typing import Union from assembler.vs.opcodes import ME, VE, MVE from assembler.vs.validator import Destination, Source, Instruction +from assembler.vs.validator import DualMathVEOperation, DualMathMEOperation, DualMathInstruction import pvs_dst import pvs_src +import pvs_dual_math def emit_destination_opcode(destination: Destination, opcode: Union[ME, VE, MVE], @@ -28,6 +30,7 @@ def emit_destination_opcode(destination: Destination, | pvs_dst.WE_W_gen(int(destination.write_enable[3])) | pvs_dst.VE_SAT_gen(ve_sat) | pvs_dst.ME_SAT_gen(me_sat) + | pvs_dst.DUAL_MATH_OP_gen(0) ) yield value @@ -85,13 +88,79 @@ def emit_instruction(ins: Instruction): ins.saturation) if len(ins.sources) >= 1: - yield from emit_source(ins.sources[0], prev_source(ins, 0)) - + source0 = ins.sources[0] source1 = ins.sources[1] if len(ins.sources) >= 2 else None source2 = ins.sources[2] if len(ins.sources) >= 3 else None + yield from emit_source(source0, prev_source(ins, 0)) yield from emit_source(source1, prev_source(ins, 1)) yield from emit_source(source2, prev_source(ins, 2)) else: yield 0 yield 0 yield 0 + + +def emit_dual_math_destination_opcode(ve_operation: DualMathVEOperation, + me_operation: DualMathMEOperation): + assert type(ve_operation.opcode) is VE + assert type(me_operation.opcode) is ME + + ve_sat = int(ve_operation.saturation) + me_sat = int(me_operation.saturation) + + destination = ve_operation.destination + value = ( + pvs_dst.OPCODE_gen(ve_operation.opcode.value) + | pvs_dst.MATH_INST_gen(0) + | pvs_dst.MACRO_INST_gen(0) + | pvs_dst.REG_TYPE_gen(destination.type.value) + | pvs_dst.OFFSET_gen(destination.offset) + | pvs_dst.WE_X_gen(int(destination.write_enable[0])) + | pvs_dst.WE_Y_gen(int(destination.write_enable[1])) + | pvs_dst.WE_Z_gen(int(destination.write_enable[2])) + | pvs_dst.WE_W_gen(int(destination.write_enable[3])) + | pvs_dst.VE_SAT_gen(ve_sat) + | pvs_dst.ME_SAT_gen(me_sat) + | pvs_dst.DUAL_MATH_OP_gen(1) + ) + yield value + +def emit_dual_math_dual_math_instruction(operation: DualMathMEOperation): + opcode_upper = (operation.opcode.value >> 4) & 0b1 + opcode_lower = (operation.opcode.value >> 0) & 0b1111 + + if len(operation.sources) == 1: + source, = operation.sources + value = ( + pvs_dual_math.SRC_REG_TYPE_gen(source.type.value) + | pvs_dual_math.DST_OPCODE_MSB_gen(opcode_upper) + | pvs_dual_math.SRC_ABS_XYZW_gen(int(source.absolute)) + | pvs_dual_math.SRC_OFFSET_gen(source.offset) + | pvs_dual_math.SRC_SWIZZLE_X_gen(source.swizzle_selects[0].value) + | pvs_dual_math.SRC_SWIZZLE_Y_gen(source.swizzle_selects[1].value) + | pvs_dual_math.DUAL_MATH_DST_OFFSET_gen(operation.destination.offset) + | pvs_dual_math.DST_OPCODE_gen(opcode_lower) + | pvs_dual_math.SRC_MODIFIER_X_gen(int(source.modifiers[0])) + | pvs_dual_math.SRC_MODIFIER_Y_gen(int(source.modifiers[1])) + | pvs_dual_math.DST_WE_SEL_gen(operation.destination.write_enable.value) + ) + else: + value = ( + pvs_dual_math.DST_OPCODE_MSB_gen(opcode_upper) + | pvs_dual_math.DUAL_MATH_DST_OFFSET_gen(operation.destination.offset) + | pvs_dual_math.DST_OPCODE_gen(opcode_lower) + | pvs_dual_math.DST_WE_SEL_gen(operation.destination.write_enable.value) + ) + yield value + +def emit_dual_math_instruction(ins: DualMathInstruction): + yield from emit_dual_math_destination_opcode(ins.ve_operation, ins.me_operation) + if len(ins.ve_operation.sources) >= 1: + source0 = ins.ve_operation.sources[0] + source1 = ins.ve_operation.sources[1] if len(ins.ve_operation.sources) >= 2 else None + yield from emit_source(source0, prev_source(ins.ve_operation, 0)) + yield from emit_source(source1, prev_source(ins.ve_operation, 1)) + else: + yield 0 + yield 0 + yield from emit_dual_math_dual_math_instruction(ins.me_operation) diff --git a/regs/assembler/vs/validator.py b/regs/assembler/vs/validator.py index 948d60d..949a02d 100644 --- a/regs/assembler/vs/validator.py +++ b/regs/assembler/vs/validator.py @@ -48,11 +48,6 @@ class Destination: offset: int write_enable: tuple[bool, bool, bool, bool] -@dataclass -class OpcodeDestination: - macro_inst: bool - reg_type: int - @dataclass class Instruction: destination: Destination @@ -60,6 +55,44 @@ class Instruction: sources: list[Source] opcode: Union[opcodes.VE, opcodes.ME, opcodes.MVE] +@dataclass +class DualMathVEOperation: + destination: Destination + saturation: bool + sources: list[Source] + opcode: opcodes.VE + +class DualMathMEWriteEnable(IntEnum): + x = 0 + y = 1 + z = 2 + w = 3 + +@dataclass +class DualMathMEDestination: + offset: int + write_enable: DualMathMEWriteEnable + +@dataclass +class DualMathMESource: + type: SourceType + absolute: bool + offset: int + swizzle_selects: tuple[SwizzleSelect, SwizzleSelect] + modifiers: tuple[bool, bool] + +@dataclass +class DualMathMEOperation: + destination: Destination + saturation: bool + sources: list[DualMathMESource] + opcode: opcodes.ME + +@dataclass +class DualMathInstruction: + ve_operation: DualMathVEOperation + me_operation: DualMathMEOperation + def validate_opcode(opcode_keyword: Token): if type(opcode_keyword.keyword) is opcodes.ME: return opcode_keyword.keyword @@ -135,7 +168,7 @@ def parse_swizzle_lexeme(token): modifier = False return tuple(zip(*swizzles)) -def validate_source(source): +def validate_source(source, swizzle_select_length): source_type_keywords = OrderedDict([ (KW.temporary , (SourceType.temporary , 128)), # 32 (KW.input , (SourceType.input , 128)), # 32 @@ -155,6 +188,10 @@ def validate_source(source): except ValueError: raise ValidatorError("invalid source swizzle", source.swizzle_identifier) + assert len(swizzle_selects) == len(modifiers) + if len(swizzle_selects) != swizzle_select_length: + raise ValidatorError("invalid source swizzle", source.swizzle_identifier) + return Source( type, absolute, @@ -215,13 +252,13 @@ def validate_instruction_inner(operation, opcode): raise ValidatorError("invalid opcode saturation suffix", operation.opcode_suffix_keyword) saturation = True if len(operation.sources) > 3: - raise ValidatorError("too many sources in operation", operation.sources[0].type_keyword) + raise ValidatorError("too many sources in operation", operation.sources[-1].type_keyword) if len(operation.sources) != opcode.operand_count: raise ValidatorError(f"incorrect number of source operands; expected {opcode.operand_count}", operation.sources[0].type_keyword) sources = [] for source in operation.sources: - sources.append(validate_source(source)) + sources.append(validate_source(source, swizzle_select_length=4)) opcode = validate_source_address_counts(operation.sources, sources, opcode) return Instruction( @@ -231,10 +268,111 @@ def validate_instruction_inner(operation, opcode): opcode ) +def validate_dual_math_ve_operation(operation, opcode): + destination = validate_destination(operation.destination) + saturation = False + if operation.opcode_suffix_keyword is not None: + if operation.opcode_suffix_keyword.keyword is not KW.saturation: + raise ValidatorError("invalid opcode saturation suffix", operation.opcode_suffix_keyword) + saturation = True + if len(operation.sources) > 2: + raise ValidatorError("too many sources in dual math VE operation", operation.sources[-1].type_keyword) + if opcode.operand_count > 2: + raise ValidatorError("3-operand opcode not valid in dual math VE operation", operation.sources[-1].type_keyword) + if len(operation.sources) != opcode.operand_count: + raise ValidatorError(f"incorrect number of source operands; expected {opcode.operand_count}", operation.sources[0].type_keyword) + + sources = [] + for source in operation.sources: + sources.append(validate_source(source, swizzle_select_length=4)) + + return DualMathVEOperation( + destination, + saturation, + sources, + opcode + ) + +def validate_dual_math_me_destination(destination): + if destination.type_keyword.keyword is not KW.alt_temporary: + raise ValidatorError("invalid dual math ME destination type keyword", destination.type_keyword) + offset = validate_identifier_number(destination.offset_identifier) + if offset >= 4: + raise ValidatorError("invalid dual math ME offset value", source.offset_identifier) + + we = bytes(destination.write_enable_identifier.lexeme).lower() + if len(we) != 1: + raise ValidatorError("invalid dual math ME write enable", destination.write_enable_identifier) + we_chars = { + c: t for c, t in zip(b"xyzw", [ + DualMathMEWriteEnable.x, + DualMathMEWriteEnable.y, + DualMathMEWriteEnable.z, + DualMathMEWriteEnable.w, + ]) + } + we_char = we[0] + if we_char not in we_chars: + ParserError("invalid dual math ME write enable", destination.write_enable_identifier) + + write_enable = we_chars[we[0]] + + return DualMathMEDestination( + offset, + write_enable, + ) + +def validate_dual_math_me_operation(operation, opcode): + destination = validate_dual_math_me_destination(operation.destination) + saturation = False + if operation.opcode_suffix_keyword is not None: + if operation.opcode_suffix_keyword.keyword is not KW.saturation: + raise ValidatorError("invalid opcode saturation suffix", operation.opcode_suffix_keyword) + saturation = True + if len(operation.sources) > 1: + raise ValidatorError("too many sources in dual math ME operation", operation.sources[-1].type_keyword) + if len(operation.sources) != opcode.operand_count: + raise ValidatorError(f"incorrect number of source operands; expected {opcode.operand_count}", operation.sources[0].type_keyword) + + sources = [] + for source in operation.sources: + sources.append(validate_source(source, swizzle_select_length=2)) + + return DualMathMEOperation( + destination, + saturation, + sources, + opcode, + ) + +def validate_dual_math_instruction(operations, _opcodes): + if type(_opcodes[0]) is opcodes.VE: + ve_operation_ast = operations[0] + ve_opcode = _opcodes[0] + me_operation_ast = operations[1] + me_opcode = _opcodes[1] + else: + ve_operation_ast = operations[1] + ve_opcode = _opcodes[1] + me_operation_ast = operations[0] + me_opcode = _opcodes[0] + + ve_operation = validate_dual_math_ve_operation(ve_operation_ast, ve_opcode) + me_operation = validate_dual_math_me_operation(me_operation_ast, me_opcode) + + all_sources_ast = ve_operation_ast.sources + me_operation_ast.sources + all_sources = ve_operation.sources + me_operation.sources + validate_opcode = validate_source_address_counts(all_sources_ast, all_sources, ve_operation.opcode) + assert validate_opcode == ve_operation.opcode + + return DualMathInstruction( + ve_operation, + me_operation, + ) + def validate_instruction(ins): if len(ins.operations) > 2: raise ValidatorError("too many operations in instruction", ins.operations[0].destination.type_keyword) - opcodes = [validate_opcode(operation.opcode_keyword) for operation in ins.operations] opcode_types = set(type(opcode) for opcode in opcodes) if len(opcode_types) != len(opcodes): @@ -242,8 +380,7 @@ def validate_instruction(ins): raise ValidatorError(f"invalid dual math operation: too many opcodes of type {opcode_type}", ins.operations[0].opcode_keyword) if len(opcodes) == 2: - assert False, "not implemented" - #return validate_dual_math_instruction(ins, opcodes) + return validate_dual_math_instruction(ins.operations, opcodes) else: assert len(opcodes) == 1 return validate_instruction_inner(ins.operations[0], opcodes[0]) @@ -255,9 +392,12 @@ if __name__ == "__main__": from assembler.vs.keywords import find_keyword from assembler.error import print_error buf = b""" - out[0].xz = VE_MAD.SAT |temp[1].-y-_0-_| const[2].x_0_ const[2].x_0_ ; + out[0].xz = VE_MAD.SAT |temp[1].-y-_0-_| const[2].x_0_ const[2].x_0_ ; +""" + buf = b""" + out[0].xz = VE_MUL.SAT |temp[1].-y-_0-_| const[2].x_0_ , + alt_temp[0].x = ME_SIN input[0].-y-_ ; """ -#atemp[0].xz = ME_SIN input[0].-y-_-0-_ ; lexer = Lexer(buf, find_keyword, emit_newlines=False, minus_is_token=False) tokens = list(lexer.lex_tokens()) diff --git a/regs/build.sh b/regs/build.sh index 110568c..a17d523 100644 --- a/regs/build.sh +++ b/regs/build.sh @@ -2,6 +2,7 @@ set -eux python parse_pvs.py PVS_DST pvs_bits/pvs_opcode_and_destination_operand.txt > pvs_dst.py python parse_pvs.py PVS_SRC pvs_bits/pvs_source_operand.txt > pvs_src.py +python parse_pvs.py PVS pvs_bits/pvs_dual_math_instruction.txt > pvs_dual_math.py python parse_pvs_bits.py pvs_bits/pvs_opcode_and_destination_operand_bits.txt > pvs_dst_bits.py python parse_pvs_bits.py pvs_bits/pvs_source_operand_bits.txt > pvs_src_bits.py python 3d_registers.py python 3d_registers.txt > registers_lookup.py diff --git a/regs/parse_pvs.py b/regs/parse_pvs.py index 9582f17..83e90e6 100644 --- a/regs/parse_pvs.py +++ b/regs/parse_pvs.py @@ -41,7 +41,7 @@ def parse_file_fields2(filename): for line in parse_file_fields(filename): field_name, bits, description = line bits = parse_bits(bits) - if not field_name.startswith(prefix + '_'): + if not field_name.startswith(prefix + '_') and field_name != 'DUAL_MATH_DST_OFFSET': assert field_name.startswith("SPARE_") continue field_name = field_name.removeprefix(prefix + '_') diff --git a/regs/pvs_bits/pvs_dual_math_instruction.txt b/regs/pvs_bits/pvs_dual_math_instruction.txt index 08d27ac..73dfdb4 100644 --- a/regs/pvs_bits/pvs_dual_math_instruction.txt +++ b/regs/pvs_bits/pvs_dual_math_instruction.txt @@ -1,15 +1,15 @@ -Field Name Bits Description -PVS_SRC_REG_TYPE 1:0 Defines the Memory Select (Register Type) for the Source Operand. See Below. -PVS_DST_OPCODE_MSB 2 Math Opcode MSB for Dual Math Inst. -PVS_SRC_ABS_XYZW 3 If set, Take absolute value of both components of Dual Math input vector. -PVS_SRC_ADDR_MODE_0 4 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE -PVS_SRC_OFFSET 12:5 Vector Offset into selected memory (Register Type) -PVS_SRC_SWIZZLE_X 15:13 X-Component Swizzle Select. See Below -PVS_SRC_SWIZZLE_Y 18:16 Y-Component Swizzle Select. See Below -DUAL_MATH_DST_OFFSET 20:19 Selects Dest Address ATRM 0-3 for Math Inst. -PVS_DST_OPCODE 24:21 Math Opcode for Dual Math Inst. -PVS_SRC_MODIFIER_X 25 If set, Negate X Component of input vector. -PVS_SRC_MODIFIER_Y 26 If set, Negate Y Component of input vector. -PVS_DST_WE_SEL 28:27 Encoded Write Enable for Dual Math Op Inst (0 = X, 1 = Y, 2 = Z, 3 = W) -PVS_SRC_ADDR_SEL 30:29 When PVS_SRC_ADDR_MODE is set, this selects which component of the 4-component address register to use. -PVS_SRC_ADDR_MODE_1 31 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE +Field Name Bits Description +PVS_SRC_REG_TYPE 1:0 Defines the Memory Select (Register Type) for the Source Operand. See Below. +PVS_DST_OPCODE_MSB 2 Math Opcode MSB for Dual Math Inst. +PVS_SRC_ABS_XYZW 3 If set, Take absolute value of both components of Dual Math input vector. +PVS_SRC_ADDR_MODE_0 4 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE +PVS_SRC_OFFSET 12:5 Vector Offset into selected memory (Register Type) +PVS_SRC_SWIZZLE_X 15:13 X-Component Swizzle Select. See Below +PVS_SRC_SWIZZLE_Y 18:16 Y-Component Swizzle Select. See Below +DUAL_MATH_DST_OFFSET 20:19 Selects Dest Address ATRM 0-3 for Math Inst. +PVS_DST_OPCODE 24:21 Math Opcode for Dual Math Inst. +PVS_SRC_MODIFIER_X 25 If set, Negate X Component of input vector. +PVS_SRC_MODIFIER_Y 26 If set, Negate Y Component of input vector. +PVS_DST_WE_SEL 28:27 Encoded Write Enable for Dual Math Op Inst (0 = X, 1 = Y, 2 = Z, 3 = W) +PVS_SRC_ADDR_SEL 30:29 When PVS_SRC_ADDR_MODE is set, this selects which component of the 4-component address register to use. +PVS_SRC_ADDR_MODE_1 31 Combine ADDR_MODE_1 (msb) with ADDR_MODE_0 (lsb) to form 2-bit ADDR_MODE diff --git a/regs/pvs_disassemble.py b/regs/pvs_disassemble.py index 968cea7..c4f07f5 100644 --- a/regs/pvs_disassemble.py +++ b/regs/pvs_disassemble.py @@ -2,6 +2,7 @@ import pvs_src import pvs_src_bits import pvs_dst import pvs_dst_bits +import pvs_dual_math import itertools from functools import partial import sys @@ -92,7 +93,6 @@ def parse_dst_op(dst_op): assert addr_mode == 0 assert pred_enable == 0 assert pred_sense == 0 - assert dual_math_op == 0 assert addr_sel == 0 parts = [] @@ -122,32 +122,29 @@ def parse_dst_op(dst_op): return parts -def src_swizzle_from_src_op(src_op): - swizzle_x = pvs_src.SWIZZLE_X(src_op) - swizzle_y = pvs_src.SWIZZLE_Y(src_op) - swizzle_z = pvs_src.SWIZZLE_Z(src_op) - swizzle_w = pvs_src.SWIZZLE_W(src_op) - modifier_x = pvs_src.MODIFIER_X(src_op) - modifier_y = pvs_src.MODIFIER_Y(src_op) - modifier_z = pvs_src.MODIFIER_Z(src_op) - modifier_w = pvs_src.MODIFIER_W(src_op) - +def src_swizzle_from_src_op(swizzles, modifiers): modifiers = [ '' if modifier == 0 else '-' - for modifier - in [modifier_x, modifier_y, modifier_z, modifier_w] + for modifier in modifiers ] src_swizzle_select = [ 'x', 'y', 'z', 'w', '0', '1', 'h', '_' ] swizzles = [ src_swizzle_select[swizzle] - for swizzle - in [swizzle_x, swizzle_y, swizzle_z, swizzle_w] + for swizzle in swizzles ] return ''.join(map(''.join, zip(modifiers, swizzles))) +def reg_type_str_from_reg_type(reg_type): + reg_type_str = pvs_src_bits.PVS_SRC_REG_TYPE[reg_type] + reg_type_str = reg_type_str.removeprefix("PVS_SRC_REG_") + reg_type_str = reg_type_str.replace("TEMPORARY", "TEMP") + reg_type_str = reg_type_str.replace("CONSTANT", "CONST") + reg_type_str = reg_type_str.lower() + return reg_type_str + def parse_src_op(src_op): reg_type = pvs_src.REG_TYPE(src_op) abs_xyzw = pvs_src.ABS_XYZW(src_op) @@ -159,17 +156,62 @@ def parse_src_op(src_op): assert addr_mode == 0 assert addr_sel == 0 - reg_type_str = pvs_src_bits.PVS_SRC_REG_TYPE[reg_type] - reg_type_str = reg_type_str.removeprefix("PVS_SRC_REG_") - reg_type_str = reg_type_str.replace("TEMPORARY", "TEMP") - reg_type_str = reg_type_str.replace("CONSTANT", "CONST") - reg_type_str = reg_type_str.lower() + reg_type_str = reg_type_str_from_reg_type(reg_type) - src_swizzle = src_swizzle_from_src_op(src_op) + swizzle_x = pvs_src.SWIZZLE_X(src_op) + swizzle_y = pvs_src.SWIZZLE_Y(src_op) + swizzle_z = pvs_src.SWIZZLE_Z(src_op) + swizzle_w = pvs_src.SWIZZLE_W(src_op) + modifier_x = pvs_src.MODIFIER_X(src_op) + modifier_y = pvs_src.MODIFIER_Y(src_op) + modifier_z = pvs_src.MODIFIER_Z(src_op) + modifier_w = pvs_src.MODIFIER_W(src_op) + swizzles = [swizzle_x, swizzle_y, swizzle_z, swizzle_w] + modifiers = [modifier_x, modifier_y, modifier_z, modifier_w] + src_swizzle = src_swizzle_from_src_op(swizzles, modifiers) + + s = f"{reg_type_str}[{offset}].{src_swizzle}" if abs_xyzw: - src_swizzle = f"abs({src_swizzle})" + return f"|{s}|" + else: + return s - return f"{reg_type_str}[{offset}].{src_swizzle}" +def parse_dual_math_instruction(instruction): + src_reg_type = pvs_dual_math.SRC_REG_TYPE(instruction) + dst_opcode = ( (pvs_dual_math.DST_OPCODE_MSB(instruction) << 4) + | (pvs_dual_math.DST_OPCODE(instruction) << 0) ) + src_abs = pvs_dual_math.SRC_ABS_XYZW(instruction) + src_addr_mode = ( (pvs_dual_math.SRC_ADDR_MODE_1(instruction) << 1) + | (pvs_dual_math.SRC_ADDR_MODE_0(instruction) << 0)) + src_offset = pvs_dual_math.SRC_OFFSET(instruction) + src_swizzle_x = pvs_dual_math.SRC_SWIZZLE_X(instruction) + src_swizzle_y = pvs_dual_math.SRC_SWIZZLE_Y(instruction) + dual_math_dst_offset = pvs_dual_math.DUAL_MATH_DST_OFFSET(instruction) + src_modifier_x = pvs_dual_math.SRC_MODIFIER_X(instruction) + src_modifier_y = pvs_dual_math.SRC_MODIFIER_Y(instruction) + dst_we_sel = pvs_dual_math.DST_WE_SEL(instruction) + src_addr_sel = pvs_dual_math.SRC_ADDR_SEL(instruction) + + assert src_addr_sel == 0 + assert src_addr_mode == 0 + + we_str = ["x", "y", "z", "w"][dst_we_sel] + dst_str = f"alt_temp[{dual_math_dst_offset}].{we_str}" + + opcode_str = op_substitutions(pvs_dst_bits.MATH_OPCODE[dst_opcode]) + + swizzles = [src_swizzle_x, src_swizzle_y] + modifiers = [src_modifier_x, src_modifier_y] + src_swizzle = src_swizzle_from_src_op(swizzles, modifiers) + + reg_type_str = reg_type_str_from_reg_type(src_reg_type) + + src_str = f"{reg_type_str}[{src_offset}].{src_swizzle}" + + if src_abs: + src_str = f"|{src}|" + + return dst_str, opcode_str, src_str def parse_instruction(instruction): dst_op = instruction[0] @@ -177,16 +219,28 @@ def parse_instruction(instruction): src_op1 = instruction[2] src_op2 = instruction[3] - dst, op, *rest = itertools.chain( - parse_dst_op(dst_op), - [ - parse_src_op(src_op0), - parse_src_op(src_op1), - parse_src_op(src_op2), - ] - ) - - print(dst.ljust(12), "=", op.ljust(12), " ".join(map(lambda s: s.ljust(17), rest))) + dual_math_op = pvs_dst.DUAL_MATH_OP(dst_op) + if dual_math_op == 0: + dst, op, *rest = itertools.chain( + parse_dst_op(dst_op), + [ + parse_src_op(src_op0), + parse_src_op(src_op1), + parse_src_op(src_op2), + ] + ) + print(dst.ljust(15), "=", op.ljust(12), " ".join(map(lambda s: s.ljust(17), rest)).rstrip(), ';') + else: + dst, op, *rest = itertools.chain( + parse_dst_op(dst_op), + [ + parse_src_op(src_op0), + parse_src_op(src_op1), + ] + ) + print(dst.ljust(15), "=", op.ljust(12), " ".join(map(lambda s: s.ljust(17), rest)).rstrip(), ',') + dm_dst, dm_op, dm_src = parse_dual_math_instruction(src_op2) + print(dm_dst.ljust(15), "=", dm_op.ljust(12), dm_src, ';') def parse_hex(s): assert s.startswith('0x') diff --git a/regs/pvs_dual_math.py b/regs/pvs_dual_math.py new file mode 100644 index 0000000..889f1c7 --- /dev/null +++ b/regs/pvs_dual_math.py @@ -0,0 +1,114 @@ +def SRC_REG_TYPE(n): + return (n >> 0) & 0x3 + +def SRC_REG_TYPE_gen(n): + assert (0x3 & n) == n, (n, 0x3) + return n << 0 + +def DST_OPCODE_MSB(n): + return (n >> 2) & 0x1 + +def DST_OPCODE_MSB_gen(n): + assert (0x1 & n) == n, (n, 0x1) + return n << 2 + +def SRC_ABS_XYZW(n): + return (n >> 3) & 0x1 + +def SRC_ABS_XYZW_gen(n): + assert (0x1 & n) == n, (n, 0x1) + return n << 3 + +def SRC_ADDR_MODE_0(n): + return (n >> 4) & 0x1 + +def SRC_ADDR_MODE_0_gen(n): + assert (0x1 & n) == n, (n, 0x1) + return n << 4 + +def SRC_OFFSET(n): + return (n >> 5) & 0xff + +def SRC_OFFSET_gen(n): + assert (0xff & n) == n, (n, 0xff) + return n << 5 + +def SRC_SWIZZLE_X(n): + return (n >> 13) & 0x7 + +def SRC_SWIZZLE_X_gen(n): + assert (0x7 & n) == n, (n, 0x7) + return n << 13 + +def SRC_SWIZZLE_Y(n): + return (n >> 16) & 0x7 + +def SRC_SWIZZLE_Y_gen(n): + assert (0x7 & n) == n, (n, 0x7) + return n << 16 + +def DUAL_MATH_DST_OFFSET(n): + return (n >> 19) & 0x3 + +def DUAL_MATH_DST_OFFSET_gen(n): + assert (0x3 & n) == n, (n, 0x3) + return n << 19 + +def DST_OPCODE(n): + return (n >> 21) & 0xf + +def DST_OPCODE_gen(n): + assert (0xf & n) == n, (n, 0xf) + return n << 21 + +def SRC_MODIFIER_X(n): + return (n >> 25) & 0x1 + +def SRC_MODIFIER_X_gen(n): + assert (0x1 & n) == n, (n, 0x1) + return n << 25 + +def SRC_MODIFIER_Y(n): + return (n >> 26) & 0x1 + +def SRC_MODIFIER_Y_gen(n): + assert (0x1 & n) == n, (n, 0x1) + return n << 26 + +def DST_WE_SEL(n): + return (n >> 27) & 0x3 + +def DST_WE_SEL_gen(n): + assert (0x3 & n) == n, (n, 0x3) + return n << 27 + +def SRC_ADDR_SEL(n): + return (n >> 29) & 0x3 + +def SRC_ADDR_SEL_gen(n): + assert (0x3 & n) == n, (n, 0x3) + return n << 29 + +def SRC_ADDR_MODE_1(n): + return (n >> 31) & 0x1 + +def SRC_ADDR_MODE_1_gen(n): + assert (0x1 & n) == n, (n, 0x1) + return n << 31 + +table = [ + ("SRC_REG_TYPE", SRC_REG_TYPE), + ("DST_OPCODE_MSB", DST_OPCODE_MSB), + ("SRC_ABS_XYZW", SRC_ABS_XYZW), + ("SRC_ADDR_MODE_0", SRC_ADDR_MODE_0), + ("SRC_OFFSET", SRC_OFFSET), + ("SRC_SWIZZLE_X", SRC_SWIZZLE_X), + ("SRC_SWIZZLE_Y", SRC_SWIZZLE_Y), + ("DUAL_MATH_DST_OFFSET", DUAL_MATH_DST_OFFSET), + ("DST_OPCODE", DST_OPCODE), + ("SRC_MODIFIER_X", SRC_MODIFIER_X), + ("SRC_MODIFIER_Y", SRC_MODIFIER_Y), + ("DST_WE_SEL", DST_WE_SEL), + ("SRC_ADDR_SEL", SRC_ADDR_SEL), + ("SRC_ADDR_MODE_1", SRC_ADDR_MODE_1), +]