Skip to content

Commit

Permalink
add divSqrtFN
Browse files Browse the repository at this point in the history
  • Loading branch information
jiahanxie353 committed Mar 5, 2025
1 parent 0d14047 commit 6346726
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 0 deletions.
21 changes: 21 additions & 0 deletions primitives/float/divSqrtFN.futil
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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.0
],
"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;
}
}
}
26 changes: 26 additions & 0 deletions tests/correctness/hardfloat/divSqrtFN.futil.data
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"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
}
}
}

0 comments on commit 6346726

Please # to comment.