Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[Floating Point Support] Add std_divSqrtFN #2424

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
22 changes: 22 additions & 0 deletions primitives/float/divSqrtFN.futil
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
extern "divSqrtFN.sv" {
primitive std_divSqrtFN[
expWidth,
sigWidth,
numWidth
](
@clk clk: 1,
@reset reset: 1,
@go go: 1,
control: 1,
sqrtOp: 1,
@write_together(1) left: numWidth,
@write_together(1) right: numWidth,
roundingMode: 3
) -> (
out: numWidth,
exceptionFlags: 5,
@done done: 1
);
}


138 changes: 138 additions & 0 deletions primitives/float/divSqrtFN.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
`ifndef __DIVSQRTFN_V__
`define __DIVSQRTFN_V__

`include "HardFloat_consts.vi"

module std_divSqrtFN #(
parameter expWidth = 8,
parameter sigWidth = 24,
parameter numWidth = 32
) (
input clk,
input reset,
input go,
input [(`floatControlWidth - 1):0] control,
input sqrtOp,
input [(expWidth + sigWidth - 1):0] left,
input [(expWidth + sigWidth - 1):0] right,
input [2:0] roundingMode,
output logic [(expWidth + sigWidth - 1):0] out,
output logic [4:0] exceptionFlags,
output logic done
);

// Intermediate signals for recoded formats
wire [(expWidth + sigWidth):0] l_recoded, r_recoded;

// Convert inputs from IEEE-754 to recoded format
fNToRecFN #(expWidth, sigWidth) convert_l(
.in(left),
.out(l_recoded)
);

fNToRecFN #(expWidth, sigWidth) convert_r(
.in(right),
.out(r_recoded)
);

// Intermediate signals from `divSqrtRecFNToRaw_small`
wire inReady, outValid;
wire [2:0] roundingModeOut;
wire invalidExc, infiniteExc, out_isNaN, out_isInf, out_isZero, out_sign;
wire signed [(expWidth + 1):0] out_sExp;
wire [(sigWidth + 2):0] out_sig;

// Call HardFloat's `divSqrtRecFNToRaw_small` instead of `divSqrtRecFN_small` because the latter has signal duplicate declaration issue.
divSqrtRecFNToRaw_small #(expWidth, sigWidth) divSqrtRecFNToRaw (
.nReset(~reset),
.clock(clk),
.control(control),
.inReady(inReady),
.inValid(go),
.sqrtOp(sqrtOp),
.a(l_recoded),
.b(r_recoded),
.roundingMode(roundingMode),
.outValid(outValid),
.sqrtOpOut(), // Not connected
.roundingModeOut(roundingModeOut),
.invalidExc(invalidExc),
.infiniteExc(infiniteExc),
.out_isNaN(out_isNaN),
.out_isInf(out_isInf),
.out_isZero(out_isZero),
.out_sign(out_sign),
.out_sExp(out_sExp),
.out_sig(out_sig)
);

// Intermediate signals for rounded result
wire [(expWidth + sigWidth):0] res_recoded;

// Round the output using HardFloat's rounding module
roundRawFNToRecFN#(expWidth, sigWidth, 0)
roundRawOut (
control,
invalidExc,
infiniteExc,
out_isNaN,
out_isInf,
out_isZero,
out_sign,
out_sExp,
out_sig,
roundingModeOut,
res_recoded,
exceptionFlags
);

// Convert result back to IEEE754 format
wire [(expWidth + sigWidth - 1):0] res_std;
recFNToFN #(expWidth, sigWidth) convert_res(
.in(res_recoded),
.out(res_std)
);

logic done_buf[31:0]; // Extend pipeline buffer to 10 cycles
assign done = done_buf[31]; // Assert `done` only after 10 cycles

// Start execution
logic start;
assign start = go;

// Reset all pipeline registers on reset
always_ff @(posedge clk) begin
if (reset) begin
done_buf <= '{default: 0}; // Reset entire pipeline
end else if (start) begin
done_buf[0] <= 1; // Start first stage
end else begin
done_buf[0] <= 0; // Clear when not starting
end
end

// Shift `done_buf` through 32 cycles. According to the Berkeley Hardfloat documentation:
// > After some number of clock cycles, outValid is asserted true for exactly one clock cycle ...
// And after running real examples, this is 30 cycles; adding 2 more cycles to be more conservative.
always_ff @(posedge clk) begin
if (reset) begin
done_buf <= '{default: 0}; // Reset again
end else begin
for (int i = 1; i < 32; i++) begin
done_buf[i] <= done_buf[i-1]; // Shift pipeline correctly
end
end
end

// Store the computed output value
always_ff @(posedge clk) begin
if (reset) begin
out <= 0;
end else if (outValid) begin
out <= res_std;
end
end

endmodule

`endif /* __DIVSQRTFN_V__ */
14 changes: 14 additions & 0 deletions tests/correctness/hardfloat/divSqrtFN.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"cycles": 32,
"memories": {
"mem_read_a": [
4.2
],
"mem_read_b": [
3
],
"mem_write": [
1.4
]
}
}
40 changes: 40 additions & 0 deletions tests/correctness/hardfloat/divSqrtFN.futil
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import "primitives/core.futil";
import "primitives/memories/comb.futil";
import "primitives/float/divSqrtFN.futil";

component main(@go go: 1) -> (@done done: 1) {
cells {
@external mem_read_a = comb_mem_d1(32, 1, 1);
@external mem_read_b = comb_mem_d1(32, 1, 1);
@external mem_write = comb_mem_d1(32, 1, 1);
divFN0 = std_divSqrtFN(8, 24, 32);
}

wires {
group div_std_format {
mem_read_a.addr0 = 1'b0;
divFN0.left = mem_read_a.read_data;

mem_read_b.addr0 = 1'b0;
divFN0.right = mem_read_b.read_data;

divFN0.go = 1'b1;

divFN0.control = 1'b0;
divFN0.roundingMode = 3'b0;
divFN0.sqrtOp = 1'b0;

mem_write.addr0 = 1'b0;
mem_write.write_data = divFN0.out;
mem_write.write_en = 1'b1;

div_std_format[done] = (mem_write.done & divFN0.done) ? 1'd1;
}
}

control {
seq {
div_std_format;
}
}
}
27 changes: 27 additions & 0 deletions tests/correctness/hardfloat/divSqrtFN.futil.data
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"mem_read_a": {
"data": [4.2],
"format": {
"numeric_type": "ieee754_float",
"is_signed": true,
"width": 32
}
},
"mem_read_b": {
"data": [3.0],
"format": {
"numeric_type": "ieee754_float",
"is_signed": true,
"width": 32
}
},
"mem_write": {
"data": [1.4],
"format": {
"numeric_type": "ieee754_float",
"is_signed": true,
"width": 32
}
}
}