149 lines
4.7 KiB
Python
149 lines
4.7 KiB
Python
from dataclasses import dataclass
|
|
from typing import Union
|
|
from collections import OrderedDict
|
|
from enum import IntEnum
|
|
|
|
from assembler.validator import ValidatorError
|
|
from assembler.fs import parser
|
|
from assembler.fs.keywords import KW
|
|
from assembler.fs.common_validator import RGBMask, AlphaMask
|
|
from assembler.fs.common_validator import validate_identifier_number
|
|
from assembler.fs.common_validator import keywords_to_string
|
|
|
|
@dataclass
|
|
class Masks:
|
|
alpha_wmask: AlphaMask
|
|
rgb_wmask: RGBMask
|
|
|
|
class TEXOp(IntEnum):
|
|
NOP = 0
|
|
LD = 1
|
|
TEXKILL = 2
|
|
PROJ = 3
|
|
LODBIAS = 4
|
|
LOD = 5
|
|
DXDY = 6
|
|
|
|
class Swizzle(IntEnum):
|
|
R = 0
|
|
G = 1
|
|
B = 2
|
|
A = 3
|
|
|
|
@dataclass
|
|
class Instruction:
|
|
tags: set[Union[KW.TEX_SEM_WAIT, KW.TEX_SEM_ACQUIRE, KW.OUT]]
|
|
masks: Masks
|
|
opcode: TEXOp
|
|
tex_id: int
|
|
src_addr: int
|
|
src_swizzle: tuple[Swizzle, Swizzle, Swizzle, Swizzle]
|
|
dst_addr: int
|
|
dst_swizzle: tuple[Swizzle, Swizzle, Swizzle, Swizzle]
|
|
|
|
def validate_swizzle(token):
|
|
if len(token.lexeme) != 4:
|
|
raise ValidatorError("invalid swizzle identifier", token)
|
|
swizzles = OrderedDict([
|
|
(ord(b"r"), Swizzle.R),
|
|
(ord(b"g"), Swizzle.G),
|
|
(ord(b"b"), Swizzle.B),
|
|
(ord(b"a"), Swizzle.A),
|
|
])
|
|
if not all(c in swizzles for c in token.lexeme):
|
|
raise ValidatorError("invalid swizzle identifier", token)
|
|
return tuple(swizzles[c] for c in token.lexeme)
|
|
|
|
def validate_mask_swizzle(token) -> tuple[AlphaMask, RGBMask]:
|
|
argb_masks = OrderedDict([
|
|
(b"none" , (AlphaMask.NONE, RGBMask.NONE)),
|
|
(b"r" , (AlphaMask.NONE, RGBMask.R)),
|
|
(b"g" , (AlphaMask.NONE, RGBMask.G)),
|
|
(b"rg" , (AlphaMask.NONE, RGBMask.RG)),
|
|
(b"b" , (AlphaMask.NONE, RGBMask.B)),
|
|
(b"rb" , (AlphaMask.NONE, RGBMask.RB)),
|
|
(b"gb" , (AlphaMask.NONE, RGBMask.GB)),
|
|
(b"rgb" , (AlphaMask.NONE, RGBMask.RGB)),
|
|
(b"ar" , (AlphaMask.A, RGBMask.R)),
|
|
(b"ag" , (AlphaMask.A, RGBMask.G)),
|
|
(b"arg" , (AlphaMask.A, RGBMask.RG)),
|
|
(b"ab" , (AlphaMask.A, RGBMask.B)),
|
|
(b"arb" , (AlphaMask.A, RGBMask.RB)),
|
|
(b"agb" , (AlphaMask.A, RGBMask.GB)),
|
|
(b"argb" , (AlphaMask.A, RGBMask.RGB)),
|
|
])
|
|
if token.lexeme not in argb_masks:
|
|
raise ValidatorError("invalid destination mask", token)
|
|
return argb_masks[token.lexeme]
|
|
|
|
def validate_masks(ins_ast: parser.TEXInstruction):
|
|
addresses = set()
|
|
dests = set()
|
|
|
|
masks = Masks(
|
|
alpha_wmask = AlphaMask.NONE,
|
|
rgb_wmask = RGBMask.NONE,
|
|
)
|
|
|
|
for dest_addr_swizzle in ins_ast.operation.dest_addr_swizzles:
|
|
dest_keyword = dest_addr_swizzle.dest_keyword
|
|
if dest_keyword.keyword is not KW.TEMP:
|
|
raise ValidatorError(f"invalid dest keyword, expected `temp`", dest_keyword)
|
|
dests.add(dest_keyword.keyword)
|
|
|
|
addr_identifier = dest_addr_swizzle.addr_identifier
|
|
addr = validate_identifier_number(addr_identifier)
|
|
addresses.add(addr)
|
|
|
|
swizzle_identifier = dest_addr_swizzle.swizzle_identifier
|
|
alpha_mask, rgb_mask = validate_mask_swizzle(swizzle_identifier)
|
|
|
|
masks.alpha_wmask = alpha_mask
|
|
masks.rgb_wmask = rgb_mask
|
|
|
|
if len(addresses) > 1:
|
|
raise ValidatorError("contradictory destination address", ins_ast.operation.dest_addr_swizzles[-1].addr_identifier)
|
|
|
|
address, = addresses
|
|
|
|
return masks, address
|
|
|
|
op_kws = OrderedDict([
|
|
(KW.NOP, TEXOp.NOP),
|
|
(KW.LD, TEXOp.LD),
|
|
(KW.TEXKILL, TEXOp.TEXKILL),
|
|
(KW.PROJ, TEXOp.PROJ),
|
|
(KW.LODBIAS, TEXOp.LODBIAS),
|
|
(KW.LOD, TEXOp.LOD),
|
|
(KW.DXDY, TEXOp.DXDY),
|
|
])
|
|
|
|
def validate_opcode(token):
|
|
if token.keyword not in op_kws:
|
|
raise ValidatorError("invalid tex opcode keyword", token)
|
|
return op_kws[token.keyword]
|
|
|
|
def validate_instruction(ins_ast: parser.TEXInstruction):
|
|
tags = set([tag.keyword for tag in ins_ast.tags])
|
|
|
|
masks, dst_addr = validate_masks(ins_ast)
|
|
opcode = validate_opcode(ins_ast.operation.opcode_keyword)
|
|
|
|
tex_id = validate_identifier_number(ins_ast.operation.tex_id_identifier)
|
|
|
|
dst_swizzle = validate_swizzle(ins_ast.operation.tex_dst_swizzle_identifier)
|
|
|
|
src_address = validate_identifier_number(ins_ast.operation.tex_src_address_identifier)
|
|
src_swizzle = validate_swizzle(ins_ast.operation.tex_src_swizzle_identifier)
|
|
|
|
return Instruction(
|
|
tags = tags,
|
|
masks = masks,
|
|
opcode = opcode,
|
|
tex_id = tex_id,
|
|
src_addr = src_address, # texture coordinate address
|
|
src_swizzle = src_swizzle, # texture coordinate swizzle
|
|
dst_addr = dst_addr, # temp address
|
|
dst_swizzle = dst_swizzle, # texture value swizzle
|
|
)
|