assembler/vs: add support for dual math operations

This commit is contained in:
Zack Buhman 2025-10-23 21:48:11 -05:00
parent d08f99d36b
commit f3f1969f4a
8 changed files with 450 additions and 67 deletions

View File

@ -3,8 +3,8 @@ import sys
from assembler.lexer import Lexer, LexerError from assembler.lexer import Lexer, LexerError
from assembler.vs.keywords import find_keyword from assembler.vs.keywords import find_keyword
from assembler.vs.parser import Parser, ParserError from assembler.vs.parser import Parser, ParserError
from assembler.vs.emitter import emit_instruction from assembler.vs.emitter import emit_instruction, emit_dual_math_instruction
from assembler.vs.validator import validate_instruction from assembler.vs.validator import validate_instruction, Instruction, DualMathInstruction
from assembler.error import print_error from assembler.error import print_error
sample = b""" sample = b"""
@ -26,7 +26,12 @@ def frontend_inner(buf):
parser = Parser(tokens) parser = Parser(tokens)
for ins in parser.instructions(): for ins in parser.instructions():
ins = validate_instruction(ins) ins = validate_instruction(ins)
if type(ins) is Instruction:
yield list(emit_instruction(ins)) 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): def frontend(filename, buf):
try: try:

View File

@ -2,9 +2,11 @@ from typing import Union
from assembler.vs.opcodes import ME, VE, MVE from assembler.vs.opcodes import ME, VE, MVE
from assembler.vs.validator import Destination, Source, Instruction from assembler.vs.validator import Destination, Source, Instruction
from assembler.vs.validator import DualMathVEOperation, DualMathMEOperation, DualMathInstruction
import pvs_dst import pvs_dst
import pvs_src import pvs_src
import pvs_dual_math
def emit_destination_opcode(destination: Destination, def emit_destination_opcode(destination: Destination,
opcode: Union[ME, VE, MVE], 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.WE_W_gen(int(destination.write_enable[3]))
| pvs_dst.VE_SAT_gen(ve_sat) | pvs_dst.VE_SAT_gen(ve_sat)
| pvs_dst.ME_SAT_gen(me_sat) | pvs_dst.ME_SAT_gen(me_sat)
| pvs_dst.DUAL_MATH_OP_gen(0)
) )
yield value yield value
@ -85,13 +88,79 @@ def emit_instruction(ins: Instruction):
ins.saturation) ins.saturation)
if len(ins.sources) >= 1: 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 source1 = ins.sources[1] if len(ins.sources) >= 2 else None
source2 = ins.sources[2] if len(ins.sources) >= 3 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(source1, prev_source(ins, 1))
yield from emit_source(source2, prev_source(ins, 2)) yield from emit_source(source2, prev_source(ins, 2))
else: else:
yield 0 yield 0
yield 0 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)

View File

