//==============================================================================
// Debug Tasks and Simulation Helpers
// Generated by PCILeech Firmware Generator
//
// This file contains simulation-only helper tasks and functions that were
// extracted from the original monolithic module. These are used for:
// - TLP injection and stimulus generation
// - Memory region inspection and debugging
// - Performance monitoring and analysis
// - Test bench integration and validation
//==============================================================================

`ifndef DEBUG_TASKS_SVH
`define DEBUG_TASKS_SVH

`ifdef SIMULATION

// ========================================================================
// TLP Injection Tasks
// ========================================================================

// Inject a complete TLP packet
task automatic inject_tlp(
    input logic [127:0] tlp_data,
    input logic sop,
    input logic eop,
    input logic [3:0] empty = 4'h0,
    input logic err = 1'b0
);
    @(posedge clk);
    tlp_rx_valid = 1'b1;
    tlp_rx_data = tlp_data;
    tlp_rx_sop = sop;
    tlp_rx_eop = eop;
    tlp_rx_empty = empty;
    tlp_rx_err = err;
    
    // Wait for ready
    while (!tlp_rx_ready) @(posedge clk);
    
    @(posedge clk);
    tlp_rx_valid = 1'b0;
    tlp_rx_sop = 1'b0;
    tlp_rx_eop = 1'b0;
    tlp_rx_empty = 4'h0;
    tlp_rx_err = 1'b0;
endtask

// Inject a memory read TLP
task automatic inject_memory_read_32(
    input logic [15:0] requester_id,
    input logic [7:0] tag,
    input logic [31:0] address,
    input logic [9:0] length,
    input logic [3:0] first_be = 4'hF,
    input logic [3:0] last_be = 4'hF
);
    logic [127:0] tlp_header;
    
    // Build TLP header for 32-bit memory read
    tlp_header = {
        5'b00000,           // Format/Type: MEM_READ_32
        3'b000,             // TC
        1'b0,               // TD
        1'b0,               // EP
        2'b00,              // Attr
        1'b0,               // TH
        length,             // Length
        requester_id,       // Requester ID
        tag,                // Tag
        first_be,           // First BE
        last_be,            // Last BE
        address[31:2],      // Address (word aligned)
        2'b00               // Reserved
    };
    
    inject_tlp(tlp_header, 1'b1, 1'b1);
    
    $display("[Debug] Injected MEM_READ_32: addr=0x%08X, len=%0d, tag=0x%02X at time %0t",
             address, length, tag, $time);
endtask

// Inject a memory write TLP
task automatic inject_memory_write_32(
    input logic [15:0] requester_id,
    input logic [7:0] tag,
    input logic [31:0] address,
    input logic [9:0] length,
    input logic [31:0] data,
    input logic [3:0] first_be = 4'hF,
    input logic [3:0] last_be = 4'hF
);
    logic [127:0] tlp_header;
    logic [127:0] tlp_data_payload;
    
    // Build TLP header for 32-bit memory write
    tlp_header = {
        5'b01000,           // Format/Type: MEM_WRITE_32
        3'b000,             // TC
        1'b0,               // TD
        1'b0,               // EP
        2'b00,              // Attr
        1'b0,               // TH
        length,             // Length
        requester_id,       // Requester ID
        tag,                // Tag
        first_be,           // First BE
        last_be,            // Last BE
        address[31:2],      // Address (word aligned)
        2'b00               // Reserved
    };
    
    // Build data payload
    tlp_data_payload = {96'h0, data};
    
    // Send header
    inject_tlp(tlp_header, 1'b1, 1'b0);
    
    // Send data
    inject_tlp(tlp_data_payload, 1'b0, 1'b1);
    
    $display("[Debug] Injected MEM_WRITE_32: addr=0x%08X, data=0x%08X, len=%0d, tag=0x%02X at time %0t",
             address, data, length, tag, $time);
endtask

// ========================================================================
// Memory Region Inspection Functions
// ========================================================================

// Read from device control region
function automatic logic [31:0] read_device_ctrl_region(input logic [31:0] offset);
    logic [31:0] word_offset;
    word_offset = offset[31:2];
    
    if (word_offset < (DEVICE_CTRL_SIZE/4)) begin
        return u_region_device_ctrl.device_ctrl_mem[word_offset];
    end else begin
        $error("[Debug] Device control region read out of bounds: offset=0x%08X", offset);
        return 32'hDEADBEEF;
    end
endfunction

// Read from status register region
function automatic logic [31:0] read_status_region(input logic [31:0] offset);
    // Status region is mostly computed values, return current performance counters
    case (offset[7:2])
        6'h02: return u_region_status.perf_counters_reg.read_count;
        6'h03: return u_region_status.perf_counters_reg.write_count;
        6'h04: return u_region_status.perf_counters_reg.completion_count;
        6'h05: return u_region_status.perf_counters_reg.error_count;
        default: begin
            $warning("[Debug] Status region read from undefined offset: 0x%08X", offset);
            return 32'h00000000;
        end
    endcase
endfunction

// Read from data buffer region
function automatic logic [31:0] read_data_buffer_region(input logic [31:0] offset);
    logic [31:0] word_offset;
    word_offset = offset[31:2];
    
    if (word_offset < (DATA_BUFFER_SIZE/4)) begin
        return u_region_data_buffer.buffer_memory[word_offset];
    end else begin
        $error("[Debug] Data buffer region read out of bounds: offset=0x%08X", offset);
        return 32'hDEADBEEF;
    end
endfunction

// Write to device control region
task automatic write_device_ctrl_region(
    input logic [31:0] offset,
    input logic [31:0] data,
    input logic [3:0] be = 4'hF
);
    logic [31:0] word_offset;
    word_offset = offset[31:2];
    
    if (word_offset < (DEVICE_CTRL_SIZE/4)) begin
        if (be[0]) u_region_device_ctrl.device_ctrl_mem[word_offset][7:0] = data[7:0];
        if (be[1]) u_region_device_ctrl.device_ctrl_mem[word_offset][15:8] = data[15:8];
        if (be[2]) u_region_device_ctrl.device_ctrl_mem[word_offset][23:16] = data[23:16];
        if (be[3]) u_region_device_ctrl.device_ctrl_mem[word_offset][31:24] = data[31:24];
        
        $display("[Debug] Device control region write: offset=0x%08X, data=0x%08X, be=0x%X at time %0t",
                 offset, data, be, $time);
    end else begin
        $error("[Debug] Device control region write out of bounds: offset=0x%08X", offset);
    end
endtask

// Write to data buffer region
task automatic write_data_buffer_region(
    input logic [31:0] offset,
    input logic [31:0] data,
    input logic [3:0] be = 4'hF
);
    logic [31:0] word_offset;
    word_offset = offset[31:2];
    
    if (word_offset < (DATA_BUFFER_SIZE/4)) begin
        if (be[0]) u_region_data_buffer.buffer_memory[word_offset][7:0] = data[7:0];
        if (be[1]) u_region_data_buffer.buffer_memory[word_offset][15:8] = data[15:8];
        if (be[2]) u_region_data_buffer.buffer_memory[word_offset][23:16] = data[23:16];
        if (be[3]) u_region_data_buffer.buffer_memory[word_offset][31:24] = data[31:24];
        
        $display("[Debug] Data buffer region write: offset=0x%08X, data=0x%08X, be=0x%X at time %0t",
                 offset, data, be, $time);
    end else begin
        $error("[Debug] Data buffer region write out of bounds: offset=0x%08X", offset);
    end
endtask

// ========================================================================
// Controller Status Functions
// ========================================================================

// Get current controller state
function automatic logic [31:0] get_controller_status();
    return {
        24'h000000,
        u_bar_dispatcher.current_state,     // [7:4] Dispatcher state
        u_tlp_frontend.current_state        // [3:0] Frontend state
    };
endfunction

// Get performance summary
function automatic logic [127:0] get_performance_summary();
    return {
        u_region_status.perf_counters_reg.read_count,       // [127:96]
        u_region_status.perf_counters_reg.write_count,      // [95:64]
        u_region_status.perf_counters_reg.completion_count, // [63:32]
        u_region_status.perf_counters_reg.error_count       // [31:0]
    };
endfunction

// Get error status summary
function automatic logic [31:0] get_error_status();
    return u_region_status.error_status_reg;
endfunction

// Check if controller is idle
function automatic logic is_controller_idle();
    return (u_tlp_frontend.current_state == tlp_frontend.PARSE_IDLE) &&
           (u_bar_dispatcher.current_state == bar_dispatcher.DISPATCH_IDLE);
endfunction

// ========================================================================
// Memory Initialization Tasks
// ========================================================================

// Initialize device control region with default values
task automatic init_device_ctrl_region();
    // Clear all memory
    for (int i = 0; i < (DEVICE_CTRL_SIZE/4); i++) begin
        u_region_device_ctrl.device_ctrl_mem[i] = 32'h00000000;
    end
    
    // Set default values
    u_region_device_ctrl.device_ctrl_mem[0] = 32'h00000001;  // PCILeech enabled
    u_region_device_ctrl.device_ctrl_mem[1] = DEVICE_CONFIG.device_signature;
    u_region_device_ctrl.device_ctrl_mem[2] = DEVICE_CONFIG.firmware_version;
    
    $display("[Debug] Device control region initialized at time %0t", $time);
endtask

// Initialize data buffer with test pattern
task automatic init_data_buffer_pattern(input logic [31:0] pattern = 32'hA5A5A5A5);
    for (int i = 0; i < (DATA_BUFFER_SIZE/4); i++) begin
        u_region_data_buffer.buffer_memory[i] = pattern ^ i;
    end
    
    $display("[Debug] Data buffer initialized with pattern 0x%08X at time %0t", pattern, $time);
endtask

// Clear all memory regions
task automatic clear_all_regions();
    // Clear device control region
    for (int i = 0; i < (DEVICE_CTRL_SIZE/4); i++) begin
        u_region_device_ctrl.device_ctrl_mem[i] = 32'h00000000;
    end
    
    // Clear data buffer region
    for (int i = 0; i < (DATA_BUFFER_SIZE/4); i++) begin
        u_region_data_buffer.buffer_memory[i] = 32'h00000000;
    end
    
    $display("[Debug] All memory regions cleared at time %0t", $time);
endtask

// ========================================================================
// Test Sequence Helpers
// ========================================================================

// Wait for controller to become idle
task automatic wait_for_idle(input int max_cycles = 1000);
    int cycle_count = 0;
    
    while (!is_controller_idle() && cycle_count < max_cycles) begin
        @(posedge clk);
        cycle_count++;
    end
    
    if (cycle_count >= max_cycles) begin
        $error("[Debug] Timeout waiting for controller to become idle");
    end else begin
        $display("[Debug] Controller idle after %0d cycles at time %0t", cycle_count, $time);
    end
endtask

// Perform a complete read-write test sequence
task automatic test_read_write_sequence(
    input logic [31:0] base_addr,
    input logic [31:0] test_data
);
    logic [15:0] req_id = 16'h1234;
    logic [7:0] tag = 8'h55;
    
    $display("[Debug] Starting read-write test sequence at addr=0x%08X, data=0x%08X", 
             base_addr, test_data);
    
    // Write data
    inject_memory_write_32(req_id, tag, base_addr, 10'h001, test_data);
    wait_for_idle();
    
    // Read back data
    inject_memory_read_32(req_id, tag + 1, base_addr, 10'h001);
    wait_for_idle();
    
    $display("[Debug] Read-write test sequence completed at time %0t", $time);
endtask

// Burst test sequence
task automatic test_burst_sequence(
    input logic [31:0] base_addr,
    input int burst_length = 16
);
    logic [15:0] req_id = 16'h5678;
    logic [7:0] tag = 8'hAA;
    
    $display("[Debug] Starting burst test sequence at addr=0x%08X, length=%0d", 
             base_addr, burst_length);
    
    // Write burst
    for (int i = 0; i < burst_length; i++) begin
        inject_memory_write_32(req_id, tag + i, base_addr + (i * 4), 10'h001, 32'hBEEF0000 + i);
        if (i % 4 == 3) wait_for_idle();  // Periodic idle waits
    end
    
    wait_for_idle();
    
    // Read burst
    for (int i = 0; i < burst_length; i++) begin
        inject_memory_read_32(req_id, tag + burst_length + i, base_addr + (i * 4), 10'h001);
        if (i % 4 == 3) wait_for_idle();  // Periodic idle waits
    end
    
    wait_for_idle();
    $display("[Debug] Burst test sequence completed at time %0t", $time);
endtask

// ========================================================================
// Performance Monitoring Tasks
// ========================================================================

// Monitor performance for a specified duration
task automatic monitor_performance(input int monitor_cycles = 10000);
    logic [31:0] start_reads, start_writes, start_completions, start_errors;
    logic [31:0] end_reads, end_writes, end_completions, end_errors;
    
    // Capture starting values
    start_reads = u_region_status.perf_counters_reg.read_count;
    start_writes = u_region_status.perf_counters_reg.write_count;
    start_completions = u_region_status.perf_counters_reg.completion_count;
    start_errors = u_region_status.perf_counters_reg.error_count;
    
    $display("[Debug] Starting performance monitoring for %0d cycles", monitor_cycles);
    
    // Wait for specified duration
    repeat(monitor_cycles) @(posedge clk);
    
    // Capture ending values
    end_reads = u_region_status.perf_counters_reg.read_count;
    end_writes = u_region_status.perf_counters_reg.write_count;
    end_completions = u_region_status.perf_counters_reg.completion_count;
    end_errors = u_region_status.perf_counters_reg.error_count;
    
    // Report results
    $display("[Debug] Performance monitoring results:");
    $display("  Reads:       %0d (+%0d)", end_reads, end_reads - start_reads);
    $display("  Writes:      %0d (+%0d)", end_writes, end_writes - start_writes);
    $display("  Completions: %0d (+%0d)", end_completions, end_completions - start_completions);
    $display("  Errors:      %0d (+%0d)", end_errors, end_errors - start_errors);
endtask

// ========================================================================
// Error Injection Tasks
// ========================================================================

// Inject a malformed TLP
task automatic inject_malformed_tlp();
    logic [127:0] bad_tlp = 128'hDEADBEEFCAFEBABEBADC0DEDEADBEEF;
    
    inject_tlp(bad_tlp, 1'b1, 1'b1, 4'h0, 1'b1);  // With error flag
    $display("[Debug] Injected malformed TLP at time %0t", $time);
endtask

// Inject TLP with invalid address
task automatic inject_invalid_address_tlp();
    logic [31:0] invalid_addr = 32'hFFFFFFFF;  // Beyond BAR aperture
    
    inject_memory_read_32(16'h9999, 8'hFF, invalid_addr, 10'h001);
    $display("[Debug] Injected TLP with invalid address 0x%08X at time %0t", invalid_addr, $time);
endtask

`endif // SIMULATION

`endif // DEBUG_TASKS_SVH