Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion arch/csr/fcsr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ fcsr:
length: 32
definedBy: F
fields:
RMODE:
FRM:
location: 7-5
description: |
Rounding modes are encoded as follows:
Expand Down
29 changes: 24 additions & 5 deletions arch/csr/mstatus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -323,14 +323,27 @@ mstatus:
FS:
location: 14-13
description: |
Floating point context status.
*Floating point context status*

When 0, floating point instructions (from F and D extensions) are disabled,
and cause `ILLEGAL INSTRUCTION` exceptions.
When a floating point register, or the fCSR register is written, FS obtains the value 3.
Values 1 and 2 are valid write values for software, but are not interpreted by hardware
other than to possibly enable a previously-disabled floating point unit.
type: RW-H

Software may write values 1, 2, or 3 into `mstatus.FS` to indicate the state is
Initial, Clean, or Dirty, respectively.

The hart may update `mstatus.FS` when floating point state is written.
If HW_MSTATUS_FS_DIRTY_UPDATE == "precise", then `mstatus.FS` is written with the value 3
exactly when floating point state (f register or `fcsr`) is written and no other time.
If HW_MSTATUS_FS_DIRTY_UPDATE == "imprecise", then `mstatus.FS` is written with the value 3
at unpredictable times by the hart.
If HW_MSTATUS_FS_DIRTY_UPDATE == "none", then the hart never writes `mstatus.FS`, other than
through software writes (_e.g._, via `csrrw`).
type(): |
if (!implemented?(ExtensionName::F) || (HW_MSTATUS_FS_DIRTY_UPDATE == "none")) {
return CsrFieldType::RW;
} else {
return CsrFieldType::RWH;
}
definedBy: F
reset_value: UNDEFINED_LEGAL
MPP:
Expand Down Expand Up @@ -509,3 +522,9 @@ mstatus:

type: RW-H
reset_value: UNDEFINED_LEGAL
sw_read(): |
if (implemented?(ExtensionName::F) && (HW_MSTATUS_FS_DIRTY_UPDATE == "imprecise")) {
unpredictable("The value of `mstatus.FS` is unpredictable");
} else {
return $bits(CSR[mstatus]);
}
16 changes: 15 additions & 1 deletion arch/ext/F.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,18 @@ F:
description: |
Indicates whether or not the `F` extension can be disabled with the `misa.F` bit.
schema:
type: boolean
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"]
71 changes: 71 additions & 0 deletions arch/inst/F/fclass.s.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# yaml-language-server: $schema=../../../schemas/inst_schema.json

fclass.s:
long_name: Single-precision floating-point classify
definedBy: F
assembly: rd, fs1
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.
|===
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
operation(): |
check_f_ok();

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;
}
49 changes: 49 additions & 0 deletions arch/inst/F/fcvt.s.w.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# yaml-language-server: $schema=../../../schemas/inst_schema.json

fcvt.s.w:
long_name: Convert signed 32-bit integer to single-precision float
definedBy: F
assembly: fd, xs1
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.

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
operation(): |
check_f_ok();

Bits<32> int_value = X[rs1];

Bits<1> sign = int_value[31];

RoundingMode rouding_mode = rm_to_mode(rm, $encoding);

if (! (int_value & 32'h7fff_ffff)) {
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();
79 changes: 79 additions & 0 deletions arch/inst/F/fcvt.w.s.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# 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
definedBy: F
assembly: rd, fs1
description: |
Converts a floating-point number in floating-point register _fs1_ to a signed 32-bit integer indicates
integer register _rd_.

For XLEN &gt;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 `-&infin;` ! `-2^31`
h! Output for out-of-range positive input ! `2^31 - 1`
h! Output for `+&infin;` 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.
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
operation(): |
check_f_ok();

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 );
}



43 changes: 43 additions & 0 deletions arch/inst/F/feq.s.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# yaml-language-server: $schema=../../../schemas/inst_schema.json

feq.s:
long_name: Single-precision floating-point equal
definedBy: F
assembly: rd, fs1, fs2
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.
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
operation(): |
check_f_ok();

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;
}
47 changes: 47 additions & 0 deletions arch/inst/F/fle.s.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# yaml-language-server: $schema=../../../schemas/inst_schema.json

fle.s:
long_name: Single-precision floating-point less than or equal
definedBy: F
assembly: rd, fs1, fs2
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.

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
operation(): |
check_f_ok();

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)) {
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 less than or equal to b if a is negative or both are zero
: ((sp_value_a == sp_value_b) || (sign_a != (sp_value_a < sp_value_b)));
X[rd] = a_lt_b ? 1 : 0;
}
Loading