diff --git a/arch/csr/fcsr.yaml b/arch/csr/F/fcsr.yaml similarity index 98% rename from arch/csr/fcsr.yaml rename to arch/csr/F/fcsr.yaml index bc114273d7..72d797472d 100644 --- a/arch/csr/fcsr.yaml +++ b/arch/csr/F/fcsr.yaml @@ -1,4 +1,4 @@ -# yaml-language-server: $schema=../../schemas/csr_schema.json +# yaml-language-server: $schema=../../../schemas/csr_schema.json fcsr: long_name: Floating-point control and status register (`frm` + `fflags`) @@ -93,7 +93,7 @@ fcsr: length: 32 definedBy: F fields: - RMODE: + FRM: location: 7-5 description: | Rounding modes are encoded as follows: @@ -179,4 +179,4 @@ fcsr: Set by hardware when a floating point operation is inexact and stays set until explicitly cleared by software. type: RW-H - reset_value: UNDEFINED_LEGAL + reset_value: UNDEFINED_LEGAL \ No newline at end of file diff --git a/arch/ext/F.yaml b/arch/ext/F.yaml index 9586d500e0..7c547e8b3c 100644 --- a/arch/ext/F.yaml +++ b/arch/ext/F.yaml @@ -239,6 +239,20 @@ F: Indicates whether or not the `F` extension can be disabled with the `misa.F` bit. schema: type: boolean + HW_MSTATUS_FS_DIRTY_UPDATE: + description: | + Indicates whether or not hardware will write to `mstatus.FS` + + Values are: + [separator="!"] + !=== + h! none ! Hardware never writes `mstatus.FS` + h! precise ! Hardware writes `mstatus.FS` to the Dirty (3) state precisely when F registers are modified + h! imprecise ! Hardware writes `mstatus.FS` imprecisely. This will result in a call to unpredictable() on any attempt to read `mstatus` or write FP state. + !=== + schema: + type: string + enum: ["none", "precise", "imprecise"] MSTATUS_FS_LEGAL_VALUES: description: | The set of values that mstatus.FS will accept from a software write. @@ -251,4 +265,7 @@ F: uniqueItems: true also_defined_in: S extra_validation: | - assert MSTATUS_FS_LEGAL_VALUES.include?(0) && MSTATUS_FS_LEGAL_VALUES.include?(3) if ext?(:F) \ No newline at end of file + assert MSTATUS_FS_LEGAL_VALUES.include?(0) && MSTATUS_FS_LEGAL_VALUES.include?(3) if ext?(:F) + + # if HW is writing FS, then Dirty (3) better be a supported value + assert MSTATUS_FS_LEGAL_VALUES.include?(3) if ext?(:F) && (HW_MSTATUS_FS_DIRTY_UPDATE != "none") \ No newline at end of file diff --git a/arch/inst/F/fadd.s.yaml b/arch/inst/F/fadd.s.yaml new file mode 100644 index 0000000000..4c459cb376 --- /dev/null +++ b/arch/inst/F/fadd.s.yaml @@ -0,0 +1,27 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fadd.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: fd, fs1, fs2, rm + encoding: + match: 0000000------------------1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fclass.s.yaml b/arch/inst/F/fclass.s.yaml new file mode 100644 index 0000000000..c484a11fe4 --- /dev/null +++ b/arch/inst/F/fclass.s.yaml @@ -0,0 +1,73 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fclass.s: + long_name: Single-precision floating-point classify. + description: | + The `fclass.s` instruction examines the value in floating-point register + _fs1_ and writes to integer register _rd_ a 10-bit mask that indicates + the class of the floating-point number. + The format of the mask is described in the table below. + The corresponding bit in _rd_ will be set if the property is true and + clear otherwise. + All other bits in _rd_ are cleared. + Note that exactly one bit in rd will be set. + `fclass.s` does not set the floating-point exception flags. + + .Format of result of `fclass` instruction. + [%autowidth,float="center",align="center",cols="^,<",options="header",] + |=== + |_rd_ bit |Meaning + |0 |_rs1_ is latexmath:[$-\infty$]. + |1 |_rs1_ is a negative normal number. + |2 |_rs1_ is a negative subnormal number. + |3 |_rs1_ is latexmath:[$-0$]. + |4 |_rs1_ is latexmath:[$+0$]. + |5 |_rs1_ is a positive subnormal number. + |6 |_rs1_ is a positive normal number. + |7 |_rs1_ is latexmath:[$+\infty$]. + |8 |_rs1_ is a signaling NaN. + |9 |_rs1_ is a quiet NaN. + |=== + + definedBy: F + assembly: xd, fs1 + encoding: + match: 111000000000-----001-----1010011 + variables: + - name: fs1 + location: 19-15 + - name: rd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: false + operation(): | + check_f_ok($encoding); + + Bits<32> sp_value = f[fs1][31:0]; + + if (is_sp_neg_inf?(sp_value)) { + X[rd] = 1 << 0; + } else if (is_sp_neg_norm?(sp_value)) { + X[rd] = 1 << 1; + } else if (is_sp_neg_subnorm?(sp_value)) { + X[rd] = 1 << 2; + } else if (is_sp_neg_zero?(sp_value)) { + X[rd] = 1 << 3; + } else if (is_sp_pos_zero?(sp_value)) { + X[rd] = 1 << 4; + } else if (is_sp_pos_subnorm?(sp_value)) { + X[rd] = 1 << 5; + } else if (is_sp_pos_norm?(sp_value)) { + X[rd] = 1 << 6; + } else if (is_sp_pos_inf?(sp_value)) { + X[rd] = 1 << 7; + } else if (is_sp_signaling_nan?(sp_value)) { + X[rd] = 1 << 8; + } else { + assert(is_sp_quiet_nan?(sp_value), "Unexpected SP value"); + X[rd] = 1 << 9; + } diff --git a/arch/inst/F/fcvt.l.s.yaml b/arch/inst/F/fcvt.l.s.yaml new file mode 100644 index 0000000000..af2b591233 --- /dev/null +++ b/arch/inst/F/fcvt.l.s.yaml @@ -0,0 +1,26 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fcvt.l.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + base: 64 + assembly: xd, fs1, rm + encoding: + match: 110000000010-------------1010011 + variables: + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: rd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fcvt.lu.s.yaml b/arch/inst/F/fcvt.lu.s.yaml new file mode 100644 index 0000000000..d11be70f71 --- /dev/null +++ b/arch/inst/F/fcvt.lu.s.yaml @@ -0,0 +1,26 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fcvt.lu.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + base: 64 + assembly: xd, fs1, rm + encoding: + match: 110000000011-------------1010011 + variables: + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: rd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fcvt.s.l.yaml b/arch/inst/F/fcvt.s.l.yaml new file mode 100644 index 0000000000..e23c2deeee --- /dev/null +++ b/arch/inst/F/fcvt.s.l.yaml @@ -0,0 +1,26 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fcvt.s.l: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + base: 64 + assembly: fd, xs1, rm + encoding: + match: 110100000010-------------1010011 + variables: + - name: rs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fcvt.s.lu.yaml b/arch/inst/F/fcvt.s.lu.yaml new file mode 100644 index 0000000000..a323d1b27a --- /dev/null +++ b/arch/inst/F/fcvt.s.lu.yaml @@ -0,0 +1,26 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fcvt.s.lu: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + base: 64 + assembly: fd, xs1, rm + encoding: + match: 110100000011-------------1010011 + variables: + - name: rs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fcvt.s.w.yaml b/arch/inst/F/fcvt.s.w.yaml new file mode 100644 index 0000000000..85a1d85a44 --- /dev/null +++ b/arch/inst/F/fcvt.s.w.yaml @@ -0,0 +1,50 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fcvt.s.w: + long_name: Convert signed 32-bit integer to single-precision float + description: | + Converts a 32-bit signed integer in integer register _rs1_ into a floating-point number in + floating-point register _fd_. + + All floating-point to integer and integer to floating-point conversion instructions round + according to the _rm_ field. + A floating-point register can be initialized to floating-point positive zero using + `fcvt.s.w rd, x0`, which will never set any exception flags. + + All floating-point conversion instructions set the Inexact exception flag if the rounded + result differs from the operand value and the Invalid exception flag is not set. + definedBy: F + assembly: fd, xs1 + encoding: + match: 110100000000-------------1010011 + variables: + - name: rs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: false + operation(): | + check_f_ok($encoding); + + Bits<32> int_value = X[rs1]; + + Bits<1> sign = int_value[31]; + + RoundingMode rounding_mode = rm_to_mode(rm, $encoding); + + if ((int_value & 32'h7fff_ffff) == 0) { + X[fd] = (sign == 1) ? packToF32UI(1, 0x9E, 0) : 0; + } else { + Bits<32> absA = (sign == 1) ? -int_value : int_value; + X[fd] = softfloat_normRoundPackToF32( sign, 0x9C, absA, rounding_mode ); + } + + mark_f_state_dirty(); + diff --git a/arch/inst/F/fcvt.s.wu.yaml b/arch/inst/F/fcvt.s.wu.yaml new file mode 100644 index 0000000000..451db4ab1d --- /dev/null +++ b/arch/inst/F/fcvt.s.wu.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fcvt.s.wu: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: fd, xs1, rm + encoding: + match: 110100000001-------------1010011 + variables: + - name: rs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fcvt.w.s.yaml b/arch/inst/F/fcvt.w.s.yaml new file mode 100644 index 0000000000..5ffb38e796 --- /dev/null +++ b/arch/inst/F/fcvt.w.s.yaml @@ -0,0 +1,80 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fcvt.w.s: + long_name: Convert single-precision float to integer word to signed 32-bit integer. + description: | + Converts a floating-point number in floating-point register _fs1_ to a signed 32-bit integer indicates + integer register _rd_. + + For XLEN >32, `fcvt.w.s` sign-extends the 32-bit result to the destination register width. + + If the rounded result is not representable as a 32-bit signed integer, it is clipped to the + nearest value and the invalid flag is set. + + The range of valid inputs and behavior for invalid inputs are: + + [separator="!"] + !=== + ! ! Value + + h! Minimum valid input (after rounding) ! `-2^31` + h! Maximum valid input (after rounding) ! `2^31 - 1` + h! Output for out-of-range negative input ! `-2^31` + h! Output for `-∞` ! `-2^31` + h! Output for out-of-range positive input ! `2^31 - 1` + h! Output for `+∞` for `NaN` ! `2^31 - 1` + !=== + + All floating-point to integer and integer to floating-point conversion instructions round + according to the _rm_ field. + A floating-point register can be initialized to floating-point positive zero using + `fcvt.s.w rd, x0`, which will never set any exception flags. + + All floating-point conversion instructions set the Inexact exception flag if the rounded + result differs from the operand value and the Invalid exception flag is not set. + + definedBy: F + assembly: xd, fs1 + encoding: + match: 110000000000-------------1010011 + variables: + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: rd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + check_f_ok($encoding); + + Bits<32> sp_value = f[fs1][31:0]; + + Bits<1> sign = sp_value[31]; + Bits<8> exp = sp_value[30:23]; + Bits<23> sig = sp_value[22:0]; + + RoundingMode rounding_mode = rm_to_mode(rm, $encoding); + + if ( (exp == 0xff) && (sig != 0)) { + sign = 0; + set_fp_flag(FpFlag::NV); + X[rd] = SP_CANONICAL_NAN; + } else { + if (exp != 0) { + sig = sig | 0x00800000; + } + Bits<64> sig64 = sig << 32; + Bits<16> shift_dist = 0xAA - exp; + if (0 < shift_dist) { + sig64 = softfloat_shiftRightJam64(sig64, shift_dist ); + } + X[rd] = softfloat_roundToI32( sign, sig64, rounding_mode ); + } + + diff --git a/arch/inst/F/fcvt.wu.s.yaml b/arch/inst/F/fcvt.wu.s.yaml new file mode 100644 index 0000000000..3ced43a238 --- /dev/null +++ b/arch/inst/F/fcvt.wu.s.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fcvt.wu.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: xd, fs1, rm + encoding: + match: 110000000001-------------1010011 + variables: + - name: rs1 + location: 19-15 + - name: rm + location: 14-12 + - name: rd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fdiv.s.yaml b/arch/inst/F/fdiv.s.yaml new file mode 100644 index 0000000000..43e135eaf8 --- /dev/null +++ b/arch/inst/F/fdiv.s.yaml @@ -0,0 +1,27 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fdiv.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: fd, fs1, fs2, rm + encoding: + match: 0001100------------------1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/feq.s.yaml b/arch/inst/F/feq.s.yaml new file mode 100644 index 0000000000..4239a5c079 --- /dev/null +++ b/arch/inst/F/feq.s.yaml @@ -0,0 +1,45 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +feq.s: + long_name: Single-precision floating-point equal + description: | + Writes 1 to _rd_ if _fs1_ and _fs2_ are equal, and 0 otherwise. + + If either operand is NaN, the result is 0 (not equal). If either operand is a signaling NaN, the invalid flag is set. + + Positive zero is considered equal to negative zero. + + definedBy: F + assembly: xd, fs1, fs2 + encoding: + match: 1010000----------010-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + check_f_ok($encoding); + + Bits<32> sp_value_a = f[fs1][31:0]; + Bits<32> sp_value_b = f[fs1][31:0]; + + if (is_sp_nan?(sp_value_a) || is_sp_nan?(sp_value_b)) { + if (is_sp_signaling_nan?(sp_value_a) || is_sp_signaling_nan?(sp_value_b)) { + set_fp_flag(FpFlag::NV); + } + X[rd] = 0; + } else { + X[rd] = ( + (sp_value_a == sp_value_b) + || ((sp_value_a | sp_value_b)[30:0] == 0) # pos 0 is equal to neg zero + ) ? 1 : 0; + } diff --git a/arch/inst/F/fle.s.yaml b/arch/inst/F/fle.s.yaml new file mode 100644 index 0000000000..c692a679ce --- /dev/null +++ b/arch/inst/F/fle.s.yaml @@ -0,0 +1,46 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fle.s: + long_name: Single-precision floating-point less than or equal + description: | + Writes 1 to _rd_ if _fs1_ is less than or equal to _fs2_, and 0 otherwise. + + If either operand is NaN, the result is 0 (not equal). + If either operand is a NaN (signaling or quiet), the invalid flag is set. + + Positive zero and negative zero are considered equal. + + definedBy: F + assembly: xd, fs1, fs2 + encoding: + match: 1010000----------000-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + check_f_ok($encoding); + + Bits<32> sp_value_a = f[fs1][31:0]; + Bits<32> sp_value_b = f[fs2][31:0]; + + if (is_sp_nan?(sp_value_a) || is_sp_nan?(sp_value_b)) { + if (is_sp_signaling_nan?(sp_value_a) || is_sp_signaling_nan?(sp_value_b)) { + set_fp_flag(FpFlag::NV); + } + X[rd] = 0; + } else { + X[rd] = ( + (sp_value_a == sp_value_b) + || ((sp_value_a | sp_value_b)[30:0] == 0) # pos 0 is equal to neg zero + ) ? 1 : 0; + } diff --git a/arch/inst/F/fleq.s.yaml b/arch/inst/F/fleq.s.yaml new file mode 100644 index 0000000000..fa42d83df1 --- /dev/null +++ b/arch/inst/F/fleq.s.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fleq.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F, Zfa + assembly: xd, fs1, fs2 + encoding: + match: 1010000----------100-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fli.s.yaml b/arch/inst/F/fli.s.yaml new file mode 100644 index 0000000000..e85e013156 --- /dev/null +++ b/arch/inst/F/fli.s.yaml @@ -0,0 +1,23 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fli.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F, Zfa + assembly: fd, fs1 + encoding: + match: 111100000001-----000-----1010011 + variables: + - name: fs1 + location: 19-15 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/flt.s.yaml b/arch/inst/F/flt.s.yaml new file mode 100644 index 0000000000..0a2d7a5dac --- /dev/null +++ b/arch/inst/F/flt.s.yaml @@ -0,0 +1,48 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +flt.s: + long_name: Single-precision floating-point less than + description: | + Writes 1 to _rd_ if _fs1_ is less than _fs2_, and 0 otherwise. + + If either operand is NaN, the result is 0 (not equal). + If either operand is a NaN (signaling or quiet), the invalid flag is set. + + definedBy: F + assembly: xd, fs1, fs2 + encoding: + match: 1010000----------001-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + check_f_ok($encoding); + + Bits<32> sp_value_a = f[fs1][31:0]; + Bits<32> sp_value_b = f[fs2][31:0]; + + if (is_sp_nan?(sp_value_a) || is_sp_nan?(sp_value_b)) { + set_fp_flag(FpFlag::NV); + X[rd] = 0; + } else { + Boolean sign_a = sp_value_a[31] == 1; + Boolean sign_b = sp_value_b[31] == 1; + + Boolean a_lt_b = + (sign_a != sign_b) + ? (sign_a && ((sp_value_a[30:0] | sp_value_b[30:0]) != 0)) # opposite sign, a is negative. a is less than b as long as both are not zero + : ((sp_value_a != sp_value_b) && (sign_a != (sp_value_a < sp_value_b))); + X[rd] = a_lt_b ? 1 : 0; + } + + diff --git a/arch/inst/F/fltq.s.yaml b/arch/inst/F/fltq.s.yaml new file mode 100644 index 0000000000..ce447071b0 --- /dev/null +++ b/arch/inst/F/fltq.s.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fltq.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F, Zfa + assembly: xd, fs1, fs2 + encoding: + match: 1010000----------101-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/flw.yaml b/arch/inst/F/flw.yaml new file mode 100644 index 0000000000..c4932d6bd3 --- /dev/null +++ b/arch/inst/F/flw.yaml @@ -0,0 +1,40 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +flw: + long_name: Single-precision floating-point load + description: | + The `flw` instruction loads a single-precision floating-point value from memory at address _rs1_ + _imm_ into floating-point register _fd_. + + `flw` does not modify the bits being transferred; in particular, the payloads of non-canonical NaNs are preserved. + + definedBy: F + assembly: fd, xs1, imm + encoding: + match: -----------------010-----0000111 + variables: + - name: imm + location: 31-20 + - name: rs1 + location: 19-15 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + check_f_ok($encoding); + + XReg virtual_address = X[rs1] + $signed(imm); + + Bits<32> sp_value = read_memory<32>(virtual_address, $encoding); + + if (implemented?(ExtensionName::D)) { + f[fd] = nan_box<32, 64>(sp_value); + } else { + f[fd] = sp_value; + } + + mark_f_state_dirty(); \ No newline at end of file diff --git a/arch/inst/F/fmadd.s.yaml b/arch/inst/F/fmadd.s.yaml new file mode 100644 index 0000000000..468f003810 --- /dev/null +++ b/arch/inst/F/fmadd.s.yaml @@ -0,0 +1,29 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fmadd.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: fd, fs1, fs2, fs3, rm + encoding: + match: -----00------------------1000011 + variables: + - name: fs3 + location: 31-27 + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fmax.s.yaml b/arch/inst/F/fmax.s.yaml new file mode 100644 index 0000000000..a0b00dcabf --- /dev/null +++ b/arch/inst/F/fmax.s.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fmax.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: fd, fs1, fs2 + encoding: + match: 0010100----------001-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fmaxm.s.yaml b/arch/inst/F/fmaxm.s.yaml new file mode 100644 index 0000000000..c7d75640c6 --- /dev/null +++ b/arch/inst/F/fmaxm.s.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fmaxm.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F, Zfa + assembly: xd, xs1, xs2 + encoding: + match: 0010100----------011-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fmin.s.yaml b/arch/inst/F/fmin.s.yaml new file mode 100644 index 0000000000..21689e3517 --- /dev/null +++ b/arch/inst/F/fmin.s.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fmin.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: xd, xs1, xs2 + encoding: + match: 0010100----------000-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fminm.s.yaml b/arch/inst/F/fminm.s.yaml new file mode 100644 index 0000000000..0cd64b1fd3 --- /dev/null +++ b/arch/inst/F/fminm.s.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fminm.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F, Zfa + assembly: fd, fs1, fs2 + encoding: + match: 0010100----------010-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fmsub.s.yaml b/arch/inst/F/fmsub.s.yaml new file mode 100644 index 0000000000..ea84674733 --- /dev/null +++ b/arch/inst/F/fmsub.s.yaml @@ -0,0 +1,29 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fmsub.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: fd, fs1, fs2, fs3, rm + encoding: + match: -----00------------------1000111 + variables: + - name: fs3 + location: 31-27 + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fmul.s.yaml b/arch/inst/F/fmul.s.yaml new file mode 100644 index 0000000000..1148506549 --- /dev/null +++ b/arch/inst/F/fmul.s.yaml @@ -0,0 +1,27 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fmul.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: fd, fs1, fs2, rm + encoding: + match: 0001000------------------1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fmv.w.x.yaml b/arch/inst/F/fmv.w.x.yaml index d25dddec60..68bb111072 100644 --- a/arch/inst/F/fmv.w.x.yaml +++ b/arch/inst/F/fmv.w.x.yaml @@ -3,10 +3,10 @@ fmv.w.x: long_name: Single-precision floating-point move from integer description: | - Moves the single-precision value encoded in IEEE 754-2008 standard encoding - from the lower 32 bits of integer register `rs1` to the floating-point - register `rd`. The bits are not modified in the transfer, and in particular, - the payloads of non-canonical NaNs are preserved. + Moves the single-precision value encoded in IEEE 754-2008 standard encoding + from the lower 32 bits of integer register `rs1` to the floating-point + register `fd`. The bits are not modified in the transfer, and in particular, + the payloads of non-canonical NaNs are preserved. definedBy: F assembly: fd, xs1 encoding: @@ -14,12 +14,23 @@ fmv.w.x: variables: - name: rs1 location: 19-15 - - name: rd + - name: fd location: 11-7 access: s: always u: always vs: always vu: always - # operation(): | - # f[rd] = X[rs1][31:0]; + data_independent_timing: true + operation(): | + check_f_ok($encoding); + + Bits<32> sp_value = X[rs1][31:0]; + + if (implemented?(ExtensionName::D)) { + f[fd] = nan_box<32, 64>(sp_value); + } else { + f[fd] = sp_value; + } + + mark_f_state_dirty(); diff --git a/arch/inst/F/fmv.x.w.yaml b/arch/inst/F/fmv.x.w.yaml new file mode 100644 index 0000000000..a57eb06588 --- /dev/null +++ b/arch/inst/F/fmv.x.w.yaml @@ -0,0 +1,30 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fmv.x.w: + long_name: Move single-precision value from floating-point to integer register + description: | + Moves the single-precision value in floating-point register rs1 represented in IEEE 754-2008 + encoding to the lower 32 bits of integer register rd. + The bits are not modified in the transfer, and in particular, the payloads of non-canonical + NaNs are preserved. + For RV64, the higher 32 bits of the destination register are filled with copies of the + floating-point number's sign bit. + definedBy: F + assembly: xd, fs1 + encoding: + match: 111000000000-----000-----1010011 + variables: + - name: fs1 + location: 19-15 + - name: rd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + check_f_ok($encoding); + + X[rd] = sext(f[fs1][31:0], 32); diff --git a/arch/inst/F/fnmadd.s.yaml b/arch/inst/F/fnmadd.s.yaml new file mode 100644 index 0000000000..d009f4de05 --- /dev/null +++ b/arch/inst/F/fnmadd.s.yaml @@ -0,0 +1,29 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fnmadd.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: fd, fs1, fs2, fs3, rm + encoding: + match: -----00------------------1001111 + variables: + - name: fs3 + location: 31-27 + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fnmsub.s.yaml b/arch/inst/F/fnmsub.s.yaml new file mode 100644 index 0000000000..ec75b319e0 --- /dev/null +++ b/arch/inst/F/fnmsub.s.yaml @@ -0,0 +1,29 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fnmsub.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: xd, xs1, xs2, xs3, rm + encoding: + match: -----00------------------1001011 + variables: + - name: fs3 + location: 31-27 + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fround.s.yaml b/arch/inst/F/fround.s.yaml new file mode 100644 index 0000000000..75e67bb741 --- /dev/null +++ b/arch/inst/F/fround.s.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fround.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F, Zfa + assembly: fd, xs1, rm + encoding: + match: 010000000100-------------1010011 + variables: + - name: rs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/froundnx.s.yaml b/arch/inst/F/froundnx.s.yaml new file mode 100644 index 0000000000..09e739fc14 --- /dev/null +++ b/arch/inst/F/froundnx.s.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +froundnx.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F, Zfa + assembly: fd, rs1, rm + encoding: + match: 010000000101-------------1010011 + variables: + - name: rs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fsgnj.s.yaml b/arch/inst/F/fsgnj.s.yaml new file mode 100644 index 0000000000..cfb1d0deff --- /dev/null +++ b/arch/inst/F/fsgnj.s.yaml @@ -0,0 +1,42 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fsgnj.s: + long_name: Single-precision sign inject + description: | + Writes _fd_ with sign bit of _fs2_ and the exponent and mantissa of _fs1_. + + Sign-injection instructions do not set floating-point exception flags, nor do they canonicalize NaNs. + + definedBy: F + assembly: fd, fs1, fs2 + encoding: + match: 0010000----------000-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + pseudoinstructions: + - when: (rs2 == rs1) + to: fmv.s + + operation(): | + check_f_ok($encoding); + + Bits<32> sp_value = {f[fs2][31], f[fs1][30:0]}; + + if (implemented?(ExtensionName::D)) { + f[fd] = nan_box<32, 64>(sp_value); + } else { + f[fd] = sp_value; + } + + mark_f_state_dirty(); diff --git a/arch/inst/F/fsgnjn.s.yaml b/arch/inst/F/fsgnjn.s.yaml new file mode 100644 index 0000000000..6baa35d888 --- /dev/null +++ b/arch/inst/F/fsgnjn.s.yaml @@ -0,0 +1,41 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fsgnjn.s: + long_name: Single-precision sign inject negate + description: | + Writes _fd_ with the opposite of the sign bit of _fs2_ and the exponent and mantissa of _fs1_. + + Sign-injection instructions do not set floating-point exception flags, nor do they canonicalize NaNs. + definedBy: F + assembly: fd, fs1, fs2 + encoding: + match: 0010000----------001-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + pseudoinstructions: + - when: (rs2 == rs1) + to: fneg.s + + operation(): | + check_f_ok($encoding); + + Bits<32> sp_value = {~f[fs2][31], f[fs1][30:0]}; + + if (implemented?(ExtensionName::D)) { + f[fd] = nan_box<32, 64>(sp_value); + } else { + f[fd] = sp_value; + } + + mark_f_state_dirty(); diff --git a/arch/inst/F/fsgnjx.s.yaml b/arch/inst/F/fsgnjx.s.yaml new file mode 100644 index 0000000000..7a27be68c6 --- /dev/null +++ b/arch/inst/F/fsgnjx.s.yaml @@ -0,0 +1,40 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fsgnjx.s: + long_name: Single-precision sign inject exclusive or + description: | + Writes _fd_ with the xor of the sign bits of _fs2_ and _fs1_ and the exponent and mantissa of _fs1_. + + Sign-injection instructions do not set floating-point exception flags, nor do they canonicalize NaNs. + definedBy: F + assembly: fd, fs1, fs2 + encoding: + match: 0010000----------010-----1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + pseudoinstructions: + - when: (rs2 == rs1) + to: fabs.s + operation(): | + check_f_ok($encoding); + + Bits<32> sp_value = {f[fs1][31] ^ f[fs2][31], f[fs1][30:0]}; + + if (implemented?(ExtensionName::D)) { + f[fd] = nan_box<32, 64>(sp_value); + } else { + f[fd] = sp_value; + } + + mark_f_state_dirty(); diff --git a/arch/inst/F/fsqrt.s.yaml b/arch/inst/F/fsqrt.s.yaml new file mode 100644 index 0000000000..3a623b289f --- /dev/null +++ b/arch/inst/F/fsqrt.s.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fsqrt.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: fd, fs1, rm + encoding: + match: 010110000000-------------1010011 + variables: + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fsub.s.yaml b/arch/inst/F/fsub.s.yaml new file mode 100644 index 0000000000..691fda24b1 --- /dev/null +++ b/arch/inst/F/fsub.s.yaml @@ -0,0 +1,27 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fsub.s: + long_name: No synopsis available. + description: | + No description available. + definedBy: F + assembly: fd, fs1, fs2, rm + encoding: + match: 0000100------------------1010011 + variables: + - name: fs2 + location: 24-20 + - name: fs1 + location: 19-15 + - name: rm + location: 14-12 + - name: fd + location: 11-7 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + diff --git a/arch/inst/F/fsw.yaml b/arch/inst/F/fsw.yaml new file mode 100644 index 0000000000..d5983548b4 --- /dev/null +++ b/arch/inst/F/fsw.yaml @@ -0,0 +1,32 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +fsw: + long_name: Single-precision floating-point store + description: | + The `fsw` instruction stores a single-precision floating-point value in _fs2_ to memory at address _rs1_ + _imm_. + + `fsw` does not modify the bits being transferred; in particular, the payloads of non-canonical NaNs are preserved. + + definedBy: F + assembly: fs2, xs1, imm + encoding: + match: -----------------010-----0100111 + variables: + - name: imm + location: 31-25|11-7 + - name: fs2 + location: 24-20 + - name: rs1 + location: 19-15 + access: + s: always + u: always + vs: always + vu: always + data_independent_timing: true + operation(): | + check_f_ok($encoding); + + XReg virtual_address = X[rs1] + $signed(imm); + + write_memory<32>(virtual_address, f[fs2][31:0], $encoding); diff --git a/arch/inst/Zfh/fcvt.h.s.yaml b/arch/inst/Zfh/fcvt.h.s.yaml index 1393f94708..a347f194c9 100644 --- a/arch/inst/Zfh/fcvt.h.s.yaml +++ b/arch/inst/Zfh/fcvt.h.s.yaml @@ -29,7 +29,7 @@ fcvt.h.s: vs: always vu: always operation(): | - check_f_ok(); + check_f_ok($encoding); Bits<16> hp_value = f[fs1][15:0]; diff --git a/arch/inst/Zfh/fcvt.s.h.yaml b/arch/inst/Zfh/fcvt.s.h.yaml index 489ea806fa..471596c828 100644 --- a/arch/inst/Zfh/fcvt.s.h.yaml +++ b/arch/inst/Zfh/fcvt.s.h.yaml @@ -26,7 +26,7 @@ fcvt.s.h: vs: always vu: always operation(): | - check_f_ok(); + check_f_ok($encoding); Bits<32> sp_value = f[fs1][31:0]; diff --git a/arch/inst/Zfh/flh.yaml b/arch/inst/Zfh/flh.yaml index 1d5ec8aa8f..d8d1fd79b7 100644 --- a/arch/inst/Zfh/flh.yaml +++ b/arch/inst/Zfh/flh.yaml @@ -27,7 +27,7 @@ flh: vs: always vu: always operation(): | - check_f_ok(); + check_f_ok($encoding); XReg virtual_address = X[rs1] + $signed(imm); diff --git a/arch/inst/Zfh/fmv.h.x.yaml b/arch/inst/Zfh/fmv.h.x.yaml index 77c9e98ef3..43b0195389 100644 --- a/arch/inst/Zfh/fmv.h.x.yaml +++ b/arch/inst/Zfh/fmv.h.x.yaml @@ -22,7 +22,7 @@ fmv.h.x: vs: always vu: always operation(): | - check_f_ok(); + check_f_ok($encoding); Bits<16> hp_value = X[rs1][15:0]; diff --git a/arch/inst/Zfh/fmv.x.h.yaml b/arch/inst/Zfh/fmv.x.h.yaml index 1a32d71457..77d0314b27 100644 --- a/arch/inst/Zfh/fmv.x.h.yaml +++ b/arch/inst/Zfh/fmv.x.h.yaml @@ -27,6 +27,6 @@ fmv.x.h: vs: always vu: always operation(): | - check_f_ok(); + check_f_ok($encoding); X[rd] = sext(f[fs1][15:0], 16); diff --git a/arch/inst/Zfh/fsh.yaml b/arch/inst/Zfh/fsh.yaml index f115a96621..1a9e974f23 100644 --- a/arch/inst/Zfh/fsh.yaml +++ b/arch/inst/Zfh/fsh.yaml @@ -30,7 +30,7 @@ fsh: vs: always vu: always operation(): | - check_f_ok(); + check_f_ok($encoding); XReg virtual_address = X[rs1] + $signed(imm); diff --git a/arch/isa/builtin_functions.idl b/arch/isa/builtin_functions.idl index 1af7555666..0769847528 100644 --- a/arch/isa/builtin_functions.idl +++ b/arch/isa/builtin_functions.idl @@ -227,93 +227,6 @@ builtin function prefetch_write { } } -# TODO: REMOVE THESE AFTER MERGE WITH FP BRANCH! -builtin function check_f_ok { - description { REmove me. } -} -builtin function mark_f_state_dirty { - description { Remove me. } -} - -# TODO: move this *fixed* function to fp.idl -function nan_box { - template U32 FROM_SIZE, U32 TO_SIZE - returns Bits - arguments Bits from_value - description { - Produces a properly NaN-boxed floating-point value from a floating-point value - of smaller size by adding all 1's to the upper bits. - } - body { - assert(FROM_SIZE < TO_SIZE, "Bad template arugments; FROM_SIZE must be less than TO_SIZE"); - - return {{TO_SIZE - FROM_SIZE{1'b1}}, from_value}; - } -} -Bits<32> SP_POS_INF = 32'b0_11111111_00000000000000000000000; -Bits<32> SP_NEG_INF = 32'b1_11111111_00000000000000000000000; -Bits<32> SP_POS_ZERO = 32'b0_00000000_00000000000000000000000; -Bits<32> SP_NEG_ZERO = 32'b1_00000000_00000000000000000000000; -Bits<32> SP_CANONICAL_NAN = 32'b0_11111111_10000000000000000000000; -Bits<16> HP_CANONICAL_NAN = 16'b0_11111_1000000000; -Bits<32> WORD_NEG_OVERFLOW = 32'h8000_0000; # minimum 32-bit integer -Bits<32> WORD_POS_OVERFLOW = 32'h7FFF_FFFF; # maximum 32-bit integer -enum FpFlag { - NX 0b00001 # Inexact - UF 0b00010 # Underflow - OF 0b00100 # Overflow - DZ 0b01000 # Divide by zero - NV 0b10000 # Invalid Operation -} -builtin function set_fp_flag { - arguments - FpFlag f - description { Remove me. } -} -function packToF32UI { - returns Bits<32> - arguments - Bits<1> sign, - Bits<8> exp, - Bits<23> sig - description { - Pack components into a 32-bit value - } - body { - return {sign, exp, sig}; - } -} - -# TODO: THis needs to move to fp.idl -function packToF16UI { - returns Bits<32> - arguments - Bits<1> sign, - Bits<5> exp, - Bits<10> sig - description { - Pack components into a 16-bit value - } - body { - return {sign, exp, sig}; - } -} - -# TODO: This need to move to fp.idl -function softfloat_normSubnormalF16Sig { - returns Bits<5>, Bits<10> - arguments - Bits<16> hp_value - description { - normalize subnormal half-precision value - } - body { - Bits<8> shift_dist = count_leading_zeros<16>(hp_value); - return {1 - shift_dist, hp_value << shift_dist}; - } -} - - builtin function fence { arguments Boolean pi, Boolean pr, Boolean po, Boolean pw, diff --git a/arch/isa/fp.idl b/arch/isa/fp.idl new file mode 100644 index 0000000000..6ddb70dd69 --- /dev/null +++ b/arch/isa/fp.idl @@ -0,0 +1,487 @@ +%version: 1.0 + +# Many functions in this file (and all prefixed with softfloat_*) are +# adapted from berkeley-softfloat-3 by John R. Hauser +# (https://github.com/ucb-bar/berkeley-softfloat-3) +# Files in berkely-softfloat-3 repository are licensed under BSD-3-clause. + +# floating point register file +U32 FLEN = 64; # implemented?(ExtensionName::D) ? 7'd64 : 7'd32; +Bits f[32] = [0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0]; + +# FP constants +Bits<32> SP_POS_INF = 32'b0_11111111_00000000000000000000000; +Bits<32> SP_NEG_INF = 32'b1_11111111_00000000000000000000000; +Bits<32> SP_POS_ZERO = 32'b0_00000000_00000000000000000000000; +Bits<32> SP_NEG_ZERO = 32'b1_00000000_00000000000000000000000; +Bits<32> SP_CANONICAL_NAN = 32'b0_11111111_10000000000000000000000; +Bits<16> HP_CANONICAL_NAN = 16'b0_11111_1000000000; + +Bits<32> WORD_NEG_OVERFLOW = 32'h8000_0000; # minimum 32-bit integer +Bits<32> WORD_POS_OVERFLOW = 32'h7FFF_FFFF; # maximum 32-bit integer + +enum RoundingMode { + RNE 0b000 # Round to Nearest, ties to Even + RTZ 0b001 # Round toward Zero + RDN 0b010 # Round Down (towards -∞) + RUP 0b011 # Round Up (towards +∞) + RMM 0b100 # Round to Nearest, ties to Max Magnitude + DYN 0b111 # Dynamic; use rm field in instruction +} + +enum FpFlag { + NX 0b00001 # Inexact + UF 0b00010 # Underflow + OF 0b00100 # Overflow + DZ 0b01000 # Divide by zero + NV 0b10000 # Invalid Operation +} + +function set_fp_flag { + arguments + FpFlag flag + description { + Add +flag+ to the sticky flags bits in CSR[fcsr] + } + body { + if (flag == FpFlag::NX) { + CSR[fcsr].NX = 1; + } else if (flag == FpFlag::UF) { + CSR[fcsr].UF = 1; + } else if (flag == FpFlag::OF) { + CSR[fcsr].OF = 1; + } else if (flag == FpFlag::DZ) { + CSR[fcsr].DZ = 1; + } else if (flag == FpFlag::NV) { + CSR[fcsr].NV = 1; + } + } +} + +function rm_to_mode { + returns RoundingMode + arguments + Bits<3> rm, # rm field from an instruction encoding + Bits<32> encoding # instruction encoding, needed to raise an exception + description { + Convert +rm+ to a RoundingMode. + + +encoding+ is the full encoding of the instruction +rm+ comes from. + + Will raise an IllegalInstruction exception if rm is a + reserved encoding. + } + body { + if (rm == $bits(RoundingMode::RNE)) { + return RoundingMode::RNE; + } else if (rm == $bits(RoundingMode::RTZ)) { + return RoundingMode::RTZ; + } else if (rm == $bits(RoundingMode::RDN)) { + return RoundingMode::RDN; + } else if (rm == $bits(RoundingMode::RUP)) { + return RoundingMode::RUP; + } else if (rm == $bits(RoundingMode::RMM)) { + return RoundingMode::RMM; + } else if (rm == $bits(RoundingMode::DYN)) { + return CSR[fcsr].FRM; + } else { + raise(ExceptionCode::IllegalInstruction, mode(), encoding); + } + } +} + +function mark_f_state_dirty { + description { + Potentially updates `mstatus.FS` to the Dirty (3) state, depending on configuration settings. + } + body { + if (HW_MSTATUS_FS_DIRTY_UPDATE== "precise") { + CSR[mstatus].FS = 3; # set dirty state + } else if (HW_MSTATUS_FS_DIRTY_UPDATE == "imprecise") { + unpredictable("The hart may or may not update mstatus.FS now"); + } + } +} + +function nan_box { + template U32 FROM_SIZE, U32 TO_SIZE + returns Bits + arguments Bits from_value + description { + Produces a properly NaN-boxed floating-point value from a floating-point value + of smaller size by adding all 1's to the upper bits. + } + body { + assert(FROM_SIZE < TO_SIZE, "Bad template arugments; FROM_SIZE must be less than TO_SIZE"); + + return {{TO_SIZE - FROM_SIZE{1'b1}}, from_value}; + } +} + +function check_f_ok { + arguments + Bits encoding + description { + Checks if instructions from the `F` extension can be executed, and, if not, + raise an exception. + } + body { + if (MUTABLE_MISA_F && CSR[misa].F == 0) { + raise(ExceptionCode::IllegalInstruction, mode(), encoding); + } + + if (CSR[mstatus].FS == 0) { + raise(ExceptionCode::IllegalInstruction, mode(), encoding); + } + } +} + +function is_sp_neg_inf? { + returns Boolean + arguments Bits<32> sp_value + description { + Return true if +sp_value+ is negative infinity. + } + body { + return sp_value == SP_NEG_INF; + } +} + +function is_sp_pos_inf? { + returns Boolean + arguments Bits<32> sp_value + description { + Return true if +sp_value+ is positive infinity. + } + body { + return sp_value == SP_POS_INF; + } +} + +function is_sp_neg_norm? { + returns Boolean + arguments Bits<32> sp_value + description { + Returns true if +sp_value+ is a negative normal number. + } + body { + return + (sp_value[31] == 1) # negative + && (sp_value[30:23] != 0b11111111) # not inf/NaN + && !( # not subnornmal + (sp_value[30:23] == 0b00000000) + && sp_value[22:0] != 0 + ); + } +} + +function is_sp_pos_norm? { + returns Boolean + arguments Bits<32> sp_value + description { + Returns true if +sp_value+ is a positive normal number. + } + body { + return + (sp_value[31] == 0) # positive + && (sp_value[30:23] != 0b11111111) # not inf/NaN + && !( # not subnornmal + (sp_value[30:23] == 0b00000000) + && sp_value[22:0] != 0 + ); + } +} + +function is_sp_neg_subnorm? { + returns Boolean + arguments Bits<32> sp_value + description { + Returns true if +sp_value+ is a negative subnormal number. + } + body { + return + (sp_value[31] == 1) # negative + && (sp_value[30:23] == 0) # subnormal exponent + && (sp_value[22:0] != 0); # not zero + } +} + +function is_sp_pos_subnorm? { + returns Boolean + arguments Bits<32> sp_value + description { + Returns true if +sp_value+ is a positive subnormal number. + } + body { + return + (sp_value[31] == 0) # positive + && (sp_value[30:23] == 0) # subnormal exponent + && (sp_value[22:0] != 0); # not zero + } +} + +function is_sp_neg_zero? { + returns Boolean + arguments Bits<32> sp_value + description { + Returns true if +sp_value+ is negative zero. + } + body { + return sp_value == SP_NEG_ZERO; + } +} + +function is_sp_pos_zero? { + returns Boolean + arguments Bits<32> sp_value + description { + Returns true if +sp_value+ is positive zero. + } + body { + return sp_value == SP_POS_ZERO; + } +} + +function is_sp_nan? { + returns Boolean + arguments Bits<32> sp_value + description { + Returns true if +sp_value+ is a NaN (quiet or signaling) + } + body { + return + (sp_value[30:23] == 0b11111111) + && (sp_value[22:0] != 0); # signaling bit + } +} + +function is_sp_signaling_nan? { + returns Boolean + arguments Bits<32> sp_value + description { + Returns true if +sp_value+ is a signaling NaN + } + body { + return + (sp_value[30:23] == 0b11111111) + && (sp_value[22] == 0) # signaling bit + && (sp_value[21:0] != 0); # not infinity + } +} + +function is_sp_quiet_nan? { + returns Boolean + arguments Bits<32> sp_value + description { + Returns true if +sp_value+ is a quiet NaN + } + body { + return + (sp_value[30:23] == 0b11111111) + && (sp_value[22] == 1); # signaling bit + } +} + +function softfloat_shiftRightJam32 { + returns Bits<32> + arguments + Bits<32> a, + Bits<32> dist + description { + Shifts +a+ right by the number of bits given in +dist+, which must not + be zero. If any nonzero bits are shifted off, they are "jammed" into the + least-significant bit of the shifted value by setting the least-significant + bit to 1. This shifted-and-jammed value is returned. + The value of +dist+ can be arbitrarily large. In particular, if +dist+ is + greater than 32, the result will be either 0 or 1, depending on whether +a+ + is zero or nonzero. + } + body { + return (dist < 31) ? a>>dist | (((a<<(-dist & 31)) != 0) ? 1 : 0) : ((a != 0) ? 1 : 0); + } +} + +function softfloat_shiftRightJam64 { + returns Bits<64> + arguments + Bits<64> a, + Bits<32> dist + description { + Shifts +a+ right by the number of bits given in +dist+, which must not + be zero. If any nonzero bits are shifted off, they are "jammed" into the + least-significant bit of the shifted value by setting the least-significant + bit to 1. This shifted-and-jammed value is returned. + + The value of 'dist' can be arbitrarily large. In particular, if +dist+ is + greater than 64, the result will be either 0 or 1, depending on whether +a+ + is zero or nonzero. + } + body { + return (dist < 63) ? a>>dist | (((a<<(-dist & 63)) != 0) ? 1 : 0) : ((a != 0) ? 1 : 0); + } +} + +function softfloat_roundToI32 { + returns Bits<32> + arguments + Bits<1> sign, + Bits<64> sig, + RoundingMode roundingMode + description { + Round to unsigned 32-bit integer, using +rounding_mode+ + } + 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) { + set_fp_flag(FpFlag::NV); + 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) < 0) != (sign == 1))) { + set_fp_flag(FpFlag::NV); + return sign == 1 ? WORD_NEG_OVERFLOW : WORD_POS_OVERFLOW; + } + + if (roundBits != 0) { + set_fp_flag(FpFlag::NX); + } + return z; + } +} + +function packToF32UI { + returns Bits<32> + arguments + Bits<1> sign, + Bits<8> exp, + Bits<23> sig + description { + Pack components into a 32-bit value + } + body { + return {sign, exp, sig}; + } +} + +function packToF16UI { + returns Bits<32> + arguments + Bits<1> sign, + Bits<5> exp, + Bits<10> sig + description { + Pack components into a 16-bit value + } + body { + return {sign, exp, sig}; + } +} + +function softfloat_normSubnormalF16Sig { + returns Bits<5>, Bits<10> + arguments + Bits<16> hp_value + description { + normalize subnormal half-precision value + } + body { + Bits<8> shift_dist = count_leading_zeros<16>(hp_value); + return {1 - shift_dist, hp_value << shift_dist}; + } +} + +function softfloat_normRoundPackToF32 { + 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 + } + 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(sign, exp, sig << shiftDist, mode); + } + } +} + +function softfloat_roundPackToF32 { + 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. + } + 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) < 0) { + Boolean isTiny = + ($signed(exp) < -8's1) || (sig + roundIncrement < 0x80000000); + sig = softfloat_shiftRightJam32( sig, -exp ); + exp = 0; + roundBits = sig & 0x7F; + if (isTiny && (roundBits != 0)) { + set_fp_flag(FpFlag::UF); + } + } else if (0xFD < $signed(exp) || (0x80000000 <= sig + roundIncrement)) { + set_fp_flag(FpFlag::OF); + set_fp_flag(FpFlag::NX); + return packToF32UI(sign, 0xFF, 0) - ((roundIncrement == 0) ? 1 : 0); + } + } + + sig = (sig + roundIncrement) >> 7; + if (roundBits != 0) { + set_fp_flag(FpFlag::NX); + } + sig = sig & ~((roundBits ^ 0x40) & ((mode == RoundingMode::RNE) ? 1 : 0)); + if ( sig == 0 ) { + exp = 0; + } + return packToF32UI(sign, exp, sig); + } +} diff --git a/arch/isa/globals.isa b/arch/isa/globals.isa index fb08d28059..88b789045c 100644 --- a/arch/isa/globals.isa +++ b/arch/isa/globals.isa @@ -2,6 +2,7 @@ include "builtin_functions.idl" include "util.idl" +include "fp.idl" # global state @@ -144,14 +145,6 @@ enum XRegWidth { # StoreAmoGuestPageFault 23 # } -enum RoundingMode { - RNE 0 # Round to nearest, ties to even - RTZ 1 # Round toward zero - RDN 2 # Round down (towards -inf) - RUP 3 # Round up (towards +inf) - RMM 4 # Round to nearest, ties to Max Magnitude -} - enum SatpMode { Bare 0 Sv32 1 @@ -225,14 +218,6 @@ bitfield (64) Sv39PageTableEntry { V 0 } -# floating point register file -# U32 FLEN = implemented?(ExtensionName::D) ? 7'd64 : 7'd32; -U32 FLEN = 7'd64; -Bits f[32] = [0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0]; - PrivilegeMode current_mode = PrivilegeMode::M; function mode { diff --git a/cfgs/generic_rv64/params.yaml b/cfgs/generic_rv64/params.yaml index 68a209e306..adb6ba7904 100644 --- a/cfgs/generic_rv64/params.yaml +++ b/cfgs/generic_rv64/params.yaml @@ -508,3 +508,4 @@ params: MSTATUS_FS_LEGAL_VALUES: [0,1,2,3] MSTATUS_FS_WRITEABLE: true MSTATUS_TVM_IMPLEMENTED: true + HW_MSTATUS_FS_DIRTY_UPDATE: precise diff --git a/lib/idl/ast.rb b/lib/idl/ast.rb index c8de487681..b6a50ddec8 100644 --- a/lib/idl/ast.rb +++ b/lib/idl/ast.rb @@ -3522,7 +3522,11 @@ def type_check(symtab) end when "!" unless exp.type(symtab).convertable_to?(:boolean) - type_error "#{exp.type(symtab)} does not support unary #{op} operator" + if exp.type(symtab).kind == :bits + type_error "#{exp.type(symtab)} does not support unary #{op} operator. Perhaps you want '#{exp.text_value} != 0'?" + else + type_error "#{exp.type(symtab)} does not support unary #{op} operator" + end end else internal_error "Unhandled op #{op}" @@ -4545,9 +4549,9 @@ def type_check(symtab) func_def_type = func_type(symtab) - type_error "Missing template arguments in call to #{@name}" if template? && func_def_type.template_names.empty? + type_error "Template arguments provided in call to non-template function #{@name}" if template? && func_def_type.template_names.empty? - type_error "Template arguments provided in call to non-template function #{@name}" if !template? && !func_def_type.template_names.empty? + type_error "Missing template arguments in call to #{@name}" if !template? && !func_def_type.template_names.empty? if template? num_targs = template_arg_nodes.size @@ -4880,6 +4884,8 @@ def arguments(symtab) @argument_nodes.each do |a| atype = a.type(symtab) + type_error "No type for #{a.text_value}" if atype.nil? + atype = atype.ref_type if atype.kind == :enum arglist << [atype, a.name] @@ -5440,7 +5446,14 @@ def type_check(symtab) level = symtab.levels if_cond.type_check(symtab) - type_error "'#{if_cond.text_value}' is not boolean" unless if_cond.type(symtab).convertable_to?(:boolean) + + unless if_cond.type(symtab).convertable_to?(:boolean) + if if_cond.type(symtab).kind == :bits + type_error "'#{if_cond.text_value}' is not boolean. Maybe you meant 'if ((#{if_cond.text_value}) != 0)'?" + else + type_error "'#{if_cond.text_value}' is not boolean" + end + end if_cond_value = nil value_try do