Skip to content
Closed
Show file tree
Hide file tree
Changes from 12 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
3 changes: 3 additions & 0 deletions spec/std/isa/inst/F/fmul.s.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ access:
vu: always
data_independent_timing: true
operation(): |
check_f_ok($encoding);
RoundingMode mode = rm_to_mode(rm, $encoding);
f[fd] = f32_mul(f[fs1], f[fs2], mode);

# SPDX-SnippetBegin
# SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model <https://github.com/riscv/sail-riscv/blob/master/LICENCE>
Expand Down
183 changes: 182 additions & 1 deletion spec/std/isa/isa/fp.idl
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ function softfloat_shiftRightJam32 {
}
}


function softfloat_shiftRightJam64 {
returns Bits<64>
arguments
Expand Down Expand Up @@ -475,6 +476,19 @@ function softfloat_normSubnormalF16Sig {
}
}

function softfloat_normSubnormalF32Sig {
returns Bits<8>, Bits<23>
arguments
Bits<32> sp_value
description {
normalize subnormal single-precision value
}
body {
Bits<8> shift_dist = count_leading_zeros<32>(sp_value) - 8;
return 1 - shift_dist, sp_value << shift_dist;
}
}

function softfloat_roundPackToF32 {
returns Bits<32> # single precision value
arguments
Expand Down Expand Up @@ -759,7 +773,7 @@ function softfloat_addMagsF32 {

U32 sigZ = 0x20000000 + sigA + sigB;
if ( sigZ < 0x40000000 ) {
expZ = expZ - 1;
expZ = expZ `- 1'b1;
sigZ = sigZ << 1;
}
}
Expand Down Expand Up @@ -1236,3 +1250,170 @@ function round_f32_to_integral {
return i32_to_f32_no_flag(intermediate, mode);
}
}

function f32_mul {
returns U32
arguments
U32 a,
U32 b,
RoundingMode mode
description {
Returns product of 2 floating point numbers
}
body {
Bits<1> signA = signF32UI(a);
Bits<8> expA = expF32UI(a);
Bits<23> sigA = fracF32UI(a);
Bits<1> signB = signF32UI(b);
Bits<8> expB = expF32UI(b);
Bits<23> sigB = fracF32UI(b);

# declare a variable to store significand of product
U32 sigZ;

# declare a variable to store sign of product
Bits<1> signZ;

# declare a variable to store the exponent part of product
Bits<8> expZ;

# calculate sign of product
signZ = signA ^ signB;

U32 magBits;

if (expA == 0xFF) {
if ((sigA != 0) || ((expB == 0xFF) && (sigB != 0))) {
return softfloat_propagateNaNF32UI(a, b);
magBits = expB | sigB;
if (magBits == 0) {
set_fp_flag(FpFlag::NV);
return UI32_NAN;
} else {
return packToF32UI(signZ, 0xFF, 0);
}
}
}

if (expB == 0xFF) {
if (sigB != 0) {
return softfloat_propagateNaNF32UI(a, b);
}
magBits = expA | sigA;
if (magBits == 0) {
set_fp_flag(FpFlag::NV);
return UI32_NAN;
} else {
return packToF32UI(signZ, 0xFF, 0);
}
}

if (expA == 0) {
if (sigA == 0) {
return packToF32UI(signZ, 0, 0);
}
(expA, sigA) = softfloat_normSubnormalF32Sig(sigA);
}

if (expB == 0) {
if (sigB == 0) {
return packToF32UI(signZ, 0, 0);
}
(expB, sigB) = softfloat_normSubnormalF32Sig(sigB);
}

expZ = expA + expB - 0x7F;
sigA = (sigA | 0x00800000)<<7;
sigB = (sigB | 0x00800000)<<8;
sigZ = softfloat_shiftRightJam64(sigA `* sigB, 32);
if (sigZ < 0x40000000) {
expZ = expZ `- 1'b1;
sigZ = sigZ << 1;
}
return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
}
}

function f32_div {
returns U32
arguments
U32 a,
U32 b,
RoundingMode mode
description {
Returns quotient of 2 floating point numbers
}
body {
Bits<1> signA = signF32UI(a);
Bits<8> expA = expF32UI(a);
Bits<23> sigA = fracF32UI(a);
Bits<1> signB = signF32UI(b);
Bits<8> expB = expF32UI(b);
Bits<23> sigB = fracF32UI(b);
Bits<1> signZ = signA ^ signB;
Bits<8> expZ;
Bits<23> sigZ;

U64 sig64A;

if (expA == 0xFF) {
if (sigA != 0) {
return softfloat_propagateNaNF32UI(a, b);
}
if ((expB == 0xFF) && (sigB != 0)) {
return softfloat_propagateNaNF32UI(a, b);
}
if ((expB == 0xFF) && (sigB == 0)) {
set_fp_flag(FpFlag::NV);
return SP_CANONICAL_NAN;
}
return packToF32UI(signZ, 0xFF, 0);
}

if (expB == 0xFF) {
if (sigB != 0) {
return softfloat_propagateNaNF32UI(a, b);
}
return packToF32UI(signZ, 0, 0);
}

if (expB == 0) {
if (sigB == 0) {
if ((expA == 0) && (sigA == 0)) {
set_fp_flag(FpFlag::NV);
return SP_CANONICAL_NAN;
}
set_fp_flag(FpFlag::OF);
set_fp_flag(FpFlag::NX);
return packToF32UI(signZ, 0xFF, 0);
}
(expB, sigB) = softfloat_normSubnormalF32Sig(sigB);
}
if (expA == 0) {
if (sigA == 0) {
return packToF32UI(signZ, 0, 0);
}
(expA, sigA) = softfloat_normSubnormalF32Sig(sigA);
}

expZ = expA - expB + 0x7E;
sigA = (sigA | 0x800000);
sigB = (sigB | 0x800000);

if (sigA < sigB) {
expZ = expZ - 1;
sig64A = sigA `<< 31;
} else {
sig64A = sigA `<< 30;
}

sigZ = sig64A / sigB;
# Check if the lower 6 bits are zero, meaning the division was exact.
# This is used to determine if rounding/jamming is needed.
if (!(sigZ & 0x3F)) {
sigZ = sigZ | ((sigB `* sigZ) != sig64A);
}

return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
}
}
Loading