// fp_mult.sv
// Floating-Point Multiplier Core (IEEE-754 single precision)

module fp_mult (
    input  logic [31:0] a,       // input operand A
    input  logic [31:0] b,       // input operand B
    input  logic [2:0]  round,   // rounding mode
    output logic [31:0] z,       // result
    output logic [7:0]  status,  // status flags (placeholder)
    input  logic        clk,
    input  logic        rst
    /*
    // debug outputs
    output logic sign_res_,
    output logic [9:0]  exp_sum_,
    output logic [47:0] mant_prod_,
    output logic [22:0] mant_norm_,
    output logic [9:0]  exp_norm_,
    output logic guard_, sticky_,
    output logic [24:0] mant_post_rnd_,
    output logic [9:0]  exp_post_rnd_
   */
);

    // === STEP 0: Parse inputs
    logic sign_a, sign_b;
    logic [7:0] exp_a, exp_b;
    logic [23:0] mant_a, mant_b;  // includes hidden bit

    always_comb begin
        sign_a = a[31];
        sign_b = b[31];
        exp_a  = a[30:23];
        exp_b  = b[30:23];
        mant_a = (exp_a == 8'd0) ? {1'b0, a[22:0]} : {1'b1, a[22:0]};
        mant_b = (exp_b == 8'd0) ? {1'b0, b[22:0]} : {1'b1, b[22:0]};
        // ^ Add hiden leading '1' on normalized numbers
        // This will lead to always 24-bits mantissa internal representation
        // for multiplication
    end

    // === STEP 1: Floating point number sign calculation
    logic sign_res;
    assign sign_res = sign_a ^ sign_b;
    //assign sign_res_ = sign_res;	  // DEBUG

    // === STEP 2,3. Exponent addition, Exponent subtraction of bias
    logic [9:0]  exp_sum;
    always_comb begin
        exp_sum   = exp_a + exp_b - 127;  // apply bias
        //exp_sum_ = exp_sum;               // DEBUG
    end

    // === STEP 4: Mantissa multiplication (including leading ones)
    logic [47:0] mant_prod;
    always_comb begin
        mant_prod = mant_a * mant_b;
        //mant_prod_ = mant_prod;          // DEBUG
    end

    // === STEP 5: Truncation and normalization
    logic [22:0] mant_norm;
    logic [9:0]  exp_norm;
    logic        guard, sticky;

    normalize_mult norm_inst (
        .mantissa_in(mant_prod),
        .exponent_in(exp_sum),
        .mantissa_out(mant_norm),
        .exponent_out(exp_norm),
        .guard_bit(guard),
        .sticky_bit(sticky)
    );
    //assign mant_norm_ = mant_norm;        // DEBUG
    //assign exp_norm_ = exp_norm;          // DEBUG
    //assign guard_    = guard;             // DEBUG
    //assign sticky_   = sticky;            // DEBUG

    // === STEP 6: Pipeline stage
    // Ehhh... We dont do that here...

    // === STEP 7: Rounding
    logic [24:0] mant_post_rnd;
    logic [9:0]  exp_post_rnd;
    logic        inexact;

    round_mult round_inst (
        .mantissa_in(mant_norm),
        .exponent_in(exp_norm),
        .sign_in(sign_res),
        .guard_bit(guard),
        .sticky_bit(sticky),
        .round(round),
        .mantissa_out(mant_post_rnd),
        .exponent_out(exp_post_rnd),
        .inexact(inexact)
    );
    //assign mant_post_rnd_ = mant_post_rnd;        // DEBUG
    //assign exp_post_rnd_ = exp_post_rnd;          // DEBUG

    // === STEP 8: Exception handling
    // overflow / underflow:
    logic [31:0] z_calc;
    logic        ovf, unf;

    assign z_calc = {sign_res, exp_post_rnd[7:0], mant_post_rnd[22:0]};
    always_comb begin
        ovf = (exp_post_rnd > 10'd254);  // MAX normal exponent
        unf = (exp_post_rnd < 10'd1);    // MIN normal exponent
    end

    exception_mult exc_inst (
        .a(a),
        .b(b),
        .z_calc(z_calc),
        .ovf(ovf),
        .unf(unf),
        .inexact(inexact),
        .round(round),
        .z(z),
        .zero_f(status[0]),
        .inf_f(status[1]),
        .nan_f(status[2]),
        .tiny_f(status[3]),
        .huge_f(status[4]),
        .inexact_f(status[5])
    );
    
endmodule

