module fp_sqrt #( parameter WIDTH = 32, parameter INT_WIDTH = 16, parameter FRAC_WIDTH = 16 ) ( input logic clk, input logic reset, input logic go, input logic [WIDTH-1:0] in, output logic [WIDTH-1:0] out, output logic done ); // The algorithm requires an even number of bits to the left of the binary // point. Thus, if INT_WIDTH is odd, we extend the input to include the // implicit leading 0. localparam EXT_WIDTH = WIDTH + (INT_WIDTH & 1); localparam ITERATIONS = EXT_WIDTH+FRAC_WIDTH >> 1; logic [$clog2(ITERATIONS)-1:0] idx; logic [EXT_WIDTH-1:0] x, x_next; logic [EXT_WIDTH-1:0] quotient, quotient_next; logic [EXT_WIDTH+1:0] acc, acc_next; logic [EXT_WIDTH+1:0] tmp; logic start, running, finished; assign start = go && !running; /* verilator lint_off WIDTH */ assign finished = (ITERATIONS - 1) == idx && running; always_ff @(posedge clk) begin if (reset || finished) running <= 0; else if (start) running <= 1; else running <= running; end always_ff @(posedge clk) begin if (running) idx <= idx + 1; else idx <= 0; end always_comb begin tmp = acc - {quotient, 2'b01}; if (tmp[EXT_WIDTH+1]) begin // tmp is negative. {acc_next, x_next} = {acc[EXT_WIDTH-1:0], x, 2'b0}; // Append a 0 to the result. quotient_next = quotient << 1; end else begin // tmp is positive. {acc_next, x_next} = {tmp[EXT_WIDTH-1:0], x, 2'b0}; // Append a 1 to the result. quotient_next = {quotient[EXT_WIDTH-2:0], 1'b1}; end end always_ff @(posedge clk) begin if (start) begin quotient <= 0; {acc, x} <= {{EXT_WIDTH + (INT_WIDTH & 1){1'b0}}, in, 2'b0}; end else begin x <= x_next; acc <= acc_next; quotient <= quotient_next; end end always_ff @(posedge clk) begin if (finished) begin done <= 1; out <= quotient_next; end else if (reset) begin done <= 0; out <= 0; end else begin done <= 0; out <= out; end end endmodule module sqrt #( parameter WIDTH = 32 ) ( input logic clk, input logic go, input logic reset, input logic [WIDTH-1:0] in, output logic [WIDTH-1:0] out, output logic done ); fp_sqrt #( .WIDTH(WIDTH), .INT_WIDTH(WIDTH), .FRAC_WIDTH(0) ) comp ( .clk(clk), .done(done), .reset(reset), .go(go), .in(in), .out(out) ); // Simulation self test against unsynthesizable implementation. `ifdef VERILATOR logic [WIDTH-1:0] radicand; always_ff @(posedge clk) begin if (go) radicand <= in; else radicand <= radicand; end always @(posedge clk) begin if (done && out != $floor($sqrt(radicand))) $error( "\nsqrt: Computed and golden outputs do not match!\n", "input: %0d\n", radicand, /* verilator lint_off REALCVT */ "expected: %0d\n", $floor($sqrt(radicand)), "computed: %0d", out ); end `endif endmodule