assembler.fs: add support for omod

This commit is contained in:
Zack Buhman 2025-11-11 14:22:16 -06:00
parent 399cd6aaf9
commit 90b486e744
5 changed files with 68 additions and 3 deletions

View File

@ -17,6 +17,9 @@ def emit_alpha_op(code, alpha_op):
if alpha_op.dest.omask is not None: if alpha_op.dest.omask is not None:
US_CMN_INST.ALPHA_OMASK(code, alpha_op.dest.omask.value) US_CMN_INST.ALPHA_OMASK(code, alpha_op.dest.omask.value)
# omod
US_ALU_ALPHA_INST.OMOD(code, alpha_op.omod.value)
# opcode # opcode
US_ALU_ALPHA_INST.ALPHA_OP(code, alpha_op.opcode.value) US_ALU_ALPHA_INST.ALPHA_OP(code, alpha_op.opcode.value)
@ -59,6 +62,9 @@ def emit_rgb_op(code, rgb_op):
if rgb_op.dest.omask is not None: if rgb_op.dest.omask is not None:
US_CMN_INST.RGB_OMASK(code, rgb_op.dest.omask.value) US_CMN_INST.RGB_OMASK(code, rgb_op.dest.omask.value)
# omod
US_ALU_RGB_INST.OMOD(code, rgb_op.omod.value)
# opcode # opcode
US_ALU_RGBA_INST.RGB_OP(code, rgb_op.opcode.value) US_ALU_RGBA_INST.RGB_OP(code, rgb_op.opcode.value)

View File

@ -110,6 +110,26 @@ class Swizzle(IntEnum):
one = 6 one = 6
unused = 7 unused = 7
class Omod(IntEnum):
mul_1 = 0
mul_2 = 1
mul_4 = 2
mul_8 = 3
div_2 = 4
div_4 = 5
div_8 = 6
disable = 7
omod_lexemes = OrderedDict([
((b"1", b"0"), Omod.mul_1),
((b"2", b"0"), Omod.mul_2),
((b"4", b"0"), Omod.mul_4),
((b"8", b"0"), Omod.mul_8),
((b"0", b"5"), Omod.div_2),
((b"0", b"25"), Omod.div_4),
((b"0", b"125"), Omod.div_8),
])
@dataclass @dataclass
class SwizzleSel: class SwizzleSel:
src: SwizzleSelSrc src: SwizzleSelSrc
@ -119,12 +139,14 @@ class SwizzleSel:
@dataclass @dataclass
class AlphaOperation: class AlphaOperation:
dest: AlphaDest dest: AlphaDest
omod: Omod
opcode: AlphaOp opcode: AlphaOp
sels: list[SwizzleSel] sels: list[SwizzleSel]
@dataclass @dataclass
class RGBOperation: class RGBOperation:
dest: RGBDest dest: RGBDest
omod: Omod
opcode: RGBOp opcode: RGBOp
sels: list[SwizzleSel] sels: list[SwizzleSel]
@ -413,14 +435,27 @@ def validate_instruction_operation_sels(swizzle_sels, is_alpha):
sels.append(SwizzleSel(src, swizzle, mod)) sels.append(SwizzleSel(src, swizzle, mod))
return sels return sels
def validate_omod_operation(operation):
omod = Omod.mul_1
if operation.omod != None:
integer, decimal = operation.omod
key = (integer.lexeme, decimal.lexeme)
if key not in omod_lexemes:
valid_omods = b", ".join(b".".join(key) for key in omod_lexemes.keys()).decode('utf-8')
raise ValidatorError(f"invalid omod, expected one of [{valid_omods}]", integer)
omod = omod_lexemes[key]
return omod
def validate_alpha_instruction_operation(operation): def validate_alpha_instruction_operation(operation):
dest = validate_instruction_operation_dest(operation.dest_addr_swizzles, dest = validate_instruction_operation_dest(operation.dest_addr_swizzles,
mask_lookup=alpha_masks, mask_lookup=alpha_masks,
type_cls=AlphaDest) type_cls=AlphaDest)
omod = validate_omod_operation(operation)
opcode = alpha_op_kws[operation.opcode_keyword.keyword] opcode = alpha_op_kws[operation.opcode_keyword.keyword]
sels = validate_instruction_operation_sels(operation.swizzle_sels, is_alpha=True) sels = validate_instruction_operation_sels(operation.swizzle_sels, is_alpha=True)
return AlphaOperation( return AlphaOperation(
dest, dest,
omod,
opcode, opcode,
sels sels
) )
@ -429,10 +464,12 @@ def validate_rgb_instruction_operation(operation):
dest = validate_instruction_operation_dest(operation.dest_addr_swizzles, dest = validate_instruction_operation_dest(operation.dest_addr_swizzles,
mask_lookup=rgb_masks, mask_lookup=rgb_masks,
type_cls=RGBDest) type_cls=RGBDest)
omod = validate_omod_operation(operation)
opcode = rgb_op_kws[operation.opcode_keyword.keyword] opcode = rgb_op_kws[operation.opcode_keyword.keyword]
sels = validate_instruction_operation_sels(operation.swizzle_sels, is_alpha=False) sels = validate_instruction_operation_sels(operation.swizzle_sels, is_alpha=False)
return RGBOperation( return RGBOperation(
dest, dest,
omod,
opcode, opcode,
sels sels
) )

