{{ header | safe }}

{# Local safe variables for performance config flags to avoid UndefinedError when perf_config is omitted #}
{%- set enable_transaction_counters = perf_config.enable_transaction_counters if (perf_config is defined and perf_config.enable_transaction_counters is defined) else false -%}
{%- set enable_bandwidth_monitoring = perf_config.enable_bandwidth_monitoring if (perf_config is defined and perf_config.enable_bandwidth_monitoring is defined) else false -%}
{%- set enable_latency_tracking = perf_config.enable_latency_tracking if (perf_config is defined and perf_config.enable_latency_tracking is defined) else false -%}
{%- set enable_latency_measurement = perf_config.enable_latency_measurement if (perf_config is defined and perf_config.enable_latency_measurement is defined) else false -%}
{%- set enable_error_counting = perf_config.enable_error_counting if (perf_config is defined and perf_config.enable_error_counting is defined) else false -%}
{%- set enable_performance_grading = perf_config.enable_performance_grading if (perf_config is defined and perf_config.enable_performance_grading is defined) else false -%}
{%- set enable_perf_outputs = perf_config.enable_perf_outputs if (perf_config is defined and perf_config.enable_perf_outputs is defined) else false -%}
{%- set enable_error_rate_tracking = perf_config.enable_error_rate_tracking if (perf_config is defined and perf_config.enable_error_rate_tracking is defined) else false -%}

{% if enable_transaction_counters %}
// Transaction Counter Logic
reg [31:0] read_transaction_count;
reg [31:0] write_transaction_count;
reg [31:0] total_transaction_count;

// Increment counters on valid transactions
always @(posedge clk) begin
    if (rst) begin
        read_transaction_count <= 32'h0;
        write_transaction_count <= 32'h0;
        total_transaction_count <= 32'h0;
    end else begin
        if (bar_read_valid && bar_read_ready) begin
            read_transaction_count <= read_transaction_count + 1'b1;
            total_transaction_count <= total_transaction_count + 1'b1;
        end
        if (bar_write_valid && bar_write_ready) begin
            write_transaction_count <= write_transaction_count + 1'b1;
            total_transaction_count <= total_transaction_count + 1'b1;
        end
    end
end
{% else %}
// Transaction counters disabled
{% endif %}

{% if enable_bandwidth_monitoring %}
// Bandwidth Monitoring Logic
reg [31:0] bytes_read_count;
reg [31:0] bytes_written_count;
reg [31:0] bandwidth_sample_counter;
reg [31:0] current_bandwidth_mbps;

localparam BANDWIDTH_SAMPLE_PERIOD = {{ bandwidth_sample_period | default(100000) }}; // Sample period in cycles

always @(posedge clk) begin
    if (rst) begin
        bytes_read_count <= 32'h0;
        bytes_written_count <= 32'h0;
        bandwidth_sample_counter <= 32'h0;
        current_bandwidth_mbps <= 32'h0;
    end else begin
        // Count bytes transferred
        if (bar_read_valid && bar_read_ready) begin
            bytes_read_count <= bytes_read_count + {{ transfer_width | default(4) }}; // Transfer width in bytes
        end
        if (bar_write_valid && bar_write_ready) begin
            bytes_written_count <= bytes_written_count + {{ transfer_width | default(4) }}; // Transfer width in bytes
        end
        
        // Calculate bandwidth periodically
        bandwidth_sample_counter <= bandwidth_sample_counter + 1'b1;
        if (bandwidth_sample_counter >= BANDWIDTH_SAMPLE_PERIOD) begin
            bandwidth_sample_counter <= 32'h0;
            // Simple bandwidth calculation (bytes per sample period)
            current_bandwidth_mbps <= (bytes_read_count + bytes_written_count) >> {{ bandwidth_shift | default(10) }}; // Approximate MB/s
        end
    end
end
{% else %}
// Bandwidth monitoring disabled
{% endif %}

{% if enable_latency_measurement or enable_latency_tracking %}
// Latency Measurement Logic
reg [31:0] read_latency_accumulator;
reg [31:0] write_latency_accumulator;
reg [15:0] read_latency_samples;
reg [15:0] write_latency_samples;
reg [31:0] avg_read_latency;
reg [31:0] avg_write_latency;
reg [31:0] latency_start_time;
reg latency_measurement_active;

// Start latency measurement on request and end on completion
always @(posedge clk) begin
    if (rst) begin
        read_latency_accumulator <= 32'h0;
        write_latency_accumulator <= 32'h0;
        read_latency_samples <= 16'h0;
        write_latency_samples <= 16'h0;
        avg_read_latency <= 32'h0;
        avg_write_latency <= 32'h0;
        latency_start_time <= 32'h0;
        latency_measurement_active <= 1'b0;
    end else begin
        // Start latency measurement on request
        if ((bar_read_valid || bar_write_valid) && !latency_measurement_active) begin
            latency_start_time <= cycle_counter;
            latency_measurement_active <= 1'b1;
        end
        
        // End latency measurement on completion
        if (latency_measurement_active && (bar_read_ready || bar_write_ready)) begin
            if (bar_read_ready) begin
                read_latency_accumulator <= read_latency_accumulator + (cycle_counter - latency_start_time);
                read_latency_samples <= read_latency_samples + 1'b1;
                if (read_latency_samples > 0) begin
                    avg_read_latency <= read_latency_accumulator / read_latency_samples;
                end
            end
            if (bar_write_ready) begin
                write_latency_accumulator <= write_latency_accumulator + (cycle_counter - latency_start_time);
                write_latency_samples <= write_latency_samples + 1'b1;
                if (write_latency_samples > 0) begin
                    avg_write_latency <= write_latency_accumulator / write_latency_samples;
                end
            end
            latency_measurement_active <= 1'b0;
        end
    end
end

// Cycle counter for latency measurement
reg [31:0] cycle_counter;
always @(posedge clk) begin
    if (rst) begin
        cycle_counter <= 32'h0;
    end else begin
        cycle_counter <= cycle_counter + 1'b1;
    end
end
{% else %}
// Latency measurement disabled
{% endif %}

{% if enable_error_rate_tracking %}
// Error Rate Tracking Logic
reg [31:0] error_count;
reg [31:0] total_operations;
reg [31:0] error_rate_percent;

always @(posedge clk) begin
    if (rst) begin
        error_count <= 32'h0;
        total_operations <= 32'h0;
        error_rate_percent <= 32'h0;
    end else begin
        // Count total operations
        if (bar_read_valid || bar_write_valid) begin
            total_operations <= total_operations + 1'b1;
        end
        
        // Count errors (with proper signal checking)
        {% if error_signals_available %}
        if (bar_error || timeout_error || parity_error) begin
            error_count <= error_count + 1'b1;
        end
        {% else %}
        // Error signals not available - using generic error detection
        if (bar_read_valid && !bar_read_ready) begin
            error_count <= error_count + 1'b1; // Timeout-like behavior
        end
        {% endif %}
        
        // Calculate error rate percentage
        if (total_operations > {{ min_operations_for_error_rate | default(100) }}) begin
            error_rate_percent <= (error_count * 100) / total_operations;
        end
    end
end
{% else %}
// Error rate tracking disabled
{% endif %}

{% if device_type == "network" %}
// Network-specific Performance Counters
reg [31:0] packet_count;
reg [31:0] packet_drop_count;
reg [31:0] network_throughput_mbps;

always @(posedge clk) begin
    if (rst) begin
        packet_count <= 32'h0;
        packet_drop_count <= 32'h0;
        network_throughput_mbps <= 32'h0;
    end else begin
        {% if network_signals_available %}
        if (packet_valid && packet_ready) begin
            packet_count <= packet_count + 1'b1;
        end
        if (packet_drop) begin
            packet_drop_count <= packet_drop_count + 1'b1;
        end
        {% else %}
        // Use generic read/write signals for network counters
        if (bar_read_valid && bar_read_ready) begin
            packet_count <= packet_count + 1'b1;
        end
        if (bar_write_valid && !bar_write_ready) begin
            packet_drop_count <= packet_drop_count + 1'b1; // Approximation
        end
        {% endif %}
        // Calculate throughput based on packet size and rate
        network_throughput_mbps <= (packet_count * {{ avg_packet_size | default(1500) }}) >> 20; // Approximate Mbps
    end
end
{% elif device_type == "storage" %}
// Storage-specific Performance Counters
reg [31:0] io_operations_count;
reg [31:0] sectors_read;
reg [31:0] sectors_written;
reg [31:0] storage_iops;

always @(posedge clk) begin
    if (rst) begin
        io_operations_count <= 32'h0;
        sectors_read <= 32'h0;
        sectors_written <= 32'h0;
        storage_iops <= 32'h0;
    end else begin
        {% if storage_signals_available %}
        if (storage_read_valid || storage_write_valid) begin
            io_operations_count <= io_operations_count + 1'b1;
        end
        if (storage_read_valid) begin
            sectors_read <= sectors_read + sector_count;
        end
        if (storage_write_valid) begin
            sectors_written <= sectors_written + sector_count;
        end
        {% else %}
        // Use generic read/write signals for storage counters
        if (bar_read_valid || bar_write_valid) begin
            io_operations_count <= io_operations_count + 1'b1;
        end
        if (bar_read_valid) begin
            sectors_read <= sectors_read + 1'b1; // Approximate as 1 sector per operation
        end
        if (bar_write_valid) begin
            sectors_written <= sectors_written + 1'b1; // Approximate as 1 sector per operation
        end
        {% endif %}
        // Calculate IOPS (operations per second approximation)
        storage_iops <= io_operations_count; // Simplified calculation
    end
end
{% elif device_type == "graphics" %}
// Graphics-specific Performance Counters
reg [31:0] frame_count;
reg [31:0] pixel_count;
reg [31:0] gpu_utilization_percent;
reg [31:0] memory_bandwidth_utilization;

always @(posedge clk) begin
    if (rst) begin
        frame_count <= 32'h0;
        pixel_count <= 32'h0;
        gpu_utilization_percent <= 32'h0;
        memory_bandwidth_utilization <= 32'h0;
    end else begin
        {% if graphics_signals_available %}
        if (frame_complete) begin
            frame_count <= frame_count + 1'b1;
        end
        if (pixel_valid) begin
            pixel_count <= pixel_count + 1'b1;
        end
        // Calculate GPU utilization (simplified)
        gpu_utilization_percent <= (active_cycles * 100) / total_cycles;
        {% else %}
        // Use generic signals for graphics approximation
        if (bar_write_valid && bar_write_ready) begin
            frame_count <= frame_count + 1'b1; // Approximate frame completion
        end
        if (bar_read_valid || bar_write_valid) begin
            pixel_count <= pixel_count + 1'b1; // Approximate pixel operations
        end
        // Simplified GPU utilization based on transaction activity
        gpu_utilization_percent <= ((bar_read_valid || bar_write_valid) ? 32'd100 : 32'd0);
        {% endif %}
    end
end
{% else %}
// Generic device performance counters
reg [31:0] generic_operation_count;
reg [31:0] generic_data_transferred;

always @(posedge clk) begin
    if (rst) begin
        generic_operation_count <= 32'h0;
        generic_data_transferred <= 32'h0;
    end else begin
        {% if generic_signals_available %}
        if (operation_valid) begin
            generic_operation_count <= generic_operation_count + 1'b1;
            generic_data_transferred <= generic_data_transferred + data_size;
        end
        {% else %}
        // Use standard BAR signals for generic operation counting
        if (bar_read_valid || bar_write_valid) begin
            generic_operation_count <= generic_operation_count + 1'b1;
            generic_data_transferred <= generic_data_transferred + {{ transfer_width | default(4) }};
        end
        {% endif %}
    end
end
{% endif %}

// Performance Grading Logic
{% if enable_performance_grading %}
reg [7:0] performance_grade; // 0-100 performance score
reg [31:0] performance_factors;

always @(posedge clk) begin
    if (rst) begin
        performance_grade <= 8'h0;
        performance_factors <= 32'h0;
    end else begin
        // Calculate performance grade based on multiple factors
        performance_factors = 32'h0;
        
        {% if enable_transaction_counters %}
        // Factor in transaction rate
        if (total_transaction_count > {{ high_performance_threshold | default(1000) }}) begin
            performance_factors = performance_factors + 25;
        end else if (total_transaction_count > {{ medium_performance_threshold | default(100) }}) begin
            performance_factors = performance_factors + 15;
        end else begin
            performance_factors = performance_factors + 5;
        end
        {% endif %}
        
        {% if enable_bandwidth_monitoring %}
        // Factor in bandwidth utilization
        if (current_bandwidth_mbps > {{ high_bandwidth_threshold | default(100) }}) begin
            performance_factors = performance_factors + 25;
        end else if (current_bandwidth_mbps > {{ medium_bandwidth_threshold | default(50) }}) begin
            performance_factors = performance_factors + 15;
        end else begin
            performance_factors = performance_factors + 5;
        end
        {% endif %}
        
        {% if enable_latency_measurement or enable_latency_tracking %}
        // Factor in latency (lower is better)
        if (avg_read_latency < {{ low_latency_threshold | default(10) }}) begin
            performance_factors = performance_factors + 25;
        end else if (avg_read_latency < {{ medium_latency_threshold | default(50) }}) begin
            performance_factors = performance_factors + 15;
        end else begin
            performance_factors = performance_factors + 5;
        end
        {% endif %}
        
        {% if enable_error_rate_tracking %}
        // Factor in error rate (lower is better)
        if (error_rate_percent < {{ low_error_threshold | default(1) }}) begin
            performance_factors = performance_factors + 25;
        end else if (error_rate_percent < {{ medium_error_threshold | default(5) }}) begin
            performance_factors = performance_factors + 10;
        end else begin
            performance_factors = performance_factors + 0; // No points for high error rate
        end
        {% endif %}
        
        // Cap the performance grade at 100
        if (performance_factors > 100) begin
            performance_grade <= 8'd100;
        end else begin
            performance_grade <= performance_factors[7:0];
        end
    end
end
{% else %}
// Performance grading disabled
{% endif %}

// Performance Counter Outputs
{% if enable_perf_outputs %}
assign perf_read_transactions = read_transaction_count;
assign perf_write_transactions = write_transaction_count;
assign perf_total_transactions = total_transaction_count;
assign perf_bandwidth_mbps = current_bandwidth_mbps;
assign perf_avg_read_latency = avg_read_latency;
assign perf_avg_write_latency = avg_write_latency;
assign perf_error_rate = error_rate_percent;
assign perf_grade = performance_grade;
{% else %}
// Performance outputs disabled
{% endif %}