private static string decodeMoveControlToFromCoprocessorOperation(string opcode, uint operation)
        {
            GP_REGISTER rt = (GP_REGISTER)((operation >> 16) & 0x1F);
            byte        rd = (byte)((operation >> 11) & 0x1F);

            return(opcode + " " + getGRPRegName(rt) + ", $v" + rd);
        }
        private static string decodeBranchOperation(string opcode, uint operation, uint address)
        {
            GP_REGISTER src            = (GP_REGISTER)((operation >> 21) & 0x1F);
            short       imm            = (short)((operation & 0xFFFF) << 2);
            uint        current_offset = (uint)((address + 4) + imm);

            return(opcode + " " + getGRPRegName(src) + ", 0x" + (current_offset).ToString("X8"));
        }
        private static string decodeSpecialShiftOperation(string opcode, uint operation)
        {
            GP_REGISTER dest = (GP_REGISTER)((operation >> 11) & 0x1F);
            GP_REGISTER src  = (GP_REGISTER)((operation >> 16) & 0x1F);

            int imm = (int)((operation >> 6) & 0x1F);

            return(opcode + " " + getGRPRegName(dest) + ", " + getGRPRegName(src) + ", " + imm);
        }
        private static string decodeBranchEqualsOperation(string opcode, uint operation, uint address)
        {
            GP_REGISTER src1 = (GP_REGISTER)((operation >> 21) & 0x1F);
            GP_REGISTER src2 = (GP_REGISTER)((operation >> 16) & 0x1F);
            short       imm  = (short)((operation & 0xFFFF) << 2);
            //Console.WriteLine("("+address.ToString("X8")+")immediate = " + imm);
            uint current_offset = (uint)((address + 4) + imm);

            return(opcode + " " + getGRPRegName(src1) + ", " + getGRPRegName(src2) + ", 0x" + current_offset.ToString("X8"));
        }
 private static string getGRPRegName(GP_REGISTER reg)
 {
     if (usingRegNames)
     {
         return(reg.ToString());
     }
     else
     {
         return("r" + ((byte)reg).ToString());
     }
 }
        private static string decodeThreeRegisterOperation(string opcode, uint operation, bool swapRT_RS)
        {
            GP_REGISTER dest = (GP_REGISTER)((operation >> 11) & 0x1F);
            GP_REGISTER src1 = (GP_REGISTER)((operation >> 21) & 0x1F);
            GP_REGISTER src2 = (GP_REGISTER)((operation >> 16) & 0x1F);

            if (!swapRT_RS)
            {
                return(opcode + " " + getGRPRegName(dest) + ", " + getGRPRegName(src1) + ", " + getGRPRegName(src2));
            }
            else
            {
                return(opcode + " " + getGRPRegName(dest) + ", " + getGRPRegName(src2) + ", " + getGRPRegName(src1));
            }
        }
        private static string decodeTwoRegistersWithImmediateOperation(string opcode, uint operation)
        {
            GP_REGISTER dest = (GP_REGISTER)((operation >> 16) & 0x1F);
            GP_REGISTER src  = (GP_REGISTER)((operation >> 21) & 0x1F);

            short imm = (short)(operation & 0xFFFF);

            if (imm < 0)
            {
                return(opcode + " " + getGRPRegName(dest) + ", " + getGRPRegName(src) + ", -0x" + (-imm).ToString("X4"));
            }
            else
            {
                return(opcode + " " + getGRPRegName(dest) + ", " + getGRPRegName(src) + ", 0x" + imm.ToString("X4"));
            }
        }
        private static string decodeNormalMIPSLoadStore(string opcode, uint operation)
        {
            GP_REGISTER dest  = (GP_REGISTER)((operation >> 16) & 0x1F);
            GP_REGISTER base_ = (GP_REGISTER)((operation >> 21) & 0x1F);

            short imm = (short)(operation & 0xFFFF);

            if (imm < 0)
            {
                opcode += " " + getGRPRegName(dest) + ", -0x" + (-imm).ToString("X4") + "(" + getGRPRegName(base_) + ")";
            }
            else
            {
                opcode += " " + getGRPRegName(dest) + ", 0x" + imm.ToString("X4") + "(" + getGRPRegName(base_) + ")";
            }
            return(opcode);
        }
        private static string decodeCOP0Operation(uint operation)
        {
            string       str = "Unimplemented (COP0 operation)";
            byte         mt  = (byte)((operation >> 21) & 0x1F);
            GP_REGISTER  rt  = (GP_REGISTER)((operation >> 16) & 0x1F);
            CP0_REGISTER rd  = (CP0_REGISTER)((operation >> 11) & 0x1F);

            switch (mt)
            {
            case 0x00:     // MFC0
                str = "mfc0 " + getGRPRegName(rt) + ", " + getCP0RegName(rd);
                break;

            case 0x04:     // MTC0
                str = "mtc0 " + getGRPRegName(rt) + ", " + getCP0RegName(rd);
                break;
            }

            return(str);
        }
        public static string decodeOPERATION(uint operation, uint address, OPTIONS options)
        {
            if (operation == 0x00000000)
            {
                return("nop");
            }

            usingRegNames       = options.HasFlag(OPTIONS.USE_GP_NAMES);
            usingLongForm       = options.HasFlag(OPTIONS.USE_LONG_FORM);
            usingArmipsCP0Names = options.HasFlag(OPTIONS.USE_ARMIPS_CP0_NAMES);

            RSP_OPCODE opcode = (RSP_OPCODE)((operation >> 26) & 0x3F);
            string     str    = "Unimplemented (opcode: " + Convert.ToString((int)opcode, 2) + "b)";

            switch (opcode)
            {
            case RSP_OPCODE.J:
            case RSP_OPCODE.JAL:
                str = opcode.ToString().ToLower() + " 0x0" + ((operation & 0x03FFFFFF) << 2).ToString("X7");
                break;

            case RSP_OPCODE.BEQ:
            case RSP_OPCODE.BNE:
                str = decodeBranchEqualsOperation(opcode.ToString().ToLower(), operation, address);
                break;

            case RSP_OPCODE.BLEZ:
            case RSP_OPCODE.BGTZ:
                str = decodeBranchOperation(opcode.ToString().ToLower(), operation, address);
                break;

            case RSP_OPCODE.ADDI:
            case RSP_OPCODE.ADDIU:
            case RSP_OPCODE.SLTI:
            case RSP_OPCODE.SLTIU:
            case RSP_OPCODE.ANDI:
            case RSP_OPCODE.ORI:
            case RSP_OPCODE.XORI:
                str = decodeTwoRegistersWithImmediateOperation(opcode.ToString().ToLower(), operation);
                break;

            case RSP_OPCODE.LUI:
                str = decodeOneRegisterWithImmediateOperation(opcode.ToString().ToLower(), operation);
                break;

            case RSP_OPCODE.COP0:
                str = decodeCOP0Operation(operation);
                break;

            case RSP_OPCODE.COP2:
            {
                //str = "Vector operation!";
                str = decodeCOP2Operation(operation);
            }
            break;

            case RSP_OPCODE.LB:
            case RSP_OPCODE.LH:
            case RSP_OPCODE.LW:
            case RSP_OPCODE.LBU:
            case RSP_OPCODE.LHU:
            case RSP_OPCODE.LWU:
            case RSP_OPCODE.SB:
            case RSP_OPCODE.SH:
            case RSP_OPCODE.SW:
                str = decodeNormalMIPSLoadStore(opcode.ToString().ToLower(), operation);
                break;

            case RSP_OPCODE.LWC2:
            {
                str = decodeLoadStoreOperation(operation, "l");
            }
            break;

            case RSP_OPCODE.SWC2:
            {
                str = decodeLoadStoreOperation(operation, "s");
            }
            break;

            case RSP_OPCODE.REGIMM:
            {
                byte subop = (byte)((operation >> 16) & 0x1F);
                switch (subop)
                {
                case 0x00:             // BLTZ operation
                    str = decodeBranchOperation("bltz", operation, address);
                    break;

                case 0x01:             // BGEZ operation
                    str = decodeBranchOperation("bgez", operation, address);
                    break;

                case 0x10:             // BLTZAL operation
                    str = decodeBranchOperation("bltzal", operation, address);
                    break;

                case 0x11:             // BGEZAL operation
                    str = decodeBranchOperation("bgezal", operation, address);
                    break;
                }
            }
            break;

            case RSP_OPCODE.SPECIAL:
            {
                byte subop = (byte)(operation & 0x3F);
                switch (subop)
                {
                case 0x00:             // SLL operation
                    str = decodeSpecialShiftOperation("sll", operation);
                    break;

                case 0x02:             // SRL operation
                    str = decodeSpecialShiftOperation("srl", operation);
                    break;

                case 0x03:             // SRA operation
                    str = decodeSpecialShiftOperation("sra", operation);
                    break;

                case 0x04:             // SLLV operation
                    str = decodeThreeRegisterOperation("sllv", operation, true);
                    break;

                case 0x06:             // SRLV operation
                    str = decodeThreeRegisterOperation("srlv", operation, true);
                    break;

                case 0x07:             // SRAV operation
                    str = decodeThreeRegisterOperation("srav", operation, true);
                    break;

                case 0x08:             // JR operation
                    str = "jr " + getGRPRegName(((GP_REGISTER)((operation >> 21) & 0x1F)));
                    break;

                case 0x09:             // JALR operation
                {
                    GP_REGISTER return_reg = (GP_REGISTER)((operation >> 11) & 0x1F);
                    if (return_reg == GP_REGISTER.ra)
                    {
                        str = "jalr " + getGRPRegName(((GP_REGISTER)((operation >> 21) & 0x1F)));
                    }
                    else
                    {
                        str = "jalr " + getGRPRegName(return_reg) + ", " + getGRPRegName(((GP_REGISTER)((operation >> 21) & 0x1F)));
                    }
                }
                break;

                case 0x0D:             // BREAK operation
                    str = "break " + ((operation >> 6) & 0xFFFFF);
                    break;

                case 0x20:             // ADD operation
                    str = decodeThreeRegisterOperation("add", operation, false);
                    break;

                case 0x21:             // ADDU operation
                    str = decodeThreeRegisterOperation("addu", operation, false);
                    break;

                case 0x22:             // SUB operation
                    str = decodeThreeRegisterOperation("sub", operation, false);
                    break;

                case 0x23:             // SUBU operation
                    str = decodeThreeRegisterOperation("subu", operation, false);
                    break;

                case 0x24:             // AND operation
                    str = decodeThreeRegisterOperation("and", operation, false);
                    break;

                case 0x25:             // OR operation
                    str = decodeThreeRegisterOperation("or", operation, false);
                    break;

                case 0x26:             // XOR operation
                    str = decodeThreeRegisterOperation("xor", operation, false);
                    break;

                case 0x27:             // NOR operation
                    str = decodeThreeRegisterOperation("nor", operation, false);
                    break;

                case 0x2A:             // SLT operation
                    str = decodeThreeRegisterOperation("slt", operation, false);
                    break;

                case 0x2B:             // SLTU operation
                    str = decodeThreeRegisterOperation("sltu", operation, false);
                    break;

                default:
                    str = "Unimplemented (special: " + Convert.ToString(subop, 2) + "b)";
                    break;
                }
            }
            break;
            }

            return(str);
        }
        private static string decodeOneRegisterWithImmediateOperation(string opcode, uint operation)
        {
            GP_REGISTER dest = (GP_REGISTER)((operation >> 16) & 0x1F);

            return(opcode + " " + getGRPRegName(dest) + ", 0x" + (operation & 0xFFFF).ToString("X4"));
        }