{#- MSI-X Capability Register Management Template -#}
{{ header | safe }}

`default_nettype none

module msix_capability_registers #(
    parameter TABLE_SIZE_MINUS_ONE = {{ (msix_config.num_vectors - 1) | default(0) }},
    parameter TABLE_OFFSET_BIR = {{ ((msix_config.table_offset | default(0x1000)) + (msix_config.table_bir | default(0))) | default(0x1000) }},
    parameter PBA_OFFSET_BIR = {{ ((msix_config.pba_offset | default(0x2000)) + (msix_config.pba_bir | default(0))) | default(0x2000) }}
)(
    input wire clk,
    input wire reset_n,
    
    // MSI-X capability register interface
    input wire        msix_cap_wr,     // Write strobe for MSI-X capability registers
    input wire [31:0] msix_cap_addr,   // Address within MSI-X capability space
    input wire [31:0] msix_cap_wdata,  // Write data for MSI-X capability registers
    input wire [3:0]  msix_cap_be,     // Byte enables for MSI-X capability writes
    output bit [31:0] msix_cap_rdata,  // Read data from MSI-X capability registers
    
    // MSI-X control outputs
    output bit        msix_enable,           // MSI-X Enable bit
    output bit        msix_function_mask,    // Function Mask bit
    output wire [10:0] msix_table_size       // Table Size field (read-only)
);

// MSI-X Message Control register fields
bit        msix_enable_reg;           // MSI-X Enable bit
bit        msix_function_mask_reg;    // Function Mask bit
bit [10:0] msix_table_size_reg;       // Table Size field (read-only)

// MSI-X Table Offset/BIR and PBA Offset/BIR registers (read-only)
bit [31:0] msix_table_offset_bir;
bit [31:0] msix_pba_offset_bir;

// Wire assignments for outputs
assign msix_enable = msix_enable_reg;
assign msix_function_mask = msix_function_mask_reg;
assign msix_table_size = msix_table_size_reg;

// MSI-X capability register initialization is handled in the reset logic below
// Table size and offset/BIR registers are read-only and set in the always_ff block

// MSI-X capability register read/write logic
always @(posedge clk or negedge reset_n) begin
    if (!reset_n) begin
        msix_enable_reg <= 1'b0;
        msix_function_mask_reg <= 1'b0;
        msix_table_size_reg <= TABLE_SIZE_MINUS_ONE;  // Table size - 1 (read-only)
        msix_table_offset_bir <= TABLE_OFFSET_BIR;    // Read-only
        msix_pba_offset_bir <= PBA_OFFSET_BIR;        // Read-only
    end else if (msix_cap_wr) begin
        // Handle writes to MSI-X Message Control register
        case (msix_cap_addr[3:0])
            4'h2: begin  // Message Control register (offset 2)
                if (msix_cap_be[1]) msix_enable_reg <= msix_cap_wdata[15];
                if (msix_cap_be[1]) msix_function_mask_reg <= msix_cap_wdata[14];
                // Table size is read-only, ignore writes
            end
            // Table Offset/BIR and PBA Offset/BIR are read-only
            default: begin
                // Other offsets are read-only or reserved
            end
        endcase
    end
end

// MSI-X capability register read data multiplexer
always @(*) begin
    case (msix_cap_addr[3:0])
        4'h0: msix_cap_rdata = {16'h0011, 8'h00, 8'h11};  // Next pointer and Capability ID
        4'h2: msix_cap_rdata = {msix_enable_reg, msix_function_mask_reg, 3'b000, msix_table_size_reg};
        4'h4: msix_cap_rdata = msix_table_offset_bir;
        4'h8: msix_cap_rdata = msix_pba_offset_bir;
        default: msix_cap_rdata = 32'h00000000;
    endcase
end

endmodule

`default_nettype wire