{#- Clock Gating Logic Template -#}
{#- Generates clock gating logic for power management -#}
{{ header | safe }}

`default_nettype none

module clock_gating #(
    parameter IDLE_THRESHOLD = {{ config.idle_threshold | default(1000) }}
) (
    input  wire  clk,
    input  wire  rst_n,
    
    // Control inputs
    input  wire  [2:0] current_state,
    input  wire  transaction_valid,
    input  wire  power_up_req,
    input  wire  power_save_mode,
    
    // Clock output
    output logic gated_clk
);

{% if (config.enable_clock_gating | default(false)) -%}
// Clock Gating Logic
logic clock_enable;
logic clock_enable_latched;
logic idle_counter_expired;
logic [15:0] idle_counter;

// Idle detection logic
always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        idle_counter <= 16'h0;
        idle_counter_expired <= 1'b0;
    end else begin
        if (transaction_valid || power_up_req) begin
            idle_counter <= 16'h0;
            idle_counter_expired <= 1'b0;
        end else if (idle_counter < IDLE_THRESHOLD) begin
            idle_counter <= idle_counter + 1'b1;
            idle_counter_expired <= 1'b0;
        end else begin
            idle_counter_expired <= 1'b1;
        end
    end
end

// Clock enable generation
always_comb begin
    case (current_state)
    {% for state in (config.supported_states | default(['D0'])) -%}
    {% set state_value = (state.value if (state is mapping and state.value is defined) else (state.get('value', state.get('name', 'D0')) if state is mapping else state)) -%}
    {% set state_name = (state.name if (state is mapping and state.name is defined) else (state.get('name', state.get('value', 'D0')) if state is mapping else state)) -%}
    {% if state_value == "D0" -%}
    {{ state_name }}: clock_enable = !idle_counter_expired || !power_save_mode;
    {% else -%}
    {{ state_name }}: clock_enable = 1'b0;
    {% endif %}
    {% endfor %}
        default: clock_enable = 1'b1;
    endcase
end

// Latch-based clock gating to prevent glitches
// This is synthesis-friendly and meets timing requirements
always_latch begin
    if (!clk) 
        clock_enable_latched <= clock_enable;
end

// Generate gated clock
assign gated_clk = clk & clock_enable_latched;

// Clock gating verification assertions
`ifdef ASSERTIONS_ON
// Ensure no glitches on gated clock
property no_clock_glitches;
    @(posedge clk) $stable(clock_enable_latched) |-> $stable(gated_clk);
endproperty
assert property (no_clock_glitches) else $error("Clock gating glitch detected");

// Ensure clock enable is stable during clock high phase
property clock_enable_stable;
    @(posedge clk) $rose(clk) |-> $stable(clock_enable_latched);
endproperty
assert property (clock_enable_stable) else $error("Clock enable unstable during clock high");
`endif

{% else -%}
// Clock gating disabled in configuration
assign gated_clk = clk;
{% endif %}

endmodule

`default_nettype wire
