// =============================================================================
// q_recip.sv : Q7.25 signed reciprocal y = 1/d  (d > 0 expected)
// -----------------------------------------------------------------------------
// Algorithm: normalize d to [0.5, 1.0), seed Newton-Raphson, iterate 3x,
// denormalize. Pipeline: 5 cycles total from `start` pulse to `done` pulse.
//
// Widths are literal 32-bit / Q7.25 to avoid Quartus parameter-elaboration
// quirks (parameter-based for-loop bounds, replication counts, bit-selects).
// =============================================================================
`default_nettype none

module q_recip (
    input  wire                clk,
    input  wire                rst_n,
    input  wire                start,
    input  wire signed [31:0]  d,
    output reg  signed [31:0]  y,
    output reg                 done
);

    // ---- Constants in Q7.25 -----------------------------------------------
    // 48/17 = 2.82352941...  -> Q7.25 = round(2.82352941 * 2^25)
    // 32/17 = 1.88235294...  -> Q7.25
    // 2.0                    -> Q7.25 = 2 << 25
    localparam signed [31:0] C_48_17 = 32'sd94732479;
    localparam signed [31:0] C_32_17 = 32'sd63154986;
    localparam signed [31:0] C_TWO   = 32'sd67108864;

    // ---- Pipeline registers -----------------------------------------------
    reg signed [31:0]   d_norm_r;
    reg [5:0]           shift_r;
    reg                 dir_left_r;       // direction we shifted d when normalizing
    reg signed [31:0]   x_r;              // current NR estimate

    // ---- Stage 0 : compute |d| and find normalization shift ---------------
    wire signed [31:0] d_abs = d[31] ? -d : d;

    // Find leading-one position of d_abs.  Result `lead_pos` in [0..30].
    // For Q7.25, value 1.0 has bit 25 set.  Want d_norm with leading bit
    // at position 24 (i.e., d_norm in [0.5, 1.0) Q7.25).
    //   shift = 24 - lead_pos
    //   if lead_pos <= 24, shift left by  (24 - lead_pos)
    //   if lead_pos >  24, shift right by (lead_pos - 24)
    integer i;
    reg [5:0] lead_pos;
    always @* begin
        lead_pos = 6'd0;
        for (i = 0; i < 31; i = i + 1)
            if (d_abs[i]) lead_pos = i[5:0];
    end

    wire        shift_left  = (lead_pos <= 6'd24);
    wire [5:0]  shift_amt   = shift_left ? (6'd24 - lead_pos) : (lead_pos - 6'd24);
    wire signed [31:0] d_norm_w = shift_left ? (d_abs <<< shift_amt)
                                              : (d_abs >>> shift_amt);

    // ---- NR iteration combinational helpers -------------------------------
    // x_next = x * (2 - d_norm * x)
    wire signed [31:0] dx;       // d_norm * x_current
    wire signed [31:0] two_dx;   // 2 - d_norm*x
    wire signed [31:0] x_next;   // x * (2 - d_norm*x)

    q_mult   u_dx     (.a(d_norm_r), .b(x_r),    .p(dx));
    q_addsub u_two_dx (.sub(1'b1), .a(C_TWO),  .b(dx),     .y(two_dx));
    q_mult   u_xn     (.a(x_r),    .b(two_dx),  .p(x_next));

    // Seed: x0 = 48/17 - (32/17)*d_norm
    wire signed [31:0] seed_mul;
    wire signed [31:0] seed_val;
    q_mult   u_seed_m (.a(C_32_17), .b(d_norm_w), .p(seed_mul));
    q_addsub u_seed_a (.sub(1'b1),  .a(C_48_17),  .b(seed_mul), .y(seed_val));

    // ---- Pipeline FSM -----------------------------------------------------
    // s0: capture d, compute d_norm, seed x  (fires on start)
    // s1: NR iter 1
    // s2: NR iter 2
    // s3: NR iter 3
    // s4: denormalize, output
    reg [2:0] stage;
    reg       busy;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            stage      <= 3'd0;
            busy       <= 1'b0;
            done       <= 1'b0;
            d_norm_r   <= 32'd0;
            shift_r    <= 6'd0;
            dir_left_r <= 1'b0;
            x_r        <= 32'd0;
            y          <= 32'd0;
        end
        else begin
            done <= 1'b0;

            if (!busy && start) begin
                d_norm_r   <= d_norm_w;
                shift_r    <= shift_amt;
                dir_left_r <= shift_left;
                x_r        <= seed_val;
                stage      <= 3'd1;
                busy       <= 1'b1;
            end
            else if (busy) begin
                case (stage)
                    3'd1, 3'd2, 3'd3: begin
                        x_r   <= x_next;
                        stage <= stage + 3'd1;
                    end
                    3'd4: begin
                        // Denormalize: 1/d = x_final * 2^(shift_amt) if we
                        // shifted d left, or x_final / 2^(shift_amt) if right.
                        if (dir_left_r) begin
                            // Saturate on left-shift overflow.
                            if (x_r > (32'sh7FFFFFFF >>> shift_r))
                                y <= 32'sh7FFFFFFF;
                            else
                                y <= x_r <<< shift_r;
                        end
                        else
                            y <= x_r >>> shift_r;
                        done  <= 1'b1;
                        busy  <= 1'b0;
                        stage <= 3'd0;
                    end
                    default: begin
                        stage <= 3'd0;
                        busy  <= 1'b0;
                    end
                endcase
            end
        end
    end

endmodule

`default_nettype wire