//==============================================================================
// Device Control Region Handler
// Generated by PCILeech Firmware Generator
//
// This module handles the device control region (0x0000-0x00FF):
// - PCILeech enable/disable control
// - Device configuration registers
// - Control register bit field management
// - Device identification and capabilities
// - Manufacturing variance simulation support
//==============================================================================

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

module region_device_ctrl
    import tlp_pkg::*;
    import bar_layout_pkg::*;
#(
    parameter device_config_t DEVICE_CONFIG = DEFAULT_DEVICE_CONFIG,
    parameter bit ENABLE_MANUFACTURING_VARIANCE = 1'b0
) (
    // 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,
    
    // PCILeech Control Outputs
    output logic                pcileech_enable,
    output logic [31:0]         pcileech_control,
    output logic [31:0]         device_capabilities,
    output logic [31:0]         device_status,
    
    // Configuration Interface
    input  logic                cfg_bus_master_enable,
    input  logic                cfg_memory_space_enable,
    input  logic                cfg_interrupt_disable,
    
    // Status Inputs
    input  logic [31:0]         error_status,
    input  logic [31:0]         performance_counter_0,
    input  logic [31:0]         performance_counter_1,
    
    // Debug and Monitoring
    output logic [7:0]          debug_register_access,
    output logic [31:0]         last_write_data,
    output logic [31:0]         last_write_addr
);

    // ========================================================================
    // Local Parameters and Register Map
    // ========================================================================
    
    // Register offsets within device control region (byte addresses)
    localparam logic [7:0] REG_DEVICE_ID        = 8'h00;  // Device identification
    localparam logic [7:0] REG_VENDOR_ID        = 8'h04;  // Vendor identification
    localparam logic [7:0] REG_DEVICE_CTRL      = 8'h08;  // Device control register
    localparam logic [7:0] REG_DEVICE_STATUS    = 8'h0C;  // Device status register
    localparam logic [7:0] REG_CAPABILITIES     = 8'h10;  // Device capabilities
    localparam logic [7:0] REG_PCILEECH_CTRL    = 8'h14;  // PCILeech control
    localparam logic [7:0] REG_PCILEECH_STATUS  = 8'h18;  // PCILeech status
    localparam logic [7:0] REG_FIRMWARE_VER     = 8'h1C;  // Firmware version
    localparam logic [7:0] REG_BUILD_TIMESTAMP  = 8'h20;  // Build timestamp
    localparam logic [7:0] REG_FEATURE_ENABLE   = 8'h24;  // Feature enable mask
    localparam logic [7:0] REG_DEBUG_CTRL       = 8'h28;  // Debug control
    localparam logic [7:0] REG_MANUFACTURING    = 8'h2C;  // Manufacturing data
    
    // Control register bit definitions
    typedef struct packed {
        logic [15:0] reserved;
        logic        reset_counters;      // [15] - Reset performance counters
        logic        reset_errors;        // [14] - Reset error status
        logic        enable_logging;      // [13] - Enable access logging
        logic        enable_interrupts;   // [12] - Enable interrupt generation
        logic        enable_dma;          // [11] - Enable DMA operations
        logic        enable_msix;         // [10] - Enable MSI-X interrupts
        logic        enable_perf_mon;     // [9]  - Enable performance monitoring
        logic        enable_error_inject; // [8]  - Enable error injection
        logic [7:0]  reserved_low;        // [7:0] - Reserved
    } device_ctrl_reg_t;
    
    typedef struct packed {
        logic [15:0] reserved;
        logic        dma_active;          // [15] - DMA operation in progress
        logic        interrupt_pending;   // [14] - Interrupt pending
        logic        error_detected;      // [13] - Error condition detected
        logic        perf_overflow;       // [12] - Performance counter overflow
        logic        config_valid;        // [11] - Configuration valid
        logic        link_up;             // [10] - PCIe link up
        logic        bus_master;          // [9]  - Bus master enabled
        logic        memory_space;        // [8]  - Memory space enabled
        logic [7:0]  device_state;        // [7:0] - Device state machine
    } device_status_reg_t;

    // ========================================================================
    // Internal Signals and Registers
    // ========================================================================
    
    // State machine
    typedef enum logic [1:0] {
        CTRL_IDLE,
        CTRL_PROCESS,
        CTRL_RESPOND
    } ctrl_state_t;
    
    ctrl_state_t            current_state, next_state;
    
    // Register storage
    device_ctrl_reg_t       device_ctrl_reg;
    device_status_reg_t     device_status_reg;
    logic [31:0]            pcileech_ctrl_reg;
    logic [31:0]            pcileech_status_reg;
    logic [31:0]            feature_enable_reg;
    logic [31:0]            debug_ctrl_reg;
    logic [31:0]            manufacturing_reg;
    
    // Request processing
    logic [31:0]            response_data;
    logic                   response_error;
    logic [7:0]             register_offset;
    logic                   valid_register_access;
    
    // Debug and monitoring
    logic [7:0]             debug_access_reg;
    logic [31:0]            last_write_data_reg;
    logic [31:0]            last_write_addr_reg;
    
    // Manufacturing variance (if enabled)
    logic [31:0]            variance_seed;
    logic [15:0]            variance_counter;

    // ========================================================================
    // State Machine
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            current_state <= CTRL_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)
            CTRL_IDLE: begin
                req_ready = 1'b1;
                if (req_valid) begin
                    next_state = CTRL_PROCESS;
                end
            end
            
            CTRL_PROCESS: begin
                next_state = CTRL_RESPOND;
            end
            
            CTRL_RESPOND: begin
                if (resp_ready) begin
                    next_state = CTRL_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 < DEVICE_CTRL_SIZE[7:0]);
    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_DEVICE_ID: begin
                    response_data = {DEVICE_CONFIG.device_id, DEVICE_CONFIG.vendor_id};
                end
                REG_VENDOR_ID: begin
                    response_data = {DEVICE_CONFIG.device_id, DEVICE_CONFIG.vendor_id};
                end
                REG_DEVICE_CTRL: begin
                    response_data = device_ctrl_reg;
                end
                REG_DEVICE_STATUS: begin
                    response_data = device_status_reg;
                end
                REG_CAPABILITIES: begin
                    response_data = {
                        16'h0000,                    // Reserved
                        ENABLE_MANUFACTURING_VARIANCE, // Manufacturing variance support
                        DEVICE_CONFIG.enable_simulation, // Simulation support
                        DEVICE_CONFIG.enable_perf_counters, // Performance counters
                        DEVICE_CONFIG.enable_error_injection, // Error injection
                        4'h0,                        // Reserved
                        NUM_MSIX[7:0]               // Number of MSI-X vectors
                    };
                end
                REG_PCILEECH_CTRL: begin
                    response_data = pcileech_ctrl_reg;
                end
                REG_PCILEECH_STATUS: begin
                    response_data = pcileech_status_reg;
                end
                REG_FIRMWARE_VER: begin
                    response_data = DEVICE_CONFIG.firmware_version;
                end
                REG_BUILD_TIMESTAMP: begin
                    // Generate pseudo-timestamp based on device signature
                    response_data = DEVICE_CONFIG.device_signature ^ 32'h20241217;
                end
                REG_FEATURE_ENABLE: begin
                    response_data = feature_enable_reg;
                end
                REG_DEBUG_CTRL: begin
                    response_data = debug_ctrl_reg;
                end
                REG_MANUFACTURING: begin
                    if (ENABLE_MANUFACTURING_VARIANCE) begin
                        response_data = manufacturing_reg;
                    end else begin
                        response_data = 32'hDEADBEEF;
                    end
                end
                default: begin
                    response_data = 32'h00000000;
                    response_error = 1'b1;
                end
            endcase
        end else if (valid_register_access && req_write) begin
            // Write operations don't return data, but we validate the access
            response_error = 1'b0;
        end
    end

    // ========================================================================
    // Register Write Logic
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            device_ctrl_reg <= '0;
            pcileech_ctrl_reg <= '0;
            feature_enable_reg <= 32'h00000001; // PCILeech enabled by default
            debug_ctrl_reg <= '0;
            manufacturing_reg <= DEVICE_CONFIG.device_signature;
            variance_seed <= DEVICE_CONFIG.device_signature;
            variance_counter <= '0;
        end else if (current_state == CTRL_PROCESS && req_write && valid_register_access) begin
            unique case (register_offset & 8'hFC)
                REG_DEVICE_CTRL: begin
                    // Write device control register with byte enables
                    if (req_be[0]) device_ctrl_reg[7:0] <= req_data[7:0];
                    if (req_be[1]) device_ctrl_reg[15:8] <= req_data[15:8];
                    if (req_be[2]) device_ctrl_reg[23:16] <= req_data[23:16];
                    if (req_be[3]) device_ctrl_reg[31:24] <= req_data[31:24];
                end
                REG_PCILEECH_CTRL: begin
                    if (req_be[0]) pcileech_ctrl_reg[7:0] <= req_data[7:0];
                    if (req_be[1]) pcileech_ctrl_reg[15:8] <= req_data[15:8];
                    if (req_be[2]) pcileech_ctrl_reg[23:16] <= req_data[23:16];
                    if (req_be[3]) pcileech_ctrl_reg[31:24] <= req_data[31:24];
                end
                REG_FEATURE_ENABLE: begin
                    if (req_be[0]) feature_enable_reg[7:0] <= req_data[7:0];
                    if (req_be[1]) feature_enable_reg[15:8] <= req_data[15:8];
                    if (req_be[2]) feature_enable_reg[23:16] <= req_data[23:16];
                    if (req_be[3]) feature_enable_reg[31:24] <= req_data[31:24];
                end
                REG_DEBUG_CTRL: begin
                    if (req_be[0]) debug_ctrl_reg[7:0] <= req_data[7:0];
                    if (req_be[1]) debug_ctrl_reg[15:8] <= req_data[15:8];
                    if (req_be[2]) debug_ctrl_reg[23:16] <= req_data[23:16];
                    if (req_be[3]) debug_ctrl_reg[31:24] <= req_data[31:24];
                end
                REG_MANUFACTURING: begin
                    if (ENABLE_MANUFACTURING_VARIANCE) begin
                        if (req_be[0]) manufacturing_reg[7:0] <= req_data[7:0];
                        if (req_be[1]) manufacturing_reg[15:8] <= req_data[15:8];
                        if (req_be[2]) manufacturing_reg[23:16] <= req_data[23:16];
                        if (req_be[3]) manufacturing_reg[31:24] <= req_data[31:24];
                    end
                end
                default: begin
                    // Read-only or invalid registers - no action
                end
            endcase
        end
        
        // Manufacturing variance simulation
        if (ENABLE_MANUFACTURING_VARIANCE) begin
            variance_counter <= variance_counter + 1;
            if (variance_counter == 16'hFFFF) begin
                variance_seed <= {variance_seed[30:0], variance_seed[31] ^ variance_seed[21]};
                manufacturing_reg <= manufacturing_reg ^ variance_seed[15:0];
            end
        end
    end

    // ========================================================================
    // Status Register Updates
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            device_status_reg <= '0;
            pcileech_status_reg <= '0;
        end else begin
            // Update device status register
            device_status_reg.bus_master <= cfg_bus_master_enable;
            device_status_reg.memory_space <= cfg_memory_space_enable;
            device_status_reg.link_up <= 1'b1; // Assume link is always up
            device_status_reg.config_valid <= 1'b1;
            device_status_reg.error_detected <= |error_status;
            device_status_reg.perf_overflow <= performance_counter_0[31] | performance_counter_1[31];
            device_status_reg.interrupt_pending <= !cfg_interrupt_disable && device_ctrl_reg.enable_interrupts;
            
            // Update PCILeech status register
            pcileech_status_reg[0] <= feature_enable_reg[0]; // PCILeech enabled
            pcileech_status_reg[1] <= device_ctrl_reg.enable_dma;
            pcileech_status_reg[2] <= device_ctrl_reg.enable_msix;
            pcileech_status_reg[3] <= device_ctrl_reg.enable_perf_mon;
            pcileech_status_reg[31:4] <= 28'h0000000;
        end
    end

    // ========================================================================
    // Debug and Monitoring
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            debug_access_reg <= '0;
            last_write_data_reg <= '0;
            last_write_addr_reg <= '0;
        end else if (current_state == CTRL_PROCESS) begin
            debug_access_reg <= {req_write, register_offset[6:0]};
            if (req_write) begin
                last_write_data_reg <= req_data;
                last_write_addr_reg <= req_addr;
            end
        end
    end

    // ========================================================================
    // Output Assignments
    // ========================================================================
    
    assign resp_valid = (current_state == CTRL_RESPOND);
    assign resp_data = response_data;
    assign resp_error = response_error;
    
    assign pcileech_enable = feature_enable_reg[0];
    assign pcileech_control = pcileech_ctrl_reg;
    assign device_capabilities = {
        16'h0000,
        ENABLE_MANUFACTURING_VARIANCE,
        DEVICE_CONFIG.enable_simulation,
        DEVICE_CONFIG.enable_perf_counters,
        DEVICE_CONFIG.enable_error_injection,
        4'h0,
        NUM_MSIX[7:0]
    };
    assign device_status = device_status_reg;
    
    assign debug_register_access = debug_access_reg;
    assign last_write_data = last_write_data_reg;
    assign last_write_addr = last_write_addr_reg;

    // ========================================================================
    // Simulation Support
    // ========================================================================
    
`ifdef SIMULATION
    // Register access logging
    always @(posedge clk) begin
        if (current_state == CTRL_PROCESS && valid_register_access) begin
            $display("[Device Control] %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
        
        if (current_state == CTRL_PROCESS && !valid_register_access) begin
            $display("[Device Control] ERROR: Invalid access to address 0x%08X at time %0t",
                     req_addr, $time);
        end
    end
    
    // Register state monitoring
    always @(posedge clk) begin
        if (device_ctrl_reg.reset_counters) begin
            $display("[Device Control] Performance counters reset at time %0t", $time);
        end
        if (device_ctrl_reg.reset_errors) begin
            $display("[Device Control] Error status reset at time %0t", $time);
        end
    end
`endif

    // ========================================================================
    // Assertions for Design Verification
    // ========================================================================
    
`ifdef SIMULATION
    // Check register alignment
    property register_alignment;
        @(posedge clk) disable iff (!reset_n)
        req_valid |-> (req_addr[1:0] == 2'b00);
    endproperty
    assert property (register_alignment) else 
        $error("Device Control: Unaligned register access detected");
    
    // Check byte enable consistency
    property byte_enable_consistency;
        @(posedge clk) disable iff (!reset_n)
        req_valid && req_write |-> (req_be != 4'b0000);
    endproperty
    assert property (byte_enable_consistency) else 
        $error("Device Control: Invalid byte enables for write operation");
    
    // Check response timing
    property response_timing;
        @(posedge clk) disable iff (!reset_n)
        (current_state == CTRL_RESPOND) |-> resp_valid;
    endproperty
    assert property (response_timing) else 
        $error("Device Control: Response not valid when expected");
`endif

endmodule