// Mixed-Precision Computing Unit — INT4/INT8/INT16 selectable
module mixed_precision #(
    parameter MAX_W = 16,
    parameter NUM_MODES = 3  // 0=INT4, 1=INT8, 2=INT16
)(
    input clk, rst_n, input en,
    input [1:0] prec_mode,  // 00=INT4, 01=INT8, 10=INT16
    input signed [MAX_W-1:0] a, b,
    input [1:0] prec_a, prec_b,  // Per-operand precision
    output reg signed [2*MAX_W-1:0] result,
    output reg r_valid,
    output reg [2:0] cycles_used
);
    reg signed [MAX_W-1:0] sa, sb;
    reg signed [2*MAX_W-1:0] mul_out;
    always_ff @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin result<='0; r_valid<=0; cycles_used<=0; sa<='0; sb<='0; mul_out<='0; end
        else if(en) begin
            // Mask operands based on precision
            case(prec_a)
              2'd00: sa <= {{(MAX_W-4){a[3]}}, a[3:0]};      // INT4 sign-extend
              2'd01: sa <= {{(MAX_W-8){a[7]}}, a[7:0]};      // INT8
              2'd10: sa <= a;                                   // INT16
              default: sa <= a;
            endcase
            case(prec_b)
              2'd00: sb <= {{(MAX_W-4){b[3]}}, b[3:0]};
              2'd01: sb <= {{(MAX_W-8){b[7]}}, b[7:0]};
              2'd10: sb <= b;
              default: sb <= b;
            endcase
            mul_out <= sa * sb;
            result <= mul_out;
            case(prec_mode)
              2'd00: cycles_used <= 1;  // INT4: fast
              2'd01: cycles_used <= 2;  // INT8: medium
              2'd10: cycles_used <= 3;  // INT16: full
            endcase
            r_valid <= 1;
        end else r_valid <= 0;
    end
endmodule

// Per-layer precision selector
module prec_selector #(parameter NLAYERS=50)(
    input clk, rst_n,
    input [$clog2(NLAYERS)-1:0] layer_id,
    input [7:0] sensitivity [0:NLAYERS-1],  // Per-layer sensitivity score
    output reg [1:0] weight_prec [0:NLAYERS-1],
    output reg [1:0] act_prec [0:NLAYERS-1],
    output reg [15:0] total_bits                       // Total bit budget
);
    integer li; reg [15:0] budget;
    always_ff @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin for(li=0;li<NLAYERS;li++) begin weight_prec[li]<=2'd10; act_prec[li]<=2'd01; end total_bits<=0; end
        else begin budget<=0;
            for(li=0;li<NLAYERS;li++) begin
                // Simple heuristic: high sensitivity → INT16, medium → INT8, low → INT4
                if(sensitivity[li]>192) begin weight_prec[li]<=2'd10; act_prec[li]<=2'd10; end
                else if(sensitivity[li]>64) begin weight_prec[li]<=2'd01; act_prec[li]<=2'd01; end
                else begin weight_prec[li]<=2'd00; act_prec[li]<=2'd01; end
                budget <= budget + (weight_prec[li]==0?4:weight_prec[li]==1?8:16);
            end
            total_bits <= budget;
        end
    end
endmodule