// round_mult.sv
// Rounds a normalized mantissa

`include "round_modes.sv"

module round_mult (
    input  logic [22:0] mantissa_in,   // Input mantissa (no implicit bit)
    input  logic [9:0]  exponent_in,   // Input exponent
    input  logic        sign_in,
    input  logic        guard_bit,
    input  logic        sticky_bit,
    input  logic [2:0]  round,
    output logic [24:0] mantissa_out,  // Rounded mantissa (24bit + 1bit possible ovf)
    output logic [9:0]  exponent_out,
    output logic        inexact
);

    logic [23:0] mantissa_extended;
    logic [24:0] mantissa_rounded;

    // === modes
    task automatic IEEE_nearest_even();
        if (guard_bit && (sticky_bit || mantissa_extended[0])) begin
            mantissa_rounded = mantissa_extended + 1;
        end
    endtask

    task automatic IEEE_zero();
        mantissa_rounded = mantissa_extended;
    endtask

    task automatic IEEE_pinf();
        if (!sign_in && (guard_bit | sticky_bit)) begin
            mantissa_rounded = mantissa_extended + 1;
        end
    endtask

    task automatic IEEE_ninf();
        if (sign_in && (guard_bit | sticky_bit)) begin
            mantissa_rounded = mantissa_extended + 1;
        end
    endtask

    task automatic near_up();
        if (guard_bit) begin
            mantissa_rounded = mantissa_extended + 1;
        end
    endtask

    task automatic away_zero();
        if (guard_bit | sticky_bit) begin
            mantissa_rounded = mantissa_extended + 1;
        end
    endtask

    //
    // ==============================
    //
    always_comb begin
        // Concatenate implicit '1' at MSB
        mantissa_extended = {1'b1, mantissa_in};

        mantissa_rounded  = mantissa_extended;
        exponent_out      = exponent_in;
        inexact           = guard_bit | sticky_bit;

        case (round)
            default:               IEEE_nearest_even();
            RND_IEEE_NEAREST_EVEN: IEEE_nearest_even();
            RND_IEEE_ZERO:         IEEE_zero();
            RND_IEEE_PINF:         IEEE_pinf();
            RND_IEEE_NINF:         IEEE_ninf();
            RND_NEAR_UP:           near_up();
            RND_AWAY_ZERO:         away_zero();
        endcase

        // Post-rounding normalization (if overflow in mantissa)
        if (mantissa_rounded[24]) begin
            mantissa_out = mantissa_rounded;
        end else begin
            mantissa_out = {1'b0, mantissa_rounded[23:0]};
        end

        // Shift and increment exponent if overflowed to bit 24
        if (mantissa_rounded[24]) begin
            exponent_out = exponent_in + 1;
        end else begin
            exponent_out = exponent_in;
        end
    end

endmodule
