assembler/vs: add support for dual math operations
This commit is contained in:
parent
d08f99d36b
commit
f3f1969f4a
@ -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:
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 + '_')
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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')
|
||||
|
||||
114
regs/pvs_dual_math.py
Normal file
114
regs/pvs_dual_math.py
Normal file
@ -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),
|
||||
]
|
||||
Loading…
x
Reference in New Issue
Block a user