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.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)
|
||||||
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):
|
def frontend(filename, buf):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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])
|
||||||
@ -255,9 +392,12 @@ if __name__ == "__main__":
|
|||||||
from assembler.vs.keywords import find_keyword
|
from assembler.vs.keywords import find_keyword
|
||||||
from assembler.error import print_error
|
from assembler.error import print_error
|
||||||
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_ ;
|
||||||
|
"""
|
||||||
|
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)
|
lexer = Lexer(buf, find_keyword, emit_newlines=False, minus_is_token=False)
|
||||||
tokens = list(lexer.lex_tokens())
|
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_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
|
||||||
|
|||||||
@ -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 + '_')
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
Field Name Bits Description
|
Field Name Bits Description
|
||||||
PVS_SRC_REG_TYPE 1:0 Defines the Memory Select (Register Type) for the Source Operand. See Below.
|
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_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_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_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_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_X 15:13 X-Component Swizzle Select. See Below
|
||||||
PVS_SRC_SWIZZLE_Y 18:16 Y-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.
|
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_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_X 25 If set, Negate X Component of input vector.
|
||||||
PVS_SRC_MODIFIER_Y 26 If set, Negate Y 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_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_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
|
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_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,16 +219,28 @@ def parse_instruction(instruction):
|
|||||||
src_op1 = instruction[2]
|
src_op1 = instruction[2]
|
||||||
src_op2 = instruction[3]
|
src_op2 = instruction[3]
|
||||||
|
|
||||||
dst, op, *rest = itertools.chain(
|
dual_math_op = pvs_dst.DUAL_MATH_OP(dst_op)
|
||||||
parse_dst_op(dst_op),
|
if dual_math_op == 0:
|
||||||
[
|
dst, op, *rest = itertools.chain(
|
||||||
parse_src_op(src_op0),
|
parse_dst_op(dst_op),
|
||||||
parse_src_op(src_op1),
|
[
|
||||||
parse_src_op(src_op2),
|
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)))
|
)
|
||||||
|
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):
|
def parse_hex(s):
|
||||||
assert s.startswith('0x')
|
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