/// <summary>
        /// 引数で渡された32bit長の命令をデコードし、cpuで実行する
        /// </summary>
        /// <param name="instruction">32bit長の命令</param>
        /// <param name="cpu">命令を実行するRV32CPU</param>
        /// <returns>実行の成否</returns>
        internal protected override bool Exec(UInt32[] ins)
        {
            bool result = false;

            // 命令の0~1bit目が "11" でない場合は対象なし
            if ((ins[0] & 0b11U) != 0b11U)
            {
                return(result);
            }

            FPRegister rd                = (FPRegister)ins[1],
                       rs1               = (FPRegister)ins[3],
                       rs2               = (FPRegister)ins[4],
                       rs3               = (FPRegister)((ins[5] >> 2) | (ins[6] << 4));
            Opcode             opcode    = (Opcode)ins[0];
            Funct3             funct3    = (Funct3)ins[2];
            Funct5             funct5    = (Funct5)(ins[5] >> 2 | (ins[6] << 4));
            FloatRoundingMode  frm       = (FloatRoundingMode)ins[2];
            Int32              immediate = 0;
            RV32_DoubleFpu     fpu;
            RV32_FloatPointLsu lsu;

            switch (opcode)
            {
            case Opcode.fl when funct3 == Funct3.fld_fsd:     // fld命令
                immediate = GetImmediate('I', ins);
                lsu       = (RV32_FloatPointLsu)Decoder.Lsu(typeof(RV32_FloatPointLsu));
                result    = lsu.Fld(rd, (Register)rs1, immediate);
                break;

            case Opcode.fs when funct3 == Funct3.fld_fsd:     // fsd命令
                immediate = GetImmediate('S', ins);
                lsu       = (RV32_FloatPointLsu)Decoder.Lsu(typeof(RV32_FloatPointLsu));
                result    = lsu.Fsd((Register)rs1, rs2, immediate);
                break;

            case Opcode.fmadd when(ins[5]& 0x3U) == 0x1U:       // fmaddd命令
                fpu = (RV32_DoubleFpu)Decoder.Alu(typeof(RV32_DoubleFpu));

                result = fpu.FmaddD(rd, rs1, rs2, rs3, frm);
                break;

            case Opcode.fmsub when(ins[5]& 0x3U) == 0x1U:       // fmsubd命令
                fpu = (RV32_DoubleFpu)Decoder.Alu(typeof(RV32_DoubleFpu));

                result = fpu.FmsubD(rd, rs1, rs2, rs3, frm);
                break;

            case Opcode.fnmadd when(ins[5]& 0x3U) == 0x1U:       // fnmaddd命令
                fpu = (RV32_DoubleFpu)Decoder.Alu(typeof(RV32_DoubleFpu));

                result = fpu.FnmaddD(rd, rs1, rs2, rs3, frm);
                break;

            case Opcode.fnmsub when(ins[5]& 0x3U) == 0x1U:       // fnmsubd命令
                fpu = (RV32_DoubleFpu)Decoder.Alu(typeof(RV32_DoubleFpu));

                result = fpu.FnmsubD(rd, rs1, rs2, rs3, frm);
                break;

            case Opcode.fmiscOp when(ins[5]& 0x3U) == 0x1U:       // Double Float-Point Op系命令(算術論理演算)
                fpu = (RV32_DoubleFpu)Decoder.Alu(typeof(RV32_DoubleFpu));

                switch (funct5)
                {
                case Funct5.fadd:         // faddd命令
                    result = fpu.FaddD(rd, rs1, rs2, frm);
                    break;

                case Funct5.fsub:         // fsubd命令
                    result = fpu.FsubD(rd, rs1, rs2, frm);
                    break;

                case Funct5.fmul:         // fmuld命令
                    result = fpu.FmulD(rd, rs1, rs2, frm);
                    break;

                case Funct5.fdiv:         // fdivd命令
                    result = fpu.FdivD(rd, rs1, rs2, frm);
                    break;

                case Funct5.fsqrt:         // fsqrtd命令
                    result = fpu.FsqrtD(rd, rs1, frm);
                    break;

                case Funct5.fsgnj:
                    switch (funct3)
                    {
                    case Funct3.fsgnj:             // fsgnjd命令
                        result = fpu.FsgnjD(rd, rs1, rs2);
                        break;

                    case Funct3.fsgnjn:             // fsgnjnd命令
                        result = fpu.FsgnjnD(rd, rs1, rs2);
                        break;

                    case Funct3.fsgnjx:             // fsgnjxd命令
                        result = fpu.FsgnjxD(rd, rs1, rs2);
                        break;
                    }
                    break;

                case Funct5.fmin_fmax:
                    switch (funct3)
                    {
                    case Funct3.fmin:             // fmind命令
                        result = fpu.FminD(rd, rs1, rs2);
                        break;

                    case Funct3.fmax:             // fmaxd命令
                        result = fpu.FmaxD(rd, rs1, rs2);
                        break;
                    }
                    break;

                case Funct5.fcompare:
                    switch (funct3)
                    {
                    case Funct3.fcompare_eq:             // feqd命令
                        result = fpu.FeqD((Register)rd, rs1, rs2);
                        break;

                    case Funct3.fcompare_lt:             // fltd命令
                        result = fpu.FltD((Register)rd, rs1, rs2);
                        break;

                    case Funct3.fcompare_le:             // fled命令
                        result = fpu.FleD((Register)rd, rs1, rs2);
                        break;
                    }
                    break;

                case Funct5.fcvttoW:
                    switch (ins[4])
                    {
                    case 0x0:             // fcvtwd命令
                        result = fpu.FcvtWD((Register)rd, rs1, frm);
                        break;

                    case 0x1:             // fcvtwud命令
                        result = fpu.FcvtWUD((Register)rd, rs1, frm);
                        break;
                    }
                    break;

                case Funct5.fcvtfromW:
                    switch (ins[4])
                    {
                    case 0x0:             // fcvtdw命令
                        result = fpu.FcvtDW(rd, (Register)rs1, frm);
                        break;

                    case 0x1:             // fcvtdwu命令
                        result = fpu.FcvtDWU(rd, (Register)rs1, frm);
                        break;
                    }
                    break;

                case Funct5.fmvXW_fclass:         // fclassd命令
                    result = fpu.FclassD((Register)rd, rs1);
                    break;

                case Funct5.fcvtSD:         // fcvtds命令
                    result = fpu.FcvtDS(rd, rs1, frm);
                    break;
                }
                break;

            case Opcode.fmiscOp when(ins[5]& 0x3U) == 0x0U && funct5 == Funct5.fcvtSD:        // fcvtsd命令
                fpu = (RV32_DoubleFpu)Decoder.Alu(typeof(RV32_DoubleFpu));

                result = fpu.FcvtSD(rd, rs1, frm);
                break;
            }
            return(result);
        }
        /// <summary>
        /// 引数で渡された32bit長の命令をデコードし、cpuで実行する
        /// </summary>
        /// <param name="instruction">32bit長の命令</param>
        /// <param name="cpu">命令を実行するRV32CPU</param>
        /// <returns>実行の成否</returns>
        internal protected override bool Exec(UInt32[] ins)
        {
            bool result = false;

            // 命令の0~1bit目が "11" でない場合は対象なし
            if ((ins[0] & 0b11U) != 0b11U)
            {
                return(result);
            }

            FPRegister rd                = (FPRegister)ins[1],
                       rs1               = (FPRegister)ins[3],
                       rs2               = (FPRegister)ins[4],
                       rs3               = (FPRegister)((ins[5] >> 2) | (ins[6] << 4));
            Opcode             opcode    = (Opcode)ins[0];
            Funct3             funct3    = (Funct3)ins[2];
            Funct5             funct5    = (Funct5)(ins[5] >> 2 | (ins[6] << 4));
            FloatRoundingMode  frm       = (FloatRoundingMode)ins[2];
            Int32              immediate = 0;
            RV32_SingleFpu     fpu;
            RV32_FloatPointLsu lsu;


            switch (opcode)
            {
            case Opcode.fl when funct3 == Funct3.flw_fsw:     // flw命令

                immediate = GetImmediate('I', ins);
                lsu       = (RV32_FloatPointLsu)Decoder.Lsu(typeof(RV32_FloatPointLsu));
                result    = lsu.Flw(rd, (Register)rs1, immediate);
                break;

            case Opcode.fs when funct3 == Funct3.flw_fsw:     // fsw命令
                immediate = GetImmediate('S', ins);
                lsu       = (RV32_FloatPointLsu)Decoder.Lsu(typeof(RV32_FloatPointLsu));
                result    = lsu.Fsw((Register)rs1, rs2, immediate);
                break;


            case Opcode.fmadd when(ins[5]& 0x3U) == 0x0U:       // fmadds命令
                fpu = (RV32_SingleFpu)Decoder.Alu(typeof(RV32_SingleFpu));

                result = fpu.FmaddS(rd, rs1, rs2, rs3, frm);
                break;

            case Opcode.fmsub when(ins[5]& 0x3U) == 0x0U:       // fmsubs命令
                fpu = (RV32_SingleFpu)Decoder.Alu(typeof(RV32_SingleFpu));

                result = fpu.FmsubS(rd, rs1, rs2, rs3, frm);
                break;

            case Opcode.fnmadd when(ins[5]& 0x3U) == 0x0U:       // fnmadds命令
                fpu = (RV32_SingleFpu)Decoder.Alu(typeof(RV32_SingleFpu));

                result = fpu.FnmaddS(rd, rs1, rs2, rs3, frm);
                break;

            case Opcode.fnmsub when(ins[5]& 0x3U) == 0x0U:       // fnmsubs命令
                fpu = (RV32_SingleFpu)Decoder.Alu(typeof(RV32_SingleFpu));

                result = fpu.FnmsubS(rd, rs1, rs2, rs3, frm);
                break;

            case Opcode.fmiscOp when(ins[5]& 0x3U) == 0x0U:       // Single Float-Point Op系命令(算術論理演算)
                fpu = (RV32_SingleFpu)Decoder.Alu(typeof(RV32_SingleFpu));

                switch (funct5)
                {
                case Funct5.fadd:         // fadds命令
                    result = fpu.FaddS(rd, rs1, rs2, frm);
                    break;

                case Funct5.fsub:         // fsubs命令
                    result = fpu.FsubS(rd, rs1, rs2, frm);
                    break;

                case Funct5.fmul:         // fmuls命令
                    result = fpu.FmulS(rd, rs1, rs2, frm);
                    break;

                case Funct5.fdiv:         // fmuls命令
                    result = fpu.FdivS(rd, rs1, rs2, frm);
                    break;

                case Funct5.fsqrt:         // fsqrts命令
                    result = fpu.FsqrtS(rd, rs1, frm);
                    break;

                case Funct5.fsgnj:
                    switch (funct3)
                    {
                    case Funct3.fsgnj:             // fsgnjs命令
                        result = fpu.FsgnjS(rd, rs1, rs2);
                        break;

                    case Funct3.fsgnjn:             // fsgnjns命令
                        result = fpu.FsgnjnS(rd, rs1, rs2);
                        break;

                    case Funct3.fsgnjx:             // fsgnjxs命令
                        result = fpu.FsgnjxS(rd, rs1, rs2);
                        break;
                    }
                    break;

                case Funct5.fmin_fmax:
                    switch (funct3)
                    {
                    case Funct3.fmin:             // fmins命令
                        result = fpu.FminS(rd, rs1, rs2);
                        break;

                    case Funct3.fmax:             // fmaxs命令
                        result = fpu.FmaxS(rd, rs1, rs2);
                        break;
                    }
                    break;

                case Funct5.fcompare:
                    switch (funct3)
                    {
                    case Funct3.fcompare_eq:             // feqs命令
                        result = fpu.FeqS((Register)rd, rs1, rs2);
                        break;

                    case Funct3.fcompare_lt:             // flts命令
                        result = fpu.FltS((Register)rd, rs1, rs2);
                        break;

                    case Funct3.fcompare_le:             // fles命令
                        result = fpu.FleS((Register)rd, rs1, rs2);
                        break;
                    }
                    break;

                case Funct5.fcvttoW:
                    switch (ins[4])
                    {
                    case 0x0:             // fcnvws命令
                        result = fpu.FcvtWS((Register)rd, rs1, frm);
                        break;

                    case 0x1:             // fcnvwus命令
                        result = fpu.FcvtWUS((Register)rd, rs1, frm);
                        break;
                    }
                    break;

                case Funct5.fcvtfromW:
                    switch (ins[4])
                    {
                    case 0x0:             // fcnvsw命令
                        result = fpu.FcvtSW(rd, (Register)rs1, frm);
                        break;

                    case 0x1:             // fcnvswu命令
                        result = fpu.FcvtSWU(rd, (Register)rs1, frm);
                        break;
                    }
                    break;

                case Funct5.fmvXW_fclass:
                    if (funct3 == (Funct3)0b000u)           // fmvxw命令
                    {
                        result = fpu.FmvXW((Register)rd, rs1);
                    }
                    else if (funct3 == (Funct3)0b001u)             // fclasss命令
                    {
                        result = fpu.FclassS((Register)rd, rs1);
                    }
                    break;

                case Funct5.fmvWX:         // fmvwx命令
                    result = fpu.FmvWX(rd, (Register)rs1);
                    break;
                }
                break;
            }
            return(result);
        }
        /// <summary>
        /// 引数で渡された32bit長の命令をデコードし、cpuで実行する
        /// </summary>
        /// <param name="instruction">32bit長の命令</param>
        /// <param name="cpu">命令を実行するRV32CPU</param>
        /// <returns>実行の成否</returns>
        internal protected override bool Exec(UInt32[] ins)
        {
            bool result = false;

            // 命令の0~1bit目が "11" でない場合は対象なし
            if ((ins[0] & 0b11U) != 0b11U)
            {
                return(result);
            }

            Register rd        = (Register)ins[1],
                     rs1       = (Register)ins[3],
                     rs2       = (Register)ins[4];
            Opcode      opcode = (Opcode)ins[0];
            Funct3      funct3 = (Funct3)ins[2];
            Funct5      funct5 = (Funct5)((ins[5] >> 2) + (ins[6] << 4));
            RV32_AmoLsu lsu;


            if (opcode == Opcode.amo && funct3 == Funct3.amo)   // 不可分命令
            {
                lsu = (RV32_AmoLsu)Decoder.Lsu(typeof(RV32_AmoLsu));
                bool ac = (ins[5] & 0b10) > 0,
                     rl = (ins[5] & 0b01) > 0;
                switch (funct5)
                {
                case Funct5.lr:     // lr命令
                    result = lsu.LrW(rd, rs1, ac, rl);
                    break;

                case Funct5.sc:     // sc命令
                    result = lsu.ScW(rd, rs1, rs2, ac, rl);
                    break;

                case Funct5.amo_swap:     // swap命令
                    result = lsu.AmoSwapW(rd, rs1, rs2, ac, rl);
                    break;

                case Funct5.amo_add:     // add命令
                    result = lsu.AmoAddW(rd, rs1, rs2, ac, rl);
                    break;

                case Funct5.amo_xor:     // xor命令
                    result = lsu.AmoXorW(rd, rs1, rs2, ac, rl);
                    break;

                case Funct5.amo_and:     // and命令
                    result = lsu.AmoAndW(rd, rs1, rs2, ac, rl);
                    break;

                case Funct5.amo_or:     // or命令
                    result = lsu.AmoOrW(rd, rs1, rs2, ac, rl);
                    break;

                case Funct5.amo_min:     // min命令
                    result = lsu.AmoMinW(rd, rs1, rs2, ac, rl);
                    break;

                case Funct5.amo_max:     // max命令
                    result = lsu.AmoMaxW(rd, rs1, rs2, ac, rl);
                    break;

                case Funct5.amo_minu:     // minu命令
                    result = lsu.AmoMinuW(rd, rs1, rs2, ac, rl);
                    break;

                case Funct5.amo_maxu:     // maxu命令
                    result = lsu.AmoMaxuW(rd, rs1, rs2, ac, rl);
                    break;
                }
            }
            return(result);
        }