//==============================================================================
// Option-ROM BAR Window Implementation
// Generated by PCILeech Firmware Generator
//
// This module implements the Option-ROM BAR window (Mode A) for PCILeech FPGA.
// It provides access to the Option-ROM content through BAR {{ ROM_BAR_INDEX }} and handles
// legacy 16-bit config cycles for ROM access.
//
// Features:
// - Exposes Option-ROM content through BAR {{ ROM_BAR_INDEX }}
// - Handles legacy 16-bit config cycles for ROM access
// - Initializes ROM content from donor device ROM data
//==============================================================================

module option_rom_bar_window #(
    parameter ROM_SIZE = {{ ROM_SIZE }},  // {{ ROM_SIZE }} bytes
    parameter ROM_BAR_INDEX = {{ ROM_BAR_INDEX }}  // BAR {{ ROM_BAR_INDEX }} for ROM
) (
    // Clock and reset
    input  logic        clk,
    input  logic        reset_n,
    
    // PCIe BAR interface
    input  logic [31:0] bar_addr,
    input  logic [31:0] bar_wr_data,
    input  logic        bar_wr_en,
    input  logic        bar_rd_en,
    output logic [31:0] bar_rd_data,
    input  logic [2:0]  bar_index,
    output logic        bar_access_match,
    
    // PCIe 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,
    
    // Legacy ROM access interface (16-bit config cycles)
    input  logic        legacy_rom_access,
    input  logic [31:0] legacy_rom_addr,
    output logic [31:0] legacy_rom_data
);

    // Calculate ROM size in 32-bit words
    localparam ROM_WORDS = ({{ ROM_SIZE }} + 3) / 4;
    
    // Option-ROM storage
    (* ram_style="block" *) logic [31:0] rom_memory[0:ROM_WORDS-1];
    
    // Internal signals
    logic is_rom_bar_access;
    logic [31:0] rom_addr;
    
    // Determine if access is to ROM BAR
    assign is_rom_bar_access = (bar_index == {{ ROM_BAR_INDEX }}) && 
                              (bar_addr < {{ ROM_SIZE }});
    
    // Signal if this module should handle the access
    assign bar_access_match = is_rom_bar_access;
    
    // Calculate ROM address (convert to DWORD index)
    assign rom_addr = bar_addr >> 2;
    
    // Read logic for BAR access
    always_comb begin
        if (bar_rd_en && is_rom_bar_access) begin
            if (rom_addr < ROM_WORDS) begin
                bar_rd_data = rom_memory[rom_addr];
            end else begin
                bar_rd_data = 32'h0; // Return 0 for out-of-range access
            end
        end else begin
            bar_rd_data = 32'h0;
        end
    end
    
{% if ALLOW_ROM_WRITES %}
    // Write logic - Option-ROM is typically read-only
    // But we implement write for completeness and potential future use
    always_ff @(posedge clk) begin
        if (!reset_n) begin
            // Initialize ROM in reset logic
{% if INIT_ROM %}
            // Initialize ROM from provided data
{% for word in INIT_ROM %}
            rom_memory[{{ loop.index0 }}] <= 32'h{{ "%08X"|format(word) }};
{% endfor %}
{% endif %}
        end else if (bar_wr_en && is_rom_bar_access && (rom_addr < ROM_WORDS)) begin
            // Allow writes to ROM for debugging/testing
            rom_memory[rom_addr] <= bar_wr_data;
        end
    end
{% endif %}
    
    // Legacy ROM access (16-bit config cycles)
    always_comb begin
        if (legacy_rom_access) begin
            // Legacy ROM access uses byte addressing
            logic [31:0] legacy_word_addr = legacy_rom_addr >> 2;
            
            if (legacy_word_addr < ROM_WORDS) begin
                legacy_rom_data = rom_memory[legacy_word_addr];
            end else begin
                legacy_rom_data = 32'h0; // Return 0 for out-of-range access
            end
        end else begin
            legacy_rom_data = 32'h0;
        end
    end
    
    // NOTE: For synthesis, ROM initialization should be done in reset logic above
    // The following is for simulation only and may cause synthesis issues:
    // initial begin
{% if INIT_ROM %}
    //     // Initialize ROM from provided data
{% for word in INIT_ROM %}
    //     rom_memory[{{ loop.index0 }}] = 32'h{{ "%08X"|format(word) }};
{% endfor %}
{% else %}
    //     // Initialize the Option-ROM from a hex file
    //     $readmemh("{{ ROM_HEX_FILE }}", rom_memory);
{% endif %}
    //
{% if ENABLE_SIGNATURE_CHECK %}
    //     // Ensure ROM signature is valid (0x55AA at offset 0)
    //     if ((rom_memory[0] & 16'hFFFF) != 16'hAA55) begin
    //         $display("Warning: Option-ROM signature not found (expected 0x55AA)");
    //     end
{% endif %}
    // end

endmodule