diff --git a/backends/instructions_appendix/all_instructions.golden.adoc b/backends/instructions_appendix/all_instructions.golden.adoc index c1e8d2fd9..81390c170 100644 --- a/backends/instructions_appendix/all_instructions.golden.adoc +++ b/backends/instructions_appendix/all_instructions.golden.adoc @@ -1,6 +1,6 @@ = Instruction Appendix :doctype: book -:wavedrom: /workspace/riscv-unified-db/node_modules/.bin/wavedrom-cli +:wavedrom: /workspaces/riscv-unified-db/node_modules/.bin/wavedrom-cli // Now the document header is complete and the wavedrom attribute is active. @@ -12951,7 +12951,7 @@ Included in:: == fround.s Synopsis:: -No synopsis available +Floating-point round single-precision float to integer Assembly:: fround.s fd, fs1, rm @@ -12963,7 +12963,13 @@ Encoding:: .... Description:: -No description available. +Rounds the single-precision floating-point number in floating-point register _fs1_ to an integer, according to the rounding mode specified in the instruction’s _rm_ field. + +It then writes that integer, represented as a single-precision floating-point number, to floating-point register _fd_. + +Zero and infinite inputs are copied to _fd_ unmodified. + +Signaling NaN inputs cause the invalid operation exception flag to be set; no other exception flags are set. FROUND.S is encoded like FCVT.S.D, but with rs2=4. Decode Variables:: diff --git a/spec/std/isa/inst/F/fli.s.yaml b/spec/std/isa/inst/Zfa/fli.s.yaml similarity index 100% rename from spec/std/isa/inst/F/fli.s.yaml rename to spec/std/isa/inst/Zfa/fli.s.yaml diff --git a/spec/std/isa/inst/F/fmaxm.s.yaml b/spec/std/isa/inst/Zfa/fmaxm.s.yaml similarity index 100% rename from spec/std/isa/inst/F/fmaxm.s.yaml rename to spec/std/isa/inst/Zfa/fmaxm.s.yaml diff --git a/spec/std/isa/inst/F/fminm.s.yaml b/spec/std/isa/inst/Zfa/fminm.s.yaml similarity index 100% rename from spec/std/isa/inst/F/fminm.s.yaml rename to spec/std/isa/inst/Zfa/fminm.s.yaml diff --git a/spec/std/isa/inst/F/fround.s.yaml b/spec/std/isa/inst/Zfa/fround.s.yaml similarity index 61% rename from spec/std/isa/inst/F/fround.s.yaml rename to spec/std/isa/inst/Zfa/fround.s.yaml index c1ea46105..a6252bfdd 100644 --- a/spec/std/isa/inst/F/fround.s.yaml +++ b/spec/std/isa/inst/Zfa/fround.s.yaml @@ -6,9 +6,15 @@ $schema: "inst_schema.json#" kind: instruction name: fround.s -long_name: No synopsis available +long_name: Floating-point round single-precision float to integer description: | - No description available. + Rounds the single-precision floating-point number in floating-point register _fs1_ to an integer, according to the rounding mode specified in the instruction’s _rm_ field. + + It then writes that integer, represented as a single-precision floating-point number, to floating-point register _fd_. + + Zero and infinite inputs are copied to _fd_ unmodified. + + Signaling NaN inputs cause the invalid operation exception flag to be set; no other exception flags are set. FROUND.S is encoded like FCVT.S.D, but with rs2=4. definedBy: Zfa assembly: fd, fs1, rm encoding: @@ -27,6 +33,10 @@ access: vu: always data_independent_timing: true operation(): | + check_f_ok($encoding); + RoundingMode rounding_mode = rm_to_mode(rm, $encoding); + f[fd] = round_f32_to_integral(f[fs1], rounding_mode); + mark_f_state_dirty(); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/F/froundnx.s.yaml b/spec/std/isa/inst/Zfa/froundnx.s.yaml similarity index 100% rename from spec/std/isa/inst/F/froundnx.s.yaml rename to spec/std/isa/inst/Zfa/froundnx.s.yaml diff --git a/spec/std/isa/isa/fp.idl b/spec/std/isa/isa/fp.idl index b10ea3f69..1dcfe70b9 100644 --- a/spec/std/isa/isa/fp.idl +++ b/spec/std/isa/isa/fp.idl @@ -32,7 +32,6 @@ Bits<32> UI32_POS_OVERFLOW = 32'hFFFF_FFFF; # maximum unsigned 32-bit integer Bits<32> UI32_NAN = 32'hFFFF_FFFF; # NaN to unsigned 32-bit integer Bits<32> I32_NAN = 32'h7FFF_FFFF; # NaN to signed 32-bit integer - enum RoundingMode { RNE 0b000 # Round to Nearest, ties to Even RTZ 0b001 # Round toward Zero @@ -423,8 +422,6 @@ function softfloat_roundToUI32 { z = z & ~32'b1; } - - if ((z != 0) && (sign == 1)) { set_fp_flag(FpFlag::NV); return sign == 1 ? UI32_NEG_OVERFLOW : UI32_POS_OVERFLOW; @@ -1044,3 +1041,198 @@ function f32_to_ui32 { return softfloat_roundToUI32(sign, sig64, mode); } } + +function softfloat_roundPackToF32_no_flag { + returns Bits<32> # single precision value + arguments + Bits<1> sign, + Bits<8> exp, + Bits<23> sig, + RoundingMode mode + description { + Round FP value according to +mdode+ and then pack it in IEEE format. + No flags to be set + } + body { + Bits<8> roundIncrement = 0x40; + if ( (mode != RoundingMode::RNE) && (mode != RoundingMode::RMM)) { + roundIncrement = + (mode == ((sign != 0) ? RoundingMode::RDN : RoundingMode::RUP)) + ? 0x7F + : 0; + } + Bits<8> roundBits = sig & 0x7f; + + if ( 0xFD <= exp ) { + if ($signed(exp) < 's0) { + Boolean isTiny = + ($signed(exp) < -8's1) || (sig + roundIncrement < 0x80000000); + sig = softfloat_shiftRightJam32( sig, -exp ); + exp = 0; + roundBits = sig & 0x7F; + } else if ('shFD < $signed(exp) || (0x80000000 <= sig + roundIncrement)) { + return packToF32UI(sign, 0xFF, 0) - ((roundIncrement == 0) ? 1 : 0); + } + } + + sig = (sig + roundIncrement) >> 7; + sig = sig & ~((roundBits ^ 0x40) & ((mode == RoundingMode::RNE) ? 1 : 0)); + if ( sig == 0 ) { + exp = 0; + } + return packToF32UI(sign, exp, sig); + } +} + +function softfloat_normRoundPackToF32_no_flag { + returns Bits<32> + arguments + Bits<1> sign, + Bits<8> exp, + Bits<23> sig, + RoundingMode mode + description { + Normalize, round, and pack into a 32-bit floating point value + No flags to be set + } + body { + Bits<8> shiftDist = count_leading_zeros<32>(sig) - 1; + exp = exp - shiftDist; + if ((7 <= shiftDist) && (exp < 0xFD)) { + return packToF32UI(sign, (sig != 0) ? exp : 0, sig << (shiftDist - 7)); + } else { + return softfloat_roundPackToF32_no_flag(sign, exp, sig << shiftDist, mode); + } + } +} + +function i32_to_f32_no_flag { + returns U32 + arguments + U32 a, + RoundingMode mode + description { + Converts 32-bit signed integer to 32-bit floating point number + No flags to be set + } + body { + # sign of integer, it is 1 when negative + Bits<1> sign = a[31]; + if ((a & 0x7FFFFFFF) == 0) { + return (sign == 1) ? packToF32UI(1, 0x9E, 0) : packToF32UI(0, 0, 0); + } + U32 magnitude_of_A = returnMag(a); + return softfloat_normRoundPackToF32_no_flag(sign, 0x9C, magnitude_of_A, mode); + } +} + +function softfloat_roundToI32_no_flag { + returns Bits<32> + arguments + Bits<1> sign, + Bits<64> sig, + RoundingMode roundingMode + description { + Round to signed 32-bit integer, using +rounding_mode+ + No flag to be set + } + body { + Bits<16> roundIncrement = 0x800; + if ( + (roundingMode != RoundingMode::RMM) + && (roundingMode != RoundingMode::RNE) + ) { + roundIncrement = 0; + if ( + sign == 1 + ? (roundingMode == RoundingMode::RDN) + : (roundingMode == RoundingMode::RUP) + ) { + roundIncrement = 0xFFF; + } + } + Bits<16> roundBits = sig & 0xFFF; + sig = sig + roundIncrement; + if ((sig & 0xFFFFF00000000000) != 0) { + return sign == 1 ? WORD_NEG_OVERFLOW : WORD_POS_OVERFLOW; + } + + Bits<32> sig32 = sig >> 12; + if ( + (roundBits == 0x800 && (roundingMode == RoundingMode::RNE)) + ) { + sig32 = sig32 & ~32'b1; + } + + Bits<32> z = (sign == 1) ? -sig32 : sig32; + if ((z != 0) && (($signed(z) < 's0) != (sign == 1))) { + return sign == 1 ? WORD_NEG_OVERFLOW : WORD_POS_OVERFLOW; + } + + return z; + } +} + +function f32_to_i32_no_flag { + returns U32 + arguments + U32 a, + RoundingMode mode + description { + Converts 32-bit floating point number to a signed 32-bit integer + No flags to be set + } + body { + Bits<1> sign = signF32UI(a); + Bits<8> exp = expF32UI(a); + Bits<23> sig = fracF32UI(a); + Bits<8> shiftDist; + U64 sig64; + # for NaN return the highest positive value and set floating-point flag to invalid. + if ((exp == 8'hFF) && (sig != 0)) { + sign = 0; + return I32_NAN; + } + + # MSB of significand is set to 1 because minimum 32-bit integer in IEEE 754 is 32'h80000000 + if (exp != 0) { + sig = sig | 32'h00800000; + } + + sig64 = sig `<< 32; + shiftDist = 8'hAA - exp; + + if (shiftDist > 0) { + sig64 = softfloat_shiftRightJam64( sig64, shiftDist); + } + + return softfloat_roundToI32_no_flag(sign, sig64, mode); + } +} + +function round_f32_to_integral { + returns U32 + arguments + U32 a, + RoundingMode mode + description { + Rounds 32-bit floating point number to a signed 32-bit integer. + This 32-bit integer is represented as a floating point number and returned. + } + body { + if ((is_sp_neg_inf?(a)) || (is_sp_pos_inf?(a)) || (is_sp_pos_zero?(a)) || (is_sp_neg_zero?(a))) { + # Return zero or infinity respectively for zero or infinity inputs + return a; + } else if (is_sp_signaling_nan?(a)) { + # set invalid flag for signaling NaN + set_fp_flag(FpFlag::NV); + return a; + } + # intermediate variable for storing 32-bit rounded integer + U32 intermediate; + # round 32-bit floating point number to integer, no flags to be set + intermediate = f32_to_i32_no_flag(a, mode); + # represent the integer as floating point number + return i32_to_f32_no_flag(intermediate, mode); + } +}