diff --git a/regs/assembler/fs/alu_emitter.py b/regs/assembler/fs/alu_emitter.py index 7a0973f..4aefd3c 100644 --- a/regs/assembler/fs/alu_emitter.py +++ b/regs/assembler/fs/alu_emitter.py @@ -17,6 +17,9 @@ def emit_alpha_op(code, alpha_op): if alpha_op.dest.omask is not None: US_CMN_INST.ALPHA_OMASK(code, alpha_op.dest.omask.value) + # omod + US_ALU_ALPHA_INST.OMOD(code, alpha_op.omod.value) + # opcode 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: US_CMN_INST.RGB_OMASK(code, rgb_op.dest.omask.value) + # omod + US_ALU_RGB_INST.OMOD(code, rgb_op.omod.value) + # opcode US_ALU_RGBA_INST.RGB_OP(code, rgb_op.opcode.value) diff --git a/regs/assembler/fs/alu_validator.py b/regs/assembler/fs/alu_validator.py index bbf2491..200f0ac 100644 --- a/regs/assembler/fs/alu_validator.py +++ b/regs/assembler/fs/alu_validator.py @@ -110,6 +110,26 @@ class Swizzle(IntEnum): one = 6 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 class SwizzleSel: src: SwizzleSelSrc @@ -119,12 +139,14 @@ class SwizzleSel: @dataclass class AlphaOperation: dest: AlphaDest + omod: Omod opcode: AlphaOp sels: list[SwizzleSel] @dataclass class RGBOperation: dest: RGBDest + omod: Omod opcode: RGBOp sels: list[SwizzleSel] @@ -413,14 +435,27 @@ def validate_instruction_operation_sels(swizzle_sels, is_alpha): sels.append(SwizzleSel(src, swizzle, mod)) 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): dest = validate_instruction_operation_dest(operation.dest_addr_swizzles, mask_lookup=alpha_masks, type_cls=AlphaDest) + omod = validate_omod_operation(operation) opcode = alpha_op_kws[operation.opcode_keyword.keyword] sels = validate_instruction_operation_sels(operation.swizzle_sels, is_alpha=True) return AlphaOperation( dest, + omod, opcode, sels ) @@ -429,10 +464,12 @@ def validate_rgb_instruction_operation(operation): dest = validate_instruction_operation_dest(operation.dest_addr_swizzles, mask_lookup=rgb_masks, type_cls=RGBDest) + omod = validate_omod_operation(operation) opcode = rgb_op_kws[operation.opcode_keyword.keyword] sels = validate_instruction_operation_sels(operation.swizzle_sels, is_alpha=False) return RGBOperation( dest, + omod, opcode, sels ) diff --git a/regs/assembler/fs/parser.py b/regs/assembler/fs/parser.py index d854502..bfb602d 100644 --- a/regs/assembler/fs/parser.py +++ b/regs/assembler/fs/parser.py @@ -35,6 +35,7 @@ class ALUSwizzleSel: @dataclass class ALUOperation: dest_addr_swizzles: list[DestAddrSwizzle] + omod: tuple[Token, Token] opcode_keyword: Token swizzle_sels: list[ALUSwizzleSel] @@ -115,6 +116,15 @@ class Parser(BaseParser): return token.keyword in opcode_keywords 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): result = self.match(TT.minus) if result: @@ -154,9 +164,17 @@ class Parser(BaseParser): def alu_operation(self): 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()) + 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") swizzle_sels = [] @@ -165,6 +183,7 @@ class Parser(BaseParser): return ALUOperation( dest_addr_swizzles, + omod, opcode_keyword, swizzle_sels ) diff --git a/regs/assembler/lexer.py b/regs/assembler/lexer.py index dfdd64b..eb13086 100644 --- a/regs/assembler/lexer.py +++ b/regs/assembler/lexer.py @@ -21,6 +21,7 @@ class TT(Enum): bar = auto() comma = auto() minus = auto() + star = auto() @dataclass class Token: @@ -112,6 +113,8 @@ class Lexer: return Token(*self.pos(), TT.semicolon, self.lexeme()) elif c == ord(','): 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('-'): self.advance() while not self.at_end_p() and self.peek() != ord('\n'): diff --git a/regs/assembler/parser.py b/regs/assembler/parser.py index 8c076f4..e5510b4 100644 --- a/regs/assembler/parser.py +++ b/regs/assembler/parser.py @@ -22,8 +22,8 @@ class BaseParser: self.current_ix += 1 return token - def match(self, token_type): - token = self.peek() + def match(self, token_type, offset=0): + token = self.peek(offset) return token.type == token_type def match_keyword(self, keyword):