//==============================================================================
// Status Register Region Handler
// Generated by PCILeech Firmware Generator
//
// This module handles the status register region (0x0100-0x01FF):
// - Performance counter access and management
// - Error status reporting and clearing
// - Device identification and runtime status
// - Read-only and read-write register handling
// - Performance monitoring and statistics
//==============================================================================

`include "../tlp_pkg.svh"
`include "../bar_layout_pkg.svh"

module region_status
    import tlp_pkg::*;
    import bar_layout_pkg::*;
#(
    parameter device_config_t DEVICE_CONFIG = DEFAULT_DEVICE_CONFIG,
    parameter bit ENABLE_PERFORMANCE_COUNTERS = 1'b1,
    parameter bit ENABLE_ERROR_LOGGING = 1'b1
) (
    // Clock and Reset
    input  logic                clk,
    input  logic                reset_n,
    
    // Request Interface from BAR Dispatcher
    input  logic                req_valid,
    input  logic [31:0]         req_addr,
    input  logic [31:0]         req_data,
    input  logic [3:0]          req_be,
    input  logic                req_write,
    input  tlp_header_t         req_header,
    output logic                req_ready,
    
    // Response Interface to BAR Dispatcher
    output logic                resp_valid,
    output logic [31:0]         resp_data,
    output logic                resp_error,
    input  logic                resp_ready,
    
    // Performance Counter Inputs
    input  logic                perf_read_increment,
    input  logic                perf_write_increment,
    input  logic                perf_completion_increment,
    input  logic                perf_error_increment,
    input  logic [15:0]         perf_latency_sample,
    input  logic                perf_latency_valid,
    
    // Error Status Inputs
    input  logic                error_address_fault,
    input  logic                error_tlp_malformed,
    input  logic                error_timeout,
    input  logic                error_parity,
    input  logic                error_completion,
    input  logic                error_unsupported,
    input  logic                error_dma_fault,
    
    // Control Inputs
    input  logic                ctrl_reset_counters,
    input  logic                ctrl_reset_errors,
    input  logic                ctrl_enable_logging,
    
    // Status Outputs
    output performance_counters_t perf_counters,
    output error_status_t       error_status,
    output logic [31:0]         uptime_seconds,
    output logic [31:0]         total_transactions
);

    // ========================================================================
    // Local Parameters and Register Map
    // ========================================================================
    
    // Register offsets within status region (byte addresses)
    localparam logic [7:0] REG_PCILEECH_STATUS    = 8'h00;  // PCILeech status
    localparam logic [7:0] REG_ERROR_STATUS       = 8'h04;  // Error status (W1C)
    localparam logic [7:0] REG_PERF_READ_COUNT    = 8'h08;  // Read operation count
    localparam logic [7:0] REG_PERF_WRITE_COUNT   = 8'h0C;  // Write operation count
    localparam logic [7:0] REG_PERF_COMPLETION    = 8'h10;  // Completion count
    localparam logic [7:0] REG_PERF_ERROR_COUNT   = 8'h14;  // Error count
    localparam logic [7:0] REG_PERF_DMA_READ      = 8'h18;  // DMA read bytes
    localparam logic [7:0] REG_PERF_DMA_WRITE     = 8'h1C;  // DMA write bytes
    localparam logic [7:0] REG_PERF_MAX_LATENCY   = 8'h20;  // Maximum latency
    localparam logic [7:0] REG_PERF_AVG_LATENCY   = 8'h24;  // Average latency
    localparam logic [7:0] REG_DEVICE_SIGNATURE   = 8'h28;  // Device signature
    localparam logic [7:0] REG_FIRMWARE_VERSION   = 8'h2C;  // Firmware version
    localparam logic [7:0] REG_UPTIME_SECONDS     = 8'h30;  // Uptime in seconds
    localparam logic [7:0] REG_TOTAL_TRANSACTIONS = 8'h34;  // Total transactions
    localparam logic [7:0] REG_LINK_STATUS        = 8'h38;  // Link status
    localparam logic [7:0] REG_POWER_STATUS       = 8'h3C;  // Power management
    localparam logic [7:0] REG_TEMPERATURE        = 8'h40;  // Temperature sensor
    localparam logic [7:0] REG_VOLTAGE            = 8'h44;  // Voltage monitor
    localparam logic [7:0] REG_CLOCK_FREQUENCY    = 8'h48;  // Clock frequency
    localparam logic [7:0] REG_BUILD_INFO         = 8'h4C;  // Build information

    // ========================================================================
    // Internal Signals and Registers
    // ========================================================================
    
    // State machine
    typedef enum logic [1:0] {
        STATUS_IDLE,
        STATUS_PROCESS,
        STATUS_RESPOND
    } status_state_t;
    
    status_state_t          current_state, next_state;
    
    // Performance counters
    performance_counters_t  perf_counters_reg;
    logic [31:0]            latency_accumulator;
    logic [15:0]            latency_sample_count;
    logic [15:0]            max_latency_reg;
    
    // Error status register
    error_status_t          error_status_reg;
    
    // Status and monitoring registers
    logic [31:0]            uptime_counter;
    logic [31:0]            uptime_seconds_reg;
    logic [31:0]            total_transactions_reg;
    logic [31:0]            link_status_reg;
    logic [31:0]            power_status_reg;
    logic [31:0]            temperature_reg;
    logic [31:0]            voltage_reg;
    logic [31:0]            clock_frequency_reg;
    
    // Request processing
    logic [31:0]            response_data;
    logic                   response_error;
    logic [7:0]             register_offset;
    logic                   valid_register_access;
    logic                   write_1_to_clear;

    // ========================================================================
    // State Machine
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            current_state <= STATUS_IDLE;
        end else begin
            current_state <= next_state;
        end
    end
    
    always_comb begin
        next_state = current_state;
        req_ready = 1'b0;
        
        unique case (current_state)
            STATUS_IDLE: begin
                req_ready = 1'b1;
                if (req_valid) begin
                    next_state = STATUS_PROCESS;
                end
            end
            
            STATUS_PROCESS: begin
                next_state = STATUS_RESPOND;
            end
            
            STATUS_RESPOND: begin
                if (resp_ready) begin
                    next_state = STATUS_IDLE;
                end
            end
        endcase
    end

    // ========================================================================
    // Address Decoding and Register Access
    // ========================================================================
    
    always_comb begin
        register_offset = req_addr[7:0];
        valid_register_access = (req_addr[31:8] == 24'h000000) && 
                               (register_offset < STATUS_REG_SIZE[7:0]);
        write_1_to_clear = (register_offset == REG_ERROR_STATUS) && req_write;
    end
    
    // Register read logic
    always_comb begin
        response_data = 32'h00000000;
        response_error = !valid_register_access;
        
        if (valid_register_access && !req_write) begin
            unique case (register_offset & 8'hFC) // Word-aligned access
                REG_PCILEECH_STATUS: begin
                    response_data = {
                        16'h0000,                           // Reserved
                        error_status_reg.dma_error,         // [15] DMA error
                        error_status_reg.malformed_tlp,     // [14] Malformed TLP
                        error_status_reg.completion_error,  // [13] Completion error
                        error_status_reg.unsupported_request, // [12] Unsupported request
                        error_status_reg.parity_error,      // [11] Parity error
                        error_status_reg.timeout_error,     // [10] Timeout error
                        error_status_reg.tlp_error,         // [9] TLP error
                        error_status_reg.address_error,     // [8] Address error
                        error_status_reg.error_count        // [7:0] Error count
                    };
                end
                REG_ERROR_STATUS: begin
                    response_data = error_status_reg;
                end
                REG_PERF_READ_COUNT: begin
                    response_data = perf_counters_reg.read_count;
                end
                REG_PERF_WRITE_COUNT: begin
                    response_data = perf_counters_reg.write_count;
                end
                REG_PERF_COMPLETION: begin
                    response_data = perf_counters_reg.completion_count;
                end
                REG_PERF_ERROR_COUNT: begin
                    response_data = perf_counters_reg.error_count;
                end
                REG_PERF_DMA_READ: begin
                    response_data = perf_counters_reg.dma_read_bytes;
                end
                REG_PERF_DMA_WRITE: begin
                    response_data = perf_counters_reg.dma_write_bytes;
                end
                REG_PERF_MAX_LATENCY: begin
                    response_data = {16'h0000, perf_counters_reg.max_latency_cycles};
                end
                REG_PERF_AVG_LATENCY: begin
                    response_data = {16'h0000, perf_counters_reg.avg_latency_cycles};
                end
                REG_DEVICE_SIGNATURE: begin
                    response_data = DEVICE_CONFIG.device_signature;
                end
                REG_FIRMWARE_VERSION: begin
                    response_data = DEVICE_CONFIG.firmware_version;
                end
                REG_UPTIME_SECONDS: begin
                    response_data = uptime_seconds_reg;
                end
                REG_TOTAL_TRANSACTIONS: begin
                    response_data = total_transactions_reg;
                end
                REG_LINK_STATUS: begin
                    response_data = link_status_reg;
                end
                REG_POWER_STATUS: begin
                    response_data = power_status_reg;
                end
                REG_TEMPERATURE: begin
                    response_data = temperature_reg;
                end
                REG_VOLTAGE: begin
                    response_data = voltage_reg;
                end
                REG_CLOCK_FREQUENCY: begin
                    response_data = clock_frequency_reg;
                end
                REG_BUILD_INFO: begin
                    response_data = {
                        DEVICE_CONFIG.vendor_id,           // [31:16] Vendor ID
                        DEVICE_CONFIG.device_id             // [15:0] Device ID
                    };
                end
                default: begin
                    response_data = 32'h00000000;
                    response_error = 1'b1;
                end
            endcase
        end else if (valid_register_access && req_write) begin
            // Most status registers are read-only, except error status (W1C)
            response_error = !write_1_to_clear;
        end
    end

    // ========================================================================
    // Performance Counter Management
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            perf_counters_reg <= '0;
            latency_accumulator <= '0;
            latency_sample_count <= '0;
            max_latency_reg <= '0;
        end else if (ctrl_reset_counters) begin
            perf_counters_reg <= '0;
            latency_accumulator <= '0;
            latency_sample_count <= '0;
            max_latency_reg <= '0;
        end else if (ENABLE_PERFORMANCE_COUNTERS) begin
            // Increment counters based on input events
            if (perf_read_increment) begin
                perf_counters_reg.read_count <= perf_counters_reg.read_count + 1;
            end
            
            if (perf_write_increment) begin
                perf_counters_reg.write_count <= perf_counters_reg.write_count + 1;
            end
            
            if (perf_completion_increment) begin
                perf_counters_reg.completion_count <= perf_counters_reg.completion_count + 1;
            end
            
            if (perf_error_increment) begin
                perf_counters_reg.error_count <= perf_counters_reg.error_count + 1;
            end
            
            // Latency tracking
            if (perf_latency_valid) begin
                latency_accumulator <= latency_accumulator + perf_latency_sample;
                latency_sample_count <= latency_sample_count + 1;
                
                // Track maximum latency
                if (perf_latency_sample > max_latency_reg) begin
                    max_latency_reg <= perf_latency_sample;
                end
            end
            
            // Update computed latency values
            perf_counters_reg.max_latency_cycles <= max_latency_reg;
            if (latency_sample_count > 0) begin
                perf_counters_reg.avg_latency_cycles <= latency_accumulator / latency_sample_count;
            end
        end
    end

    // ========================================================================
    // Error Status Management
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            error_status_reg <= '0;
        end else if (ctrl_reset_errors) begin
            error_status_reg <= '0;
        end else begin
            // Set error bits based on input events
            if (error_address_fault) begin
                error_status_reg.address_error <= 1'b1;
                error_status_reg.error_count <= error_status_reg.error_count + 1;
            end
            
            if (error_tlp_malformed) begin
                error_status_reg.malformed_tlp <= 1'b1;
                error_status_reg.error_count <= error_status_reg.error_count + 1;
            end
            
            if (error_timeout) begin
                error_status_reg.timeout_error <= 1'b1;
                error_status_reg.error_count <= error_status_reg.error_count + 1;
            end
            
            if (error_parity) begin
                error_status_reg.parity_error <= 1'b1;
                error_status_reg.error_count <= error_status_reg.error_count + 1;
            end
            
            if (error_completion) begin
                error_status_reg.completion_error <= 1'b1;
                error_status_reg.error_count <= error_status_reg.error_count + 1;
            end
            
            if (error_unsupported) begin
                error_status_reg.unsupported_request <= 1'b1;
                error_status_reg.error_count <= error_status_reg.error_count + 1;
            end
            
            if (error_dma_fault) begin
                error_status_reg.dma_error <= 1'b1;
                error_status_reg.error_count <= error_status_reg.error_count + 1;
            end
            
            // Write-1-to-clear functionality for error status register
            if (write_1_to_clear && current_state == STATUS_PROCESS) begin
                if (req_be[0]) error_status_reg[7:0] <= error_status_reg[7:0] & ~req_data[7:0];
                if (req_be[1]) error_status_reg[15:8] <= error_status_reg[15:8] & ~req_data[15:8];
                if (req_be[2]) error_status_reg[23:16] <= error_status_reg[23:16] & ~req_data[23:16];
                if (req_be[3]) error_status_reg[31:24] <= error_status_reg[31:24] & ~req_data[31:24];
            end
        end
    end

    // ========================================================================
    // System Status Monitoring
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            uptime_counter <= '0;
            uptime_seconds_reg <= '0;
            total_transactions_reg <= '0;
            link_status_reg <= 32'h00000001; // Link up
            power_status_reg <= 32'h00000000;
            temperature_reg <= 32'h00000050; // 80°C in hex
            voltage_reg <= 32'h00000C80;     // 3.2V in mV
            clock_frequency_reg <= 32'h07735940; // 125MHz in Hz
        end else begin
            // Uptime counter (assuming 125MHz clock)
            if (uptime_counter < 32'd124_999_999) begin
                uptime_counter <= uptime_counter + 1;
            end else begin
                uptime_counter <= '0;
                uptime_seconds_reg <= uptime_seconds_reg + 1;
            end
            
            // Total transaction counter
            if (perf_read_increment || perf_write_increment) begin
                total_transactions_reg <= total_transactions_reg + 1;
            end
            
            // Simulate varying temperature (for demonstration)
            if (uptime_counter[19:0] == 20'h00000) begin
                temperature_reg <= temperature_reg + 1;
                if (temperature_reg > 32'h00000060) begin // Max 96°C
                    temperature_reg <= 32'h00000040; // Reset to 64°C
                end
            end
        end
    end

    // ========================================================================
    // Output Assignments
    // ========================================================================
    
    assign resp_valid = (current_state == STATUS_RESPOND);
    assign resp_data = response_data;
    assign resp_error = response_error;
    
    assign perf_counters = perf_counters_reg;
    assign error_status = error_status_reg;
    assign uptime_seconds = uptime_seconds_reg;
    assign total_transactions = total_transactions_reg;

    // ========================================================================
    // Simulation Support
    // ========================================================================
    
`ifdef SIMULATION
    // Performance counter logging
    always @(posedge clk) begin
        if (ENABLE_PERFORMANCE_COUNTERS) begin
            if (perf_read_increment) begin
                $display("[Status Region] Read counter incremented to %0d at time %0t",
                         perf_counters_reg.read_count + 1, $time);
            end
            if (perf_write_increment) begin
                $display("[Status Region] Write counter incremented to %0d at time %0t",
                         perf_counters_reg.write_count + 1, $time);
            end
        end
        
        if (ENABLE_ERROR_LOGGING) begin
            if (error_address_fault) begin
                $display("[Status Region] Address fault error detected at time %0t", $time);
            end
            if (error_tlp_malformed) begin
                $display("[Status Region] Malformed TLP error detected at time %0t", $time);
            end
        end
    end
    
    // Register access logging
    always @(posedge clk) begin
        if (current_state == STATUS_PROCESS && valid_register_access) begin
            $display("[Status Region] %s access to offset 0x%02X, data=0x%08X at time %0t",
                     req_write ? "WRITE" : "READ",
                     register_offset,
                     req_write ? req_data : response_data,
                     $time);
        end
    end
`endif

    // ========================================================================
    // Assertions for Design Verification
    // ========================================================================
    
`ifdef SIMULATION
    // Check counter overflow protection
    property counter_overflow_protection;
        @(posedge clk) disable iff (!reset_n)
        (perf_counters_reg.read_count == 32'hFFFFFFFF) |-> 
        ##1 (perf_counters_reg.read_count == 32'hFFFFFFFF);
    endproperty
    assert property (counter_overflow_protection) else 
        $error("Status Region: Counter overflow not handled properly");
    
    // Check error status write-1-to-clear
    property error_status_w1c;
        @(posedge clk) disable iff (!reset_n)
        (write_1_to_clear && req_data[0] && error_status_reg.address_error) |->
        ##1 !error_status_reg.address_error;
    endproperty
    assert property (error_status_w1c) else 
        $error("Status Region: Write-1-to-clear not working for error status");
    
    // Check response timing
    property response_timing;
        @(posedge clk) disable iff (!reset_n)
        (current_state == STATUS_RESPOND) |-> resp_valid;
    endproperty
    assert property (response_timing) else 
        $error("Status Region: Response not valid when expected");
`endif

endmodule