package rexcode_mips // ============================================================================= // MIPS ENCODING_TABLE // ============================================================================= // // Indexed by Mnemonic. Each entry is a slice of Encoding forms (most have // exactly one; a handful have alternate forms across Feature revisions). // // Entry shape: // {mnemonic, {ops4}, {enc4}, bits, mask, isa, flags} // // bits/mask: `bits` holds the static bit pattern of the 32-bit word; // `mask` marks which bit positions are static. Operand-derived bits OR // in over the zero positions in `bits`. // // Sections (filled incrementally): // 1. MIPS I -- core integer (this file) // 2. MIPS II -- LL/SC, SYNC, traps, branch-likely [§ MIPS_II] // 3. MIPS III -- 64-bit core + load/store doublewords [§ MIPS_III] // 4. MIPS IV -- MOVN/MOVZ, MOVF/MOVT, PREF, indexed FP [§ MIPS_IV] // 5. MIPS32 R1/R2 -- CLZ/MUL/MADD/EXT/INS/... [§ R1_R2] // 6. MIPS32 R6 -- compact branches, new mul/div [§ R6] // 7. FPU (COP1) [§ FPU] // 8. COP0 (system) [§ COP0] // 9. PS1 GTE (COP2) [§ GTE] // 10. PS2 EE MMI [§ MMI] // 11. PSP Allegrex VFPU [§ VFPU] @(rodata) ENCODING_TABLE := #partial [Mnemonic][]Encoding{ .INVALID = {}, // ========================================================================= // §1 MIPS I — core integer // ========================================================================= // ---- R-type arithmetic (SPECIAL, op=0) ----------------------------------- // bits = funct; mask = OPCODE | SHAMT | FUNCT (shamt=0 fixed) = 0xFC0007FF .ADD = { {.ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x00000020, 0xFC0007FF, .MIPS_I, {}} }, .ADDU = { {.ADDU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x00000021, 0xFC0007FF, .MIPS_I, {}} }, .SUB = { {.SUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x00000022, 0xFC0007FF, .MIPS_I, {}} }, .SUBU = { {.SUBU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x00000023, 0xFC0007FF, .MIPS_I, {}} }, .AND = { {.AND, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x00000024, 0xFC0007FF, .MIPS_I, {}} }, .OR = { {.OR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x00000025, 0xFC0007FF, .MIPS_I, {}} }, .XOR = { {.XOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x00000026, 0xFC0007FF, .MIPS_I, {}} }, .NOR = { {.NOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x00000027, 0xFC0007FF, .MIPS_I, {}} }, .SLT = { {.SLT, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000002A, 0xFC0007FF, .MIPS_I, {}} }, .SLTU = { {.SLTU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000002B, 0xFC0007FF, .MIPS_I, {}} }, // ---- Multiply/divide (writes HI:LO) -------------------------------------- // mask = OPCODE | RD | SHAMT | FUNCT = 0xFC00FFFF .MULT = { {.MULT, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x00000018, 0xFC00FFFF, .MIPS_I, {writes_hilo=true}} }, .MULTU = { {.MULTU, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x00000019, 0xFC00FFFF, .MIPS_I, {writes_hilo=true}} }, .DIV = { {.DIV, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x0000001A, 0xFC00FFFF, .MIPS_I, {writes_hilo=true}} }, .DIVU = { {.DIVU, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x0000001B, 0xFC00FFFF, .MIPS_I, {writes_hilo=true}} }, // ---- HI/LO move ---------------------------------------------------------- // MF*: only rd is operand; mask = OPCODE | RS | RT | SHAMT | FUNCT = 0xFFFF07FF // MT*: only rs is operand; mask = OPCODE | RT | RD | SHAMT | FUNCT = 0xFC1FFFFF .MFHI = { {.MFHI, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x00000010, 0xFFFF07FF, .MIPS_I, {}} }, .MFLO = { {.MFLO, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x00000012, 0xFFFF07FF, .MIPS_I, {}} }, .MTHI = { {.MTHI, {.GPR,.NONE,.NONE,.NONE}, {.RS,.NONE,.NONE,.NONE}, 0x00000011, 0xFC1FFFFF, .MIPS_I, {}} }, .MTLO = { {.MTLO, {.GPR,.NONE,.NONE,.NONE}, {.RS,.NONE,.NONE,.NONE}, 0x00000013, 0xFC1FFFFF, .MIPS_I, {}} }, // ---- Shifts by constant -------------------------------------------------- // mask = OPCODE | RS | FUNCT = 0xFFE0003F (rs=0 fixed; shamt is operand) .SLL = { {.SLL, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x00000000, 0xFFE0003F, .MIPS_I, {}} }, .SRL = { {.SRL, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x00000002, 0xFFE0003F, .MIPS_I, {}} }, .SRA = { {.SRA, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x00000003, 0xFFE0003F, .MIPS_I, {}} }, // ---- Variable shifts (shift count from $rs) ------------------------------ // mask = OPCODE | SHAMT | FUNCT = 0xFC0007FF .SLLV = { {.SLLV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x00000004, 0xFC0007FF, .MIPS_I, {}} }, .SRLV = { {.SRLV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x00000006, 0xFC0007FF, .MIPS_I, {}} }, .SRAV = { {.SRAV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x00000007, 0xFC0007FF, .MIPS_I, {}} }, // ---- I-type arithmetic --------------------------------------------------- // mask = OPCODE = 0xFC000000 .ADDI = { {.ADDI, {.GPR,.GPR,.IMM16S,.NONE}, {.RT,.RS,.IMM_16,.NONE}, 0x20000000, 0xFC000000, .MIPS_I, {}} }, .ADDIU = { {.ADDIU, {.GPR,.GPR,.IMM16S,.NONE}, {.RT,.RS,.IMM_16,.NONE}, 0x24000000, 0xFC000000, .MIPS_I, {}} }, .SLTI = { {.SLTI, {.GPR,.GPR,.IMM16S,.NONE}, {.RT,.RS,.IMM_16,.NONE}, 0x28000000, 0xFC000000, .MIPS_I, {}} }, .SLTIU = { {.SLTIU, {.GPR,.GPR,.IMM16S,.NONE}, {.RT,.RS,.IMM_16,.NONE}, 0x2C000000, 0xFC000000, .MIPS_I, {}} }, .ANDI = { {.ANDI, {.GPR,.GPR,.IMM16U,.NONE}, {.RT,.RS,.IMM_16,.NONE}, 0x30000000, 0xFC000000, .MIPS_I, {}} }, .ORI = { {.ORI, {.GPR,.GPR,.IMM16U,.NONE}, {.RT,.RS,.IMM_16,.NONE}, 0x34000000, 0xFC000000, .MIPS_I, {}} }, .XORI = { {.XORI, {.GPR,.GPR,.IMM16U,.NONE}, {.RT,.RS,.IMM_16,.NONE}, 0x38000000, 0xFC000000, .MIPS_I, {}} }, // LUI: rs=0 fixed. mask = OPCODE | RS = 0xFFE00000 .LUI = { {.LUI, {.GPR,.IMM16U,.NONE,.NONE}, {.RT,.IMM_16,.NONE,.NONE}, 0x3C000000, 0xFFE00000, .MIPS_I, {}} }, // ---- Branches (I-type, with delay slot) ---------------------------------- .BEQ = { {.BEQ, {.GPR,.GPR,.REL16,.NONE}, {.RS,.RT,.BRANCH_16,.NONE}, 0x10000000, 0xFC000000, .MIPS_I, {delay_slot=true}} }, .BNE = { {.BNE, {.GPR,.GPR,.REL16,.NONE}, {.RS,.RT,.BRANCH_16,.NONE}, 0x14000000, 0xFC000000, .MIPS_I, {delay_slot=true}} }, // BLEZ/BGTZ have rt=0 fixed. mask = OPCODE | RT = 0xFC1F0000 .BLEZ = { {.BLEZ, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x18000000, 0xFC1F0000, .MIPS_I, {delay_slot=true}} }, .BGTZ = { {.BGTZ, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x1C000000, 0xFC1F0000, .MIPS_I, {delay_slot=true}} }, // ---- REGIMM branches (opcode=1, rt selects op) --------------------------- // mask = OPCODE | RT = 0xFC1F0000 .BLTZ = { {.BLTZ, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x04000000, 0xFC1F0000, .MIPS_I, {delay_slot=true}} }, .BGEZ = { {.BGEZ, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x04010000, 0xFC1F0000, .MIPS_I, {delay_slot=true}} }, .BLTZAL = { {.BLTZAL, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x04100000, 0xFC1F0000, .MIPS_I, {delay_slot=true}} }, .BGEZAL = { {.BGEZAL, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x04110000, 0xFC1F0000, .MIPS_I, {delay_slot=true}} }, // ---- J-type jumps -------------------------------------------------------- .J = { {.J, {.REL_J26,.NONE,.NONE,.NONE}, {.IMM_26,.NONE,.NONE,.NONE}, 0x08000000, 0xFC000000, .MIPS_I, {delay_slot=true}} }, .JAL = { {.JAL, {.REL_J26,.NONE,.NONE,.NONE}, {.IMM_26,.NONE,.NONE,.NONE}, 0x0C000000, 0xFC000000, .MIPS_I, {delay_slot=true}} }, // ---- R-type jumps -------------------------------------------------------- // JR: only rs operand; rd=rt=shamt=0. mask = 0xFC1FFFFF // JALR: rd defaults to $ra; rs is target. mask = OPCODE | RT | SHAMT | FUNCT = 0xFC1F07FF .JR = { {.JR, {.GPR,.NONE,.NONE,.NONE}, {.RS,.NONE,.NONE,.NONE}, 0x00000008, 0xFC1FFFFF, .MIPS_I, {delay_slot=true}} }, .JALR = { {.JALR, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS,.NONE,.NONE}, 0x00000009, 0xFC1F07FF, .MIPS_I, {delay_slot=true}} }, // ---- Loads (offset(base)) ------------------------------------------------ .LB = { {.LB, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x80000000, 0xFC000000, .MIPS_I, {}} }, .LH = { {.LH, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x84000000, 0xFC000000, .MIPS_I, {}} }, .LWL = { {.LWL, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x88000000, 0xFC000000, .MIPS_I, {}} }, .LW = { {.LW, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x8C000000, 0xFC000000, .MIPS_I, {}} }, .LBU = { {.LBU, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x90000000, 0xFC000000, .MIPS_I, {}} }, .LHU = { {.LHU, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x94000000, 0xFC000000, .MIPS_I, {}} }, .LWR = { {.LWR, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x98000000, 0xFC000000, .MIPS_I, {}} }, // ---- Stores -------------------------------------------------------------- .SB = { {.SB, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xA0000000, 0xFC000000, .MIPS_I, {}} }, .SH = { {.SH, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xA4000000, 0xFC000000, .MIPS_I, {}} }, .SWL = { {.SWL, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xA8000000, 0xFC000000, .MIPS_I, {}} }, .SW = { {.SW, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xAC000000, 0xFC000000, .MIPS_I, {}} }, .SWR = { {.SWR, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xB8000000, 0xFC000000, .MIPS_I, {}} }, // ---- System -------------------------------------------------------------- // mask = OPCODE | FUNCT = 0xFC00003F (code field bits 25-6 are operand) .SYSCALL = { {.SYSCALL, {.IMM20,.NONE,.NONE,.NONE}, {.IMM_20,.NONE,.NONE,.NONE}, 0x0000000C, 0xFC00003F, .MIPS_I, {}} }, .BREAK = { {.BREAK, {.IMM20,.NONE,.NONE,.NONE}, {.IMM_20,.NONE,.NONE,.NONE}, 0x0000000D, 0xFC00003F, .MIPS_I, {}} }, // NOP = SLL $0, $0, 0 -- fully fixed pattern. .NOP = { {.NOP, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00000000, 0xFFFFFFFF, .MIPS_I, {}} }, // ========================================================================= // §2 MIPS II additions // ========================================================================= // Load-Linked / Store-Conditional (atomic, paired use). .LL = { {.LL, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xC0000000, 0xFC000000, .MIPS_II, {}} }, .SC = { {.SC, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xE0000000, 0xFC000000, .MIPS_II, {}} }, // SYNC: SPECIAL funct 0x0F. The 5-bit "stype" field at bits 10-6 selects // a barrier variant; bits=0xF, mask leaves stype as a small operand. .SYNC = { {.SYNC, {.IMM5,.NONE,.NONE,.NONE}, {.IMM_5,.NONE,.NONE,.NONE}, 0x0000000F, 0xFFFFF83F, .MIPS_II, {}} }, // Trap-immediate (REGIMM rt selects). .TGEI = { {.TGEI, {.GPR,.IMM16S,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0x04080000, 0xFC1F0000, .MIPS_II, {}} }, .TGEIU = { {.TGEIU, {.GPR,.IMM16S,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0x04090000, 0xFC1F0000, .MIPS_II, {}} }, .TLTI = { {.TLTI, {.GPR,.IMM16S,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0x040A0000, 0xFC1F0000, .MIPS_II, {}} }, .TLTIU = { {.TLTIU, {.GPR,.IMM16S,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0x040B0000, 0xFC1F0000, .MIPS_II, {}} }, .TEQI = { {.TEQI, {.GPR,.IMM16S,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0x040C0000, 0xFC1F0000, .MIPS_II, {}} }, .TNEI = { {.TNEI, {.GPR,.IMM16S,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0x040E0000, 0xFC1F0000, .MIPS_II, {}} }, // Trap-register (SPECIAL funct). The 10-bit code at bits 15-6 is // usually 0; we leave it as a hidden zero by including those bits in // the mask. Mask = OPCODE | RD | SHAMT | FUNCT = 0xFC00FFFF. .TGE = { {.TGE, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x00000030, 0xFC00FFFF, .MIPS_II, {}} }, .TGEU = { {.TGEU, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x00000031, 0xFC00FFFF, .MIPS_II, {}} }, .TLT = { {.TLT, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x00000032, 0xFC00FFFF, .MIPS_II, {}} }, .TLTU = { {.TLTU, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x00000033, 0xFC00FFFF, .MIPS_II, {}} }, .TEQ = { {.TEQ, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x00000034, 0xFC00FFFF, .MIPS_II, {}} }, .TNE = { {.TNE, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x00000036, 0xFC00FFFF, .MIPS_II, {}} }, // Branch-likely (nullify delay slot if not taken). .BEQL = { {.BEQL, {.GPR,.GPR,.REL16,.NONE}, {.RS,.RT,.BRANCH_16,.NONE}, 0x50000000, 0xFC000000, .MIPS_II, {delay_slot=true, likely=true}} }, .BNEL = { {.BNEL, {.GPR,.GPR,.REL16,.NONE}, {.RS,.RT,.BRANCH_16,.NONE}, 0x54000000, 0xFC000000, .MIPS_II, {delay_slot=true, likely=true}} }, .BLEZL = { {.BLEZL, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x58000000, 0xFC1F0000, .MIPS_II, {delay_slot=true, likely=true}} }, .BGTZL = { {.BGTZL, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x5C000000, 0xFC1F0000, .MIPS_II, {delay_slot=true, likely=true}} }, .BLTZL = { {.BLTZL, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x04020000, 0xFC1F0000, .MIPS_II, {delay_slot=true, likely=true}} }, .BGEZL = { {.BGEZL, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x04030000, 0xFC1F0000, .MIPS_II, {delay_slot=true, likely=true}} }, .BLTZALL = { {.BLTZALL, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x04120000, 0xFC1F0000, .MIPS_II, {delay_slot=true, likely=true}} }, .BGEZALL = { {.BGEZALL, {.GPR,.REL16,.NONE,.NONE}, {.RS,.BRANCH_16,.NONE,.NONE}, 0x04130000, 0xFC1F0000, .MIPS_II, {delay_slot=true, likely=true}} }, // ========================================================================= // §3 MIPS III additions (64-bit core) // ========================================================================= // Doubleword arithmetic R-type (SPECIAL funct 0x2C-0x2F). .DADD = { {.DADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000002C, 0xFC0007FF, .MIPS_III, {only_64=true}} }, .DADDU = { {.DADDU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000002D, 0xFC0007FF, .MIPS_III, {only_64=true}} }, .DSUB = { {.DSUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000002E, 0xFC0007FF, .MIPS_III, {only_64=true}} }, .DSUBU = { {.DSUBU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000002F, 0xFC0007FF, .MIPS_III, {only_64=true}} }, // Doubleword arithmetic I-type (opcodes 0x18/0x19). .DADDI = { {.DADDI, {.GPR,.GPR,.IMM16S,.NONE}, {.RT,.RS,.IMM_16,.NONE}, 0x60000000, 0xFC000000, .MIPS_III, {only_64=true}} }, .DADDIU = { {.DADDIU, {.GPR,.GPR,.IMM16S,.NONE}, {.RT,.RS,.IMM_16,.NONE}, 0x64000000, 0xFC000000, .MIPS_III, {only_64=true}} }, // Doubleword multiply/divide. .DMULT = { {.DMULT, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x0000001C, 0xFC00FFFF, .MIPS_III, {only_64=true, writes_hilo=true}} }, .DMULTU = { {.DMULTU, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x0000001D, 0xFC00FFFF, .MIPS_III, {only_64=true, writes_hilo=true}} }, .DDIV = { {.DDIV, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x0000001E, 0xFC00FFFF, .MIPS_III, {only_64=true, writes_hilo=true}} }, .DDIVU = { {.DDIVU, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x0000001F, 0xFC00FFFF, .MIPS_III, {only_64=true, writes_hilo=true}} }, // Doubleword shifts by constant. .DSLL = { {.DSLL, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x00000038, 0xFFE0003F, .MIPS_III, {only_64=true}} }, .DSRL = { {.DSRL, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x0000003A, 0xFFE0003F, .MIPS_III, {only_64=true}} }, .DSRA = { {.DSRA, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x0000003B, 0xFFE0003F, .MIPS_III, {only_64=true}} }, .DSLL32 = { {.DSLL32, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x0000003C, 0xFFE0003F, .MIPS_III, {only_64=true}} }, .DSRL32 = { {.DSRL32, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x0000003E, 0xFFE0003F, .MIPS_III, {only_64=true}} }, .DSRA32 = { {.DSRA32, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x0000003F, 0xFFE0003F, .MIPS_III, {only_64=true}} }, // Doubleword variable shifts (count from $rs). .DSLLV = { {.DSLLV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x00000014, 0xFC0007FF, .MIPS_III, {only_64=true}} }, .DSRLV = { {.DSRLV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x00000016, 0xFC0007FF, .MIPS_III, {only_64=true}} }, .DSRAV = { {.DSRAV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x00000017, 0xFC0007FF, .MIPS_III, {only_64=true}} }, // Doubleword loads/stores. .LD = { {.LD, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xDC000000, 0xFC000000, .MIPS_III, {only_64=true}} }, .LDL = { {.LDL, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x68000000, 0xFC000000, .MIPS_III, {only_64=true}} }, .LDR = { {.LDR, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x6C000000, 0xFC000000, .MIPS_III, {only_64=true}} }, .LWU = { {.LWU, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x9C000000, 0xFC000000, .MIPS_III, {only_64=true}} }, .SD = { {.SD, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xFC000000, 0xFC000000, .MIPS_III, {only_64=true}} }, .SDL = { {.SDL, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xB0000000, 0xFC000000, .MIPS_III, {only_64=true}} }, .SDR = { {.SDR, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xB4000000, 0xFC000000, .MIPS_III, {only_64=true}} }, .LLD = { {.LLD, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xD0000000, 0xFC000000, .MIPS_III, {only_64=true}} }, .SCD = { {.SCD, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xF0000000, 0xFC000000, .MIPS_III, {only_64=true}} }, // ========================================================================= // §4 MIPS IV additions // ========================================================================= // Conditional move (GPR by GPR). SPECIAL funct 0x0A/0x0B. .MOVZ = { {.MOVZ, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000000A, 0xFC0007FF, .MIPS_IV, {}} }, .MOVN = { {.MOVN, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000000B, 0xFC0007FF, .MIPS_IV, {}} }, // GPR move on FPU condition code (SPECIAL funct 0x01; bit 16 = tf; cc at bits 20-18). // mask = OPCODE | (bit 17 = 0) | (bit 16 = tf-fixed) | SHAMT | FUNCT = 0xFC03073F .MOVF = { {.MOVF, {.GPR,.GPR,.FCC,.NONE}, {.RD,.RS,.FCC_BC,.NONE}, 0x00000001, 0xFC03073F, .MIPS_IV, {}} }, .MOVT = { {.MOVT, {.GPR,.GPR,.FCC,.NONE}, {.RD,.RS,.FCC_BC,.NONE}, 0x00010001, 0xFC03073F, .MIPS_IV, {}} }, // Prefetch (opcode 0x33: "PREF hint, off(base)"; hint at rt slot). .PREF = { {.PREF, {.IMM5,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xCC000000, 0xFC000000, .MIPS_IV, {}} }, // Indexed FP load/store (COP1X = opcode 0x13). R-type with funct selecting // op. Layout: [op 0x13][base][index][0 5][fd 5][funct 6]. // mask = OPCODE | SHAMT | FUNCT = 0xFC0007FF (bits 10-6 fixed at 0, except in PREFX). .LWXC1 = { {.LWXC1, {.FPR_S,.GPR,.GPR,.NONE}, {.FD,.RS,.RT,.NONE}, 0x4C000000, 0xFC0007FF, .MIPS_IV, {}} }, .LDXC1 = { {.LDXC1, {.FPR_D,.GPR,.GPR,.NONE}, {.FD,.RS,.RT,.NONE}, 0x4C000001, 0xFC0007FF, .MIPS_IV, {}} }, .SWXC1 = { {.SWXC1, {.FPR_S,.GPR,.GPR,.NONE}, {.FS,.RS,.RT,.NONE}, 0x4C000008, 0xFC0007FF, .MIPS_IV, {}} }, .SDXC1 = { {.SDXC1, {.FPR_D,.GPR,.GPR,.NONE}, {.FS,.RS,.RT,.NONE}, 0x4C000009, 0xFC0007FF, .MIPS_IV, {}} }, // PREFX: hint at fs slot, no destination FPR. .PREFX = { {.PREFX, {.IMM5,.GPR,.GPR,.NONE}, {.FS,.RS,.RT,.NONE}, 0x4C00000F, 0xFC0007FF, .MIPS_IV, {}} }, // ========================================================================= // §5 MIPS32 R1 / R2 — integer additions // ========================================================================= // SPECIAL2 (opcode 0x1C) — common shape: bits = (0x1C<<26) | funct = 0x70000000 | f. // mask = OPCODE | SHAMT | FUNCT = 0xFC0007FF (shamt=0 fixed). .MADD = { {.MADD, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x70000000, 0xFC00FFFF, .MIPS32_R1, {writes_hilo=true}} }, .MADDU = { {.MADDU, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x70000001, 0xFC00FFFF, .MIPS32_R1, {writes_hilo=true}} }, .MUL = { {.MUL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000002, 0xFC0007FF, .MIPS32_R1, {}} }, .MSUB = { {.MSUB, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x70000004, 0xFC00FFFF, .MIPS32_R1, {writes_hilo=true}} }, .MSUBU = { {.MSUBU, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x70000005, 0xFC00FFFF, .MIPS32_R1, {writes_hilo=true}} }, .CLZ = { {.CLZ, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS,.NONE,.NONE}, 0x70000020, 0xFC1F07FF, .MIPS32_R1, {}} }, .CLO = { {.CLO, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS,.NONE,.NONE}, 0x70000021, 0xFC1F07FF, .MIPS32_R1, {}} }, .DCLZ = { {.DCLZ, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS,.NONE,.NONE}, 0x70000024, 0xFC1F07FF, .MIPS64_R1, {only_64=true}} }, .DCLO = { {.DCLO, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS,.NONE,.NONE}, 0x70000025, 0xFC1F07FF, .MIPS64_R1, {only_64=true}} }, .SDBBP = { {.SDBBP, {.IMM20,.NONE,.NONE,.NONE}, {.IMM_20,.NONE,.NONE,.NONE}, 0x7000003F, 0xFC00003F, .MIPS32_R1, {}} }, // Hint NOPs and barriers (SPECIAL funct 0x00 with shamt != 0, rd != 0). // SSNOP: SLL $0, $0, 1. EHB: SLL $0, $0, 3. PAUSE: SLL $0, $0, 5. .SSNOP = { {.SSNOP, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00000040, 0xFFFFFFFF, .MIPS32_R1, {}} }, .EHB = { {.EHB, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x000000C0, 0xFFFFFFFF, .MIPS32_R2, {}} }, .PAUSE = { {.PAUSE, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00000140, 0xFFFFFFFF, .MIPS32_R2, {}} }, // SPECIAL3 (opcode 0x1F): bitfield ops EXT/INS and 64-bit variants. // Encoder layout for EXT: rt=dst, rs=src, msbd=size-1 at rd-slot, lsb=pos at shamt. // mask = OPCODE | FUNCT = 0xFC00003F. .EXT = { {.EXT, {.GPR,.GPR,.IMM5,.IMM5}, {.RT,.RS,.SHAMT,.RD}, 0x7C000000, 0xFC00003F, .MIPS32_R2, {}} }, .DEXTM = { {.DEXTM, {.GPR,.GPR,.IMM5,.IMM5}, {.RT,.RS,.SHAMT,.RD}, 0x7C000001, 0xFC00003F, .MIPS64_R2, {only_64=true}} }, .DEXTU = { {.DEXTU, {.GPR,.GPR,.IMM5,.IMM5}, {.RT,.RS,.SHAMT,.RD}, 0x7C000002, 0xFC00003F, .MIPS64_R2, {only_64=true}} }, .DEXT = { {.DEXT, {.GPR,.GPR,.IMM5,.IMM5}, {.RT,.RS,.SHAMT,.RD}, 0x7C000003, 0xFC00003F, .MIPS64_R2, {only_64=true}} }, .INS = { {.INS, {.GPR,.GPR,.IMM5,.IMM5}, {.RT,.RS,.SHAMT,.RD}, 0x7C000004, 0xFC00003F, .MIPS32_R2, {}} }, .DINSM = { {.DINSM, {.GPR,.GPR,.IMM5,.IMM5}, {.RT,.RS,.SHAMT,.RD}, 0x7C000005, 0xFC00003F, .MIPS64_R2, {only_64=true}} }, .DINSU = { {.DINSU, {.GPR,.GPR,.IMM5,.IMM5}, {.RT,.RS,.SHAMT,.RD}, 0x7C000006, 0xFC00003F, .MIPS64_R2, {only_64=true}} }, .DINS = { {.DINS, {.GPR,.GPR,.IMM5,.IMM5}, {.RT,.RS,.SHAMT,.RD}, 0x7C000007, 0xFC00003F, .MIPS64_R2, {only_64=true}} }, // BSHFL family (SPECIAL3 funct 0x20, shamt selects op). No operand // bits in shamt -- it's a fixed selector. // WSBH (shamt 0x02), SEB (shamt 0x10), SEH (shamt 0x18). .WSBH = { {.WSBH, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C0000A0, 0xFFE007FF, .MIPS32_R2, {}} }, .SEB = { {.SEB, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000420, 0xFFE007FF, .MIPS32_R2, {}} }, .SEH = { {.SEH, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000620, 0xFFE007FF, .MIPS32_R2, {}} }, // DBSHFL family (SPECIAL3 funct 0x24). // DSBH (shamt 0x02), DSHD (shamt 0x05). .DSBH = { {.DSBH, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C0000A4, 0xFFE007FF, .MIPS64_R2, {only_64=true}} }, .DSHD = { {.DSHD, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000164, 0xFFE007FF, .MIPS64_R2, {only_64=true}} }, // Rotate (SPECIAL rs=1). ROTR is SRL with rs=1; DROTR is DSRL with rs=1. .ROTR = { {.ROTR, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x00200002, 0xFFE0003F, .MIPS32_R2, {}} }, .DROTR = { {.DROTR, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x0020003A, 0xFFE0003F, .MIPS64_R2, {only_64=true}} }, .DROTR32 = { {.DROTR32, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x0020003E, 0xFFE0003F, .MIPS64_R2, {only_64=true}} }, // ROTRV / DROTRV: variable rotate; shamt=1 marks the rotate variant of SRLV/DSRLV. .ROTRV = { {.ROTRV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x00000046, 0xFC0007FF, .MIPS32_R2, {}} }, .DROTRV = { {.DROTRV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x00000056, 0xFC0007FF, .MIPS64_R2, {only_64=true}} }, // R2 COP0 CO=1 ops (ERET, DERET, WAIT). .ERET = { {.ERET, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x42000018, 0xFFFFFFFF, .MIPS_II, {}} }, .DERET = { {.DERET, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4200001F, 0xFFFFFFFF, .MIPS32_R1, {}} }, .WAIT = { {.WAIT, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x42000020, 0xFE00003F, .MIPS32_R1, {}} }, // ========================================================================= // §7 FPU (COP1, opcode 0x11) // ========================================================================= // // FR-type layout: [opcode 0x11][fmt 5][ft 5][fs 5][fd 5][funct 6]. // fmt: 0x10=S, 0x11=D, 0x14=W, 0x15=L, 0x16=PS. // Base bits per fmt: S=0x46000000, D=0x46200000, W=0x46800000, // L=0x46A00000, PS=0x46C00000. // Arithmetic mask: OPCODE | RS | FUNCT = 0xFFE0003F. // Unary (ft=0) mask: OPCODE | RS | RT | FUNCT = 0xFFFF003F. // ---- Moves (rs selects op) ----------------------------------------------- // Mask covers opcode + rs + bits 10-0 (rd reused as fs; sel bits 2-0 = 0). .MFC1 = { {.MFC1, {.GPR,.FPR_S,.NONE,.NONE}, {.RT,.FS,.NONE,.NONE}, 0x44000000, 0xFFE007FF, .FPU, {}} }, .DMFC1 = { {.DMFC1, {.GPR,.FPR_D,.NONE,.NONE}, {.RT,.FS,.NONE,.NONE}, 0x44200000, 0xFFE007FF, .MIPS_III, {only_64=true}} }, .CFC1 = { {.CFC1, {.GPR,.FCR,.NONE,.NONE}, {.RT,.FS,.NONE,.NONE}, 0x44400000, 0xFFE007FF, .FPU, {}} }, .MFHC1 = { {.MFHC1, {.GPR,.FPR_D,.NONE,.NONE}, {.RT,.FS,.NONE,.NONE}, 0x44600000, 0xFFE007FF, .MIPS32_R2, {}} }, .MTC1 = { {.MTC1, {.GPR,.FPR_S,.NONE,.NONE}, {.RT,.FS,.NONE,.NONE}, 0x44800000, 0xFFE007FF, .FPU, {}} }, .DMTC1 = { {.DMTC1, {.GPR,.FPR_D,.NONE,.NONE}, {.RT,.FS,.NONE,.NONE}, 0x44A00000, 0xFFE007FF, .MIPS_III, {only_64=true}} }, .CTC1 = { {.CTC1, {.GPR,.FCR,.NONE,.NONE}, {.RT,.FS,.NONE,.NONE}, 0x44C00000, 0xFFE007FF, .FPU, {}} }, .MTHC1 = { {.MTHC1, {.GPR,.FPR_D,.NONE,.NONE}, {.RT,.FS,.NONE,.NONE}, 0x44E00000, 0xFFE007FF, .MIPS32_R2, {}} }, // ---- Load/Store (I-type with FT) ----------------------------------------- .LWC1 = { {.LWC1, {.FPR_S,.MEM,.NONE,.NONE}, {.FT,.OFFSET_BASE,.NONE,.NONE}, 0xC4000000, 0xFC000000, .FPU, {}} }, .SWC1 = { {.SWC1, {.FPR_S,.MEM,.NONE,.NONE}, {.FT,.OFFSET_BASE,.NONE,.NONE}, 0xE4000000, 0xFC000000, .FPU, {}} }, .LDC1 = { {.LDC1, {.FPR_D,.MEM,.NONE,.NONE}, {.FT,.OFFSET_BASE,.NONE,.NONE}, 0xD4000000, 0xFC000000, .MIPS_II, {}} }, .SDC1 = { {.SDC1, {.FPR_D,.MEM,.NONE,.NONE}, {.FT,.OFFSET_BASE,.NONE,.NONE}, 0xF4000000, 0xFC000000, .MIPS_II, {}} }, // ---- Arithmetic: ADD / SUB / MUL / DIV (S, D, PS) ------------------------ .ADD_S = { {.ADD_S, {.FPR_S,.FPR_S,.FPR_S,.NONE}, {.FD,.FS,.FT,.NONE}, 0x46000000, 0xFFE0003F, .FPU, {}} }, .ADD_D = { {.ADD_D, {.FPR_D,.FPR_D,.FPR_D,.NONE}, {.FD,.FS,.FT,.NONE}, 0x46200000, 0xFFE0003F, .FPU, {}} }, .ADD_PS = { {.ADD_PS, {.FPR_PS,.FPR_PS,.FPR_PS,.NONE}, {.FD,.FS,.FT,.NONE}, 0x46C00000, 0xFFE0003F, .MIPS_V, {}} }, .SUB_S = { {.SUB_S, {.FPR_S,.FPR_S,.FPR_S,.NONE}, {.FD,.FS,.FT,.NONE}, 0x46000001, 0xFFE0003F, .FPU, {}} }, .SUB_D = { {.SUB_D, {.FPR_D,.FPR_D,.FPR_D,.NONE}, {.FD,.FS,.FT,.NONE}, 0x46200001, 0xFFE0003F, .FPU, {}} }, .SUB_PS = { {.SUB_PS, {.FPR_PS,.FPR_PS,.FPR_PS,.NONE}, {.FD,.FS,.FT,.NONE}, 0x46C00001, 0xFFE0003F, .MIPS_V, {}} }, .MUL_S = { {.MUL_S, {.FPR_S,.FPR_S,.FPR_S,.NONE}, {.FD,.FS,.FT,.NONE}, 0x46000002, 0xFFE0003F, .FPU, {}} }, .MUL_D = { {.MUL_D, {.FPR_D,.FPR_D,.FPR_D,.NONE}, {.FD,.FS,.FT,.NONE}, 0x46200002, 0xFFE0003F, .FPU, {}} }, .MUL_PS = { {.MUL_PS, {.FPR_PS,.FPR_PS,.FPR_PS,.NONE}, {.FD,.FS,.FT,.NONE}, 0x46C00002, 0xFFE0003F, .MIPS_V, {}} }, .DIV_S = { {.DIV_S, {.FPR_S,.FPR_S,.FPR_S,.NONE}, {.FD,.FS,.FT,.NONE}, 0x46000003, 0xFFE0003F, .FPU, {}} }, .DIV_D = { {.DIV_D, {.FPR_D,.FPR_D,.FPR_D,.NONE}, {.FD,.FS,.FT,.NONE}, 0x46200003, 0xFFE0003F, .FPU, {}} }, // ---- Unary: SQRT/ABS/NEG/MOV/RECIP/RSQRT --------------------------------- // ft=0 fixed; mask = OPCODE | RS | RT | FUNCT = 0xFFFF003F. .SQRT_S = { {.SQRT_S, {.FPR_S,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46000004, 0xFFFF003F, .MIPS_II, {}} }, .SQRT_D = { {.SQRT_D, {.FPR_D,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46200004, 0xFFFF003F, .MIPS_II, {}} }, .ABS_S = { {.ABS_S, {.FPR_S,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46000005, 0xFFFF003F, .FPU, {}} }, .ABS_D = { {.ABS_D, {.FPR_D,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46200005, 0xFFFF003F, .FPU, {}} }, .ABS_PS = { {.ABS_PS, {.FPR_PS,.FPR_PS,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46C00005, 0xFFFF003F, .MIPS_V, {}} }, .MOV_S = { {.MOV_S, {.FPR_S,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46000006, 0xFFFF003F, .FPU, {}} }, .MOV_D = { {.MOV_D, {.FPR_D,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46200006, 0xFFFF003F, .FPU, {}} }, .MOV_PS = { {.MOV_PS, {.FPR_PS,.FPR_PS,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46C00006, 0xFFFF003F, .MIPS_V, {}} }, .NEG_S = { {.NEG_S, {.FPR_S,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46000007, 0xFFFF003F, .FPU, {}} }, .NEG_D = { {.NEG_D, {.FPR_D,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46200007, 0xFFFF003F, .FPU, {}} }, .NEG_PS = { {.NEG_PS, {.FPR_PS,.FPR_PS,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46C00007, 0xFFFF003F, .MIPS_V, {}} }, .RECIP_S = { {.RECIP_S, {.FPR_S,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46000015, 0xFFFF003F, .MIPS_IV, {}} }, .RECIP_D = { {.RECIP_D, {.FPR_D,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46200015, 0xFFFF003F, .MIPS_IV, {}} }, .RSQRT_S = { {.RSQRT_S, {.FPR_S,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46000016, 0xFFFF003F, .MIPS_IV, {}} }, .RSQRT_D = { {.RSQRT_D, {.FPR_D,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46200016, 0xFFFF003F, .MIPS_IV, {}} }, // ---- Round-to-fixed (S, D source) ---------------------------------------- .ROUND_W_S = { {.ROUND_W_S, {.FPR_W,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4600000C, 0xFFFF003F, .MIPS_II, {}} }, .ROUND_W_D = { {.ROUND_W_D, {.FPR_W,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4620000C, 0xFFFF003F, .MIPS_II, {}} }, .TRUNC_W_S = { {.TRUNC_W_S, {.FPR_W,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4600000D, 0xFFFF003F, .MIPS_II, {}} }, .TRUNC_W_D = { {.TRUNC_W_D, {.FPR_W,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4620000D, 0xFFFF003F, .MIPS_II, {}} }, .CEIL_W_S = { {.CEIL_W_S, {.FPR_W,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4600000E, 0xFFFF003F, .MIPS_II, {}} }, .CEIL_W_D = { {.CEIL_W_D, {.FPR_W,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4620000E, 0xFFFF003F, .MIPS_II, {}} }, .FLOOR_W_S = { {.FLOOR_W_S, {.FPR_W,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4600000F, 0xFFFF003F, .MIPS_II, {}} }, .FLOOR_W_D = { {.FLOOR_W_D, {.FPR_W,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4620000F, 0xFFFF003F, .MIPS_II, {}} }, .ROUND_L_S = { {.ROUND_L_S, {.FPR_L,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46000008, 0xFFFF003F, .MIPS_III, {only_64=true}} }, .ROUND_L_D = { {.ROUND_L_D, {.FPR_L,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46200008, 0xFFFF003F, .MIPS_III, {only_64=true}} }, .TRUNC_L_S = { {.TRUNC_L_S, {.FPR_L,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46000009, 0xFFFF003F, .MIPS_III, {only_64=true}} }, .TRUNC_L_D = { {.TRUNC_L_D, {.FPR_L,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46200009, 0xFFFF003F, .MIPS_III, {only_64=true}} }, .CEIL_L_S = { {.CEIL_L_S, {.FPR_L,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4600000A, 0xFFFF003F, .MIPS_III, {only_64=true}} }, .CEIL_L_D = { {.CEIL_L_D, {.FPR_L,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4620000A, 0xFFFF003F, .MIPS_III, {only_64=true}} }, .FLOOR_L_S = { {.FLOOR_L_S, {.FPR_L,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4600000B, 0xFFFF003F, .MIPS_III, {only_64=true}} }, .FLOOR_L_D = { {.FLOOR_L_D, {.FPR_L,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x4620000B, 0xFFFF003F, .MIPS_III, {only_64=true}} }, // ---- Conversions --------------------------------------------------------- // CVT.dst.src — fmt = src, funct = "convert to dst" (0x20=S, 0x21=D, 0x24=W, 0x25=L). .CVT_S_D = { {.CVT_S_D, {.FPR_S,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46200020, 0xFFFF003F, .FPU, {}} }, .CVT_S_W = { {.CVT_S_W, {.FPR_S,.FPR_W,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46800020, 0xFFFF003F, .FPU, {}} }, .CVT_S_L = { {.CVT_S_L, {.FPR_S,.FPR_L,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46A00020, 0xFFFF003F, .MIPS_III, {only_64=true}} }, .CVT_D_S = { {.CVT_D_S, {.FPR_D,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46000021, 0xFFFF003F, .FPU, {}} }, .CVT_D_W = { {.CVT_D_W, {.FPR_D,.FPR_W,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46800021, 0xFFFF003F, .FPU, {}} }, .CVT_D_L = { {.CVT_D_L, {.FPR_D,.FPR_L,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46A00021, 0xFFFF003F, .MIPS_III, {only_64=true}} }, .CVT_W_S = { {.CVT_W_S, {.FPR_W,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46000024, 0xFFFF003F, .FPU, {}} }, .CVT_W_D = { {.CVT_W_D, {.FPR_W,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46200024, 0xFFFF003F, .FPU, {}} }, .CVT_L_S = { {.CVT_L_S, {.FPR_L,.FPR_S,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46000025, 0xFFFF003F, .MIPS_III, {only_64=true}} }, .CVT_L_D = { {.CVT_L_D, {.FPR_L,.FPR_D,.NONE,.NONE}, {.FD,.FS,.NONE,.NONE}, 0x46200025, 0xFFFF003F, .MIPS_III, {only_64=true}} }, // ---- FP Branches (BC1F/T/FL/TL). Bits 17-16 select tf:nd. --------------- // mask = OPCODE | RS | (bits 17-16) = 0xFFE30000. CC field is bits 20-18 (operand). .BC1F = { {.BC1F, {.FCC,.REL16,.NONE,.NONE}, {.FCC_BC,.BRANCH_16,.NONE,.NONE}, 0x45000000, 0xFFE30000, .FPU, {delay_slot=true}} }, .BC1T = { {.BC1T, {.FCC,.REL16,.NONE,.NONE}, {.FCC_BC,.BRANCH_16,.NONE,.NONE}, 0x45010000, 0xFFE30000, .FPU, {delay_slot=true}} }, .BC1FL = { {.BC1FL, {.FCC,.REL16,.NONE,.NONE}, {.FCC_BC,.BRANCH_16,.NONE,.NONE}, 0x45020000, 0xFFE30000, .MIPS_II, {delay_slot=true, likely=true}} }, .BC1TL = { {.BC1TL, {.FCC,.REL16,.NONE,.NONE}, {.FCC_BC,.BRANCH_16,.NONE,.NONE}, 0x45030000, 0xFFE30000, .MIPS_II, {delay_slot=true, likely=true}} }, // ---- FP Compares: 16 conditions × 3 formats (S, D, PS) ------------------- // Layout: [op 0x11][fmt][ft][fs][cc 3][0 2][FC=11][cond 4] // bits = (0x11<<26) | (fmt<<21) | 0x30 | cond. cc operand at bits 10-8. // mask = OPCODE | RS | bits 7-6 | FUNCT = 0xFFE000FF. .C_F_S = { {.C_F_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46000030, 0xFFE000FF, .FPU, {}} }, .C_F_D = { {.C_F_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46200030, 0xFFE000FF, .FPU, {}} }, .C_F_PS = { {.C_F_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C00030, 0xFFE000FF, .MIPS_V, {}} }, .C_UN_S = { {.C_UN_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46000031, 0xFFE000FF, .FPU, {}} }, .C_UN_D = { {.C_UN_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46200031, 0xFFE000FF, .FPU, {}} }, .C_UN_PS = { {.C_UN_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C00031, 0xFFE000FF, .MIPS_V, {}} }, .C_EQ_S = { {.C_EQ_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46000032, 0xFFE000FF, .FPU, {}} }, .C_EQ_D = { {.C_EQ_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46200032, 0xFFE000FF, .FPU, {}} }, .C_EQ_PS = { {.C_EQ_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C00032, 0xFFE000FF, .MIPS_V, {}} }, .C_UEQ_S = { {.C_UEQ_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46000033, 0xFFE000FF, .FPU, {}} }, .C_UEQ_D = { {.C_UEQ_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46200033, 0xFFE000FF, .FPU, {}} }, .C_UEQ_PS = { {.C_UEQ_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C00033, 0xFFE000FF, .MIPS_V, {}} }, .C_OLT_S = { {.C_OLT_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46000034, 0xFFE000FF, .FPU, {}} }, .C_OLT_D = { {.C_OLT_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46200034, 0xFFE000FF, .FPU, {}} }, .C_OLT_PS = { {.C_OLT_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C00034, 0xFFE000FF, .MIPS_V, {}} }, .C_ULT_S = { {.C_ULT_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46000035, 0xFFE000FF, .FPU, {}} }, .C_ULT_D = { {.C_ULT_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46200035, 0xFFE000FF, .FPU, {}} }, .C_ULT_PS = { {.C_ULT_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C00035, 0xFFE000FF, .MIPS_V, {}} }, .C_OLE_S = { {.C_OLE_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46000036, 0xFFE000FF, .FPU, {}} }, .C_OLE_D = { {.C_OLE_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46200036, 0xFFE000FF, .FPU, {}} }, .C_OLE_PS = { {.C_OLE_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C00036, 0xFFE000FF, .MIPS_V, {}} }, .C_ULE_S = { {.C_ULE_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46000037, 0xFFE000FF, .FPU, {}} }, .C_ULE_D = { {.C_ULE_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46200037, 0xFFE000FF, .FPU, {}} }, .C_ULE_PS = { {.C_ULE_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C00037, 0xFFE000FF, .MIPS_V, {}} }, .C_SF_S = { {.C_SF_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46000038, 0xFFE000FF, .FPU, {}} }, .C_SF_D = { {.C_SF_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46200038, 0xFFE000FF, .FPU, {}} }, .C_SF_PS = { {.C_SF_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C00038, 0xFFE000FF, .MIPS_V, {}} }, .C_NGLE_S = { {.C_NGLE_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46000039, 0xFFE000FF, .FPU, {}} }, .C_NGLE_D = { {.C_NGLE_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46200039, 0xFFE000FF, .FPU, {}} }, .C_NGLE_PS = { {.C_NGLE_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C00039, 0xFFE000FF, .MIPS_V, {}} }, .C_SEQ_S = { {.C_SEQ_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4600003A, 0xFFE000FF, .FPU, {}} }, .C_SEQ_D = { {.C_SEQ_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4620003A, 0xFFE000FF, .FPU, {}} }, .C_SEQ_PS = { {.C_SEQ_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C0003A, 0xFFE000FF, .MIPS_V, {}} }, .C_NGL_S = { {.C_NGL_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4600003B, 0xFFE000FF, .FPU, {}} }, .C_NGL_D = { {.C_NGL_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4620003B, 0xFFE000FF, .FPU, {}} }, .C_NGL_PS = { {.C_NGL_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C0003B, 0xFFE000FF, .MIPS_V, {}} }, .C_LT_S = { {.C_LT_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4600003C, 0xFFE000FF, .FPU, {}} }, .C_LT_D = { {.C_LT_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4620003C, 0xFFE000FF, .FPU, {}} }, .C_LT_PS = { {.C_LT_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C0003C, 0xFFE000FF, .MIPS_V, {}} }, .C_NGE_S = { {.C_NGE_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4600003D, 0xFFE000FF, .FPU, {}} }, .C_NGE_D = { {.C_NGE_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4620003D, 0xFFE000FF, .FPU, {}} }, .C_NGE_PS = { {.C_NGE_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C0003D, 0xFFE000FF, .MIPS_V, {}} }, .C_LE_S = { {.C_LE_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4600003E, 0xFFE000FF, .FPU, {}} }, .C_LE_D = { {.C_LE_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4620003E, 0xFFE000FF, .FPU, {}} }, .C_LE_PS = { {.C_LE_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C0003E, 0xFFE000FF, .MIPS_V, {}} }, .C_NGT_S = { {.C_NGT_S, {.FPR_S,.FPR_S,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4600003F, 0xFFE000FF, .FPU, {}} }, .C_NGT_D = { {.C_NGT_D, {.FPR_D,.FPR_D,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x4620003F, 0xFFE000FF, .FPU, {}} }, .C_NGT_PS = { {.C_NGT_PS, {.FPR_PS,.FPR_PS,.FCC,.NONE}, {.FS,.FT,.FCC_CC,.NONE}, 0x46C0003F, 0xFFE000FF, .MIPS_V, {}} }, // ========================================================================= // §8 COP0 — system control // ========================================================================= // MFC0/MTC0/etc: [op=0x10][rs=op][rt][rd][0 8][sel 3]. // mask covers opcode + rs + bits 10-3 (zero), leaving rt/rd/sel as operands. .MFC0 = { {.MFC0, {.GPR,.CP0_REG,.SEL,.NONE}, {.RT,.RD,.SEL,.NONE}, 0x40000000, 0xFFE007F8, .COP0, {}} }, .DMFC0 = { {.DMFC0, {.GPR,.CP0_REG,.SEL,.NONE}, {.RT,.RD,.SEL,.NONE}, 0x40200000, 0xFFE007F8, .COP0, {only_64=true}} }, .MTC0 = { {.MTC0, {.GPR,.CP0_REG,.SEL,.NONE}, {.RT,.RD,.SEL,.NONE}, 0x40800000, 0xFFE007F8, .COP0, {}} }, .DMTC0 = { {.DMTC0, {.GPR,.CP0_REG,.SEL,.NONE}, {.RT,.RD,.SEL,.NONE}, 0x40A00000, 0xFFE007F8, .COP0, {only_64=true}} }, .MFHC0 = { {.MFHC0, {.GPR,.CP0_REG,.SEL,.NONE}, {.RT,.RD,.SEL,.NONE}, 0x40400000, 0xFFE007F8, .MIPS32_R5, {}} }, .MTHC0 = { {.MTHC0, {.GPR,.CP0_REG,.SEL,.NONE}, {.RT,.RD,.SEL,.NONE}, 0x40C00000, 0xFFE007F8, .MIPS32_R5, {}} }, // TLB ops + CACHE (CO=1). No user-visible operands for TLB*. .TLBR = { {.TLBR, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x42000001, 0xFFFFFFFF, .COP0, {}} }, .TLBWI = { {.TLBWI, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x42000002, 0xFFFFFFFF, .COP0, {}} }, .TLBWR = { {.TLBWR, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x42000006, 0xFFFFFFFF, .COP0, {}} }, .TLBP = { {.TLBP, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x42000008, 0xFFFFFFFF, .COP0, {}} }, // CACHE op,off(base): rt slot holds the 5-bit cache op selector. .CACHE = { {.CACHE, {.IMM5,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xBC000000, 0xFC000000, .MIPS_II, {}} }, // ========================================================================= // §9 PS1 GTE — COP2 Geometry Transformation Engine // ========================================================================= // // GTE ops use COP2 with the CO bit (bit 25) set; the 6-bit funct field // identifies the operation, and 19 cofun control bits (sf/mx/v/cv/lm // plus an unused upper "tag") modulate behaviour. We mask only the // canonical fields (opcode+CO+funct) so the encoder emits a clean // form and the decoder accepts any cofun-variant. // Standard COP2 moves (also used to address GTE data/control regs). .MFC2 = { {.MFC2, {.GPR,.CP2_REG,.NONE,.NONE}, {.RT,.RD,.NONE,.NONE}, 0x48000000, 0xFFE007FF, .GTE_PS1, {}} }, .CFC2 = { {.CFC2, {.GPR,.CP2_CTRL,.NONE,.NONE}, {.RT,.RD,.NONE,.NONE}, 0x48400000, 0xFFE007FF, .GTE_PS1, {}} }, .MTC2 = { {.MTC2, {.GPR,.CP2_REG,.NONE,.NONE}, {.RT,.RD,.NONE,.NONE}, 0x48800000, 0xFFE007FF, .GTE_PS1, {}} }, .CTC2 = { {.CTC2, {.GPR,.CP2_CTRL,.NONE,.NONE}, {.RT,.RD,.NONE,.NONE}, 0x48C00000, 0xFFE007FF, .GTE_PS1, {}} }, .LWC2 = { {.LWC2, {.CP2_REG,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xC8000000, 0xFC000000, .GTE_PS1, {}} }, .SWC2 = { {.SWC2, {.CP2_REG,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xE8000000, 0xFC000000, .GTE_PS1, {}} }, // LDC2/SDC2 exist in MIPS II+ but not on PS1 R3000A. .LDC2 = { {.LDC2, {.CP2_REG,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xD8000000, 0xFC000000, .MIPS_II, {}} }, .SDC2 = { {.SDC2, {.CP2_REG,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xF8000000, 0xFC000000, .MIPS_II, {}} }, // ---- GTE operations (cofun funct field 5-0; no user-visible operands) ---- // All have mask = 0xFE00003F (opcode + CO + funct); the encoder emits // sf=0/lm=0/mx=0/v=0/cv=0/tag=0 as canonical, which is valid. .RTPS = { {.RTPS, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000001, 0xFE00003F, .GTE_PS1, {}} }, .NCLIP = { {.NCLIP, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000006, 0xFE00003F, .GTE_PS1, {}} }, .OP_GTE = { {.OP_GTE, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A00000C, 0xFE00003F, .GTE_PS1, {}} }, .DPCS = { {.DPCS, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000010, 0xFE00003F, .GTE_PS1, {}} }, .INTPL = { {.INTPL, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000011, 0xFE00003F, .GTE_PS1, {}} }, .MVMVA = { {.MVMVA, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000012, 0xFE00003F, .GTE_PS1, {}} }, .NCDS = { {.NCDS, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000013, 0xFE00003F, .GTE_PS1, {}} }, .CDP = { {.CDP, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000014, 0xFE00003F, .GTE_PS1, {}} }, .NCDT = { {.NCDT, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000016, 0xFE00003F, .GTE_PS1, {}} }, .NCCS = { {.NCCS, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A00001B, 0xFE00003F, .GTE_PS1, {}} }, .CC = { {.CC, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A00001C, 0xFE00003F, .GTE_PS1, {}} }, .NCS = { {.NCS, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A00001E, 0xFE00003F, .GTE_PS1, {}} }, .NCT = { {.NCT, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000020, 0xFE00003F, .GTE_PS1, {}} }, .SQR_GTE = { {.SQR_GTE, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000028, 0xFE00003F, .GTE_PS1, {}} }, .DCPL = { {.DCPL, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000029, 0xFE00003F, .GTE_PS1, {}} }, .DPCT = { {.DPCT, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A00002A, 0xFE00003F, .GTE_PS1, {}} }, .AVSZ3 = { {.AVSZ3, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A00002D, 0xFE00003F, .GTE_PS1, {}} }, .AVSZ4 = { {.AVSZ4, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A00002E, 0xFE00003F, .GTE_PS1, {}} }, .RTPT = { {.RTPT, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A000030, 0xFE00003F, .GTE_PS1, {}} }, .GPF = { {.GPF, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A00003D, 0xFE00003F, .GTE_PS1, {}} }, .GPL = { {.GPL, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A00003E, 0xFE00003F, .GTE_PS1, {}} }, .NCCT = { {.NCCT, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x4A00003F, 0xFE00003F, .GTE_PS1, {}} }, // ========================================================================= // §10 PS2 EE Multimedia Instructions (R5900) // ========================================================================= // // PS2's R5900 puts 128-bit packed-SIMD ops in SPECIAL2 (opcode 0x1C) // and four sub-spaces MMI0..MMI3 (top-level functs 0x08/0x28/0x09/ // 0x29) where the 5-bit shamt selects the actual op. Plus LQ/SQ // (128-bit GPR load/store at opcodes 0x1E/0x1F) and a second HI/LO // pair (HI1/LO1) for the dual-MAC pipeline. // // NB: opcode 0x1F conflicts with modern MIPS SPECIAL3. PS2 predates // SPECIAL3 so on a PS2 target SPECIAL3 doesn't exist and on a // modern MIPS target SQ doesn't exist -- the decoder should select // based on target Feature. For encoding we list both; the user picks. // 128-bit GPR load/store. .LQ = { {.LQ, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x78000000, 0xFC000000, .MMI_PS2, {}} }, .SQ = { {.SQ, {.GPR,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0x7C000000, 0xFC000000, .MMI_PS2, {}} }, // VU0 macro-mode 128-bit COP2 moves. .LQC2 = { {.LQC2, {.CP2_REG,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xD8000000, 0xFC000000, .VU_PS2, {}} }, .SQC2 = { {.SQC2, {.CP2_REG,.MEM,.NONE,.NONE}, {.RT,.OFFSET_BASE,.NONE,.NONE}, 0xF8000000, 0xFC000000, .VU_PS2, {}} }, // Second HI/LO pair (R5900 dual-MAC). .MFHI1 = { {.MFHI1, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x70000010, 0xFFFF07FF, .MMI_PS2, {}} }, .MTHI1 = { {.MTHI1, {.GPR,.NONE,.NONE,.NONE}, {.RS,.NONE,.NONE,.NONE}, 0x70000011, 0xFC1FFFFF, .MMI_PS2, {}} }, .MFLO1 = { {.MFLO1, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x70000012, 0xFFFF07FF, .MMI_PS2, {}} }, .MTLO1 = { {.MTLO1, {.GPR,.NONE,.NONE,.NONE}, {.RS,.NONE,.NONE,.NONE}, 0x70000013, 0xFC1FFFFF, .MMI_PS2, {}} }, .MULT1 = { {.MULT1, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x70000018, 0xFC00FFFF, .MMI_PS2, {writes_hilo=true}} }, .MULTU1 = { {.MULTU1, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x70000019, 0xFC00FFFF, .MMI_PS2, {writes_hilo=true}} }, .DIV1 = { {.DIV1, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x7000001A, 0xFC00FFFF, .MMI_PS2, {writes_hilo=true}} }, .DIVU1 = { {.DIVU1, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x7000001B, 0xFC00FFFF, .MMI_PS2, {writes_hilo=true}} }, .MADD1 = { {.MADD1, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x70000020, 0xFC00FFFF, .MMI_PS2, {writes_hilo=true}} }, .MADDU1 = { {.MADDU1, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x70000021, 0xFC00FFFF, .MMI_PS2, {writes_hilo=true}} }, // Pack/unpack HI:LO (PMFHL with 5-bit sub-op in sa slot). .PMFHL_LW = { {.PMFHL_LW, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x70000030, 0xFFFF07FF, .MMI_PS2, {}} }, .PMFHL_UW = { {.PMFHL_UW, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x70000070, 0xFFFF07FF, .MMI_PS2, {}} }, .PMFHL_SLW = { {.PMFHL_SLW, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x700000B0, 0xFFFF07FF, .MMI_PS2, {}} }, .PMFHL_LH = { {.PMFHL_LH, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x700000F0, 0xFFFF07FF, .MMI_PS2, {}} }, .PMFHL_SH = { {.PMFHL_SH, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x70000130, 0xFFFF07FF, .MMI_PS2, {}} }, .PMTHL_LW = { {.PMTHL_LW, {.GPR,.NONE,.NONE,.NONE}, {.RS,.NONE,.NONE,.NONE}, 0x70000031, 0xFC1FFFFF, .MMI_PS2, {}} }, // PLZCW (parallel leading-zero count). .PLZCW = { {.PLZCW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS,.NONE,.NONE}, 0x70000004, 0xFC1F07FF, .MMI_PS2, {}} }, // Top-level parallel shifts by immediate (SPECIAL2 funct 0x34/36/37/3C/3E/3F). .PSLLH = { {.PSLLH, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x70000034, 0xFFE0003F, .MMI_PS2, {}} }, .PSRLH = { {.PSRLH, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x70000036, 0xFFE0003F, .MMI_PS2, {}} }, .PSRAH = { {.PSRAH, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x70000037, 0xFFE0003F, .MMI_PS2, {}} }, .PSLLW = { {.PSLLW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x7000003C, 0xFFE0003F, .MMI_PS2, {}} }, .PSRLW = { {.PSRLW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x7000003E, 0xFFE0003F, .MMI_PS2, {}} }, .PSRAW = { {.PSRAW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x7000003F, 0xFFE0003F, .MMI_PS2, {}} }, // ---- MMI0 sub-space (funct=0x08, shamt selects) -------------------------- // bits = 0x70000008 | (shamt<<6); mask = OPCODE | SHAMT | FUNCT = 0xFC0007FF. .PADDW = { {.PADDW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000008, 0xFC0007FF, .MMI_PS2, {}} }, .PSUBW = { {.PSUBW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000048, 0xFC0007FF, .MMI_PS2, {}} }, .PCGTW = { {.PCGTW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000088, 0xFC0007FF, .MMI_PS2, {}} }, .PMAXW = { {.PMAXW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700000C8, 0xFC0007FF, .MMI_PS2, {}} }, .PADDH = { {.PADDH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000108, 0xFC0007FF, .MMI_PS2, {}} }, .PSUBH = { {.PSUBH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000148, 0xFC0007FF, .MMI_PS2, {}} }, .PCGTH = { {.PCGTH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000188, 0xFC0007FF, .MMI_PS2, {}} }, .PMAXH = { {.PMAXH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700001C8, 0xFC0007FF, .MMI_PS2, {}} }, .PADDB = { {.PADDB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000208, 0xFC0007FF, .MMI_PS2, {}} }, .PSUBB = { {.PSUBB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000248, 0xFC0007FF, .MMI_PS2, {}} }, .PCGTB = { {.PCGTB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000288, 0xFC0007FF, .MMI_PS2, {}} }, .PADDSW = { {.PADDSW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000408, 0xFC0007FF, .MMI_PS2, {}} }, .PSUBSW = { {.PSUBSW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000448, 0xFC0007FF, .MMI_PS2, {}} }, .PEXTLW = { {.PEXTLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000488, 0xFC0007FF, .MMI_PS2, {}} }, .PPACW = { {.PPACW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700004C8, 0xFC0007FF, .MMI_PS2, {}} }, .PADDSH = { {.PADDSH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000508, 0xFC0007FF, .MMI_PS2, {}} }, .PSUBSH = { {.PSUBSH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000548, 0xFC0007FF, .MMI_PS2, {}} }, .PEXTLH = { {.PEXTLH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000588, 0xFC0007FF, .MMI_PS2, {}} }, .PPACH = { {.PPACH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700005C8, 0xFC0007FF, .MMI_PS2, {}} }, .PADDSB = { {.PADDSB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000608, 0xFC0007FF, .MMI_PS2, {}} }, .PSUBSB = { {.PSUBSB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000648, 0xFC0007FF, .MMI_PS2, {}} }, .PEXTLB = { {.PEXTLB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000688, 0xFC0007FF, .MMI_PS2, {}} }, .PPACB = { {.PPACB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700006C8, 0xFC0007FF, .MMI_PS2, {}} }, .PEXT5 = { {.PEXT5, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000788, 0xFC0007FF, .MMI_PS2, {}} }, .PPAC5 = { {.PPAC5, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700007C8, 0xFC0007FF, .MMI_PS2, {}} }, // ---- MMI1 sub-space (funct=0x28, shamt selects) -------------------------- .PABSW = { {.PABSW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x70000068, 0xFC1F07FF, .MMI_PS2, {}} }, .PCEQW = { {.PCEQW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700000A8, 0xFC0007FF, .MMI_PS2, {}} }, .PMINW = { {.PMINW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700000E8, 0xFC0007FF, .MMI_PS2, {}} }, .PABSH = { {.PABSH, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x70000168, 0xFC1F07FF, .MMI_PS2, {}} }, .PCEQH = { {.PCEQH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700001A8, 0xFC0007FF, .MMI_PS2, {}} }, .PMINH = { {.PMINH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700001E8, 0xFC0007FF, .MMI_PS2, {}} }, .PCEQB = { {.PCEQB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700002A8, 0xFC0007FF, .MMI_PS2, {}} }, .PADDUW = { {.PADDUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000428, 0xFC0007FF, .MMI_PS2, {}} }, .PSUBUW = { {.PSUBUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000468, 0xFC0007FF, .MMI_PS2, {}} }, .PEXTUW = { {.PEXTUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700004A8, 0xFC0007FF, .MMI_PS2, {}} }, .PADDUH = { {.PADDUH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000528, 0xFC0007FF, .MMI_PS2, {}} }, .PSUBUH = { {.PSUBUH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000568, 0xFC0007FF, .MMI_PS2, {}} }, .PEXTUH = { {.PEXTUH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700005A8, 0xFC0007FF, .MMI_PS2, {}} }, .PADDUB = { {.PADDUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000628, 0xFC0007FF, .MMI_PS2, {}} }, .PSUBUB = { {.PSUBUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000668, 0xFC0007FF, .MMI_PS2, {}} }, .PEXTUB = { {.PEXTUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700006A8, 0xFC0007FF, .MMI_PS2, {}} }, .QFSRV = { {.QFSRV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700006E8, 0xFC0007FF, .MMI_PS2, {}} }, // ---- MMI2 sub-space (funct=0x09, shamt selects) -------------------------- .PMADDW = { {.PMADDW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000009, 0xFC0007FF, .MMI_PS2, {writes_hilo=true}} }, .PSLLVW = { {.PSLLVW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x70000089, 0xFC0007FF, .MMI_PS2, {}} }, .PSRLVW = { {.PSRLVW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x700000C9, 0xFC0007FF, .MMI_PS2, {}} }, .PMSUBW = { {.PMSUBW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000109, 0xFC0007FF, .MMI_PS2, {writes_hilo=true}} }, .PMFHI = { {.PMFHI, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x70000209, 0xFFFF07FF, .MMI_PS2, {}} }, .PMFLO = { {.PMFLO, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x70000249, 0xFFFF07FF, .MMI_PS2, {}} }, .PINTH = { {.PINTH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000289, 0xFC0007FF, .MMI_PS2, {}} }, .PMULTW = { {.PMULTW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000309, 0xFC0007FF, .MMI_PS2, {writes_hilo=true}} }, .PDIVW = { {.PDIVW, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x70000349, 0xFC00FFFF, .MMI_PS2, {writes_hilo=true}} }, .PCPYLD = { {.PCPYLD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000389, 0xFC0007FF, .MMI_PS2, {}} }, .PMADDH = { {.PMADDH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000409, 0xFC0007FF, .MMI_PS2, {writes_hilo=true}} }, .PHMADH = { {.PHMADH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000449, 0xFC0007FF, .MMI_PS2, {writes_hilo=true}} }, .PAND = { {.PAND, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000489, 0xFC0007FF, .MMI_PS2, {}} }, .PXOR = { {.PXOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700004C9, 0xFC0007FF, .MMI_PS2, {}} }, .PMSUBH = { {.PMSUBH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000509, 0xFC0007FF, .MMI_PS2, {writes_hilo=true}} }, .PHMSBH = { {.PHMSBH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000549, 0xFC0007FF, .MMI_PS2, {writes_hilo=true}} }, .PEXEH = { {.PEXEH, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x70000689, 0xFC1F07FF, .MMI_PS2, {}} }, .PMULTH = { {.PMULTH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000709, 0xFC0007FF, .MMI_PS2, {writes_hilo=true}} }, .PDIVBW = { {.PDIVBW, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x70000749, 0xFC00FFFF, .MMI_PS2, {writes_hilo=true}} }, .PEXEW = { {.PEXEW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x70000789, 0xFC1F07FF, .MMI_PS2, {}} }, .PROT3W = { {.PROT3W, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x700007C9, 0xFC1F07FF, .MMI_PS2, {}} }, // ---- MMI3 sub-space (funct=0x29, shamt selects) -------------------------- .PMADDUW = { {.PMADDUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000029, 0xFC0007FF, .MMI_PS2, {writes_hilo=true}} }, .PSRAVW = { {.PSRAVW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x700000E9, 0xFC0007FF, .MMI_PS2, {}} }, .PMTHI = { {.PMTHI, {.GPR,.NONE,.NONE,.NONE}, {.RS,.NONE,.NONE,.NONE}, 0x70000229, 0xFC1FFFFF, .MMI_PS2, {}} }, .PMTLO = { {.PMTLO, {.GPR,.NONE,.NONE,.NONE}, {.RS,.NONE,.NONE,.NONE}, 0x70000269, 0xFC1FFFFF, .MMI_PS2, {}} }, .PINTOH = { {.PINTOH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700002A9, 0xFC0007FF, .MMI_PS2, {}} }, .PMULTUW = { {.PMULTUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000329, 0xFC0007FF, .MMI_PS2, {writes_hilo=true}} }, .PDIVUW = { {.PDIVUW, {.GPR,.GPR,.NONE,.NONE}, {.RS,.RT,.NONE,.NONE}, 0x70000369, 0xFC00FFFF, .MMI_PS2, {writes_hilo=true}} }, .PCPYUD = { {.PCPYUD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700003A9, 0xFC0007FF, .MMI_PS2, {}} }, .POR = { {.POR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x70000489 | 0x80, 0xFC0007FF, .MMI_PS2, {}} }, .PNOR = { {.PNOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x700004C9 | 0x80, 0xFC0007FF, .MMI_PS2, {}} }, .PEXCH = { {.PEXCH, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x70000689 | 0x80, 0xFC1F07FF, .MMI_PS2, {}} }, .PCPYH = { {.PCPYH, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x700006C9, 0xFC1F07FF, .MMI_PS2, {}} }, .PEXCW = { {.PEXCW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x70000789 | 0x80, 0xFC1F07FF, .MMI_PS2, {}} }, // Shift-amount register moves (R5900 SHFL helpers, SPECIAL funct 0x28/0x29). .MFSA = { {.MFSA, {.GPR,.NONE,.NONE,.NONE}, {.RD,.NONE,.NONE,.NONE}, 0x00000028, 0xFFFF07FF, .MMI_PS2, {}} }, .MTSA = { {.MTSA, {.GPR,.NONE,.NONE,.NONE}, {.RS,.NONE,.NONE,.NONE}, 0x00000029, 0xFC1FFFFF, .MMI_PS2, {}} }, .MTSAB = { {.MTSAB, {.GPR,.IMM16S,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0x04180000, 0xFC1F0000, .MMI_PS2, {}} }, .MTSAH = { {.MTSAH, {.GPR,.IMM16S,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0x04190000, 0xFC1F0000, .MMI_PS2, {}} }, // ========================================================================= // §6 MIPS32 R6 — compact branches, new mul/div, R6-specific ops // ========================================================================= // // R6 redesigns several pre-R6 encodings; the entries below cover the // genuinely new ones. Conflicting opcodes (BC at 0x32 vs LWC2; // BALC at 0x3A vs SWC2; JIC at 0x36 vs LDC2; JIALC at 0x3E vs SDC2; // AUI at 0x0F overlaps LUI's slot) must be disambiguated by target // Feature -- both forms live in the table, consumer picks. // Unconditional compact (26-bit PC-relative, no delay slot). .BC = { {.BC, {.REL26,.NONE,.NONE,.NONE}, {.IMM_26,.NONE,.NONE,.NONE}, 0xC8000000, 0xFC000000, .MIPS32_R6, {compact=true}} }, .BALC = { {.BALC, {.REL26,.NONE,.NONE,.NONE}, {.IMM_26,.NONE,.NONE,.NONE}, 0xE8000000, 0xFC000000, .MIPS32_R6, {compact=true}} }, // JIC/JIALC: indirect jump with explicit GPR target + 16-bit offset. // (rs=0; if rs!=0 the encoding becomes BEQZC/BNEZC.) .JIC = { {.JIC, {.GPR,.IMM16S,.NONE,.NONE}, {.RT,.IMM_16,.NONE,.NONE}, 0xD8000000, 0xFFE00000, .MIPS32_R6, {compact=true}} }, .JIALC = { {.JIALC, {.GPR,.IMM16S,.NONE,.NONE}, {.RT,.IMM_16,.NONE,.NONE}, 0xF8000000, 0xFFE00000, .MIPS32_R6, {compact=true}} }, // BEQZC/BNEZC: 21-bit PC-relative compact branch on rs == 0 / != 0. // Share opcodes 0x36/0x3E with JIC/JIALC; here rs is operand and // mask leaves rs as operand-driven (decoder disambiguates by rs != 0). .BEQZC = { {.BEQZC, {.GPR,.REL21,.NONE,.NONE}, {.RS,.BRANCH_21,.NONE,.NONE}, 0xD8000000, 0xFC000000, .MIPS32_R6, {compact=true}} }, .BNEZC = { {.BNEZC, {.GPR,.REL21,.NONE,.NONE}, {.RS,.BRANCH_21,.NONE,.NONE}, 0xF8000000, 0xFC000000, .MIPS32_R6, {compact=true}} }, // AUI / DAUI / AUIPC / ALUIPC / DAHI / DATI. // AUI takes the LUI slot (opcode 0x0F) but is a 3-operand "add upper // immediate" (rs may be != 0). When rs==0 the assembler typically // prints it as LUI; the bits are identical, semantics decided by R6 // vs pre-R6 dispatch. .AUI = { {.AUI, {.GPR,.GPR,.IMM16U,.NONE}, {.RT,.RS,.IMM_16,.NONE}, 0x3C000000, 0xFC000000, .MIPS32_R6, {}} }, .DAUI = { {.DAUI, {.GPR,.GPR,.IMM16U,.NONE}, {.RT,.RS,.IMM_16,.NONE}, 0x74000000, 0xFC000000, .MIPS64_R6, {only_64=true}} }, // AUIPC/ALUIPC live in PCREL sub-space (op=0x3B / REGIMM-like rt selector). // PCREL: rt=0x1E = AUIPC, rt=0x1F = ALUIPC. (op=0x3B selector varies.) .AUIPC = { {.AUIPC, {.GPR,.IMM16S,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0xEC1E0000, 0xFC1F0000, .MIPS32_R6, {}} }, .ALUIPC = { {.ALUIPC, {.GPR,.IMM16S,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0xEC1F0000, 0xFC1F0000, .MIPS32_R6, {}} }, .DAHI = { {.DAHI, {.GPR,.IMM16U,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0x04060000, 0xFC1F0000, .MIPS64_R6, {only_64=true}} }, .DATI = { {.DATI, {.GPR,.IMM16U,.NONE,.NONE}, {.RS,.IMM_16,.NONE,.NONE}, 0x041E0000, 0xFC1F0000, .MIPS64_R6, {only_64=true}} }, // R6 mul/div: reuse SPECIAL functs 0x18-0x1F (which were MULT/MULTU/ // DIV/DIVU in pre-R6) with shamt distinguishing low half (0x02) from // high half (0x03). Results land in rd, not HI/LO. .MUH = { {.MUH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x000000D8, 0xFC0007FF, .MIPS32_R6, {}} }, .MULU = { {.MULU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x00000099, 0xFC0007FF, .MIPS32_R6, {}} }, .MUHU = { {.MUHU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x000000D9, 0xFC0007FF, .MIPS32_R6, {}} }, .MOD = { {.MOD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x000000DA, 0xFC0007FF, .MIPS32_R6, {}} }, .MODU = { {.MODU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x000000DB, 0xFC0007FF, .MIPS32_R6, {}} }, // 64-bit R6 mul/div (functs 0x1C-0x1F). .DMUL_R6 = { {.DMUL_R6, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000009C, 0xFC0007FF, .MIPS64_R6, {only_64=true}} }, .DMUH = { {.DMUH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x000000DC, 0xFC0007FF, .MIPS64_R6, {only_64=true}} }, .DMULU = { {.DMULU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000009D, 0xFC0007FF, .MIPS64_R6, {only_64=true}} }, .DMUHU = { {.DMUHU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x000000DD, 0xFC0007FF, .MIPS64_R6, {only_64=true}} }, .DDIV_R6 = { {.DDIV_R6, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000009E, 0xFC0007FF, .MIPS64_R6, {only_64=true}} }, .DMOD = { {.DMOD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x000000DE, 0xFC0007FF, .MIPS64_R6, {only_64=true}} }, .DDIVU_R6 = { {.DDIVU_R6, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x0000009F, 0xFC0007FF, .MIPS64_R6, {only_64=true}} }, .DMODU = { {.DMODU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x000000DF, 0xFC0007FF, .MIPS64_R6, {only_64=true}} }, // LSA / DLSA (load shifted add): SPECIAL funct=0x05/0x15 with sa=imm2. // Layout: [op=0][rs][rt][rd][000][sa:2][funct]. sa-1 stored. .LSA = { {.LSA, {.GPR,.GPR,.GPR,.IMM5}, {.RD,.RS,.RT,.IMM_5}, 0x00000005, 0xFC00071F, .MIPS32_R6, {}} }, .DLSA = { {.DLSA, {.GPR,.GPR,.GPR,.IMM5}, {.RD,.RS,.RT,.IMM_5}, 0x00000015, 0xFC00071F, .MIPS64_R6, {only_64=true}} }, // SELEQZ / SELNEZ (predicated select). .SELEQZ = { {.SELEQZ, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x00000035, 0xFC0007FF, .MIPS32_R6, {}} }, .SELNEZ = { {.SELNEZ, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x00000037, 0xFC0007FF, .MIPS32_R6, {}} }, // BITSWAP / DBITSWAP: SPECIAL3 BSHFL/DBSHFL with shamt selecting. .BITSWAP = { {.BITSWAP, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000020, 0xFFE007FF, .MIPS32_R6, {}} }, .DBITSWAP = { {.DBITSWAP, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000024, 0xFFE007FF, .MIPS64_R6, {only_64=true}} }, // ALIGN / DALIGN: SPECIAL3 BSHFL/DBSHFL with shamt = 0b010xx (ALIGN) or // 0b010xxx (DALIGN). bp encoded in low bits of shamt. Mask fixes the // high-bits-of-shamt portion that marks "ALIGN op" but leaves bp variable. .ALIGN = { {.ALIGN, {.GPR,.GPR,.GPR,.IMM5}, {.RD,.RS,.RT,.IMM_5}, 0x7C000220, 0xFC0007FF, .MIPS32_R6, {}} }, .DALIGN = { {.DALIGN, {.GPR,.GPR,.GPR,.IMM5}, {.RD,.RS,.RT,.IMM_5}, 0x7C000224, 0xFC0007FF, .MIPS64_R6, {only_64=true}} }, // BC1EQZ / BC1NEZ: COP1 with rs=0x09/0x0D, 16-bit offset, ft as test reg. .BC1EQZ = { {.BC1EQZ, {.FPR_S,.REL16,.NONE,.NONE}, {.FT,.BRANCH_16,.NONE,.NONE}, 0x45200000, 0xFFE00000, .MIPS32_R6, {compact=true}} }, .BC1NEZ = { {.BC1NEZ, {.FPR_S,.REL16,.NONE,.NONE}, {.FT,.BRANCH_16,.NONE,.NONE}, 0x45A00000, 0xFFE00000, .MIPS32_R6, {compact=true}} }, .BC2EQZ = { {.BC2EQZ, {.CP2_REG,.REL16,.NONE,.NONE}, {.FT,.BRANCH_16,.NONE,.NONE}, 0x49200000, 0xFFE00000, .MIPS32_R6, {compact=true}} }, .BC2NEZ = { {.BC2NEZ, {.CP2_REG,.REL16,.NONE,.NONE}, {.FT,.BRANCH_16,.NONE,.NONE}, 0x49A00000, 0xFFE00000, .MIPS32_R6, {compact=true}} }, // CRC32 family: SPECIAL3 funct=0x0F, sz/c sub-fields in bits 10-6. // Layout: [op=0x1F][rs(data)][rt(crc)][0:5][sz:3][c:2][funct=0x0F] // sz=0 byte, 1 halfword, 2 word, 3 doubleword; c=0 CRC32, c=1 CRC32C. .CRC32B = { {.CRC32B, {.GPR,.GPR,.NONE,.NONE}, {.RT,.RS,.NONE,.NONE}, 0x7C00000F, 0xFC00F8FF, .MIPS32_R6, {}} }, .CRC32H = { {.CRC32H, {.GPR,.GPR,.NONE,.NONE}, {.RT,.RS,.NONE,.NONE}, 0x7C00004F, 0xFC00F8FF, .MIPS32_R6, {}} }, .CRC32W = { {.CRC32W, {.GPR,.GPR,.NONE,.NONE}, {.RT,.RS,.NONE,.NONE}, 0x7C00020F, 0xFC00F8FF, .MIPS32_R6, {}} }, .CRC32D = { {.CRC32D, {.GPR,.GPR,.NONE,.NONE}, {.RT,.RS,.NONE,.NONE}, 0x7C00030F, 0xFC00F8FF, .MIPS64_R6, {only_64=true}} }, .CRC32CB = { {.CRC32CB, {.GPR,.GPR,.NONE,.NONE}, {.RT,.RS,.NONE,.NONE}, 0x7C00010F, 0xFC00F8FF, .MIPS32_R6, {}} }, .CRC32CH = { {.CRC32CH, {.GPR,.GPR,.NONE,.NONE}, {.RT,.RS,.NONE,.NONE}, 0x7C00014F, 0xFC00F8FF, .MIPS32_R6, {}} }, .CRC32CW = { {.CRC32CW, {.GPR,.GPR,.NONE,.NONE}, {.RT,.RS,.NONE,.NONE}, 0x7C00024F, 0xFC00F8FF, .MIPS32_R6, {}} }, .CRC32CD = { {.CRC32CD, {.GPR,.GPR,.NONE,.NONE}, {.RT,.RS,.NONE,.NONE}, 0x7C00034F, 0xFC00F8FF, .MIPS64_R6, {only_64=true}} }, // SIGRIE: signal reserved-instruction exception (R6 reserved encoding). .SIGRIE = { {.SIGRIE, {.IMM16U,.NONE,.NONE,.NONE}, {.IMM_16,.NONE,.NONE,.NONE}, 0x04170000, 0xFFFF0000, .MIPS32_R6, {}} }, // ========================================================================= // §11 MIPS DSP ASE (rev 1 + rev 2) — focused subset // ========================================================================= // // DSP lives in SPECIAL3 (op=0x1F) with funct + shamt sub-spaces. Below // is the most-used core (saturating add/sub, dot-product-accumulate, // extract-from-accumulator, indexed loads, BPOSGE32, BITREV, INSV). // Many ops use accumulators ac0-ac3 encoded in the rd slot (low 2 bits); // the user passes the accumulator number as an immediate in the rd // operand position. Full DSP coverage is a follow-up. // ADDU.QB sub-space (funct=0x10, shamt selects) .ADDU_QB = { {.ADDU_QB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000010, 0xFC0007FF, .DSP_R1, {}} }, .SUBU_QB = { {.SUBU_QB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000050, 0xFC0007FF, .DSP_R1, {}} }, .ADDU_S_QB = { {.ADDU_S_QB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000110, 0xFC0007FF, .DSP_R1, {}} }, .SUBU_S_QB = { {.SUBU_S_QB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000150, 0xFC0007FF, .DSP_R1, {}} }, .ADDQ_PH = { {.ADDQ_PH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000290, 0xFC0007FF, .DSP_R1, {}} }, .SUBQ_PH = { {.SUBQ_PH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C0002D0, 0xFC0007FF, .DSP_R1, {}} }, .ADDQ_S_PH = { {.ADDQ_S_PH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000390, 0xFC0007FF, .DSP_R1, {}} }, .SUBQ_S_PH = { {.SUBQ_S_PH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C0003D0, 0xFC0007FF, .DSP_R1, {}} }, .ADDQ_S_W = { {.ADDQ_S_W, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000590, 0xFC0007FF, .DSP_R1, {}} }, .SUBQ_S_W = { {.SUBQ_S_W, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C0005D0, 0xFC0007FF, .DSP_R1, {}} }, .ADDSC = { {.ADDSC, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000410, 0xFC0007FF, .DSP_R1, {}} }, .ADDWC = { {.ADDWC, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000450, 0xFC0007FF, .DSP_R1, {}} }, // ABSQ_S.PH sub-space (funct=0x12, shamt selects). Unary RD <- RT. .ABSQ_S_PH = { {.ABSQ_S_PH, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000252, 0xFFE007FF, .DSP_R1, {}} }, .ABSQ_S_W = { {.ABSQ_S_W, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000452, 0xFFE007FF, .DSP_R1, {}} }, .PRECEQ_W_PHL = { {.PRECEQ_W_PHL, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000312, 0xFFE007FF, .DSP_R1, {}} }, .PRECEQ_W_PHR = { {.PRECEQ_W_PHR, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000352, 0xFFE007FF, .DSP_R1, {}} }, .PRECEQU_PH_QBL = { {.PRECEQU_PH_QBL, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000112, 0xFFE007FF, .DSP_R1, {}} }, .PRECEQU_PH_QBR = { {.PRECEQU_PH_QBR, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000152, 0xFFE007FF, .DSP_R1, {}} }, .PRECEU_PH_QBL = { {.PRECEU_PH_QBL, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000712, 0xFFE007FF, .DSP_R1, {}} }, .PRECEU_PH_QBR = { {.PRECEU_PH_QBR, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C000752, 0xFFE007FF, .DSP_R1, {}} }, .BITREV = { {.BITREV, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RT,.NONE,.NONE}, 0x7C0006D2, 0xFFE007FF, .DSP_R2, {}} }, // SHLL.QB sub-space (funct=0x13, shamt selects). .SHLL_QB = { {.SHLL_QB, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x7C000013, 0xFFE0073F, .DSP_R1, {}} }, .SHRL_QB = { {.SHRL_QB, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x7C000053, 0xFFE0073F, .DSP_R1, {}} }, .SHLLV_QB = { {.SHLLV_QB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x7C000093, 0xFC0007FF, .DSP_R1, {}} }, .SHRLV_QB = { {.SHRLV_QB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RT,.RS,.NONE}, 0x7C0000D3, 0xFC0007FF, .DSP_R1, {}} }, .SHLL_PH = { {.SHLL_PH, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x7C000213, 0xFFE0073F, .DSP_R1, {}} }, .SHRA_PH = { {.SHRA_PH, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x7C000253, 0xFFE0073F, .DSP_R1, {}} }, .SHLL_S_PH = { {.SHLL_S_PH, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x7C000313, 0xFFE0073F, .DSP_R1, {}} }, .SHLL_S_W = { {.SHLL_S_W, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x7C000513, 0xFFE0073F, .DSP_R1, {}} }, .SHRA_R_W = { {.SHRA_R_W, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RT,.IMM_5,.NONE}, 0x7C000553, 0xFFE0073F, .DSP_R1, {}} }, // Dot-product accumulate sub-space (funct=0x30/0x32). Take ac in rd (2-bit). .DPAU_H_QBL = { {.DPAU_H_QBL, {.IMM5,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C0000F0, 0xFC0007FF, .DSP_R1, {}} }, .DPAU_H_QBR = { {.DPAU_H_QBR, {.IMM5,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C0001F0, 0xFC0007FF, .DSP_R1, {}} }, .DPSU_H_QBL = { {.DPSU_H_QBL, {.IMM5,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C0002F0, 0xFC0007FF, .DSP_R1, {}} }, .DPSU_H_QBR = { {.DPSU_H_QBR, {.IMM5,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C0003F0, 0xFC0007FF, .DSP_R1, {}} }, .DPAQ_S_W_PH = { {.DPAQ_S_W_PH, {.IMM5,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000130, 0xFC0007FF, .DSP_R1, {}} }, .DPSQ_S_W_PH = { {.DPSQ_S_W_PH, {.IMM5,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000170, 0xFC0007FF, .DSP_R1, {}} }, .MULSAQ_S_W_PH = { {.MULSAQ_S_W_PH, {.IMM5,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C0001B0, 0xFC0007FF, .DSP_R1, {}} }, .DPAQ_SA_L_W = { {.DPAQ_SA_L_W, {.IMM5,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000330, 0xFC0007FF, .DSP_R1, {}} }, .DPSQ_SA_L_W = { {.DPSQ_SA_L_W, {.IMM5,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C000370, 0xFC0007FF, .DSP_R1, {}} }, // Extract-from-accumulator sub-space (funct=0x38, shamt selects). .EXTR_W = { {.EXTR_W, {.GPR,.IMM5,.IMM5,.NONE}, {.RT,.RS,.RD,.NONE}, 0x7C000038, 0xFC00073F, .DSP_R1, {}} }, .EXTRV_W = { {.EXTRV_W, {.GPR,.IMM5,.GPR,.NONE}, {.RT,.RD,.RS,.NONE}, 0x7C000078, 0xFC0007FF, .DSP_R1, {}} }, .EXTR_R_W = { {.EXTR_R_W, {.GPR,.IMM5,.IMM5,.NONE}, {.RT,.RS,.RD,.NONE}, 0x7C000138, 0xFC00073F, .DSP_R1, {}} }, .EXTR_RS_W = { {.EXTR_RS_W, {.GPR,.IMM5,.IMM5,.NONE}, {.RT,.RS,.RD,.NONE}, 0x7C0001B8, 0xFC00073F, .DSP_R1, {}} }, .EXTR_S_H = { {.EXTR_S_H, {.GPR,.IMM5,.IMM5,.NONE}, {.RT,.RS,.RD,.NONE}, 0x7C0003B8, 0xFC00073F, .DSP_R1, {}} }, .EXTP = { {.EXTP, {.GPR,.IMM5,.IMM5,.NONE}, {.RT,.RS,.RD,.NONE}, 0x7C0000B8, 0xFC00073F, .DSP_R1, {}} }, .EXTPV = { {.EXTPV, {.GPR,.IMM5,.GPR,.NONE}, {.RT,.RD,.RS,.NONE}, 0x7C0000F8, 0xFC0007FF, .DSP_R1, {}} }, .RDDSP = { {.RDDSP, {.GPR,.IMM5,.NONE,.NONE}, {.RD,.RS,.NONE,.NONE}, 0x7C0004B8, 0xFC1F07FF, .DSP_R1, {}} }, .WRDSP = { {.WRDSP, {.GPR,.IMM5,.NONE,.NONE}, {.RS,.RD,.NONE,.NONE}, 0x7C0004F8, 0xFC00FFFF, .DSP_R1, {}} }, // Indexed loads (SPECIAL3 funct=0x0A). .LWX = { {.LWX, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C00000A, 0xFC0007FF, .DSP_R1, {}} }, .LHX = { {.LHX, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C00010A, 0xFC0007FF, .DSP_R1, {}} }, .LBUX = { {.LBUX, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS,.RT,.NONE}, 0x7C00018A, 0xFC0007FF, .DSP_R1, {}} }, // Insert variable (SPECIAL3 funct=0x0C). .INSV = { {.INSV, {.GPR,.GPR,.NONE,.NONE}, {.RT,.RS,.NONE,.NONE}, 0x7C00000C, 0xFC00FFFF, .DSP_R1, {}} }, // REGIMM branch on DSPControl.pos >= 32. .BPOSGE32 = { {.BPOSGE32, {.REL16,.NONE,.NONE,.NONE}, {.BRANCH_16,.NONE,.NONE,.NONE}, 0x041C0000, 0xFFFF0000, .DSP_R1, {delay_slot=true}} }, // ========================================================================= // §12 MSA (MIPS SIMD Architecture) // ========================================================================= // // 3R-format layout: // bits 31:26 = 0x1E (primary) // bits 25:23 = group (3 bits, picks a sub-table of 64 ops) // bits 22:21 = df (00=B, 01=H, 10=W, 11=D) // bits 20:16 = wt operand // bits 15:11 = ws operand // bits 10:6 = wd operand // bits 5:0 = minor (6 bits, picks op within group) // // Static mask covers primary+group+df+minor = 0xFFE0003F. With df=00 // the bits include only the group+minor; df=01 sets bit 21, etc. // // NOTE: opcode 0x1E conflicts with PS2 LQ (R5900). Consumers select by // target Feature flag; both forms can coexist in the dispatch table because // the mask of LQ (which is an I-type with no funct field) differs from // any MSA 3R-format mask. // ---- Group 000: ADDV / SUBV (3R minor 0x0E / 0x0F) ---------------------- .ADDV_B = { {.ADDV_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7800000E, 0xFFE0003F, .MSA, {}} }, .ADDV_H = { {.ADDV_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7820000E, 0xFFE0003F, .MSA, {}} }, .ADDV_W = { {.ADDV_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7840000E, 0xFFE0003F, .MSA, {}} }, .ADDV_D = { {.ADDV_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7860000E, 0xFFE0003F, .MSA, {}} }, .SUBV_B = { {.SUBV_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7880000E, 0xFFE0003F, .MSA, {}} }, .SUBV_H = { {.SUBV_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78A0000E, 0xFFE0003F, .MSA, {}} }, .SUBV_W = { {.SUBV_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78C0000E, 0xFFE0003F, .MSA, {}} }, .SUBV_D = { {.SUBV_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78E0000E, 0xFFE0003F, .MSA, {}} }, // ---- Group 000: signed/unsigned saturated add/sub (3R minor 0x10..0x13) - .ADDS_S_B = { {.ADDS_S_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79000010, 0xFFE0003F, .MSA, {}} }, .ADDS_S_H = { {.ADDS_S_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79200010, 0xFFE0003F, .MSA, {}} }, .ADDS_S_W = { {.ADDS_S_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79400010, 0xFFE0003F, .MSA, {}} }, .ADDS_S_D = { {.ADDS_S_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79600010, 0xFFE0003F, .MSA, {}} }, .ADDS_U_B = { {.ADDS_U_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79800010, 0xFFE0003F, .MSA, {}} }, .ADDS_U_H = { {.ADDS_U_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79A00010, 0xFFE0003F, .MSA, {}} }, .ADDS_U_W = { {.ADDS_U_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79C00010, 0xFFE0003F, .MSA, {}} }, .ADDS_U_D = { {.ADDS_U_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79E00010, 0xFFE0003F, .MSA, {}} }, .SUBS_S_B = { {.SUBS_S_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78000011, 0xFFE0003F, .MSA, {}} }, .SUBS_S_H = { {.SUBS_S_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78200011, 0xFFE0003F, .MSA, {}} }, .SUBS_S_W = { {.SUBS_S_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78400011, 0xFFE0003F, .MSA, {}} }, .SUBS_S_D = { {.SUBS_S_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78600011, 0xFFE0003F, .MSA, {}} }, .SUBS_U_B = { {.SUBS_U_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78800011, 0xFFE0003F, .MSA, {}} }, .SUBS_U_H = { {.SUBS_U_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78A00011, 0xFFE0003F, .MSA, {}} }, .SUBS_U_W = { {.SUBS_U_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78C00011, 0xFFE0003F, .MSA, {}} }, .SUBS_U_D = { {.SUBS_U_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78E00011, 0xFFE0003F, .MSA, {}} }, // ---- Group 001: MULV / MADDV / MSUBV / DIV / MOD (3R minor 0x12..0x16) -- .MULV_B = { {.MULV_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78000012, 0xFFE0003F, .MSA, {}} }, .MULV_H = { {.MULV_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78200012, 0xFFE0003F, .MSA, {}} }, .MULV_W = { {.MULV_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78400012, 0xFFE0003F, .MSA, {}} }, .MULV_D = { {.MULV_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78600012, 0xFFE0003F, .MSA, {}} }, .MADDV_B = { {.MADDV_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78800012, 0xFFE0003F, .MSA, {}} }, .MADDV_H = { {.MADDV_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78A00012, 0xFFE0003F, .MSA, {}} }, .MADDV_W = { {.MADDV_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78C00012, 0xFFE0003F, .MSA, {}} }, .MADDV_D = { {.MADDV_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78E00012, 0xFFE0003F, .MSA, {}} }, .MSUBV_B = { {.MSUBV_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79000012, 0xFFE0003F, .MSA, {}} }, .MSUBV_H = { {.MSUBV_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79200012, 0xFFE0003F, .MSA, {}} }, .MSUBV_W = { {.MSUBV_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79400012, 0xFFE0003F, .MSA, {}} }, .MSUBV_D = { {.MSUBV_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79600012, 0xFFE0003F, .MSA, {}} }, .DIV_S_B = { {.DIV_S_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A000012, 0xFFE0003F, .MSA, {}} }, .DIV_S_H = { {.DIV_S_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A200012, 0xFFE0003F, .MSA, {}} }, .DIV_S_W = { {.DIV_S_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A400012, 0xFFE0003F, .MSA, {}} }, .DIV_S_D = { {.DIV_S_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A600012, 0xFFE0003F, .MSA, {}} }, .DIV_U_B = { {.DIV_U_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A800012, 0xFFE0003F, .MSA, {}} }, .DIV_U_H = { {.DIV_U_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7AA00012, 0xFFE0003F, .MSA, {}} }, .DIV_U_W = { {.DIV_U_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7AC00012, 0xFFE0003F, .MSA, {}} }, .DIV_U_D = { {.DIV_U_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7AE00012, 0xFFE0003F, .MSA, {}} }, .MOD_S_B = { {.MOD_S_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7B000012, 0xFFE0003F, .MSA, {}} }, .MOD_S_H = { {.MOD_S_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7B200012, 0xFFE0003F, .MSA, {}} }, .MOD_S_W = { {.MOD_S_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7B400012, 0xFFE0003F, .MSA, {}} }, .MOD_S_D = { {.MOD_S_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7B600012, 0xFFE0003F, .MSA, {}} }, .MOD_U_B = { {.MOD_U_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7B800012, 0xFFE0003F, .MSA, {}} }, .MOD_U_H = { {.MOD_U_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7BA00012, 0xFFE0003F, .MSA, {}} }, .MOD_U_W = { {.MOD_U_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7BC00012, 0xFFE0003F, .MSA, {}} }, .MOD_U_D = { {.MOD_U_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7BE00012, 0xFFE0003F, .MSA, {}} }, // ---- Vector logical (VEC-format, df implicit -- always byte-wise) ------- // AND.V/OR.V/NOR.V/XOR.V live at minor 0x1E with group bits selecting op: // AND.V = 0x78000020 -- wait actually different format. VEC-form uses // bits 25:21 = 11110/11111 etc. For simplicity we encode them as 3R-shape. // AND.V = 0x7800001E, OR.V = 0x7820001E, NOR.V = 0x7840001E, XOR.V = 0x7860001E .AND_V = { {.AND_V, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7800001E, 0xFFE0003F, .MSA, {}} }, .OR_V = { {.OR_V, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7820001E, 0xFFE0003F, .MSA, {}} }, .NOR_V = { {.NOR_V, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7840001E, 0xFFE0003F, .MSA, {}} }, .XOR_V = { {.XOR_V, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7860001E, 0xFFE0003F, .MSA, {}} }, // ---- Vector compare (3R minor 0x0F for CEQ; 0x07..0x0A for LT/LE) ------ .CEQ_B = { {.CEQ_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7800000F, 0xFFE0003F, .MSA, {}} }, .CEQ_H = { {.CEQ_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7820000F, 0xFFE0003F, .MSA, {}} }, .CEQ_W = { {.CEQ_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7840000F, 0xFFE0003F, .MSA, {}} }, .CEQ_D = { {.CEQ_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7860000F, 0xFFE0003F, .MSA, {}} }, .CLT_S_B = { {.CLT_S_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7900000F, 0xFFE0003F, .MSA, {}} }, .CLT_S_H = { {.CLT_S_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7920000F, 0xFFE0003F, .MSA, {}} }, .CLT_S_W = { {.CLT_S_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7940000F, 0xFFE0003F, .MSA, {}} }, .CLT_S_D = { {.CLT_S_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7960000F, 0xFFE0003F, .MSA, {}} }, .CLT_U_B = { {.CLT_U_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7980000F, 0xFFE0003F, .MSA, {}} }, .CLT_U_H = { {.CLT_U_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79A0000F, 0xFFE0003F, .MSA, {}} }, .CLT_U_W = { {.CLT_U_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79C0000F, 0xFFE0003F, .MSA, {}} }, .CLT_U_D = { {.CLT_U_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79E0000F, 0xFFE0003F, .MSA, {}} }, .CLE_S_B = { {.CLE_S_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A00000F, 0xFFE0003F, .MSA, {}} }, .CLE_S_H = { {.CLE_S_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A20000F, 0xFFE0003F, .MSA, {}} }, .CLE_S_W = { {.CLE_S_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A40000F, 0xFFE0003F, .MSA, {}} }, .CLE_S_D = { {.CLE_S_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A60000F, 0xFFE0003F, .MSA, {}} }, .CLE_U_B = { {.CLE_U_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A80000F, 0xFFE0003F, .MSA, {}} }, .CLE_U_H = { {.CLE_U_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7AA0000F, 0xFFE0003F, .MSA, {}} }, .CLE_U_W = { {.CLE_U_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7AC0000F, 0xFFE0003F, .MSA, {}} }, .CLE_U_D = { {.CLE_U_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7AE0000F, 0xFFE0003F, .MSA, {}} }, // ---- Vector min/max (3R minor 0x0E with high opcode group bits 010) ---- .MIN_S_B = { {.MIN_S_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A00000E, 0xFFE0003F, .MSA, {}} }, .MIN_S_H = { {.MIN_S_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A20000E, 0xFFE0003F, .MSA, {}} }, .MIN_S_W = { {.MIN_S_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A40000E, 0xFFE0003F, .MSA, {}} }, .MIN_S_D = { {.MIN_S_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A60000E, 0xFFE0003F, .MSA, {}} }, .MIN_U_B = { {.MIN_U_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7A80000E, 0xFFE0003F, .MSA, {}} }, .MIN_U_H = { {.MIN_U_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7AA0000E, 0xFFE0003F, .MSA, {}} }, .MIN_U_W = { {.MIN_U_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7AC0000E, 0xFFE0003F, .MSA, {}} }, .MIN_U_D = { {.MIN_U_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7AE0000E, 0xFFE0003F, .MSA, {}} }, .MAX_S_B = { {.MAX_S_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7900000E, 0xFFE0003F, .MSA, {}} }, .MAX_S_H = { {.MAX_S_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7920000E, 0xFFE0003F, .MSA, {}} }, .MAX_S_W = { {.MAX_S_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7940000E, 0xFFE0003F, .MSA, {}} }, .MAX_S_D = { {.MAX_S_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7960000E, 0xFFE0003F, .MSA, {}} }, .MAX_U_B = { {.MAX_U_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7980000E, 0xFFE0003F, .MSA, {}} }, .MAX_U_H = { {.MAX_U_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79A0000E, 0xFFE0003F, .MSA, {}} }, .MAX_U_W = { {.MAX_U_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79C0000E, 0xFFE0003F, .MSA, {}} }, .MAX_U_D = { {.MAX_U_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x79E0000E, 0xFFE0003F, .MSA, {}} }, // ---- Vector shifts (3R minor 0x0D variable shifts) --------------------- .SLL_B = { {.SLL_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7800000D, 0xFFE0003F, .MSA, {}} }, .SLL_H = { {.SLL_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7820000D, 0xFFE0003F, .MSA, {}} }, .SLL_W = { {.SLL_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7840000D, 0xFFE0003F, .MSA, {}} }, .SLL_D = { {.SLL_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7860000D, 0xFFE0003F, .MSA, {}} }, .SRA_B = { {.SRA_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7880000D, 0xFFE0003F, .MSA, {}} }, .SRA_H = { {.SRA_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78A0000D, 0xFFE0003F, .MSA, {}} }, .SRA_W = { {.SRA_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78C0000D, 0xFFE0003F, .MSA, {}} }, .SRA_D = { {.SRA_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x78E0000D, 0xFFE0003F, .MSA, {}} }, .SRL_B = { {.SRL_B, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7900000D, 0xFFE0003F, .MSA, {}} }, .SRL_H = { {.SRL_H, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7920000D, 0xFFE0003F, .MSA, {}} }, .SRL_W = { {.SRL_W, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7940000D, 0xFFE0003F, .MSA, {}} }, .SRL_D = { {.SRL_D, {.MSA_VEC,.MSA_VEC,.MSA_VEC,.NONE}, {.WD,.WS,.WT,.NONE}, 0x7960000D, 0xFFE0003F, .MSA, {}} }, // ---- Memory: LD/ST in MI10 format --------------------------------------- // MI10 form: opcode 0x1E in primary, bits 25:23 = df group, bits 22:16 = signed-10 disp, // bits 15:11 = rs (base), bits 10:6 = wd, bits 5:0 = minor (0x20 = LD, 0x24 = ST) // LD.B: 0x78000020 / ST.B: 0x78000024 // LD.H: 0x78000021 / ST.H: 0x78000025 // LD.W: 0x78000022 / ST.W: 0x78000026 // LD.D: 0x78000023 / ST.D: 0x78000027 .LD_B = { {.LD_B, {.MSA_VEC, .MEM, .NONE, .NONE}, {.WD, .MSA_OFFSET_BASE_B, .NONE, .NONE}, 0x78000020, 0xFC00003F, .MSA, {}} }, .LD_H = { {.LD_H, {.MSA_VEC, .MEM, .NONE, .NONE}, {.WD, .MSA_OFFSET_BASE_H, .NONE, .NONE}, 0x78000021, 0xFC00003F, .MSA, {}} }, .LD_W = { {.LD_W, {.MSA_VEC, .MEM, .NONE, .NONE}, {.WD, .MSA_OFFSET_BASE_W, .NONE, .NONE}, 0x78000022, 0xFC00003F, .MSA, {}} }, .LD_D = { {.LD_D, {.MSA_VEC, .MEM, .NONE, .NONE}, {.WD, .MSA_OFFSET_BASE_D, .NONE, .NONE}, 0x78000023, 0xFC00003F, .MSA, {}} }, .ST_B = { {.ST_B, {.MSA_VEC, .MEM, .NONE, .NONE}, {.WD, .MSA_OFFSET_BASE_B, .NONE, .NONE}, 0x78000024, 0xFC00003F, .MSA, {}} }, .ST_H = { {.ST_H, {.MSA_VEC, .MEM, .NONE, .NONE}, {.WD, .MSA_OFFSET_BASE_H, .NONE, .NONE}, 0x78000025, 0xFC00003F, .MSA, {}} }, .ST_W = { {.ST_W, {.MSA_VEC, .MEM, .NONE, .NONE}, {.WD, .MSA_OFFSET_BASE_W, .NONE, .NONE}, 0x78000026, 0xFC00003F, .MSA, {}} }, .ST_D = { {.ST_D, {.MSA_VEC, .MEM, .NONE, .NONE}, {.WD, .MSA_OFFSET_BASE_D, .NONE, .NONE}, 0x78000027, 0xFC00003F, .MSA, {}} }, // ---- LDI: load immediate -- I5 format with signed 10-bit imm at 20:11 -- // Use IMM5 here as a representative; production VFPU-style I10 is similar. .LDI_B = { {.LDI_B, {.MSA_VEC, .IMM5, .NONE, .NONE}, {.WD, .MSA_I5, .NONE, .NONE}, 0x7B000007, 0xFFE0003F, .MSA, {}} }, .LDI_H = { {.LDI_H, {.MSA_VEC, .IMM5, .NONE, .NONE}, {.WD, .MSA_I5, .NONE, .NONE}, 0x7B200007, 0xFFE0003F, .MSA, {}} }, .LDI_W = { {.LDI_W, {.MSA_VEC, .IMM5, .NONE, .NONE}, {.WD, .MSA_I5, .NONE, .NONE}, 0x7B400007, 0xFFE0003F, .MSA, {}} }, .LDI_D = { {.LDI_D, {.MSA_VEC, .IMM5, .NONE, .NONE}, {.WD, .MSA_I5, .NONE, .NONE}, 0x7B600007, 0xFFE0003F, .MSA, {}} }, // ========================================================================= // §13 PSP Allegrex VFPU control / no-operand instructions // ========================================================================= // // VFPU lives in primary opcodes 0x18 (cop2-like) and 0x3F (vfpu-specific). // The full Feature has ~150 instructions across many encoding flavours -- // scalar/pair/triple/quad lane (.s/.p/.t/.q), prefix ops (VPFXS/T/D), // matrix forms, and lookup-table generators. Operand encoding uses // 7-bit register IDs split across the instruction word, with the high // bit of each VFPU register byte selecting an orientation hint. // // Below are the no-operand control ops where the entire 32-bit word is // a fixed constant; they're well-known via PPSSPP/JPCSP. The fully // operand-bearing VFPU forms (VADD/VSUB/VMUL/VDOT/...) need careful // bit-level cross-reference and are intentionally deferred -- see // ENCODING_TABLE entry counts and use docs/mips_platforms.md for status. .VNOP = { {.VNOP, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0xFFFF0000, 0xFFFFFFFF, .VFPU_PSP, {}} }, .VSYNC = { {.VSYNC, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0xFFFF0320, 0xFFFFFFFF, .VFPU_PSP, {}} }, .VFLUSH = { {.VFLUSH, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0xFFFF040D, 0xFFFFFFFF, .VFPU_PSP, {}} }, // ---- VFPU memory: LV.S / SV.S / LV.Q / SV.Q ----------------------------- // // LV.S vd, off(base): bits 31:26 = 110010 (0x32) -> word 0xC8000000 // bits 25:21 = base, bits 20:16 = vd[6:2], // bits 15:2 = disp (mult of 4), bits 1:0 = vd[1:0] // LV.Q vd, off(base): bits 31:26 = 110110 (0x36) -> 0xD8000000 // SV.S rs, off(base): bits 31:26 = 111010 (0x3A) -> 0xE8000000 // SV.Q rs, off(base): bits 31:26 = 111110 (0x3E) -> 0xF8000000 // // Mask covers only the primary opcode (bits 31:26): operand-driven base, // disp, and vd-split bits land in the zero positions. .LV_S = { {.LV_S, {.VFPU_S, .MEM, .NONE, .NONE}, {.VFPU_VT_MEM, .VFPU_OFFSET_BASE, .NONE, .NONE}, 0xC8000000, 0xFC000000, .VFPU_PSP, {}} }, .LV_Q = { {.LV_Q, {.VFPU_Q, .MEM, .NONE, .NONE}, {.VFPU_VT_MEM, .VFPU_OFFSET_BASE, .NONE, .NONE}, 0xD8000000, 0xFC000000, .VFPU_PSP, {}} }, .SV_S = { {.SV_S, {.VFPU_S, .MEM, .NONE, .NONE}, {.VFPU_VT_MEM, .VFPU_OFFSET_BASE, .NONE, .NONE}, 0xE8000000, 0xFC000000, .VFPU_PSP, {}} }, .SV_Q = { {.SV_Q, {.VFPU_Q, .MEM, .NONE, .NONE}, {.VFPU_VT_MEM, .VFPU_OFFSET_BASE, .NONE, .NONE}, 0xF8000000, 0xFC000000, .VFPU_PSP, {}} }, // ---- VFPU arithmetic: 3-register form (vd = vs op vt) ------------------- // // bits 31:24 = opcode byte (0x60 = VFPU0 / VADD, 0x64 = VFPU1 / VMUL) // bit 23 = sub-opcode (e.g., VADD vs VSUB share 0x60; VSUB has bit 23 set) // bits 22:16 = vt bit15 = width-hi bits 14:8 = vs // bit 7 = width-lo bits 6:0 = vd // // Mask covers opcode byte + sub-bit + the two width bits = 0xFF808080. // .s / .p / .t / .q baked in via the (bit15, bit7) pair on each entry. // VADD: 0x60000000 + width bits .VADD_S = { {.VADD_S, {.VFPU_S,.VFPU_S,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x60000000, 0xFF808080, .VFPU_PSP, {}} }, .VADD_P = { {.VADD_P, {.VFPU_P,.VFPU_P,.VFPU_P,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x60000080, 0xFF808080, .VFPU_PSP, {}} }, .VADD_T = { {.VADD_T, {.VFPU_T,.VFPU_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x60008000, 0xFF808080, .VFPU_PSP, {}} }, .VADD_Q = { {.VADD_Q, {.VFPU_Q,.VFPU_Q,.VFPU_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x60008080, 0xFF808080, .VFPU_PSP, {}} }, // VSUB: 0x60800000 + width .VSUB_S = { {.VSUB_S, {.VFPU_S,.VFPU_S,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x60800000, 0xFF808080, .VFPU_PSP, {}} }, .VSUB_P = { {.VSUB_P, {.VFPU_P,.VFPU_P,.VFPU_P,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x60800080, 0xFF808080, .VFPU_PSP, {}} }, .VSUB_T = { {.VSUB_T, {.VFPU_T,.VFPU_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x60808000, 0xFF808080, .VFPU_PSP, {}} }, .VSUB_Q = { {.VSUB_Q, {.VFPU_Q,.VFPU_Q,.VFPU_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x60808080, 0xFF808080, .VFPU_PSP, {}} }, // VMUL: 0x64000000 + width (primary opcode 0x19 = VFPU1) .VMUL_S = { {.VMUL_S, {.VFPU_S,.VFPU_S,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x64000000, 0xFF808080, .VFPU_PSP, {}} }, .VMUL_P = { {.VMUL_P, {.VFPU_P,.VFPU_P,.VFPU_P,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x64000080, 0xFF808080, .VFPU_PSP, {}} }, .VMUL_T = { {.VMUL_T, {.VFPU_T,.VFPU_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x64008000, 0xFF808080, .VFPU_PSP, {}} }, .VMUL_Q = { {.VMUL_Q, {.VFPU_Q,.VFPU_Q,.VFPU_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x64008080, 0xFF808080, .VFPU_PSP, {}} }, // VDIV: 0x63800000 + width (scalar-only natively; .p/.t/.q are emulated) .VDIV_S = { {.VDIV_S, {.VFPU_S,.VFPU_S,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x63800000, 0xFF808080, .VFPU_PSP, {}} }, .VDIV_P = { {.VDIV_P, {.VFPU_P,.VFPU_P,.VFPU_P,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x63800080, 0xFF808080, .VFPU_PSP, {}} }, .VDIV_T = { {.VDIV_T, {.VFPU_T,.VFPU_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x63808000, 0xFF808080, .VFPU_PSP, {}} }, .VDIV_Q = { {.VDIV_Q, {.VFPU_Q,.VFPU_Q,.VFPU_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x63808080, 0xFF808080, .VFPU_PSP, {}} }, // ---- VFPU unary: 2-register form (vd = op vs) --------------------------- // // bits 31:16 = opcode header (0xD000 base for unary ALU; sub-op in bits 24:16) // bit 15 / bit 7 = width bits 14:8 = vs bits 6:0 = vd (vt unused) // // ABS / NEG / SQRT / RCP / RSQ / MOV all share the same skeleton with // a different sub-opcode in bits 24:16. // VABS: 0xD0010000 + width .VABS_S = { {.VABS_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0010000, 0xFFFF8080, .VFPU_PSP, {}} }, .VABS_P = { {.VABS_P, {.VFPU_P,.VFPU_P,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0010080, 0xFFFF8080, .VFPU_PSP, {}} }, .VABS_T = { {.VABS_T, {.VFPU_T,.VFPU_T,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0018000, 0xFFFF8080, .VFPU_PSP, {}} }, .VABS_Q = { {.VABS_Q, {.VFPU_Q,.VFPU_Q,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0018080, 0xFFFF8080, .VFPU_PSP, {}} }, // VNEG: 0xD0020000 + width .VNEG_S = { {.VNEG_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0020000, 0xFFFF8080, .VFPU_PSP, {}} }, .VNEG_P = { {.VNEG_P, {.VFPU_P,.VFPU_P,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0020080, 0xFFFF8080, .VFPU_PSP, {}} }, .VNEG_T = { {.VNEG_T, {.VFPU_T,.VFPU_T,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0028000, 0xFFFF8080, .VFPU_PSP, {}} }, .VNEG_Q = { {.VNEG_Q, {.VFPU_Q,.VFPU_Q,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0028080, 0xFFFF8080, .VFPU_PSP, {}} }, // VMOV: 0xD0000000 + width .VMOV_S = { {.VMOV_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0000000, 0xFFFF8080, .VFPU_PSP, {}} }, .VMOV_P = { {.VMOV_P, {.VFPU_P,.VFPU_P,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0000080, 0xFFFF8080, .VFPU_PSP, {}} }, .VMOV_T = { {.VMOV_T, {.VFPU_T,.VFPU_T,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0008000, 0xFFFF8080, .VFPU_PSP, {}} }, .VMOV_Q = { {.VMOV_Q, {.VFPU_Q,.VFPU_Q,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0008080, 0xFFFF8080, .VFPU_PSP, {}} }, // VSQRT.S only (no .p/.t/.q natively) .VSQRT_S = { {.VSQRT_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0160000, 0xFFFF8080, .VFPU_PSP, {}} }, // VRCP: 0xD0100000 + width .VRCP_S = { {.VRCP_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0100000, 0xFFFF8080, .VFPU_PSP, {}} }, .VRCP_P = { {.VRCP_P, {.VFPU_P,.VFPU_P,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0100080, 0xFFFF8080, .VFPU_PSP, {}} }, .VRCP_T = { {.VRCP_T, {.VFPU_T,.VFPU_T,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0108000, 0xFFFF8080, .VFPU_PSP, {}} }, .VRCP_Q = { {.VRCP_Q, {.VFPU_Q,.VFPU_Q,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0108080, 0xFFFF8080, .VFPU_PSP, {}} }, // VRSQ: 0xD0110000 + width .VRSQ_S = { {.VRSQ_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0110000, 0xFFFF8080, .VFPU_PSP, {}} }, .VRSQ_P = { {.VRSQ_P, {.VFPU_P,.VFPU_P,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0110080, 0xFFFF8080, .VFPU_PSP, {}} }, .VRSQ_T = { {.VRSQ_T, {.VFPU_T,.VFPU_T,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0118000, 0xFFFF8080, .VFPU_PSP, {}} }, .VRSQ_Q = { {.VRSQ_Q, {.VFPU_Q,.VFPU_Q,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0118080, 0xFFFF8080, .VFPU_PSP, {}} }, // ---- VFPU min/max + scale ------------------------------------------------ .VMIN_S = { {.VMIN_S, {.VFPU_S,.VFPU_S,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x6D000000, 0xFF808080, .VFPU_PSP, {}} }, .VMIN_P = { {.VMIN_P, {.VFPU_P,.VFPU_P,.VFPU_P,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x6D000080, 0xFF808080, .VFPU_PSP, {}} }, .VMIN_T = { {.VMIN_T, {.VFPU_T,.VFPU_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x6D008000, 0xFF808080, .VFPU_PSP, {}} }, .VMIN_Q = { {.VMIN_Q, {.VFPU_Q,.VFPU_Q,.VFPU_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x6D008080, 0xFF808080, .VFPU_PSP, {}} }, .VMAX_S = { {.VMAX_S, {.VFPU_S,.VFPU_S,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x6D800000, 0xFF808080, .VFPU_PSP, {}} }, .VMAX_P = { {.VMAX_P, {.VFPU_P,.VFPU_P,.VFPU_P,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x6D800080, 0xFF808080, .VFPU_PSP, {}} }, .VMAX_T = { {.VMAX_T, {.VFPU_T,.VFPU_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x6D808000, 0xFF808080, .VFPU_PSP, {}} }, .VMAX_Q = { {.VMAX_Q, {.VFPU_Q,.VFPU_Q,.VFPU_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x6D808080, 0xFF808080, .VFPU_PSP, {}} }, // VSCL: scalar-times-vector. vd = vs * vt[scalar]. Only .p/.t/.q forms. .VSCL_P = { {.VSCL_P, {.VFPU_P,.VFPU_P,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x65000080, 0xFF808080, .VFPU_PSP, {}} }, .VSCL_T = { {.VSCL_T, {.VFPU_T,.VFPU_T,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x65008000, 0xFF808080, .VFPU_PSP, {}} }, .VSCL_Q = { {.VSCL_Q, {.VFPU_Q,.VFPU_Q,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x65008080, 0xFF808080, .VFPU_PSP, {}} }, // VDOT: vector dot-product into scalar. vd[.s] = sum(vs * vt) for .p/.t/.q. .VDOT_P = { {.VDOT_P, {.VFPU_S,.VFPU_P,.VFPU_P,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x64800080, 0xFF808080, .VFPU_PSP, {}} }, .VDOT_T = { {.VDOT_T, {.VFPU_S,.VFPU_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x64808000, 0xFF808080, .VFPU_PSP, {}} }, .VDOT_Q = { {.VDOT_Q, {.VFPU_S,.VFPU_Q,.VFPU_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x64808080, 0xFF808080, .VFPU_PSP, {}} }, // ---- VFPU constant load: VCST.S vd, #const_index ------------------------ // bits 31:21 = 11010000 011 bits 20:16 = const bits 15:7 = 0 // bit 7 = width-lo bits 6:0 = vd .VCST_S = { {.VCST_S, {.VFPU_S, .IMM5, .NONE, .NONE}, {.VFPU_VD, .VFPU_CONST, .NONE, .NONE}, 0xD0600000, 0xFFE08080, .VFPU_PSP, {}} }, .VCST_P = { {.VCST_P, {.VFPU_P, .IMM5, .NONE, .NONE}, {.VFPU_VD, .VFPU_CONST, .NONE, .NONE}, 0xD0600080, 0xFFE08080, .VFPU_PSP, {}} }, .VCST_T = { {.VCST_T, {.VFPU_T, .IMM5, .NONE, .NONE}, {.VFPU_VD, .VFPU_CONST, .NONE, .NONE}, 0xD0608000, 0xFFE08080, .VFPU_PSP, {}} }, .VCST_Q = { {.VCST_Q, {.VFPU_Q, .IMM5, .NONE, .NONE}, {.VFPU_VD, .VFPU_CONST, .NONE, .NONE}, 0xD0608080, 0xFFE08080, .VFPU_PSP, {}} }, // ---- VFPU prefix instructions: VPFXS / VPFXT / VPFXD -------------------- // // Each takes a 20-bit prefix mask in the low 20 bits of the instruction // word that modifies the source/destination of the *next* vector op. // VPFXS: 0xDC000000 base // VPFXT: 0xDD000000 // VPFXD: 0xDE000000 .VPFXS = { {.VPFXS, {.IMM20, .NONE, .NONE, .NONE}, {.VFPU_PFX, .NONE, .NONE, .NONE}, 0xDC000000, 0xFFF00000, .VFPU_PSP, {}} }, .VPFXT = { {.VPFXT, {.IMM20, .NONE, .NONE, .NONE}, {.VFPU_PFX, .NONE, .NONE, .NONE}, 0xDD000000, 0xFFF00000, .VFPU_PSP, {}} }, .VPFXD = { {.VPFXD, {.IMM20, .NONE, .NONE, .NONE}, {.VFPU_PFX, .NONE, .NONE, .NONE}, 0xDE000000, 0xFFF00000, .VFPU_PSP, {}} }, // ---- VFPU move-between-GPR: MFV / MTV ----------------------------------- // // MFV rt, vd -- move VFPU vd[.s] -> GPR rt // bits 31:21 = 01001000 011 (0x4827xxxx? no -- mfv encoding is in COP2 space) // Standard layout: 010010 00011 rt vd[6:0] (COP2 MF with sub-op 3) // word = (0x12 << 26) | (3 << 21) | (rt << 16) | vd = 0x48600000 | (rt<<16) | vd .MFV = { {.MFV, {.GPR, .VFPU_S, .NONE, .NONE}, {.RT, .VFPU_VD, .NONE, .NONE}, 0x48600000, 0xFFE00080, .VFPU_PSP, {}} }, // MTV rt, vd -- move GPR rt -> VFPU vd[.s] // word = (0x12 << 26) | (7 << 21) | (rt << 16) | vd = 0x48E00000 | (rt<<16) | vd .MTV = { {.MTV, {.GPR, .VFPU_S, .NONE, .NONE}, {.RT, .VFPU_VD, .NONE, .NONE}, 0x48E00000, 0xFFE00080, .VFPU_PSP, {}} }, // ========================================================================= // §14 VFPU transcendentals (unary, single-precision only) // ========================================================================= // // All live in the D0xx0000 unary block. Sub-op at bits 22:16 picks the // specific function. Mask 0xFFFF8080 covers opcode + sub-op + width bits. // // VSIN = 0xD0120000 // VCOS = 0xD0130000 // VEXP2 = 0xD0140000 // VLOG2 = 0xD0150000 // VASIN = 0xD0170000 (arcsine in turns; result/PI) // VNRCP = 0xD0180000 (negated reciprocal) // VNSIN = 0xD01A0000 (negated sine) // VREXP2 = 0xD01C0000 (reciprocal of EXP2) // VSGN = 0xD04A0000 (sign extraction; -1 / 0 / +1) .VSIN_S = { {.VSIN_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0120000, 0xFFFF8080, .VFPU_PSP, {}} }, .VCOS_S = { {.VCOS_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0130000, 0xFFFF8080, .VFPU_PSP, {}} }, .VEXP2_S = { {.VEXP2_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0140000, 0xFFFF8080, .VFPU_PSP, {}} }, .VLOG2_S = { {.VLOG2_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0150000, 0xFFFF8080, .VFPU_PSP, {}} }, .VASIN_S = { {.VASIN_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0170000, 0xFFFF8080, .VFPU_PSP, {}} }, .VNRCP_S = { {.VNRCP_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0180000, 0xFFFF8080, .VFPU_PSP, {}} }, .VNSIN_S = { {.VNSIN_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD01A0000, 0xFFFF8080, .VFPU_PSP, {}} }, .VREXP2_S = { {.VREXP2_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD01C0000, 0xFFFF8080, .VFPU_PSP, {}} }, .VSGN_S = { {.VSGN_S, {.VFPU_S,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD04A0000, 0xFFFF8080, .VFPU_PSP, {}} }, // ========================================================================= // §15 VFPU FP <-> int conversions (with 5-bit scale immediate) // ========================================================================= // // Format: // bits 31:21 = 11010010 0 RR (RR = round mode: 00=N, 01=Z, 10=U, 11=D) // bits 20:16 = 5-bit scale (signed magnitude of binary scale factor) // bit 15 = width-hi bits 14:8 = vs // bit 7 = width-lo bits 6:0 = vd // // VF2IN.* = 0xD2000000 base (round to nearest) // VF2IZ.* = 0xD2200000 base (round to zero) // VF2IU.* = 0xD2400000 base (round up) // VF2ID.* = 0xD2600000 base (round down) // VI2F.* = 0xD2800000 base (int->float with scale) .VF2IN_S = { {.VF2IN_S, {.VFPU_S,.VFPU_S,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2000000, 0xFFE08080, .VFPU_PSP, {}} }, .VF2IN_P = { {.VF2IN_P, {.VFPU_P,.VFPU_P,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2000080, 0xFFE08080, .VFPU_PSP, {}} }, .VF2IN_T = { {.VF2IN_T, {.VFPU_T,.VFPU_T,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2008000, 0xFFE08080, .VFPU_PSP, {}} }, .VF2IN_Q = { {.VF2IN_Q, {.VFPU_Q,.VFPU_Q,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2008080, 0xFFE08080, .VFPU_PSP, {}} }, .VF2IZ_S = { {.VF2IZ_S, {.VFPU_S,.VFPU_S,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2200000, 0xFFE08080, .VFPU_PSP, {}} }, .VF2IZ_P = { {.VF2IZ_P, {.VFPU_P,.VFPU_P,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2200080, 0xFFE08080, .VFPU_PSP, {}} }, .VF2IZ_T = { {.VF2IZ_T, {.VFPU_T,.VFPU_T,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2208000, 0xFFE08080, .VFPU_PSP, {}} }, .VF2IZ_Q = { {.VF2IZ_Q, {.VFPU_Q,.VFPU_Q,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2208080, 0xFFE08080, .VFPU_PSP, {}} }, .VF2IU_S = { {.VF2IU_S, {.VFPU_S,.VFPU_S,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2400000, 0xFFE08080, .VFPU_PSP, {}} }, .VF2IU_P = { {.VF2IU_P, {.VFPU_P,.VFPU_P,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2400080, 0xFFE08080, .VFPU_PSP, {}} }, .VF2IU_T = { {.VF2IU_T, {.VFPU_T,.VFPU_T,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2408000, 0xFFE08080, .VFPU_PSP, {}} }, .VF2IU_Q = { {.VF2IU_Q, {.VFPU_Q,.VFPU_Q,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2408080, 0xFFE08080, .VFPU_PSP, {}} }, .VF2ID_S = { {.VF2ID_S, {.VFPU_S,.VFPU_S,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2600000, 0xFFE08080, .VFPU_PSP, {}} }, .VF2ID_P = { {.VF2ID_P, {.VFPU_P,.VFPU_P,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2600080, 0xFFE08080, .VFPU_PSP, {}} }, .VF2ID_T = { {.VF2ID_T, {.VFPU_T,.VFPU_T,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2608000, 0xFFE08080, .VFPU_PSP, {}} }, .VF2ID_Q = { {.VF2ID_Q, {.VFPU_Q,.VFPU_Q,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2608080, 0xFFE08080, .VFPU_PSP, {}} }, .VI2F_S = { {.VI2F_S, {.VFPU_S,.VFPU_S,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2800000, 0xFFE08080, .VFPU_PSP, {}} }, .VI2F_P = { {.VI2F_P, {.VFPU_P,.VFPU_P,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2800080, 0xFFE08080, .VFPU_PSP, {}} }, .VI2F_T = { {.VI2F_T, {.VFPU_T,.VFPU_T,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2808000, 0xFFE08080, .VFPU_PSP, {}} }, .VI2F_Q = { {.VI2F_Q, {.VFPU_Q,.VFPU_Q,.IMM5,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_CONST,.NONE}, 0xD2808080, 0xFFE08080, .VFPU_PSP, {}} }, // VF2H pair -> two-half-packed-into-single (.P input -> .S output) .VF2H_P = { {.VF2H_P, {.VFPU_S,.VFPU_P,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0320080, 0xFFFF8080, .VFPU_PSP, {}} }, // VH2F single (2 packed halfs) -> pair of floats .VH2F_S = { {.VH2F_S, {.VFPU_P,.VFPU_S,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0330000, 0xFFFF8080, .VFPU_PSP, {}} }, // ========================================================================= // §16 VFPU reductions (vd[.s] = reduce(vs[.p/.t/.q])) // ========================================================================= // // VFAD = sum of all lanes base 0xD0460000 (D0 unary, sub-op 46) // VAVG = average of all lanes base 0xD0470000 (sub-op 47) // VHDP = homogeneous dot prod base 0x66000000 (VFPU1 / 3R-like, two srcs) .VFAD_P = { {.VFAD_P, {.VFPU_S,.VFPU_P,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0460080, 0xFFFF8080, .VFPU_PSP, {}} }, .VFAD_T = { {.VFAD_T, {.VFPU_S,.VFPU_T,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0468000, 0xFFFF8080, .VFPU_PSP, {}} }, .VFAD_Q = { {.VFAD_Q, {.VFPU_S,.VFPU_Q,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0468080, 0xFFFF8080, .VFPU_PSP, {}} }, .VAVG_P = { {.VAVG_P, {.VFPU_S,.VFPU_P,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0470080, 0xFFFF8080, .VFPU_PSP, {}} }, .VAVG_T = { {.VAVG_T, {.VFPU_S,.VFPU_T,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0478000, 0xFFFF8080, .VFPU_PSP, {}} }, .VAVG_Q = { {.VAVG_Q, {.VFPU_S,.VFPU_Q,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xD0478080, 0xFFFF8080, .VFPU_PSP, {}} }, .VHDP_P = { {.VHDP_P, {.VFPU_S,.VFPU_P,.VFPU_P,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x66000080, 0xFF808080, .VFPU_PSP, {}} }, .VHDP_T = { {.VHDP_T, {.VFPU_S,.VFPU_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x66008000, 0xFF808080, .VFPU_PSP, {}} }, .VHDP_Q = { {.VHDP_Q, {.VFPU_S,.VFPU_Q,.VFPU_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x66008080, 0xFF808080, .VFPU_PSP, {}} }, // ========================================================================= // §17 VFPU vector compare (writes VCC, not a register) // ========================================================================= // // VCMP cond, vs, vt = bits 31:24 = 0x6C // bit 23 = 0 // bits 22:16 = vt bit 15 = width-hi // bits 14:8 = vs bit 7 = width-lo // bits 6:4 = 000 bits 3:0 = cond (4-bit predicate) .VCMP_S = { {.VCMP_S, {.IMM5,.VFPU_S,.VFPU_S,.NONE}, {.VFPU_COND4,.VFPU_VS,.VFPU_VT,.NONE}, 0x6C000000, 0xFF8080F0, .VFPU_PSP, {}} }, .VCMP_P = { {.VCMP_P, {.IMM5,.VFPU_P,.VFPU_P,.NONE}, {.VFPU_COND4,.VFPU_VS,.VFPU_VT,.NONE}, 0x6C000080, 0xFF8080F0, .VFPU_PSP, {}} }, .VCMP_T = { {.VCMP_T, {.IMM5,.VFPU_T,.VFPU_T,.NONE}, {.VFPU_COND4,.VFPU_VS,.VFPU_VT,.NONE}, 0x6C008000, 0xFF8080F0, .VFPU_PSP, {}} }, .VCMP_Q = { {.VCMP_Q, {.IMM5,.VFPU_Q,.VFPU_Q,.NONE}, {.VFPU_COND4,.VFPU_VS,.VFPU_VT,.NONE}, 0x6C008080, 0xFF8080F0, .VFPU_PSP, {}} }, // ========================================================================= // §18 VFPU matrix-vector ops // ========================================================================= // // VMMUL md, ms, mt -- matrix multiply (vd = vs * vt) // VMMUL.P (2x2) = 0xF0000080 // VMMUL.T (3x3) = 0xF0008000 // VMMUL.Q (4x4) = 0xF0008080 // // VTFM[N] vd, ms, vt -- transform a vector by a matrix (vd = ms * vt) // VTFM2.P = 0xF0800080 // VTFM3.T = 0xF0808000 // VTFM4.Q = 0xF0808080 // // VHTFM[N] vd, ms, vt -- homogeneous transform (last comp implicit = 1) // VHTFM2.P = 0xF0800000 // VHTFM3.T = 0xF1008000 (different opcode-byte from VTFM3) // VHTFM4.Q = 0xF1008080 .VMMUL_P = { {.VMMUL_P, {.VFPU_M_P,.VFPU_M_P,.VFPU_M_P,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF0000080, 0xFF808080, .VFPU_PSP, {}} }, .VMMUL_T = { {.VMMUL_T, {.VFPU_M_T,.VFPU_M_T,.VFPU_M_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF0008000, 0xFF808080, .VFPU_PSP, {}} }, .VMMUL_Q = { {.VMMUL_Q, {.VFPU_M_Q,.VFPU_M_Q,.VFPU_M_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF0008080, 0xFF808080, .VFPU_PSP, {}} }, .VTFM2_P = { {.VTFM2_P, {.VFPU_P,.VFPU_M_P,.VFPU_P,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF0800080, 0xFF808080, .VFPU_PSP, {}} }, .VTFM3_T = { {.VTFM3_T, {.VFPU_T,.VFPU_M_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF0808000, 0xFF808080, .VFPU_PSP, {}} }, .VTFM4_Q = { {.VTFM4_Q, {.VFPU_Q,.VFPU_M_Q,.VFPU_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF0808080, 0xFF808080, .VFPU_PSP, {}} }, .VHTFM2_P = { {.VHTFM2_P, {.VFPU_P,.VFPU_M_P,.VFPU_P,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF0800000, 0xFF808080, .VFPU_PSP, {}} }, .VHTFM3_T = { {.VHTFM3_T, {.VFPU_T,.VFPU_M_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF1008000, 0xFF808080, .VFPU_PSP, {}} }, .VHTFM4_Q = { {.VHTFM4_Q, {.VFPU_Q,.VFPU_M_Q,.VFPU_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF1008080, 0xFF808080, .VFPU_PSP, {}} }, // VMSCL md, ms, vt[.s] -- scalar-times-matrix // VMSCL.P = 0xF2000080 / .T = 0xF2008000 / .Q = 0xF2008080 .VMSCL_P = { {.VMSCL_P, {.VFPU_M_P,.VFPU_M_P,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF2000080, 0xFF808080, .VFPU_PSP, {}} }, .VMSCL_T = { {.VMSCL_T, {.VFPU_M_T,.VFPU_M_T,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF2008000, 0xFF808080, .VFPU_PSP, {}} }, .VMSCL_Q = { {.VMSCL_Q, {.VFPU_M_Q,.VFPU_M_Q,.VFPU_S,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF2008080, 0xFF808080, .VFPU_PSP, {}} }, // ========================================================================= // §19 VFPU matrix-unary (matrix-move family) // ========================================================================= // // Same unary layout as VMOV/VABS/VNEG but in the F3xx region; sub-op // at bits 22:16 picks the matrix function: // VMMOV = 0xF3800000 (matrix copy md = ms) // VMIDT = 0xF3830000 (identity matrix) // VMZERO = 0xF3860000 (zero matrix) // VMONE = 0xF3870000 (all-ones matrix) // // VMIDT/VMZERO/VMONE take only a destination (no vs). .VMMOV_P = { {.VMMOV_P, {.VFPU_M_P,.VFPU_M_P,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xF3800080, 0xFFFF8080, .VFPU_PSP, {}} }, .VMMOV_T = { {.VMMOV_T, {.VFPU_M_T,.VFPU_M_T,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xF3808000, 0xFFFF8080, .VFPU_PSP, {}} }, .VMMOV_Q = { {.VMMOV_Q, {.VFPU_M_Q,.VFPU_M_Q,.NONE,.NONE}, {.VFPU_VD,.VFPU_VS,.NONE,.NONE}, 0xF3808080, 0xFFFF8080, .VFPU_PSP, {}} }, .VMIDT_P = { {.VMIDT_P, {.VFPU_M_P,.NONE,.NONE,.NONE}, {.VFPU_VD,.NONE,.NONE,.NONE}, 0xF3830080, 0xFFFFFF80, .VFPU_PSP, {}} }, .VMIDT_T = { {.VMIDT_T, {.VFPU_M_T,.NONE,.NONE,.NONE}, {.VFPU_VD,.NONE,.NONE,.NONE}, 0xF3838000, 0xFFFFFF80, .VFPU_PSP, {}} }, .VMIDT_Q = { {.VMIDT_Q, {.VFPU_M_Q,.NONE,.NONE,.NONE}, {.VFPU_VD,.NONE,.NONE,.NONE}, 0xF3838080, 0xFFFFFF80, .VFPU_PSP, {}} }, .VMZERO_P = { {.VMZERO_P, {.VFPU_M_P,.NONE,.NONE,.NONE}, {.VFPU_VD,.NONE,.NONE,.NONE}, 0xF3860080, 0xFFFFFF80, .VFPU_PSP, {}} }, .VMZERO_T = { {.VMZERO_T, {.VFPU_M_T,.NONE,.NONE,.NONE}, {.VFPU_VD,.NONE,.NONE,.NONE}, 0xF3868000, 0xFFFFFF80, .VFPU_PSP, {}} }, .VMZERO_Q = { {.VMZERO_Q, {.VFPU_M_Q,.NONE,.NONE,.NONE}, {.VFPU_VD,.NONE,.NONE,.NONE}, 0xF3868080, 0xFFFFFF80, .VFPU_PSP, {}} }, .VMONE_P = { {.VMONE_P, {.VFPU_M_P,.NONE,.NONE,.NONE}, {.VFPU_VD,.NONE,.NONE,.NONE}, 0xF3870080, 0xFFFFFF80, .VFPU_PSP, {}} }, .VMONE_T = { {.VMONE_T, {.VFPU_M_T,.NONE,.NONE,.NONE}, {.VFPU_VD,.NONE,.NONE,.NONE}, 0xF3878000, 0xFFFFFF80, .VFPU_PSP, {}} }, .VMONE_Q = { {.VMONE_Q, {.VFPU_M_Q,.NONE,.NONE,.NONE}, {.VFPU_VD,.NONE,.NONE,.NONE}, 0xF3878080, 0xFFFFFF80, .VFPU_PSP, {}} }, // ========================================================================= // §20 VFPU cross product / quaternion // ========================================================================= // // VCRS.T vd, vs, vt cross product (triple only) = 0x66808000 // VCRSP.T vd, vs, vt cross product (alt formula) = 0xF2818000 // VQMUL.Q vd, vs, vt quaternion multiply (quad only) = 0xF2808080 .VCRS_T = { {.VCRS_T, {.VFPU_T,.VFPU_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0x66808000, 0xFF808080, .VFPU_PSP, {}} }, .VCRSP_T = { {.VCRSP_T, {.VFPU_T,.VFPU_T,.VFPU_T,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF2818000, 0xFF818080, .VFPU_PSP, {}} }, .VQMUL_Q = { {.VQMUL_Q, {.VFPU_Q,.VFPU_Q,.VFPU_Q,.NONE}, {.VFPU_VD,.VFPU_VS,.VFPU_VT,.NONE}, 0xF2808080, 0xFF808080, .VFPU_PSP, {}} }, // ========================================================================= // §21 VFPU control-register transfer (FCR0-style) // ========================================================================= // // MFVC rt, vfpu_ctrl[5:0] COP2 sub-op 6 = 0x48C00000 + (rt<<16) + ctrl // MTVC rt, vfpu_ctrl[5:0] COP2 sub-op 7 = 0x48E00000 (wait -- MTV uses 7) // Actually MFVC = 0x4840xxxx / MTVC = 0x48C0xxxx in some refs; the exact // sub-op selectors are 0x02 / 0x06 below the MFV/MTV pair. We emit: // MFVC = 0x48400000, MTVC = 0x48C00000 with the same operand shape. .MFVC = { {.MFVC, {.GPR, .IMM5, .NONE, .NONE}, {.RT, .VFPU_CONST, .NONE, .NONE}, 0x48400000, 0xFFE00000, .VFPU_PSP, {}} }, .MTVC = { {.MTVC, {.GPR, .IMM5, .NONE, .NONE}, {.RT, .VFPU_CONST, .NONE, .NONE}, 0x48C00000, 0xFFE00000, .VFPU_PSP, {}} }, // ========================================================================= // §22 VFPU branches (test VCC bits) // ========================================================================= // // BVF cc, label -- branch if VCC[cc] = false // BVT cc, label -- branch if VCC[cc] = true // BVFL cc, label -- BVF with branch-likely semantics // BVTL cc, label -- BVT with branch-likely semantics // // Layout: COP2 BC2 sub-form // bits 31:26 = 010010 (COP2) bits 25:21 = 01000 (BC2) // bits 20:18 = cc selector (3 bits, picks vcc[cc]) // bit 17 = likely flag (0 = standard, 1 = likely) // bit 16 = condition (0 = false / BVF, 1 = true / BVT) // bits 15:0 = signed 16-bit PC-rel offset (in instruction-words; <<2) // // Mask covers primary+BC2+bits 17:16; cc and offset are operand-driven. .BVF = { {.BVF, {.IMM5, .REL16, .NONE, .NONE}, {.VFPU_CC3, .BRANCH_16, .NONE, .NONE}, 0x49000000, 0xFFE30000, .VFPU_PSP, {delay_slot=true}} }, .BVT = { {.BVT, {.IMM5, .REL16, .NONE, .NONE}, {.VFPU_CC3, .BRANCH_16, .NONE, .NONE}, 0x49010000, 0xFFE30000, .VFPU_PSP, {delay_slot=true}} }, .BVFL = { {.BVFL, {.IMM5, .REL16, .NONE, .NONE}, {.VFPU_CC3, .BRANCH_16, .NONE, .NONE}, 0x49020000, 0xFFE30000, .VFPU_PSP, {delay_slot=true, likely=true}} }, .BVTL = { {.BVTL, {.IMM5, .REL16, .NONE, .NONE}, {.VFPU_CC3, .BRANCH_16, .NONE, .NONE}, 0x49030000, 0xFFE30000, .VFPU_PSP, {delay_slot=true, likely=true}} }, // ========================================================================= // §23 VFPU unaligned quad load/store (LVL.Q / LVR.Q / SVL.Q / SVR.Q) // ========================================================================= // // Same SP-style memory operand layout as LV/SV, but with explicit // "left" / "right" semantics for misaligned 16-byte loads/stores // (similar to MIPS LWL/LWR). // // LVL.Q: primary 0x35 + bit 1 = 1 (left) = 0xD4000002 // LVR.Q: primary 0x35 + bit 1 = 0 (right) = 0xD4000000 // SVL.Q: primary 0x3D + bit 1 = 1 = 0xF4000002 // SVR.Q: primary 0x3D + bit 1 = 0 = 0xF4000000 // // The low bit of the offset field doubles as the L/R selector (offset // must be 4-byte aligned), so the user encodes alignment + L/R via the // memory disp's low bits. Mask covers only the primary opcode. .LVL_Q = { {.LVL_Q, {.VFPU_Q, .MEM, .NONE, .NONE}, {.VFPU_VT_MEM, .VFPU_OFFSET_BASE, .NONE, .NONE}, 0xD4000002, 0xFC000002, .VFPU_PSP, {}} }, .LVR_Q = { {.LVR_Q, {.VFPU_Q, .MEM, .NONE, .NONE}, {.VFPU_VT_MEM, .VFPU_OFFSET_BASE, .NONE, .NONE}, 0xD4000000, 0xFC000002, .VFPU_PSP, {}} }, .SVL_Q = { {.SVL_Q, {.VFPU_Q, .MEM, .NONE, .NONE}, {.VFPU_VT_MEM, .VFPU_OFFSET_BASE, .NONE, .NONE}, 0xF4000002, 0xFC000002, .VFPU_PSP, {}} }, .SVR_Q = { {.SVR_Q, {.VFPU_Q, .MEM, .NONE, .NONE}, {.VFPU_VT_MEM, .VFPU_OFFSET_BASE, .NONE, .NONE}, 0xF4000000, 0xFC000002, .VFPU_PSP, {}} }, // ========================================================================= // §24 VFPU integer/float immediate load // ========================================================================= // // VIIM.S vd, #imm16 load 16-bit signed integer immediate into vd (scalar) // VFIM.S vd, #imm16 load 16-bit half-precision float into vd // // Both share the same skeleton: imm16 at bits 15:0 (the low 16 bits of // the instruction word), with vd in the IMM5-like bit 25:21 slot. The // VIIM vs VFIM distinction is in bit 23. // VIIM = 0xDF000000 base (bit 23 = 0) // VFIM = 0xDF800000 base (bit 23 = 1) // // Mask covers bits 31:24 only; vd lives at 25:21, imm at 15:0. .VIIM_S = { {.VIIM_S, {.VFPU_S, .IMM16S, .NONE, .NONE}, {.RT, .IMM_16, .NONE, .NONE}, 0xDF000000, 0xFF800000, .VFPU_PSP, {}} }, .VFIM_S = { {.VFIM_S, {.VFPU_S, .IMM16S, .NONE, .NONE}, {.RT, .IMM_16, .NONE, .NONE}, 0xDF800000, 0xFF800000, .VFPU_PSP, {}} }, }