{#- PCILeech Top-Level Wrapper Template -#}
{{ header | safe }}

`default_nettype none
{% from "_helpers.j2" import safe_int, get_vendor_id, get_device_id %}
{# Emit visible device identifiers for diagnostics/tests (0x-prefixed) #}
{% set _devcfg = active_device_config if active_device_config is defined else (device_config if device_config is defined else none) %}
{% set _vendor_str = get_vendor_id(_devcfg, device, config_space, vendor_id_int | default(none)) %}
{% set _device_str = get_device_id(_devcfg, device, config_space, device_id_int | default(none)) %}
// Device IDs: vendor=0x{{ _vendor_str }}, device=0x{{ _device_str }}
{#- Determine lane count from context.
    Prefer explicit board/pcie_config values; fall back to max_lanes, else X1. -#}
{% set lane_ns = namespace(values=[]) %}
{% if board is defined and board is not none and board.max_lanes is not none %}
    {% set _ = lane_ns.values.append((safe_int(board.max_lanes, default=0) | int)) %}
{% endif %}
{% if pcie_config is defined and pcie_config is not none %}
    {% for key in ["max_lanes", "link_width", "maximum_link_width", "pl_link_cap_max_link_width", "configured_lanes"] %}
        {% if key in pcie_config and pcie_config[key] is not none %}
            {% set _ = lane_ns.values.append((safe_int(pcie_config[key], default=0) | int)) %}
        {% endif %}
    {% endfor %}
{% endif %}
{% if max_lanes is defined %}
    {% set _ = lane_ns.values.append((safe_int(max_lanes, default=0) | int)) %}
{% endif %}
{% set _ = lane_ns.values.append(1) %}
{% set _max_lanes = (lane_ns.values | max) %}
{% set _max_lanes = (_max_lanes if _max_lanes > 0 else 1) %}
{% set _lane_width = (_max_lanes - 1) %}
{%- set _dsn_value = device_serial_number_int | default(0) %}
{%- set _dsn_value = (_dsn_value % (2 ** 64)) %}
{%- set _dsn_hex = "{:016X}".format(_dsn_value) %}
{%- set _dsn_valid = (_dsn_value != 0) %}
{#- Normalize data width for 7-series core: clamp to supported 32/64-bit paths -#}
{% set _raw_data_width = (data_width | default(64) | safe_int(64)) %}
{% if _raw_data_width < 32 %}
    {% set _raw_data_width = 32 %}
{% endif %}
{% if _raw_data_width not in [32, 64] %}
    {% set _raw_data_width = 64 %}
{% endif %}
{% set data_width = _raw_data_width %}

module pcileech_top (
    // PCIe physical transceiver interface
    output wire [{{ _lane_width }}:0]  pci_exp_txp,
    output wire [{{ _lane_width }}:0]  pci_exp_txn,
    input  wire [{{ _lane_width }}:0]  pci_exp_rxp,
    input  wire [{{ _lane_width }}:0]  pci_exp_rxn,

    // System clock and reset (external)
    // Note: sys_clk_p connects to internal IBUFDS_GTE2 within PCIe IP
    // The differential pair is handled inside the IP core
    input  wire        sys_clk_p,
        input  wire        sys_clk_n,
    input  wire        sys_rst_n
{%- set _enable_pme_flag = enable_pme|default(false) %}
{%- set _enable_wake_events_flag = enable_wake_events|default(false) %}
{#- Expose sideband pins only when explicitly requested by context -#}
{%- set _expose_pm_sideband_flag = expose_pm_sideband|default(power_management.has_interface_signals if power_management is defined else false) %}
{#- Only add the leading comma if at least one optional port will be emitted -#}
{%- set _has_optional_ports = _expose_pm_sideband_flag and (_enable_pme_flag or _enable_wake_events_flag) %}
{%- if _has_optional_ports %}
    ,
    // Optional PCIe power management sideband (expose for integration)
{%- if _enable_pme_flag %}
    input  wire         pme_turnoff,
    input  wire         aux_pwr_present,
    output logic        pme_to_ack{%- if _enable_wake_events_flag %},{% endif %}
{%- endif %}
{%- if _enable_wake_events_flag %}
    output logic        wake_n
{%- endif %}
{%- endif %}
);

    // Internal PCIe interface signals
    {% include "sv/top_level/internal_signals.sv.j2" %}

    // Convert differential PCIe reference clock to single-ended
    IBUFDS_GTE2 #(
        .CLKCM_CFG("TRUE"),
        .CLKRCV_TRST("TRUE"),
        .CLKSWING_CFG(2'b11)
    ) pcie_refclk_ibuf (
        .O(pcie_sys_clk),
        .ODIV2(pcie_sys_clk_div2),
        .CEB(1'b0),
        .I(sys_clk_p),
        .IB(sys_clk_n)
    );

    // Unused divided clock exposed for completeness
    wire __unused_sys_clk_div2 = pcie_sys_clk_div2;

    {% include "sv/top_level/pcie_core_instance.sv.j2" %}

    {% include "sv/top_level/bar_controller_block.sv.j2" %}

    {% include "sv/top_level/tlp_processing.sv.j2" %}

{%- if board is defined and board.has_status_leds | default(false) %}
    // LED status output - show device ready and current state
    assign led_status = { {% if board.num_status_leds | default(8) > 3 %}{{ (board.num_status_leds | default(8)) - 3 }}'h0, {% endif %}device_ready, tlp_state};
{%- endif %}

endmodule

`default_nettype wire