Skip to content

Commit

Permalink
Add initial (untested) implementation of some F instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
dhower-qc committed Aug 19, 2024
1 parent be96f79 commit 2e8f432
Show file tree
Hide file tree
Showing 25 changed files with 1,118 additions and 65 deletions.
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

0 comments on commit 2e8f432

Please sign in to comment.