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.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:

View File

@ -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)

View File

@ -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())

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_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

View File

@ -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 + '_')

View File

@ -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

View File

@ -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
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),
]