@ -48,11 +48,6 @@ class Destination:
offset: int offset: int
write_enable: tuple[bool, bool, bool, bool] write_enable: tuple[bool, bool, bool, bool]
@dataclass
class OpcodeDestination:
macro_inst: bool
reg_type: int
@dataclass @dataclass
class Instruction: class Instruction:
destination: Destination destination: Destination
@ -60,6 +55,44 @@ class Instruction:
sources: list[Source] sources: list[Source]
opcode: Union[opcodes.VE, opcodes.ME, opcodes.MVE] 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): def validate_opcode(opcode_keyword: Token):
if type(opcode_keyword.keyword) is opcodes.ME: if type(opcode_keyword.keyword) is opcodes.ME:
return opcode_keyword.keyword return opcode_keyword.keyword
@ -135,7 +168,7 @@ def parse_swizzle_lexeme(token):
modifier = False modifier = False
return tuple(zip(*swizzles)) return tuple(zip(*swizzles))
def validate_source(source): def validate_source(source, swizzle_select_length):
source_type_keywords = OrderedDict([ source_type_keywords = OrderedDict([
(KW.temporary , (SourceType.temporary , 128)), # 32 (KW.temporary , (SourceType.temporary , 128)), # 32
(KW.input , (SourceType.input , 128)), # 32 (KW.input , (SourceType.input , 128)), # 32
@ -155,6 +188,10 @@ def validate_source(source):
except ValueError: except ValueError:
raise ValidatorError("invalid source swizzle", source.swizzle_identifier) 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( return Source(
type, type,
absolute, absolute,
@ -215,13 +252,13 @@ def validate_instruction_inner(operation, opcode):
raise ValidatorError("invalid opcode saturation suffix", operation.opcode_suffix_keyword) raise ValidatorError("invalid opcode saturation suffix", operation.opcode_suffix_keyword)
saturation = True saturation = True
if len(operation.sources) > 3: 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: if len(operation.sources) != opcode.operand_count:
raise ValidatorError(f"incorrect number of source operands; expected {opcode.operand_count}", operation.sources[0].type_keyword) raise ValidatorError(f"incorrect number of source operands; expected {opcode.operand_count}", operation.sources[0].type_keyword)
sources = [] sources = []
for source in operation.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) opcode = validate_source_address_counts(operation.sources, sources, opcode)
return Instruction( return Instruction(
@ -231,10 +268,111 @@ def validate_instruction_inner(operation, opcode):
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): def validate_instruction(ins):
if len(ins.operations) > 2: if len(ins.operations) > 2:
raise ValidatorError("too many operations in instruction", ins.operations[0].destination.type_keyword) raise ValidatorError("too many operations in instruction", ins.operations[0].destination.type_keyword)
opcodes = [validate_opcode(operation.opcode_keyword) for operation in ins.operations] opcodes = [validate_opcode(operation.opcode_keyword) for operation in ins.operations]
opcode_types = set(type(opcode) for opcode in opcodes) opcode_types = set(type(opcode) for opcode in opcodes)
if len(opcode_types) != len(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) raise ValidatorError(f"invalid dual math operation: too many opcodes of type {opcode_type}", ins.operations[0].opcode_keyword)
if len(opcodes) == 2: if len(opcodes) == 2:
assert False, "not implemented" return validate_dual_math_instruction(ins.operations, opcodes)
#return validate_dual_math_instruction(ins, opcodes)
else: else:
assert len(opcodes) == 1 assert len(opcodes) == 1
return validate_instruction_inner(ins.operations[0], opcodes[0]) return validate_instruction_inner(ins.operations[0], opcodes[0])
@ -257,7 +394,10 @@ if __name__ == "__main__":
buf = b""" 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_ ;
""" """
#atemp[0].xz = ME_SIN input[0].-y-_-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-_ ;
"""
lexer = Lexer(buf, find_keyword, emit_newlines=False, minus_is_token=False) lexer = Lexer(buf, find_keyword, emit_newlines=False, minus_is_token=False)
tokens = list(lexer.lex_tokens()) tokens = list(lexer.lex_tokens())

View File

@ -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_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_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_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 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 python 3d_registers.py python 3d_registers.txt > registers_lookup.py

View File

@ -41,7 +41,7 @@ def parse_file_fields2(filename):
for line in parse_file_fields(filename): for line in parse_file_fields(filename):
field_name, bits, description = line field_name, bits, description = line
bits = parse_bits(bits) 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_") assert field_name.startswith("SPARE_")
continue continue
field_name = field_name.removeprefix(prefix + '_') field_name = field_name.removeprefix(prefix + '_')

View File

@ -2,6 +2,7 @@ import pvs_src
import pvs_src_bits import pvs_src_bits
import pvs_dst import pvs_dst
import pvs_dst_bits import pvs_dst_bits
import pvs_dual_math
import itertools import itertools
from functools import partial from functools import partial
import sys import sys
@ -92,7 +93,6 @@ def parse_dst_op(dst_op):
assert addr_mode == 0 assert addr_mode == 0
assert pred_enable == 0 assert pred_enable == 0
assert pred_sense == 0 assert pred_sense == 0
assert dual_math_op == 0
assert addr_sel == 0 assert addr_sel == 0
parts = [] parts = []
@ -122,32 +122,29 @@ def parse_dst_op(dst_op):
return parts return parts
def src_swizzle_from_src_op(src_op): def src_swizzle_from_src_op(swizzles, modifiers):
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)
modifiers = [ modifiers = [
'' if modifier == 0 else '-' '' if modifier == 0 else '-'
for modifier for modifier in modifiers
in [modifier_x, modifier_y, modifier_z, modifier_w]
] ]
src_swizzle_select = [ src_swizzle_select = [
'x', 'y', 'z', 'w', '0', '1', 'h', '_' 'x', 'y', 'z', 'w', '0', '1', 'h', '_'
] ]
swizzles = [ swizzles = [
src_swizzle_select[swizzle] src_swizzle_select[swizzle]
for swizzle for swizzle in swizzles
in [swizzle_x, swizzle_y, swizzle_z, swizzle_w]
] ]
return ''.join(map(''.join, zip(modifiers, 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): def parse_src_op(src_op):
reg_type = pvs_src.REG_TYPE(src_op) reg_type = pvs_src.REG_TYPE(src_op)
abs_xyzw = pvs_src.ABS_XYZW(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_mode == 0
assert addr_sel == 0 assert addr_sel == 0
reg_type_str = pvs_src_bits.PVS_SRC_REG_TYPE[reg_type] reg_type_str = reg_type_str_from_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()
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: 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): def parse_instruction(instruction):
dst_op = instruction[0] dst_op = instruction[0]
@ -177,6 +219,8 @@ def parse_instruction(instruction):
src_op1 = instruction[2] src_op1 = instruction[2]
src_op2 = instruction[3] src_op2 = instruction[3]
dual_math_op = pvs_dst.DUAL_MATH_OP(dst_op)
if dual_math_op == 0:
dst, op, *rest = itertools.chain( dst, op, *rest = itertools.chain(
parse_dst_op(dst_op), parse_dst_op(dst_op),
[ [
@ -185,8 +229,18 @@ def parse_instruction(instruction):
parse_src_op(src_op2), parse_src_op(src_op2),
] ]
) )
print(dst.ljust(15), "=", op.ljust(12), " ".join(map(lambda s: s.ljust(17), rest)).rstrip(), ';')
print(dst.ljust(12), "=", op.ljust(12), " ".join(map(lambda s: s.ljust(17), rest))) 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): def parse_hex(s):
assert s.startswith('0x') assert s.startswith('0x')

114
regs/pvs_dual_math.py Normal file
View 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),
]