{#
IP Configuration Template - PCIe Core Setup
Variables:
- header: TCL header comment
- device: Device information (vendor_id, device_id, etc.)
- board: Board information (name, fpga_part, etc.)
#}
{{ header }}

{% from "_helpers.j2" import safe_fpga_part, safe_name, safe_attr, get_vendor_id, get_device_id, get_subsystem_vendor_id, get_subsystem_device_id %}
puts "Creating PCIe IP core for device {{ get_vendor_id(device_config, device, config_space, vendor_id_int) }}:{{ get_device_id(device_config, device, config_space, device_id_int) }}..."
{% if board is string %}
puts "FPGA Part: {{ safe_fpga_part(board) }}"
puts "Board: {{ board }}"
{% else %}
puts "FPGA Part: {{ safe_fpga_part(board) }}"
puts "Board: {{ safe_name(board) }}"
{% endif %}

# Create PCIe IP core based on FPGA family
{% set pcie_type = safe_attr(board, 'pcie_ip_type', None) %}
{% if pcie_type == "pcie_7x" %}
# Update IP catalog to ensure all IP cores are available
puts "Updating IP catalog..."
update_ip_catalog

# Check available PCIe IP cores
puts "Available PCIe IP cores:"
set available_ips [get_ipdefs -filter {NAME =~ "*pcie*"}]
foreach ip $available_ips {
    puts "  [get_property NAME $ip] - [get_property VERSION $ip]"
}

# Try to create PCIe 7-series IP core (try without version first)
set pcie_created 0
if {[catch {
    create_ip -name pcie_7x -vendor xilinx.com -library ip -module_name pcie_7x_bridge
    set pcie_created 1
    puts "Successfully created PCIe 7-series IP core (auto version)"
}]} {
    puts "Failed to create PCIe IP without version, trying with version 3.3..."
    if {[catch {
        create_ip -name pcie_7x -vendor xilinx.com -library ip -version 3.3 -module_name pcie_7x_bridge
        set pcie_created 1
        puts "Successfully created PCIe 7-series IP core (version 3.3)"
    }]} {
        puts "Failed to create PCIe IP with version 3.3, trying latest available..."
        # Get the latest available version
        set pcie_versions [get_ipdefs -filter {NAME == "pcie_7x"}]
        if {[llength $pcie_versions] > 0} {
            set latest_version [lindex $pcie_versions 0]
            set version_str [get_property VERSION $latest_version]
            puts "Trying latest available version: $version_str"
            if {[catch {
                create_ip -name pcie_7x -vendor xilinx.com -library ip -version $version_str -module_name pcie_7x_bridge
                set pcie_created 1
                puts "Successfully created PCIe 7-series IP core (version $version_str)"
            }]} {
                puts "ERROR: Failed to create PCIe IP core with any available version"
                puts "This may indicate that PCIe IP is not installed or not available for this FPGA part"
                exit 1
            }
        } else {
            puts "ERROR: No PCIe 7-series IP cores found in catalog"
            puts "Please ensure PCIe IP is installed in Vivado"
            exit 1
        }
    }
}

if {!$pcie_created} {
    puts "ERROR: Failed to create PCIe IP core"
    exit 1
}

# Helper procedure to safely set IP properties
proc safe_set {ip key val} {
    if {[lsearch -exact [list_property $ip] $key] < 0} {
        error "IP $ip has no parameter $key"
    }
    set_property $key $val $ip
}

# Get IP instance once for cleaner code
set ip [get_ips pcie_7x_bridge]

# Configure PCIe IP core with device-specific settings using safe_set
# BAR-0 configuration: use plain integer for size, not string with units
safe_set $ip CONFIG.Bar0_Scale {Kilobytes}
safe_set $ip CONFIG.Bar0_Size {128}
safe_set $ip CONFIG.Device_ID {{ get_device_id(device_config, device, config_space, device_id_int) }}
safe_set $ip CONFIG.Vendor_ID {{ get_vendor_id(device_config, device, config_space, vendor_id_int) }}
safe_set $ip CONFIG.Subsystem_Vendor_ID {{ get_subsystem_vendor_id(device_config, device, vendor_id_int) }}
safe_set $ip CONFIG.Subsystem_ID {{ get_subsystem_device_id(device_config, device, device_id_int) }}
safe_set $ip CONFIG.Revision_ID {{ device.revision_id }}
# Link speed must use exact enum values with underscores
safe_set $ip CONFIG.Link_Speed {2.5_GT/s}
safe_set $ip CONFIG.Link_Width {X1}
safe_set $ip CONFIG.Maximum_Link_Width {X1}
safe_set $ip CONFIG.Support_Slot_Clk_Config {false}
safe_set $ip CONFIG.Legacy_Interrupt {NONE}
# MSI/MSIX configuration: disable MSI, enable MSIX
safe_set $ip CONFIG.MSI_Enabled {false}
safe_set $ip CONFIG.MSIX_Enabled {true}

# Generate IP targets for complete synthesis flow
generate_target {instantiation_template synthesis implementation} $ip

# Export IP user files for out-of-context runs
export_ip_user_files -of_objects $ip -force
{% elif pcie_type == "pcie_ultrascale" %}
# Update IP catalog to ensure all IP cores are available
puts "Updating IP catalog..."
update_ip_catalog

# Check available PCIe IP cores
puts "Available PCIe IP cores:"
set available_ips [get_ipdefs -filter {NAME =~ "*pcie*"}]
foreach ip $available_ips {
    puts "  [get_property NAME $ip] - [get_property VERSION $ip]"
}

# Try to create PCIe UltraScale IP core (try without version first)
set pcie_created 0
if {[catch {
    create_ip -name pcie4_uscale_plus -vendor xilinx.com -library ip -module_name pcie4_uscale_plus_bridge
    set pcie_created 1
    puts "Successfully created PCIe UltraScale IP core (auto version)"
}]} {
    puts "Failed to create PCIe IP without version, trying with version 1.3..."
    if {[catch {
        create_ip -name pcie4_uscale_plus -vendor xilinx.com -library ip -version 1.3 -module_name pcie4_uscale_plus_bridge
        set pcie_created 1
        puts "Successfully created PCIe UltraScale IP core (version 1.3)"
    }]} {
        puts "Failed to create PCIe IP with version 1.3, trying latest available..."
        # Get the latest available version
        set pcie_versions [get_ipdefs -filter {NAME == "pcie4_uscale_plus"}]
        if {[llength $pcie_versions] > 0} {
            set latest_version [lindex $pcie_versions 0]
            set version_str [get_property VERSION $latest_version]
            puts "Trying latest available version: $version_str"
            if {[catch {
                create_ip -name pcie4_uscale_plus -vendor xilinx.com -library ip -version $version_str -module_name pcie4_uscale_plus_bridge
                set pcie_created 1
                puts "Successfully created PCIe UltraScale IP core (version $version_str)"
            }]} {
                puts "ERROR: Failed to create PCIe IP core with any available version"
                puts "This may indicate that PCIe IP is not installed or not available for this FPGA part"
                exit 1
            }
        } else {
            puts "ERROR: No PCIe UltraScale IP cores found in catalog"
            puts "Please ensure PCIe IP is installed in Vivado"
            exit 1
        }
    }
}

if {!$pcie_created} {
    puts "ERROR: Failed to create PCIe IP core"
    exit 1
}

# Get IP instance for cleaner code
set ip [get_ips pcie4_uscale_plus_bridge]

# Configure PCIe UltraScale IP core with device-specific settings
set_property -dict [list \
    CONFIG.PL_LINK_CAP_MAX_LINK_SPEED {2.5_GT/s} \
    CONFIG.PL_LINK_CAP_MAX_LINK_WIDTH {X1} \
    CONFIG.AXISTEN_IF_EXT_512_RQ_STRADDLE {false} \
    CONFIG.PF0_DEVICE_ID {{ get_device_id(device_config, device, config_space, device_id_int) }} \
    CONFIG.PF0_VENDOR_ID {{ get_vendor_id(device_config, device, config_space, vendor_id_int) }} \
    CONFIG.PF0_SUBSYSTEM_VENDOR_ID {{ get_subsystem_vendor_id(device_config, device, vendor_id_int) }} \
    CONFIG.PF0_SUBSYSTEM_ID {{ get_subsystem_device_id(device_config, device, device_id_int) }} \
    CONFIG.PF0_REVISION_ID {{ device.revision_id }} \
    CONFIG.PF0_CLASS_CODE {040300} \
    CONFIG.PF0_BAR0_SCALE {Kilobytes} \
    CONFIG.PF0_BAR0_SIZE {128} \
    CONFIG.PF0_MSI_ENABLED {false} \
    CONFIG.PF0_MSIX_ENABLED {true} \
] $ip

# Generate IP targets for complete synthesis flow
generate_target {instantiation_template synthesis implementation} $ip

# Export IP user files for out-of-context runs
export_ip_user_files -of_objects $ip -force
{% else %}
# Custom PCIe implementation for {{ safe_name(board) }}
# This part uses custom SystemVerilog modules instead of Xilinx IP cores

# Set device-specific parameters for custom PCIe implementation
set DEVICE_ID {{ device.device_id }}
set VENDOR_ID {{ device.vendor_id }}
set REVISION_ID {{ device.revision_id }}
set SUBSYSTEM_VENDOR_ID {{ device.vendor_id }}
set SUBSYSTEM_ID 0000

puts "Using custom PCIe implementation for {{ safe_name(board) }}"
puts "Device ID: $DEVICE_ID"
puts "Vendor ID: $VENDOR_ID"
puts "Revision ID: $REVISION_ID"

# No IP cores required - PCIe functionality implemented in custom SystemVerilog modules
{% endif %}

puts "PCIe IP core configuration completed"