View File

@ -35,6 +35,7 @@ class ALUSwizzleSel:
@dataclass @dataclass
class ALUOperation: class ALUOperation:
dest_addr_swizzles: list[DestAddrSwizzle] dest_addr_swizzles: list[DestAddrSwizzle]
omod: tuple[Token, Token]
opcode_keyword: Token opcode_keyword: Token
swizzle_sels: list[ALUSwizzleSel] swizzle_sels: list[ALUSwizzleSel]
@ -115,6 +116,15 @@ class Parser(BaseParser):
return token.keyword in opcode_keywords return token.keyword in opcode_keywords
return False return False
def alu_is_omod(self):
is_omod = (
self.match(TT.identifier, offset=0)
and self.match(TT.dot, offset=1)
and self.match(TT.identifier, offset=2)
and self.match(TT.star, offset=3)
)
return is_omod
def alu_is_neg(self): def alu_is_neg(self):
result = self.match(TT.minus) result = self.match(TT.minus)
if result: if result:
@ -154,9 +164,17 @@ class Parser(BaseParser):
def alu_operation(self): def alu_operation(self):
dest_addr_swizzles = [] dest_addr_swizzles = []
while not self.alu_is_opcode(): while not (self.alu_is_opcode() or self.alu_is_omod()):
dest_addr_swizzles.append(self.dest_addr_swizzle()) dest_addr_swizzles.append(self.dest_addr_swizzle())
omod = None
if self.alu_is_omod():
omod_integer = self.consume(TT.identifier, "expected omod decimal identifier")
self.consume(TT.dot, "expected omod decimal dot")
omod_decimal = self.consume(TT.identifier, "expected omod decimal identifier")
self.consume(TT.star, "expected omod star")
omod = (omod_integer, omod_decimal)
opcode_keyword = self.consume(TT.keyword, "expected opcode keyword") opcode_keyword = self.consume(TT.keyword, "expected opcode keyword")
swizzle_sels = [] swizzle_sels = []
@ -165,6 +183,7 @@ class Parser(BaseParser):
return ALUOperation( return ALUOperation(
dest_addr_swizzles, dest_addr_swizzles,
omod,
opcode_keyword, opcode_keyword,
swizzle_sels swizzle_sels
) )

View File

@ -21,6 +21,7 @@ class TT(Enum):
bar = auto() bar = auto()
comma = auto() comma = auto()
minus = auto() minus = auto()
star = auto()
@dataclass @dataclass
class Token: class Token:
@ -112,6 +113,8 @@ class Lexer:
return Token(*self.pos(), TT.semicolon, self.lexeme()) return Token(*self.pos(), TT.semicolon, self.lexeme())
elif c == ord(','): elif c == ord(','):
return Token(*self.pos(), TT.comma, self.lexeme()) return Token(*self.pos(), TT.comma, self.lexeme())
elif c == ord('*'):
return Token(*self.pos(), TT.star, self.lexeme())
elif c == ord('-') and self.peek() == ord('-'): elif c == ord('-') and self.peek() == ord('-'):
self.advance() self.advance()
while not self.at_end_p() and self.peek() != ord('\n'): while not self.at_end_p() and self.peek() != ord('\n'):

View File

@ -22,8 +22,8 @@ class BaseParser:
self.current_ix += 1 self.current_ix += 1
return token return token
def match(self, token_type): def match(self, token_type, offset=0):
token = self.peek() token = self.peek(offset)
return token.type == token_type return token.type == token_type
def match_keyword(self, keyword): def match_keyword(self, keyword):