From 634672670950074fac964e3efdb547ffcc67e886 Mon Sep 17 00:00:00 2001 From: Jiahan Xie Date: Tue, 4 Mar 2025 20:22:06 -0500 Subject: [PATCH] add divSqrtFN --- primitives/float/divSqrtFN.futil | 21 +++ primitives/float/divSqrtFN.sv | 138 ++++++++++++++++++ tests/correctness/hardfloat/divSqrtFN.expect | 14 ++ tests/correctness/hardfloat/divSqrtFN.futil | 40 +++++ .../hardfloat/divSqrtFN.futil.data | 26 ++++ 5 files changed, 239 insertions(+) create mode 100644 primitives/float/divSqrtFN.futil create mode 100644 primitives/float/divSqrtFN.sv create mode 100644 tests/correctness/hardfloat/divSqrtFN.expect create mode 100644 tests/correctness/hardfloat/divSqrtFN.futil create mode 100644 tests/correctness/hardfloat/divSqrtFN.futil.data diff --git a/primitives/float/divSqrtFN.futil b/primitives/float/divSqrtFN.futil new file mode 100644 index 000000000..320670f47 --- /dev/null +++ b/primitives/float/divSqrtFN.futil @@ -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 + ); +} + diff --git a/primitives/float/divSqrtFN.sv b/primitives/float/divSqrtFN.sv new file mode 100644 index 000000000..9150f8713 --- /dev/null +++ b/primitives/float/divSqrtFN.sv @@ -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__ */ diff --git a/tests/correctness/hardfloat/divSqrtFN.expect b/tests/correctness/hardfloat/divSqrtFN.expect new file mode 100644 index 000000000..2e588c9ab --- /dev/null +++ b/tests/correctness/hardfloat/divSqrtFN.expect @@ -0,0 +1,14 @@ +{ + "cycles": 32, + "memories": { + "mem_read_a": [ + 4.2 + ], + "mem_read_b": [ + 3.0 + ], + "mem_write": [ + 1.4 + ] + } +} diff --git a/tests/correctness/hardfloat/divSqrtFN.futil b/tests/correctness/hardfloat/divSqrtFN.futil new file mode 100644 index 000000000..da44d48a8 --- /dev/null +++ b/tests/correctness/hardfloat/divSqrtFN.futil @@ -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; + } + } +} diff --git a/tests/correctness/hardfloat/divSqrtFN.futil.data b/tests/correctness/hardfloat/divSqrtFN.futil.data new file mode 100644 index 000000000..987b1031a --- /dev/null +++ b/tests/correctness/hardfloat/divSqrtFN.futil.data @@ -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 + } + } +}