// Convolution Fusion Engine — Fuses Conv+BN+ReLU
module conv_fusion #(parameter DW=16, QW=8, CH=16)(
    input clk, rst_n, input en,
    // Conv output (already computed)
    input signed [DW-1:0] conv_out, input conv_valid, input [7:0] ch_idx,
    // BatchNorm parameters (per-channel)
    input signed [DW-1:0] bn_gamma [0:CH-1], input signed [DW-1:0] bn_beta [0:CH-1],
    input signed [DW-1:0] bn_mean [0:CH-1], input signed [DW-1:0] bn_var [0:CH-1],
    // Fused scale/offset: y = gamma * (x - mean) / sqrt(var + eps) + beta
    // Pre-computed: scale = gamma / sqrt(var+eps), offset = beta - scale * mean
    input signed [DW-1:0] bn_scale [0:CH-1], input signed [DW-1:0] bn_offset [0:CH-1],
    // Activation
    input act_type, // 0=ReLU, 1=ReLU6, 2=SIGMOID(LUT)
    // Output
    output reg signed [DW-1:0] fused_out, output reg fused_valid
);
    reg signed [DW*2-1:0] bn_result;
    reg signed [DW-1:0] activated;
    always_ff @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin fused_out<='0; fused_valid<=0; bn_result<='0; activated<='0; end
        else if(en && conv_valid) begin
            // Stage 1: BatchNorm = scale * x + offset
            bn_result <= conv_out * bn_scale[ch_idx] + (bn_offset[ch_idx] <<< DW);
            // Stage 2: Activation
            case(act_type)
              0: activated <= (bn_result[DW*2-1]) ? '0 : bn_result[DW*2-1:DW]; // ReLU
              1: begin // ReLU6
                if(bn_result[DW*2-1]) activated <= '0;
                else if(bn_result[DW*2-1:DW] > 6) activated <= 6;
                else activated <= bn_result[DW*2-1:DW];
              end
              2: activated <= bn_result[DW*2-1:DW]; // SIGMOID placeholder (needs LUT)
              default: activated <= bn_result[DW*2-1:DW];
            endcase
            fused_out <= activated;
            fused_valid <= 1;
        end else fused_valid <= 0;
    end
endmodule

// Residual Add fusion: out = Conv2(BN2(ReLU(BN1(Conv1(x))))) + x
module residual_fusion #(parameter DW=16)(
    input clk, rst_n, input en,
    input signed [DW-1:0] shortcut, input signed [DW-1:0] main_path, input valid,
    output reg signed [DW-1:0] result, output reg r_valid
);
    always_ff @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin result<='0; r_valid<=0; end
        else if(en && valid) begin result<=shortcut+main_path; r_valid<=1; end
        else r_valid<=0;
    end
endmodule