export function JAL_ENCODE ( data ) { return 0x0C000000 | ( ( data >> 2 ) & 0x3FFFFFF ) ; } export function J_ENCODE ( data ) { return 0x08000000 | ( ( data >> 2 ) & 0x3FFFFFF ) ; } export function JAL_DECODE ( data ) { return ( ( data . readUInt32BE ( 0 ) & 0x3FFFFFF ) << 2 ) ; } export function LUIORI_ENCODE ( data , immediate ) { let instruction_base = data . readUInt16BE ( 0 ) ; data . writeUInt16BE ( immediate , 2 ) ; return data . readUInt32BE ( 0 ) ; } export function LUIORI_DECODE ( data ) { return data . readUInt16BE ( 2 ) ; } export enum OPCODE_DEFAULT { SPEC , BCOND , J , JAL , BEQ , BNE , BLEZ , BGTZ , ADDI , ADDIU , SLTI , SLTIU , ANDI , ORI , XORI , LUI , COP0 , COP1 , COP2 , COP3 , BEQL , BNEL , BLEZL , BGTZL , DADDI , DADDIU , LDL , LDR , OP34 , OP35 , OP36 , OP37 , LB , LH , LWL , LW , LBU , LHU , LWR , LWU , SB , SH , SWL , SW , SDL , SDR , SWR , CACHE , LL , LWC1 , LWC2 , LWC3 , LLD , LDC1 , LDC2 , LD , SC , SWC1 , SWC2 , SWC3 , SCD , SDC1 , SDC2 , SD , COUNT } ; export enum OPCODE_SPECIAL0 { SLL , SPEC01 , SRL , SRA , SLLV , SPEC05 , SRLV , SRAV , JR , JALR , SPEC12 , SPEC13 , SYSCALL , BREAK , SPEC16 , SYNC , MFHI , MTHI , MFLO , MTLO , DSLLV , SPEC25 , DSRLV , DSRAV , MULT , MULTU , DIV , DIVU , DMULT , DMULTU , DDIV , DDIVU , ADD , ADDU , SUB , SUBU , AND , OR , XOR , NOR , SPEC50 , SPEC51 , SLT , SLTU , DADD , DADDU , DSUB , DSUBU , TGE , TGEU , TLT , TLTU , TEQ , SPEC65 , TNE , SPEC67 , DSLL , SPEC71 , DSRL , DSRA , DSLL32 , SPEC75 , DSRL32 , DSRA32 , COUNT } ; export enum OPCODE_SPECIAL1 { MAD , MADU , MUL , SPEC3 , COUNT } export enum OPCODE_COND { BLTZ , BGEZ , BLTZL , BGEZL , UNKNOWN0 , UNKNOWN1 , UNKNOWN2 , UNKNOWN3 , TGEI , TGEIU , TLTI , TLTIU , TEQI , UNKNOWN4 , TNEI , UNKNOWN5 , BLTZAL , BGEZAL , BLTZALL , BGEZALL , UNKNOWN6 , UNKNOWN7 , UNKNOWN8 , UNKNOWN9 , UNKNOWN10 , UNKNOWN11 , UNKNOWN12 , UNKNOWN13 , UNKNOWN14 , UNKNOWN15 , UNKNOWN16 , UNKNOWN17 , COUNT } ; export enum OPCODETYPE { NONE , IMMEDIATE , JUMP , REGISTER , FR , COUNT } export enum OPCODEINDEXTYPE { NONE , DEFAULT , SPECIAL0 , SPECIAL1 , COND , COUNT } export enum REGISTER { R0 , AT , V0 , V1 , A0 , A1 , A2 , A3 , T0 , T1 , T2 , T3 , T4 , T5 , T6 , T7 , S0 , S1 , S2 , S3 , S4 , S5 , S6 , S7 , T8 , T9 , K0 , K1 , GP , SP , S8 , RA , COUNT } export class Instruction { type : OPCODEINDEXTYPE = OPCODEINDEXTYPE . NONE ; indx : number | OPCODE_DEFAULT | OPCODE_SPECIAL0 | OPCODE_SPECIAL1 | OPCODE_COND = 0 ; data : Buffer = Buffer . alloc ( 4 ) ; uint : number = 0 ; code : string = "NOP" ; } export function DecodeOpcode ( inst ) { let instruction_index = 0 ; let instruction = new Instruction ( ) ; instruction . data = inst ; instruction . uint = inst . readUInt32BE ( 0 ) ; instruction . type = OPCODEINDEXTYPE . DEFAULT ; if ( instruction . uint === 0 ) { instruction . code = "NOP" ; return instruction ; } instruction_index = instruction . uint >> 26 ; if ( instruction_index < OPCODE_DEFAULT . COUNT ) instruction . code = OPCODE_DEFAULT [ instruction_index ] ; else instruction . code = "UNKNOWN" ; if ( instruction_index === OPCODE_DEFAULT . SPEC ) { instruction_index = instruction . uint & 0b111111 ; instruction . type = OPCODEINDEXTYPE . SPECIAL0 ; instruction . code = OPCODE_SPECIAL0 [ instruction_index ] ; } else if ( instruction_index === OPCODE_DEFAULT . COUNT ) { instruction_index = instruction . uint & 0b111111 ; instruction . type = OPCODEINDEXTYPE . SPECIAL1 ; instruction . code = OPCODE_SPECIAL1 [ instruction_index ] ; } else if ( instruction_index === OPCODE_DEFAULT . BCOND ) { instruction_index = instruction . uint & 0b111111 ; instruction . type = OPCODEINDEXTYPE . COND ; instruction . code = OPCODE_COND [ instruction_index ] ; } instruction . indx = instruction_index ; return instruction ; } export function EncodeOffset ( inst , offset ) { return DecodeOpcode ( inst . data ) ; } export function DecodeOffset ( inst ) { return ( inst . uint & 0x0000FFFF ) << 2 ; } export function EncodeShift ( inst , shift ) { return DecodeOpcode ( inst . data ) ; } export function DecodeShift ( inst ) { return ( inst . uint >> 6 ) & 0x1F ; } export function EncodeRegisterDestination ( inst , register ) { return DecodeOpcode ( inst . data ) ; } export function DecodeRegisterDestination ( inst ) { return ( ( inst . uint >> 11 ) & 0x1F ) as REGISTER ; } export function EncodeRegisterTarget ( inst , target ) { return DecodeOpcode ( inst . data ) ; } export function DecodeRegisterTarget ( inst ) { return ( inst . uint >> 16 ) & 0x1F ; } export function EncodeRegisterSource ( inst , source ) { return DecodeOpcode ( inst . data ) ; } export function DecodeRegisterSource ( inst ) { return ( inst . uint >> 21 ) & 0x1F ; } export function EncodeImmediate ( inst , immediate ) { inst . data . writeUInt16BE ( immediate & 0x0000FFFF , 2 ) ; return DecodeOpcode ( inst . data ) ; } export function DecodeImmediate ( inst ) { return inst . data . readUInt16BE ( 2 ) ; } export function EncodeJumpTarget ( inst , target ) { inst . data . writeUInt32BE ( 0x0C000000 | ( ( target >> 2 ) & 0x3FFFFFF ) , 0 ) ; return DecodeOpcode ( inst . data ) ; } export function DecodeJumpTarget ( inst ) { return ( ( inst . uint & 0x3FFFFFF ) << 2 ) ; } export function EncodeInstruction ( data ) { let encoded = 0 ; let index = 0 ; let buf = Buffer . alloc ( 4 ) ; for ( index = 0 ; index < data . length ; index ++ ) { encoded |= data [ index ] ; } buf . writeUInt32BE ( encoded , 0 ) ; return DecodeOpcode ( buf ) ; } export function GetOpcodeName ( inst ) { if ( inst . type === OPCODEINDEXTYPE . DEFAULT ) return OPCODE_DEFAULT [ inst . indx ] ; else if ( inst . type === OPCODEINDEXTYPE . SPECIAL0 ) return OPCODE_SPECIAL0 [ inst . indx ] ; else if ( inst . type === OPCODEINDEXTYPE . SPECIAL1 ) return OPCODE_SPECIAL1 [ inst . indx ] ; else return OPCODE_COND [ inst . indx ] ; }