// Error Recovery Logic Template
// Handles recovery from detected errors based on configuration
{{ header | safe }}

`default_nettype none

module error_recovery #(
    parameter MAX_RETRY_COUNT = {{ error_config.max_retry_count | default(3) }}
) (
    input  wire  clk,
    input  wire  rst_n,
    
    // Error inputs
    input  wire  error_detected,
    input  wire  [7:0] error_type,
    
    // Recovery outputs
    output logic recovery_active,
    output logic recovery_complete,
    output logic [7:0] retry_count,
    output logic [31:0] recovery_timer
);

logic [7:0] recovery_state;

// Error type classification
logic is_recoverable_error;
logic is_fatal_error;

always_comb begin
    is_recoverable_error = 1'b0;
    is_fatal_error = 1'b0;
    
    {% for error in recoverable_errors %}
    {%- if error is string -%}
        {%- set error_value = error -%}
    {%- elif error is mapping -%}
        {%- set error_value = error.get('value', error.get('name', '0')) -%}
    {%- elif error is defined and error.value is defined -%}
        {%- set error_value = error.value -%}
    {%- else -%}
        {%- set error_value = '0' -%}
    {%- endif -%}
    if (error_type == {{ error_value }}) is_recoverable_error = 1'b1;
    {% endfor %}
    
    {% for error in fatal_errors %}
    {%- if error is string -%}
        {%- set error_value = error -%}
    {%- elif error is mapping -%}
        {%- set error_value = error.get('value', error.get('name', '0')) -%}
    {%- elif error is defined and error.value is defined -%}
        {%- set error_value = error.value -%}
    {%- else -%}
        {%- set error_value = '0' -%}
    {%- endif -%}
    if (error_type == {{ error_value }}) is_fatal_error = 1'b1;
    {% endfor %}
end

// Recovery state machine
typedef enum logic [2:0] {
    RECOVERY_IDLE     = 3'b000,
    RECOVERY_ANALYZE  = 3'b001,
    RECOVERY_RETRY    = 3'b010,
    RECOVERY_RESET    = 3'b011,
    RECOVERY_COMPLETE = 3'b100,
    RECOVERY_FAILED   = 3'b101
} recovery_state_t;

recovery_state_t current_recovery_state, next_recovery_state;

always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        current_recovery_state <= RECOVERY_IDLE;
        retry_count <= 8'h0;
        recovery_timer <= 32'h0;
    end else begin
        current_recovery_state <= next_recovery_state;
        
        case (current_recovery_state)
            RECOVERY_RETRY: begin
                if (recovery_timer < 32'd1000) begin
                    recovery_timer <= recovery_timer + 1'b1;
                end else begin
                    recovery_timer <= 32'h0;
                    retry_count <= retry_count + 1'b1;
                end
            end
            RECOVERY_COMPLETE, RECOVERY_FAILED: begin
                retry_count <= 8'h0;
                recovery_timer <= 32'h0;
            end
            default: begin
                if (recovery_timer < 32'hFFFFFFFF) begin
                    recovery_timer <= recovery_timer + 1'b1;
                end
            end
        endcase
    end
end

// Recovery state machine logic
always_comb begin
    next_recovery_state = current_recovery_state;
    recovery_active = 1'b0;
    recovery_complete = 1'b0;
    
    case (current_recovery_state)
        RECOVERY_IDLE: begin
            if (error_detected) begin
                next_recovery_state = RECOVERY_ANALYZE;
            end
        end
        
        RECOVERY_ANALYZE: begin
            recovery_active = 1'b1;
            if (is_fatal_error) begin
                next_recovery_state = RECOVERY_FAILED;
            end else if (is_recoverable_error) begin
                next_recovery_state = RECOVERY_RETRY;
            end else begin
                next_recovery_state = RECOVERY_COMPLETE;
            end
        end
        
        RECOVERY_RETRY: begin
            recovery_active = 1'b1;
            if (retry_count >= 8'd{{ error_config.max_retry_count | default(3) }}) begin
                next_recovery_state = RECOVERY_FAILED;
            end else if (recovery_timer >= 32'd1000) begin
                // Retry attempt complete, check if error persists
                if (!error_detected) begin
                    next_recovery_state = RECOVERY_COMPLETE;
                end
                // Stay in retry state for another attempt
            end
        end
        
        RECOVERY_RESET: begin
            recovery_active = 1'b1;
            if (recovery_timer >= 32'd10000) begin
                next_recovery_state = RECOVERY_COMPLETE;
            end
        end
        
        RECOVERY_COMPLETE: begin
            recovery_complete = 1'b1;
            next_recovery_state = RECOVERY_IDLE;
        end
        
        RECOVERY_FAILED: begin
            recovery_complete = 1'b1;
            // Stay in failed state until system reset
        end
        
        default: begin
            next_recovery_state = RECOVERY_IDLE;
        end
    endcase
end

// Error threshold checking
{% for error_type, threshold in error_thresholds.items() %}
logic [15:0] {{ error_type.name.lower() }}_count;
logic {{ error_type.name.lower() }}_threshold_exceeded;

always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        {%- if error_type is string -%}
            {%- set error_name = error_type.lower() -%}
            {%- set error_value = error_type -%}
        {%- elif error_type is mapping -%}
            {%- set error_name = error_type.get('name', 'error').lower() -%}
            {%- set error_value = error_type.get('value', error_type.get('name', '0')) -%}
        {%- elif error_type is defined and error_type.name is defined -%}
            {%- set error_name = error_type.name.lower() -%}
            {%- set error_value = error_type.value if error_type.value is defined else '0' -%}
        {%- else -%}
            {%- set error_name = 'error' -%}
            {%- set error_value = '0' -%}
        {%- endif -%}
        {{ error_name }}_count <= 16'h0;
    end else if (error_detected && (error_type == {{ error_value }})) begin
        if ({{ error_name }}_count < 16'hFFFF) begin
            {{ error_name }}_count <= {{ error_name }}_count + 1'b1;
        end
    end
end

assign {{ error_name }}_threshold_exceeded = ({{ error_name }}_count >= 16'd{{ threshold }});
{% endfor %}

endmodule

`default_nettype wire
