{#- Enhanced PCILeech TLP 128-bit BAR Controller Template -#}
{{ header | safe }}

`default_nettype none

{% from "_helpers.j2" import safe_int, get_vendor_id, get_device_id %}
module pcileech_tlps128_bar_controller #(
    // BAR Configuration Parameters
    parameter BAR_APERTURE_SIZE = {{ bar_config.aperture_size | default(65536) }},
    parameter BAR_INDEX = {{ bar_config.bar_index | default(0) }},
    parameter BAR_TYPE = {{ bar_config.bar_type | default(0) }}, // 0=32-bit, 1=64-bit
    parameter BAR_PREFETCHABLE = {{ '1\'b1' if bar_config.prefetchable | default(false) else '1\'b0' }},
    
    // MSI-X Configuration
    parameter NUM_MSIX = {{ msix_config.num_vectors | default(4) }},
    parameter MSIX_TABLE_BIR = {{ msix_config.table_bir | default(0) }},
    parameter MSIX_TABLE_OFFSET = {{ (msix_config.table_offset | default(4096)) | sv_hex(32) }},
    parameter MSIX_PBA_BIR = {{ msix_config.pba_bir | default(0) }},
    parameter MSIX_PBA_OFFSET = {{ (msix_config.pba_offset | default(8192)) | sv_hex(32) }},
    
    // Address map compatibility (top-level wrapper expectations)
    // top 4 KB reserved for cfg space shadow, next-to-top 4 KB for custom regs
    // Provide safe defaults when not explicitly set in context
    parameter CONFIG_SHDW_HI  = {{ CONFIG_SHDW_HI | default("20'hFFFFF") }},
    parameter CUSTOM_WIN_BASE = {{ CUSTOM_WIN_BASE | default("20'hFFFFE") }},
    
    // Unmapped region default read value (configurable)
    parameter DEFAULT_UNMAPPED_VALUE = 32'h00000000,
    
    // PCILeech Memory Layout
    parameter DEVICE_CTRL_BASE = 32'h00000000,  // Device Control Region
    parameter DEVICE_CTRL_SIZE = 32'h00000100,  // 256 bytes
    parameter STATUS_REG_BASE = 32'h00000100,   // Status Registers
    parameter STATUS_REG_SIZE = 32'h00000100,   // 256 bytes
    parameter DATA_BUFFER_BASE = 32'h00000200,  // Data Buffer
    parameter DATA_BUFFER_SIZE = 32'h00000200,  // 512 bytes
    parameter CUSTOM_REGION_BASE = 32'h00000400, // Custom PIO Region
    parameter CUSTOM_REGION_SIZE = 32'h00000C00, // 3KB
    
    // Device-Specific Timing Parameters
    parameter READ_LATENCY = {{ timing_config.read_latency | default(4) }},
    parameter WRITE_LATENCY = {{ timing_config.write_latency | default(2) }},
    parameter BURST_LENGTH = {{ timing_config.burst_length | default(16) }},
    parameter INTER_BURST_GAP = {{ timing_config.inter_burst_gap | default(8) }},
    
    // Performance and Error Handling
    parameter ENABLE_PERFORMANCE_COUNTERS = {{ '1\'b1' if device_config.enable_perf_counters else '1\'b0' }},
    parameter TIMEOUT_CYCLES = {{ timing_config.timeout_cycles | default(1024) }}
) (
    // Clock and Reset
    input  logic                clk,
    input  logic                reset_n,
    
    // PCIe TLP 128-bit Interface
    input  logic                tlp_rx_valid,
    input  logic [127:0]        tlp_rx_data,
    input  logic                tlp_rx_sop,
    input  logic                tlp_rx_eop,
    input  logic [3:0]          tlp_rx_empty,
    input  logic                tlp_rx_err,
    output logic                tlp_rx_ready,
    
    output logic                tlp_tx_valid,
    output logic [127:0]        tlp_tx_data,
    output logic                tlp_tx_sop,
    output logic                tlp_tx_eop,
    output logic [3:0]          tlp_tx_empty,
    input  logic                tlp_tx_ready,
    output logic                tlp_tx_err,
    
    // BAR Access Interface
    input  logic [31:0]         bar_addr,
    input  logic [31:0]         bar_wr_data,
    input  logic [3:0]          bar_wr_be,
    input  logic                bar_wr_en,
    input  logic                bar_rd_en,
    output logic [31:0]         bar_rd_data,
    output logic                bar_rd_valid,
    
    // Configuration Space Interface
    input  logic                cfg_ext_read_received,
    input  logic                cfg_ext_write_received,
    input  logic [9:0]          cfg_ext_register_number,
    input  logic [3:0]          cfg_ext_function_number,
    input  logic [31:0]         cfg_ext_write_data,
    input  logic [3:0]          cfg_ext_write_byte_enable,
    output logic [31:0]         cfg_ext_read_data,
    output logic                cfg_ext_read_data_valid,
    
    // MSI-X Interrupt Interface
    output logic                msix_interrupt,
    output logic [10:0]         msix_vector,
    input  logic                msix_interrupt_ack,
    
    // --- Custom window hook (compatibility with basic controller) ---------
    output logic                custom_win_sel,
    output logic [11:0]         custom_win_addr,
    output logic [31:0]         custom_win_wdata,
    output logic [3:0]          custom_win_be,
    output logic                custom_win_we,
    output logic                custom_win_re,
    input  logic [31:0]         custom_win_rdata,
    
    // PCILeech Control Interface
    input  logic                pcileech_enable,
    input  logic [31:0]         pcileech_command,
    input  logic [63:0]         pcileech_address,
    input  logic [31:0]         pcileech_length,
    output logic [31:0]         pcileech_status,
    output logic                pcileech_ready,
    
    // DMA Interface
    output logic                dma_read_req,
    output logic [63:0]         dma_read_addr,
    output logic [31:0]         dma_read_len,
    input  logic                dma_read_ack,
    input  logic [127:0]        dma_read_data,
    input  logic                dma_read_valid,
    
    output logic                dma_write_req,
    output logic [63:0]         dma_write_addr,
    output logic [31:0]         dma_write_len,
    output logic [127:0]        dma_write_data,
    input  logic                dma_write_ack,
    
    // Status and Debug
    output logic [31:0]         error_status,
    output logic [31:0]         performance_counter_0,
    output logic [31:0]         performance_counter_1,
    output logic [7:0]          debug_state
);

    // ========================================================================
    // Local Parameters and Type Definitions
    // ========================================================================
    // Device signature constant, used in status/debug registers
    // Force into a sized SV hex literal to avoid malformed tokens
    localparam [31:0] DEVICE_SIGNATURE = {% if device_signature %}{{ device_signature | sv_hex(32) }}{% else %}32'hDEAD_BEEF{% endif %};
    
    // TLP Types
    localparam [4:0] TLP_MEM_READ_32    = 5'b00000;
    localparam [4:0] TLP_MEM_READ_64    = 5'b00001;
    localparam [4:0] TLP_MEM_WRITE_32   = 5'b01000;
    localparam [4:0] TLP_MEM_WRITE_64   = 5'b01001;
    localparam [4:0] TLP_COMPLETION     = 5'b01010;
    localparam [4:0] TLP_COMPLETION_DATA = 5'b01011;
    
    // PCILeech Command Opcodes
    localparam [7:0] PCILEECH_CMD_READ      = 8'h01;
    localparam [7:0] PCILEECH_CMD_WRITE     = 8'h02;
    localparam [7:0] PCILEECH_CMD_PROBE     = 8'h03;
    localparam [7:0] PCILEECH_CMD_WRITE_SCATTER = 8'h04;
    localparam [7:0] PCILEECH_CMD_READ_SCATTER  = 8'h05;
    localparam [7:0] PCILEECH_CMD_EXEC      = 8'h06;
    localparam [7:0] PCILEECH_CMD_STATUS    = 8'h07;
    
    // PCI Command Register Bit Fields
    localparam int CMD_REG_IO_SPACE_ENABLE     = 0;
    localparam int CMD_REG_MEMORY_SPACE_ENABLE = 1;
    localparam int CMD_REG_BUS_MASTER_ENABLE   = 2;
    localparam int CMD_REG_SPECIAL_CYCLE_EN    = 3;
    localparam int CMD_REG_MEM_WRITE_INV_EN    = 4;
    localparam int CMD_REG_VGA_PALETTE_SNOOP   = 5;
    localparam int CMD_REG_PARITY_ERR_RESP     = 6;
    localparam int CMD_REG_IDSEL_STEPPING      = 7;
    localparam int CMD_REG_SERR_ENABLE         = 8;
    localparam int CMD_REG_FAST_BACK2BACK_EN   = 9;
    localparam int CMD_REG_INTERRUPT_DISABLE   = 10;
    
    // PCI Command Register Reserved Fields
    localparam [4:0] CMD_REG_RESERVED_15_11    = 5'h00;  // Bits 15:11
    localparam [3:0] CMD_REG_RESERVED_9_6      = 4'h0;   // Bits 9:6
    localparam       CMD_REG_RESERVED_0        = 1'h0;   // Bit 0 (I/O Space Enable)
    
    // Memory Region Selectors
    typedef enum logic [3:0] {
        REGION_DEVICE_CTRL,
        REGION_STATUS_REG,
        REGION_DATA_BUFFER,
        REGION_CUSTOM_PIO,
        REGION_MSIX_TABLE,
        REGION_MSIX_PBA,
        REGION_CONFIG_SHADOW,
        REGION_GENERAL_MEM,
        REGION_INVALID
    } region_select_t;
    
    // State Machine States
    typedef enum logic [3:0] {
        STATE_IDLE,
        STATE_TLP_DECODE,
        STATE_ADDRESS_DECODE,
        STATE_READ_PROCESS,
        STATE_WRITE_PROCESS,
        STATE_COMPLETION_GEN,
        STATE_DMA_READ,
        STATE_DMA_WRITE,
        STATE_ERROR_HANDLE,
        STATE_PCILEECH_EXEC
    } controller_state_t;
    
    // ========================================================================
    // Internal Signal Declarations
    // ========================================================================
    
    // State Machine
    controller_state_t current_state, next_state;
    
    // TLP Parsing
    logic [127:0]       tlp_header;
    logic [4:0]         tlp_type;
    logic [2:0]         tlp_tc;
    logic               tlp_td, tlp_ep, tlp_attr, tlp_th;
    logic [9:0]         tlp_length;
    logic [15:0]        tlp_requester_id;
    logic [7:0]         tlp_tag;
    logic [3:0]         tlp_first_be, tlp_last_be;
    logic [63:0]        tlp_address;
    logic [127:0]       tlp_data;
    
    // Address Decoding
    region_select_t     target_region;
    logic [31:0]        region_offset;
    logic               address_valid;
    
    // Memory Regions
    (* ram_style = "block" *) logic [31:0] device_ctrl_mem [0:(DEVICE_CTRL_SIZE/4)-1];
    (* ram_style = "block" *) logic [31:0] status_reg_mem [0:(STATUS_REG_SIZE/4)-1];
    (* ram_style = "block" *) logic [31:0] data_buffer_mem [0:(DATA_BUFFER_SIZE/4)-1];
    (* ram_style = "block" *) logic [31:0] custom_region_mem [0:(CUSTOM_REGION_SIZE/4)-1];
    
    // PCILeech Control Registers
    logic [31:0]        pcileech_ctrl_reg;
    logic [31:0]        pcileech_stat_reg;
    logic [63:0]        pcileech_addr_reg;
    logic [31:0]        pcileech_len_reg;
    logic [31:0]        pcileech_data_reg;
    
    // Performance Counters
    logic [31:0]        perf_counter_0;
    logic [31:0]        perf_counter_1;
    logic [31:0]        read_count;
    logic [31:0]        write_count;
    logic [31:0]        error_count;
    
    // Timing Control
    logic [15:0]        timing_counter;
    logic [7:0]         burst_counter;
    logic               timing_active;
    logic               burst_in_progress;
    
    // Error Handling
    logic [31:0]        error_status_reg;
    logic               timeout_error;
    logic               address_error;
    logic               tlp_error;
    logic [15:0]        timeout_counter;
    
    // MSI-X Integration
    logic               msix_table_access;
    logic               msix_pba_access;
    logic [31:0]        msix_table_data;
    logic [31:0]        msix_pba_data;
    
    // Configuration Space Shadow
    logic               cfg_shadow_access;
    logic [31:0]        cfg_shadow_data;
    
    // Debug monitoring
    logic [31:0]        prev_pcileech_command;

    // --------------------------------------------------------------------
    // Default tie-offs for custom window interface (not used internally)
    // --------------------------------------------------------------------
    assign custom_win_sel   = 1'b0;
    assign custom_win_addr  = 12'h000;
    assign custom_win_wdata = 32'h0000_0000;
    assign custom_win_be    = 4'h0;
    assign custom_win_we    = 1'b0;
    assign custom_win_re    = 1'b0;
    
    // ========================================================================
    // Command Register Bit Extraction
    // ========================================================================
    
    // Extract command register bits from pcileech_command input
    logic cfg_bus_master_enable_dynamic;
    logic cfg_memory_space_enable_dynamic;
    logic cfg_interrupt_disable_dynamic;
    
    always_comb begin
        // Extract individual bits from pcileech_command (PCI command register format)
        cfg_bus_master_enable_dynamic = pcileech_command[2];     // Bit 2: Bus Master Enable
        cfg_memory_space_enable_dynamic = pcileech_command[1];   // Bit 1: Memory Space Enable
        cfg_interrupt_disable_dynamic = pcileech_command[10];    // Bit 10: Interrupt Disable
    end
    
    // ========================================================================
    // TLP Parsing and Decoding
    // ========================================================================
    
    // TLP Header Parsing
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            tlp_header <= '0;
            tlp_type <= '0;
            tlp_tc <= '0;
            tlp_td <= '0;
            tlp_ep <= '0;
            tlp_attr <= '0;
            tlp_th <= '0;
            tlp_length <= '0;
            tlp_requester_id <= '0;
            tlp_tag <= '0;
            tlp_first_be <= '0;
            tlp_last_be <= '0;
            tlp_address <= '0;
            tlp_data <= '0;
        end else if (tlp_rx_valid && tlp_rx_ready && tlp_rx_sop) begin
            tlp_header <= tlp_rx_data;
            
            // Parse TLP header fields
            tlp_type <= tlp_rx_data[127:123];
            tlp_tc <= tlp_rx_data[122:120];
            tlp_td <= tlp_rx_data[119];
            tlp_ep <= tlp_rx_data[118];
            tlp_attr <= tlp_rx_data[117];
            tlp_th <= tlp_rx_data[116];
            tlp_length <= tlp_rx_data[105:96];
            tlp_requester_id <= tlp_rx_data[95:80];
            tlp_tag <= tlp_rx_data[79:72];
            tlp_first_be <= tlp_rx_data[71:68];
            tlp_last_be <= tlp_rx_data[67:64];
            
            // Extract address based on TLP type
            if (tlp_rx_data[127:123] == TLP_MEM_READ_64 || tlp_rx_data[127:123] == TLP_MEM_WRITE_64) begin
                tlp_address <= {tlp_rx_data[63:32], tlp_rx_data[31:2], 2'b00};
            end else begin
                tlp_address <= {32'h00000000, tlp_rx_data[63:34], 2'b00};
            end
        end else if (tlp_rx_valid && tlp_rx_ready && !tlp_rx_sop) begin
            tlp_data <= tlp_rx_data;
        end
    end
    
    // ========================================================================
    // Address Decoding and Region Selection
    // ========================================================================
    
    always_comb begin
        target_region = REGION_INVALID;
        region_offset = '0;
        address_valid = 1'b0;
        
        if (tlp_address >= DEVICE_CTRL_BASE && 
            tlp_address < (DEVICE_CTRL_BASE + DEVICE_CTRL_SIZE)) begin
            target_region = REGION_DEVICE_CTRL;
            region_offset = tlp_address - DEVICE_CTRL_BASE;
            address_valid = 1'b1;
        end else if (tlp_address >= STATUS_REG_BASE && 
                     tlp_address < (STATUS_REG_BASE + STATUS_REG_SIZE)) begin
            target_region = REGION_STATUS_REG;
            region_offset = tlp_address - STATUS_REG_BASE;
            address_valid = 1'b1;
        end else if (tlp_address >= DATA_BUFFER_BASE && 
                     tlp_address < (DATA_BUFFER_BASE + DATA_BUFFER_SIZE)) begin
            target_region = REGION_DATA_BUFFER;
            region_offset = tlp_address - DATA_BUFFER_BASE;
            address_valid = 1'b1;
        end else if (tlp_address >= CUSTOM_REGION_BASE && 
                     tlp_address < (CUSTOM_REGION_BASE + CUSTOM_REGION_SIZE)) begin
            target_region = REGION_CUSTOM_PIO;
            region_offset = tlp_address - CUSTOM_REGION_BASE;
            address_valid = 1'b1;
        end else if (tlp_address >= MSIX_TABLE_OFFSET && 
                     tlp_address < (MSIX_TABLE_OFFSET + NUM_MSIX * 16)) begin
            target_region = REGION_MSIX_TABLE;
            region_offset = tlp_address - MSIX_TABLE_OFFSET;
            address_valid = 1'b1;
        end else if (tlp_address >= MSIX_PBA_OFFSET && 
                     tlp_address < (MSIX_PBA_OFFSET + ((NUM_MSIX + 31) / 32) * 4)) begin
            target_region = REGION_MSIX_PBA;
            region_offset = tlp_address - MSIX_PBA_OFFSET;
            address_valid = 1'b1;
        end else if (tlp_address < BAR_APERTURE_SIZE) begin
            target_region = REGION_GENERAL_MEM;
            region_offset = tlp_address;
            address_valid = 1'b1;
        end
    end
    
    // ========================================================================
    // Main Controller State Machine
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            current_state <= STATE_IDLE;
        end else begin
            current_state <= next_state;
        end
    end
    
    always_comb begin
        next_state = current_state;
        tlp_rx_ready = 1'b0;
        tlp_tx_valid = 1'b0;
        tlp_tx_data = '0;
        tlp_tx_sop = 1'b0;
        tlp_tx_eop = 1'b0;
        tlp_tx_empty = '0;
        tlp_tx_err = 1'b0;
        
        case (current_state)
            STATE_IDLE: begin
                tlp_rx_ready = 1'b1;
                if (tlp_rx_valid && tlp_rx_sop) begin
                    next_state = STATE_TLP_DECODE;
                end
            end
            
            STATE_TLP_DECODE: begin
                tlp_rx_ready = 1'b1;
                next_state = STATE_ADDRESS_DECODE;
            end
            
            STATE_ADDRESS_DECODE: begin
                if (address_valid) begin
                    if (tlp_type == TLP_MEM_READ_32 || tlp_type == TLP_MEM_READ_64) begin
                        next_state = STATE_READ_PROCESS;
                    end else if (tlp_type == TLP_MEM_WRITE_32 || tlp_type == TLP_MEM_WRITE_64) begin
                        next_state = STATE_WRITE_PROCESS;
                    end else begin
                        next_state = STATE_ERROR_HANDLE;
                    end
                end else begin
                    next_state = STATE_ERROR_HANDLE;
                end
            end
            
            STATE_READ_PROCESS: begin
                // Process read based on target region
                next_state = STATE_COMPLETION_GEN;
            end
            
            STATE_WRITE_PROCESS: begin
                tlp_rx_ready = 1'b1;
                if (tlp_rx_valid && tlp_rx_eop) begin
                    next_state = STATE_COMPLETION_GEN;
                end
            end
            
            STATE_COMPLETION_GEN: begin
                tlp_tx_valid = 1'b1;
                tlp_tx_sop = 1'b1;
                tlp_tx_eop = 1'b1;
                if (tlp_tx_ready) begin
                    next_state = STATE_IDLE;
                end
            end
            
            STATE_DMA_READ: begin
                // Handle DMA read operations
                if (dma_read_ack) begin
                    next_state = STATE_COMPLETION_GEN;
                end
            end
            
            STATE_DMA_WRITE: begin
                // Handle DMA write operations
                if (dma_write_ack) begin
                    next_state = STATE_COMPLETION_GEN;
                end
            end
            
            STATE_ERROR_HANDLE: begin
                // Generate error completion
                tlp_tx_valid = 1'b1;
                tlp_tx_sop = 1'b1;
                tlp_tx_eop = 1'b1;
                tlp_tx_err = 1'b1;
                if (tlp_tx_ready) begin
                    next_state = STATE_IDLE;
                end
            end
            
            STATE_PCILEECH_EXEC: begin
                // Execute PCILeech commands
                if (pcileech_ready) begin
                    next_state = STATE_COMPLETION_GEN;
                end
            end
        endcase
    end
    
    // ========================================================================
    // Memory Region Access Logic
    // ========================================================================
    
    // Device Control Region Access
    logic [31:0] device_ctrl_rdata;
    always_ff @(posedge clk) begin
        if (current_state == STATE_WRITE_PROCESS && target_region == REGION_DEVICE_CTRL) begin
            if (region_offset[31:2] < (DEVICE_CTRL_SIZE/4)) begin
                device_ctrl_mem[region_offset[31:2]] <= tlp_data[31:0];
            end
        end
    end
    
    always_comb begin
        device_ctrl_rdata = '0;
        if (target_region == REGION_DEVICE_CTRL && region_offset[31:2] < (DEVICE_CTRL_SIZE/4)) begin
            device_ctrl_rdata = device_ctrl_mem[region_offset[31:2]];
        end
    end
    
    // Status Register Region Access
    logic [31:0] status_reg_rdata;
    always_ff @(posedge clk) begin
        if (current_state == STATE_WRITE_PROCESS && target_region == REGION_STATUS_REG) begin
            if (region_offset[31:2] < (STATUS_REG_SIZE/4)) begin
                status_reg_mem[region_offset[31:2]] <= tlp_data[31:0];
            end
        end
    end
    
    always_comb begin
        status_reg_rdata = '0;
        if (target_region == REGION_STATUS_REG) begin
            case (region_offset[7:2])
                6'h00: status_reg_rdata = pcileech_stat_reg;
                6'h01: status_reg_rdata = error_status_reg;
                6'h02: status_reg_rdata = perf_counter_0;
                6'h03: status_reg_rdata = perf_counter_1;
                6'h04: status_reg_rdata = read_count;
                6'h05: status_reg_rdata = write_count;
                6'h06: status_reg_rdata = error_count;
                6'h07: status_reg_rdata = DEVICE_SIGNATURE;
                default: begin
                    if (region_offset[31:2] < (STATUS_REG_SIZE/4)) begin
                        status_reg_rdata = status_reg_mem[region_offset[31:2]];
                    end
                end
            endcase
        end
    end
    
    // Data Buffer Region Access
    logic [31:0] data_buffer_rdata;
    always_ff @(posedge clk) begin
        if (current_state == STATE_WRITE_PROCESS && target_region == REGION_DATA_BUFFER) begin
            if (region_offset[31:2] < (DATA_BUFFER_SIZE/4)) begin
                data_buffer_mem[region_offset[31:2]] <= tlp_data[31:0];
            end
        end
    end
    
    always_comb begin
        data_buffer_rdata = '0;
        if (target_region == REGION_DATA_BUFFER && region_offset[31:2] < (DATA_BUFFER_SIZE/4)) begin
            data_buffer_rdata = data_buffer_mem[region_offset[31:2]];
        end
    end
    
    // ========================================================================
    // Device-Specific Timing Pattern Implementation
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            timing_counter <= '0;
            burst_counter <= '0;
            timing_active <= 1'b1;
            burst_in_progress <= 1'b0;
        end else begin
            // Implement device-specific timing patterns from behavior profiler
            if (timing_active) begin
                if (burst_in_progress) begin
                    if (burst_counter < BURST_LENGTH-1) begin
                        burst_counter <= burst_counter + 1;
                    end else begin
                        burst_in_progress <= 1'b0;
                        burst_counter <= '0;
                        timing_counter <= '0;
                    end
                end else begin
                    if (timing_counter < INTER_BURST_GAP-1) begin
                        timing_counter <= timing_counter + 1;
                    end else begin
                        burst_in_progress <= 1'b1;
                        timing_counter <= '0;
                    end
                end
            end
        end
    end
    
    // ========================================================================
    // PCILeech Command Processing
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            pcileech_ctrl_reg <= '0;
            pcileech_stat_reg <= '0;
            pcileech_addr_reg <= '0;
            pcileech_len_reg <= '0;
            pcileech_data_reg <= '0;
        end else begin
            // Update PCILeech control registers based on commands
            if (pcileech_enable && current_state == STATE_PCILEECH_EXEC) begin
                case (pcileech_command[7:0])
                    PCILEECH_CMD_READ: begin
                        pcileech_addr_reg <= pcileech_address;
                        pcileech_len_reg <= pcileech_length;
                        pcileech_stat_reg[0] <= 1'b1; // Busy
                    end
                    PCILEECH_CMD_WRITE: begin
                        pcileech_addr_reg <= pcileech_address;
                        pcileech_len_reg <= pcileech_length;
                        pcileech_stat_reg[0] <= 1'b1; // Busy
                    end
                    PCILEECH_CMD_PROBE: begin
                        pcileech_data_reg <= DEVICE_SIGNATURE;
                        pcileech_stat_reg[1] <= 1'b1; // Ready
                    end
                    PCILEECH_CMD_STATUS: begin
                        pcileech_stat_reg[2] <= 1'b1; // Status available
                    end
                endcase
            end
        end
    end
    
    assign pcileech_status = pcileech_stat_reg;
    assign pcileech_ready = pcileech_stat_reg[1];
    
    // ========================================================================
    // MSI-X Integration
    // ========================================================================
    
    // MSI-X Table Access
    msix_table #(
        .NUM_MSIX(NUM_MSIX),
        .MSIX_TABLE_BIR(MSIX_TABLE_BIR),
        .MSIX_TABLE_OFFSET(MSIX_TABLE_OFFSET),
        .MSIX_PBA_BIR(MSIX_PBA_BIR),
        .MSIX_PBA_OFFSET(MSIX_PBA_OFFSET)
    ) msix_table_inst (
        .clk(clk),
        .reset_n(reset_n),
        .bar_addr(tlp_address[31:0]),
        .bar_index(BAR_INDEX[2:0]),
        .bar_wr_data(tlp_data[31:0]),
        .bar_wr_en(current_state == STATE_WRITE_PROCESS && target_region == REGION_MSIX_TABLE),
        .bar_wr_be(tlp_first_be),
        .bar_rd_en(current_state == STATE_READ_PROCESS && target_region == REGION_MSIX_TABLE),
        .bar_rd_data(msix_table_data),
        .bar_access_match(msix_table_access),
        .msix_enable(device_ctrl_mem[0][0]), // MSI-X enable from control register
        .msix_function_mask(device_ctrl_mem[0][1]), // Function mask from control register
        .msix_interrupt(msix_interrupt),
        .msix_vector(msix_vector),
        .msix_interrupt_ack(msix_interrupt_ack)
    );
    
    // ========================================================================
    // Performance Counters and Error Handling
    // ========================================================================
    
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            perf_counter_0 <= '0;
            perf_counter_1 <= '0;
            read_count <= '0;
            write_count <= '0;
            error_count <= '0;
            error_status_reg <= '0;
            timeout_counter <= '0;
        end else begin
            // Performance counters
            if (ENABLE_PERFORMANCE_COUNTERS) begin
                if (current_state == STATE_READ_PROCESS) begin
                    read_count <= read_count + 1;
                    perf_counter_0 <= perf_counter_0 + 1;
                end
                if (current_state == STATE_WRITE_PROCESS) begin
                    write_count <= write_count + 1;
                    perf_counter_1 <= perf_counter_1 + 1;
                end
            end
            
            // Error detection
            if (current_state == STATE_ERROR_HANDLE) begin
                error_count <= error_count + 1;
                error_status_reg[0] <= 1'b1; // Address error
            end
            
            if (tlp_rx_err) begin
                error_status_reg[1] <= 1'b1; // TLP error
                error_count <= error_count + 1;
            end
            
            // Timeout detection
            if (current_state != STATE_IDLE) begin
                if (timeout_counter < TIMEOUT_CYCLES-1) begin
                    timeout_counter <= timeout_counter + 1;
                end else begin
                    error_status_reg[2] <= 1'b1; // Timeout error
                    error_count <= error_count + 1;
                    timeout_counter <= '0;
                end
            end else begin
                timeout_counter <= '0;
            end
            
            // Clear errors on write to error status register
            if (current_state == STATE_WRITE_PROCESS && target_region == REGION_STATUS_REG && 
                region_offset[7:2] == 6'h01 && tlp_data[31]) begin
                error_status_reg <= '0;
            end
        end
    end
    
    assign error_status = error_status_reg;
    assign performance_counter_0 = perf_counter_0;
    assign performance_counter_1 = perf_counter_1;
    
    // ========================================================================
    // BAR Interface Logic
    // ========================================================================
    
    always_comb begin
        bar_rd_data = '0;
        bar_rd_valid = 1'b0;
        
        if (bar_rd_en) begin
            bar_rd_valid = 1'b1;
            case (target_region)
                REGION_DEVICE_CTRL: bar_rd_data = device_ctrl_rdata;
                REGION_STATUS_REG:  bar_rd_data = status_reg_rdata;
                REGION_DATA_BUFFER: bar_rd_data = data_buffer_rdata;
                REGION_MSIX_TABLE:  bar_rd_data = msix_table_data;
                REGION_MSIX_PBA:    bar_rd_data = msix_pba_data;
                default:            bar_rd_data = DEFAULT_UNMAPPED_VALUE;
            endcase
        end
    end
    
    // ========================================================================
    // Configuration Space Interface
    // ========================================================================
    
    always_comb begin
        cfg_ext_read_data = '0;
        cfg_ext_read_data_valid = 1'b0;
        
        if (cfg_ext_read_received) begin
            cfg_ext_read_data_valid = 1'b1;
            case (cfg_ext_register_number)
                10'h000: cfg_ext_read_data = 32'h{{ get_device_id(device_config, device, config_space, device_id_int) }}{{ get_vendor_id(device_config, device, config_space, vendor_id_int) }};
                10'h001: cfg_ext_read_data = {16'h{{ "%04X" % (config_space.status | default(0x0010) | int) }}, 
                                             CMD_REG_RESERVED_15_11, 
                                             cfg_interrupt_disable_dynamic, 
                                             CMD_REG_RESERVED_9_6, 
                                             cfg_bus_master_enable_dynamic, 
                                             cfg_memory_space_enable_dynamic, 
                                             CMD_REG_RESERVED_0};  // Dynamic command register
                10'h002: cfg_ext_read_data = 32'h{{ "%06X%02X" % ((config_space.class_code | int), (config_space.revision_id | int)) }};
                10'h040: cfg_ext_read_data = pcileech_ctrl_reg; // PCILeech control register
                10'h041: cfg_ext_read_data = pcileech_stat_reg; // PCILeech status register
                10'h042: cfg_ext_read_data = error_status_reg;  // Error status register
                default: cfg_ext_read_data = 32'h00000000;
            endcase
        end
    end
    
    // Configuration space write handling
    always_ff @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            // Initialize configuration space registers
        end else if (cfg_ext_write_received) begin
            case (cfg_ext_register_number)
                10'h040: begin // PCILeech control register
                    if (cfg_ext_write_byte_enable[0]) pcileech_ctrl_reg[7:0] <= cfg_ext_write_data[7:0];
                    if (cfg_ext_write_byte_enable[1]) pcileech_ctrl_reg[15:8] <= cfg_ext_write_data[15:8];
                    if (cfg_ext_write_byte_enable[2]) pcileech_ctrl_reg[23:16] <= cfg_ext_write_data[23:16];
                    if (cfg_ext_write_byte_enable[3]) pcileech_ctrl_reg[31:24] <= cfg_ext_write_data[31:24];
                end
                10'h042: begin // Error status register (write-1-to-clear)
                    if (cfg_ext_write_byte_enable[0]) error_status_reg[7:0] <= error_status_reg[7:0] & ~cfg_ext_write_data[7:0];
                    if (cfg_ext_write_byte_enable[1]) error_status_reg[15:8] <= error_status_reg[15:8] & ~cfg_ext_write_data[15:8];
                    if (cfg_ext_write_byte_enable[2]) error_status_reg[23:16] <= error_status_reg[23:16] & ~cfg_ext_write_data[23:16];
                    if (cfg_ext_write_byte_enable[3]) error_status_reg[31:24] <= error_status_reg[31:24] & ~cfg_ext_write_data[31:24];
                end
            endcase
        end
    end
    
    // ========================================================================
    // DMA Interface Logic
    // ========================================================================
    
    always_comb begin
        dma_read_req = 1'b0;
        dma_read_addr = '0;
        dma_read_len = '0;
        dma_write_req = 1'b0;
        dma_write_addr = '0;
        dma_write_len = '0;
        dma_write_data = '0;
        
        if (current_state == STATE_DMA_READ) begin
            dma_read_req = 1'b1;
            dma_read_addr = pcileech_addr_reg;
            dma_read_len = pcileech_len_reg;
        end else if (current_state == STATE_DMA_WRITE) begin
            dma_write_req = 1'b1;
            dma_write_addr = pcileech_addr_reg;
            dma_write_len = pcileech_len_reg;
            dma_write_data = {96'h0, pcileech_data_reg}; // Extend to 128-bit
        end
    end
    
    // ========================================================================
    // Debug and Status Output
    // ========================================================================
    
    assign debug_state = {4'h0, current_state};
    
    // ========================================================================
    // Simulation and Debug Support
    // ========================================================================
    
    {% if device_config.enable_simulation_support | default(true) %}
`ifdef XILINX_SIMULATOR
    // Initialize memory regions for simulation
    initial begin
        for (int i = 0; i < (DEVICE_CTRL_SIZE/4); i++) device_ctrl_mem[i] = 32'h0;
        for (int i = 0; i < (STATUS_REG_SIZE/4); i++) status_reg_mem[i] = 32'h0;
        for (int i = 0; i < (DATA_BUFFER_SIZE/4); i++) data_buffer_mem[i] = 32'h0;
        for (int i = 0; i < (CUSTOM_REGION_SIZE/4); i++) custom_region_mem[i] = 32'h0;
        
        // Initialize PCILeech control registers
        device_ctrl_mem[0] = 32'h00000001; // Enable PCILeech by default
    device_ctrl_mem[1] = DEVICE_SIGNATURE;
        device_ctrl_mem[2] = {{ device_config.firmware_version | default('32\'h00010000') }};
        
        // Initialize debug monitoring
        prev_pcileech_command = 32'h0;
    end
    
    // Debug tasks for software models
    task automatic inject_tlp(input logic [127:0] tlp_data, input logic sop, input logic eop);
        @(posedge clk);
        tlp_rx_valid = 1'b1;
        tlp_rx_data = tlp_data;
        tlp_rx_sop = sop;
        tlp_rx_eop = eop;
        @(posedge clk);
        tlp_rx_valid = 1'b0;
        tlp_rx_sop = 1'b0;
        tlp_rx_eop = 1'b0;
    endtask
    
    // Debug function to read memory region
    function automatic logic [31:0] read_memory_region(input region_select_t region, input logic [31:0] offset);
        case (region)
            REGION_DEVICE_CTRL: return device_ctrl_mem[offset[31:2]];
            REGION_STATUS_REG:  return status_reg_mem[offset[31:2]];
            REGION_DATA_BUFFER: return data_buffer_mem[offset[31:2]];
            REGION_CUSTOM_PIO:  return custom_region_mem[offset[31:2]];
            default:            return DEFAULT_UNMAPPED_VALUE;
        endcase
    endfunction
    
    // Debug function to get controller status
    function automatic logic [31:0] get_controller_status();
        return {24'h0, current_state, 4'h0};
    endfunction
    
    // Performance monitoring
    always @(posedge clk) begin
        if (current_state == STATE_READ_PROCESS) begin
            $display("[PCILeech BAR Controller] Read access to region %0d, offset 0x%08X at time %0t", 
                     target_region, region_offset, $time);
        end
        if (current_state == STATE_WRITE_PROCESS) begin
            $display("[PCILeech BAR Controller] Write access to region %0d, offset 0x%08X, data 0x%08X at time %0t", 
                     target_region, region_offset, tlp_data[31:0], $time);
        end
        if (current_state == STATE_ERROR_HANDLE) begin
            $display("[PCILeech BAR Controller] Error condition detected at time %0t", $time);
        end
        
        // Monitor command register bit changes
        if (pcileech_command != prev_pcileech_command) begin
            $display("[PCILeech BAR Controller] Command register changed: 0x%08X -> 0x%08X at time %0t",
                     prev_pcileech_command, pcileech_command, $time);
            $display("[PCILeech BAR Controller]   Bus Master: %b, Memory Space: %b, Interrupt Disable: %b",
                     cfg_bus_master_enable_dynamic, cfg_memory_space_enable_dynamic, cfg_interrupt_disable_dynamic);
            prev_pcileech_command = pcileech_command;
        end
    end
`endif
    {% endif %}

endmodule

`default_nettype wire