/// <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 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 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 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 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 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 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); }
internal static bool IsNaN(Binary64 binary) => (binary & ExpMask) == 0x7ff0_0000_0000_0000U && (binary & MantMask) > 0U;
internal static bool IsNormalNum(Binary64 binary) => (binary & ExpMask) > 0U && (binary & ExpMask) < 0x7ff0_0000_0000_0000U;
internal static bool IsDenormalNum(Binary64 binary) => (binary & ExpMask) == 0U && !IsZero(binary);
internal static bool IsZero(Binary64 binary) => (binary & (ExpMask | MantMask)) == Zero;