/// <summary> /// Floating-Point Load Double Word命令 /// レジスタrs1+offsetのアドレスにあるメモリから、8バイトを浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">ロードする対象のアドレスのベースが格納されているレジスタ番号</param> /// <param name="offset">オフセット</param> public bool Fld(FPRegister rd, Register rs1, Int32 offset, UInt32 insLength = 4U) { UInt32 addr = (UInt32)(reg.GetValue(rs1) + offset); if (reg.Mem.CanOperate(addr, 8) && reg.IsFPAvailable()) { byte[] bytes = new byte[8]; try { bytes[0] = reg.Mem[addr + 0]; bytes[1] = reg.Mem[addr + 1]; bytes[2] = reg.Mem[addr + 2]; bytes[3] = reg.Mem[addr + 3]; bytes[4] = reg.Mem[addr + 4]; bytes[5] = reg.Mem[addr + 5]; bytes[6] = reg.Mem[addr + 6]; bytes[7] = reg.Mem[addr + 7]; reg.SetValue(rd, BitConverter.ToUInt64(bytes, 0)); } catch (RiscvException e) when(((RiscvExceptionCause)e.Data["cause"]) == RiscvExceptionCause.LoadPageFault) { } } reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Multiply, Double-Precision命令 /// 浮動小数点レジスタrs1とrs2の積を浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <param name="rs2">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FmulD(FPRegister rd, FPRegister rs1, FPRegister rs2, FloatRoundingMode frm, UInt32 insLength = 4U) { Binary64 binary1 = reg.GetValue(rs1); Binary64 binary2 = reg.GetValue(rs2); Binary64 result; FloatCSR fcsr = 0; result = ToBinary(ToDouble(binary1) * ToDouble(binary2)); result = IsNaN(result) ? NaN : result; if (IsSigNaN(binary1) || IsSigNaN(binary2)) { // いずれかの数値がシグナリングNaNの場合 fcsr.NV = true; } else if (ToDouble(result) != ToDouble(binary1) * ToDouble(binary2)) { // 結果が一致しない場合 fcsr.NX = true; } else if (IsRounded(result, binary1) || IsRounded(result, binary2)) { // 桁丸めが発生している場合 fcsr.NX = true; } reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Classigy, Double-Precision命令 /// 浮動小数点レジスタrs1のクラスを示すマスクを整数レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FclassD(Register rd, FPRegister rs1, UInt32 insLength = 4U) { Binary64 binary1 = reg.GetValue(rs1); UInt32 result = 0U; if (IsNegative(binary1) && IsInfinity(binary1)) { // rs1が-∞の場合 result |= 0b00_0000_0001; } else if (IsNegative(binary1) && IsNormalNum(binary1)) { // rs1が負の正規数の場合 result |= 0b00_0000_0010; } else if (IsNegative(binary1) && IsDenormalNum(binary1)) { // rs1が負の非正規数の場合 result |= 0b00_0000_0100; } else if (IsNegative(binary1) && IsZero(binary1)) { // rs1が-0の場合 result |= 0b00_0000_1000; } else if (IsPositive(binary1) && IsZero(binary1)) { // rs1が+0の場合 result |= 0b00_0001_0000; } else if (IsPositive(binary1) && IsDenormalNum(binary1)) { // rs1が正の非正規数の場合 result |= 0b00_0010_0000; } else if (IsPositive(binary1) && IsNormalNum(binary1)) { // rs1が正の正規数の場合 result |= 0b00_0100_0000; } else if (IsPositive(binary1) && IsInfinity(binary1)) { // rs1が+∞の場合 result |= 0b00_1000_0000; } else if (IsSigNaN(binary1)) { // rs1がシグナル型非数の場合 result |= 0b01_0000_0000; } else if (IsQuietNaN(binary1)) { // rs1がクワイエット型非数の場合 result |= 0b10_0000_0000; } reg.SetValue(rd, result); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Square Root, Double-Precision命令 /// 浮動小数点レジスタrs1の平方根を浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <param name="rs2">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FsqrtD(FPRegister rd, FPRegister rs1, FloatRoundingMode frm, UInt32 insLength = 4U) { Binary64 binary1 = reg.GetValue(rs1); Binary64 result; FloatCSR fcsr = 0; result = ToBinary((Double)Math.Sqrt(ToDouble(binary1))); result = IsNaN(result) ? NaN : result; if (IsSigNaN(binary1)) { // いずれかの数値がシグナリングNaNの場合 fcsr.NV = true; } else if (IsNegative(binary1)) { // 負数の平方根を求めようとした場合 fcsr.NV = true; } else if (ToDouble(result) * ToDouble(result) != ToDouble(binary1)) { // 結果が一致しない場合 fcsr.NX = true; } else if (IsRounded(binary1, result)) { // 桁丸めが発生している場合 fcsr.NX = true; } reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Move to Word from Integer命令 /// 整数レジスタrs1(符号付き)を浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FmvWX(FPRegister rd, Register rs1, UInt32 insLength = 4U) { UInt32 value1 = reg.GetValue(rs1); Binary32 result; result = value1; reg.SetValue(rd, result); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Move to Integer from Word命令 /// 浮動小数点レジスタrs1を整数レジスタrd(符号付き)に書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FmvXW(Register rd, FPRegister rs1, UInt32 insLength = 4U) { Binary32 binary1 = (Binary32)reg.GetValue(rs1); UInt32 result; result = binary1; reg.SetValue(rd, result); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Convert to Single from Double命令 /// 浮動小数点レジスタrs1の倍精度浮動小数を単精度浮動小数に変換して、浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FcvtSD(FPRegister rd, FPRegister rs1, FloatRoundingMode frm, UInt32 insLength = 4U) { Binary64 binary1 = reg.GetValue(rs1); Binary32 result; FloatCSR fcsr = 0; Binary32 sign = (Binary32)((binary1 & SignMask) >> 32); if (IsInfinity(binary1)) { // +-∞の場合 result = sign | RV32_SingleFpu.Infinity; } else if (IsZero(binary1)) { // +-0の場合 result = sign | RV32_SingleFpu.Zero; } else if (IsSigNaN(binary1)) { // シグナリングNaNの場合 fcsr.NV = true; result = RV32_SingleFpu.NaN; } else if (IsQuietNaN(binary1)) { result = RV32_SingleFpu.NaN; } else { result = RV32_SingleFpu.ToBinary((Single)ToDouble(binary1)); if (RV32_SingleFpu.ToSingle(result) != ToDouble(binary1)) { // 結果が一致しない場合 fcsr.NX = true; if (ToDouble(binary1) > 0) { fcsr.OF = true; } else { fcsr.UF = true; } } } reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Sign Inject, Double-Precision命令 /// 浮動小数点レジスタrs1の指数と仮数と、rs2の符号を組み立てて /// 浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <param name="rs2">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FsgnjD(FPRegister rd, FPRegister rs1, FPRegister rs2, UInt32 insLength = 4U) { Binary64 binary1 = reg.GetValue(rs1); Binary64 binary2 = reg.GetValue(rs2); Binary64 result; result = binary1 & 0x7fff_ffffU | binary2 & 0x8000_0000U; reg.SetValue(rd, result); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Convert to Double from Single命令 /// 浮動小数点レジスタrs1の単精度浮動小数を倍精度浮動小数に変換して、浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FcvtDS(FPRegister rd, FPRegister rs1, FloatRoundingMode frm, UInt32 insLength = 4U) { Binary32 binary1 = (Binary32)reg.GetValue(rs1); Binary64 result; FloatCSR fcsr = 0; result = ToBinary((Double)RV32_SingleFpu.ToSingle(binary1)); reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Sign Inject, Double-Precision命令 /// 浮動小数点レジスタrs1の指数と仮数と、rs1の符号とrs2の符号の排他的論理和を組み立てて /// 浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <param name="rs2">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FsgnjxD(FPRegister rd, FPRegister rs1, FPRegister rs2, UInt32 insLength = 4U) { Binary64 binary1 = reg.GetValue(rs1); Binary64 binary2 = reg.GetValue(rs2); Binary64 result; FloatCSR fcsr = 0; result = binary1 & 0x7fff_ffffU | (binary1 ^ binary2) & 0x8000_0000U; reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Divide, Double-Precision命令 /// 浮動小数点レジスタrs1とrs2の商を浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <param name="rs2">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FdivD(FPRegister rd, FPRegister rs1, FPRegister rs2, FloatRoundingMode frm, UInt32 insLength = 4U) { Binary64 binary1 = reg.GetValue(rs1); Binary64 binary2 = reg.GetValue(rs2); Binary64 result; FloatCSR fcsr = 0; if (binary1 == 0f && binary2 == 0f) { // 被除数、除数ともに0の場合 result = NaN; fcsr.DZ = true; } else if (IsZero(binary2)) { // ゼロ除算の場合 result = Infinity | ((binary1 & SignMask) ^ (binary2 & SignMask)); fcsr.DZ = true; } else { result = ToBinary(ToDouble(binary1) / ToDouble(binary2)); result = IsNaN(result) ? NaN : result; if (IsSigNaN(binary1) || IsSigNaN(binary2)) { // いずれかの数値がシグナリングNaNの場合 fcsr.NV = true; } else if (ToDouble(result) != ToDouble(binary1) / ToDouble(binary2)) { // 結果が一致しない場合 fcsr.NX = true; } else if (IsRounded(result, binary1) || IsRounded(result, binary2)) { // 桁丸めが発生している場合 fcsr.NX = true; } } reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Convert to Double from Unsigned Word命令 /// 整数レジスタrs1(符号なし)の整数を倍精度浮動小数に変換して、浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FcvtDWU(FPRegister rd, Register rs1, FloatRoundingMode frm, UInt32 insLength = 4U) { UInt32 value1 = reg.GetValue(rs1); Binary64 result; FloatCSR fcsr = 0; result = ToBinary((Double)value1); if ((UInt32)ToDouble(result) != value1) { fcsr.NX = true; } reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Less Then or Equal, Double-Precision命令 /// 浮動小数点レジスタrs1がrs2以下であれば 1 を、そうでなければ 0 を /// 整数レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FleD(Register rd, FPRegister rs1, FPRegister rs2, UInt32 insLength = 4U) { Binary64 binary1 = reg.GetValue(rs1); Binary64 binary2 = reg.GetValue(rs2); UInt32 result; FloatCSR fcsr = 0; result = ToDouble(binary1) <= ToDouble(binary2) ? 1U : 0U; if (IsNaN(binary1) || IsNaN(binary2)) { fcsr.NV = true; } reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Equals, Single-Precision命令 /// 浮動小数点レジスタrs1とrs2が等しければ 1 を、そうでなければ 0 を /// 整数レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FeqS(Register rd, FPRegister rs1, FPRegister rs2, UInt32 insLength = 4U) { Binary32 binary1 = (Binary32)reg.GetValue(rs1); Binary32 binary2 = (Binary32)reg.GetValue(rs2); UInt32 result; FloatCSR fcsr = 0; result = ToSingle(binary1) == ToSingle(binary2) ? 1U : 0U; if (IsSigNaN(binary1) || IsSigNaN(binary2)) { fcsr.NV = true; } reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Maximum, Double-Precision命令 /// 浮動小数点レジスタrs1とrs2の大きい方を浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <param name="rs2">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FmaxD(FPRegister rd, FPRegister rs1, FPRegister rs2, UInt32 insLength = 4U) { Binary64 binary1 = reg.GetValue(rs1); Binary64 binary2 = reg.GetValue(rs2); Binary64 result; FloatCSR fcsr = 0; result = ToDouble(binary1) > ToDouble(binary2) ? binary1 : (IsPositive(binary1) && IsZero(binary1) ? binary1 : binary2); result = IsNaN(result) ? NaN : result; if (IsSigNaN(binary1) || IsSigNaN(binary2)) { fcsr.NV = true; } reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Store Word命令 /// 浮動小数点レジスタrs2から4バイトをレジスタrs1+offsetのアドレスのメモリに格納する /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">ストアする対象のアドレスのベースが格納されているレジスタ番号</param> /// <param name="offset">オフセット</param> public bool Fsw(Register rs1, FPRegister rs2, Int32 offset, UInt32 insLength = 4U) { UInt32 addr = (UInt32)(reg.GetValue(rs1) + offset); if (reg.Mem.CanOperate(addr, 4) && reg.IsFPAvailable()) { byte[] bytes = BitConverter.GetBytes(reg.GetValue(rs2)); try { reg.Mem[addr + 0] = bytes[0]; reg.Mem[addr + 1] = bytes[1]; reg.Mem[addr + 2] = bytes[2]; reg.Mem[addr + 3] = bytes[3]; } catch (RiscvException e) when(((RiscvExceptionCause)e.Data["cause"]) == RiscvExceptionCause.StoreAMOPageFault) { } } reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Minimum, Single-Precision命令 /// 浮動小数点レジスタrs1とrs2の小さい方を浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <param name="rs2">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FminS(FPRegister rd, FPRegister rs1, FPRegister rs2, UInt32 insLength = 4U) { Binary32 binary1 = (Binary32)reg.GetValue(rs1); Binary32 binary2 = (Binary32)reg.GetValue(rs2); Binary32 result; FloatCSR fcsr = 0; result = ToSingle(binary1) < ToSingle(binary2) ? binary1 : (IsNegative(binary1) && IsZero(binary1) ? binary1 : binary2); result = IsNaN(result) ? NaN : result; if (IsSigNaN(binary1) || IsSigNaN(binary2)) { fcsr.NV = true; } reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Convert to Unsigned Word from Double命令 /// 浮動小数点レジスタrs1の倍精度浮動小数を整数(符号なし)に変換して、整数レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FcvtWUD(Register rd, FPRegister rs1, FloatRoundingMode frm, UInt32 insLength = 4U) { Binary64 binary1 = reg.GetValue(rs1); UInt32 result; FloatCSR fcsr = 0; Double value1 = ToDouble(binary1); Double rvalue1 = ToDouble(RoundNum(binary1, 0, frm)); result = (UInt32)rvalue1; if ((IsPositive(binary1) && IsInfinity(binary1)) || IsNaN(binary1)) { fcsr.NV = true; result = UInt32.MaxValue; } else if (IsNegative(binary1) && IsInfinity(binary1)) { fcsr.NV = true; result = UInt32.MinValue; } else if (UInt32.MaxValue < rvalue1) { fcsr.NV = true; result = UInt32.MaxValue; } else if (UInt32.MinValue > rvalue1) { fcsr.NV = true; result = UInt32.MinValue; } else if (result != value1) { fcsr.NX = true; } reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <summary> /// Floating-Point Fused Multiply-Subtract, Double-Precision命令 /// 浮動小数点レジスタrs1とrs2の積からrs3を引いた値を浮動小数点レジスタrdに書き込む /// </summary> /// <param name="rd">結果を格納するレジスタ番号</param> /// <param name="rs1">レジスタ番号</param> /// <param name="rs2">レジスタ番号</param> /// <param name="rs3">レジスタ番号</param> /// <returns>処理の成否</returns> public bool FmsubD(FPRegister rd, FPRegister rs1, FPRegister rs2, FPRegister rs3, FloatRoundingMode frm, UInt32 insLength = 4U) { Binary64 binary1 = reg.GetValue(rs1); Binary64 binary2 = reg.GetValue(rs2); Binary64 binary3 = reg.GetValue(rs3); Binary64 result; FloatCSR fcsr = 0; result = ToBinary((ToDouble(binary1) * ToDouble(binary2)) - ToDouble(binary3)); result = IsNaN(result) ? NaN : result; if ((IsInfinity(binary1) || IsInfinity(binary2)) && IsInfinity(binary3) && ((IsNegative(binary1) ^ IsPositive(binary2)) ^ IsPositive(binary3))) { // ∞ + -∞ もしくは -∞ + ∞の場合 result = NaN; fcsr.NV = true; } else if (IsSigNaN(binary1) || IsSigNaN(binary2) || IsSigNaN(binary3)) { // いずれかの数値がシグナリングNaNの場合 fcsr.NV = true; } else if (ToDouble(result) != (ToDouble(binary1) * ToDouble(binary2)) - ToDouble(binary3)) { // 結果が一致しない場合 fcsr.NX = true; } else if (IsRounded(result, binary1) || IsRounded(result, binary2) || IsRounded(result, binary3)) { // 桁丸めが発生している場合 fcsr.NX = true; } reg.SetValue(rd, result); reg.SetFflagsCSR(fcsr); reg.IncrementPc(insLength); return(true); }
/// <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); }