{{ header | safe }}

{# ========== Constants and Configuration ========== #}
{% set CAP_OFFSET_PM = 0x40 %}
{% set CAP_OFFSET_MSI = 0x48 %}
{% set CAP_OFFSET_MSIX = 0x50 %}
{% set CAP_OFFSET_PCIE = 0x60 %}
{% set CAP_OFFSET_AER = 0xA0 %}
{% set EXTENDED_CFG_START = 0x100 %}
{% set EXTENDED_CFG_END = 0x1000 %}

{# ========== Helper Functions and Macros ========== #}

{# Import small helper macros for safe attribute access #}
{% from "_helpers.j2" import safe_name, safe_fpga_part, safe_attr, safe_int, get_vendor_id, get_device_id, get_subsystem_vendor_id, get_subsystem_device_id %}

{# Helper function to check if MSI-X is supported with consistent logic #}
{% macro is_msix_supported() %}
{{ (msix_config is defined) and (msix_config and (msix_config.is_supported if hasattr(msix_config, 'is_supported') else (msix_config.num_vectors|default(0) > 0))) }}
{% endmacro %}

{# Macro for BAR validation #}
{% macro validate_bar_configs() %}
{# Be permissive during migration: warn when bars are missing and emit disabled BARs instead of failing to render #}
{% if not bar_config or (bar_config.bars is defined and bar_config.bars|length == 0) %}
  ; Warning: no BAR configuration available - template will emit disabled BARs
{% endif %}
{% endmacro %}

{# Macro for formatting BAR entries consistently - NO DEFAULT VALUES allowed for base address #}
{% macro render_bar(index, bar=None, is_io=false) %}
{% set bar_name = "BAR" ~ index %}
{% if bar %}
  {% if (bar.size is defined and bar.size > 0) and hasattr(bar, 'get_size_encoding') %}
; {{ bar_name }}: {{ bar.bar_type | default('mem') }} BAR, Size: 0x{{ "%X" % (bar.size | safe_int(0)) }} bytes
{{ "%08X" % (bar.get_size_encoding() | safe_int(0)) }},
  {% elif bar.base_address is defined %}
; {{ bar_name }}: Using base address
{{ "%08X" % (bar.base_address | safe_int(0)) }},
  {% else %}
; {{ bar_name }}: Disabled (no size/base) - emitting zero
00000000,
  {% endif %}
{% else %}
  {% if not (bar_config is defined and bar_config.bars is defined and bar_config.bars|length > 0) %}
; {{ bar_name }}: Disabled (not configured)
00000000,
  {% else %}
; {{ bar_name }}: Disabled (not configured)
00000000,
  {% endif %}
{% endif %}
{% endmacro %}

{# ========== Comprehensive Validation (permissive) ========== #}
{# Provide safe local defaults so templates can render during migration. Runtime should validate strictly. #}
{% set config_space = config_space or {} %}
{% set bar_config = bar_config or {} %}
{% set device_config = device_config or {} %}
{% set timing_config = timing_config or {} %}
{% set pcileech_config = pcileech_config or {} %}
{% set msix_config = msix_config or {} %}

{# Local guarded variables for PCILeech config values used in comments or non-fatal output #}
{% set pcileech_command_timeout = pcileech_config.command_timeout if (pcileech_config is defined and pcileech_config.command_timeout is defined) else 1000 %}
{% set pcileech_buffer_size = pcileech_config.buffer_size if (pcileech_config is defined and pcileech_config.buffer_size is defined) else 4096 %}

{# Use centralized helper functions for consistent ID handling #}
{% set vendor_id_int = get_vendor_id(device_config, device, config_space, vendor_id_int) %}
{% set device_id_int = get_device_id(device_config, device, config_space, device_id_int) %}

; Device Information (fallbacks used when fields are missing):
; - Vendor ID: {{ get_vendor_id(device_config, device, config_space, vendor_id_int) }}
; - Device ID: {{ get_device_id(device_config, device, config_space, device_id_int) }}
; - Class Code: {{ safe_attr(config_space, 'class_code', '00') }}
; - Revision ID: {{ safe_attr(config_space, 'revision_id', '00') }}
;
; Generation Metadata:
; - Generated: {{ safe_attr(generation_metadata, 'generated_at', 'unknown') }}
; - Device BDF: {{ safe_attr(device_config, 'device_bdf', '00:00.0') }}
; - Has Behavior Profile: {{ safe_attr(device_config, 'behavior_profile', false) }}
; - MSI-X Vectors: {{ safe_attr(msix_config, 'num_vectors', 0) }}

memory_initialization_radix=16;
memory_initialization_vector=

{{ validate_bar_configs() }}
; =====================================================================
; Standard PCI Configuration Header (0x00-0x3F)
; =====================================================================

; Vendor ID (0x00-0x01) and Device ID (0x02-0x03)
{{ get_device_id(device_config, device, config_space, device_id_int) }}{{ get_vendor_id(device_config, device, config_space, vendor_id_int) }},

; Command Register (0x04-0x05) and Status Register (0x06-0x07)
; Command: Memory Space Enable + Bus Master Enable
; Status: Capabilities List + Fast Back-to-Back + 66MHz Capable
{% set command_register = "0210" if (safe_attr(device_config, 'enable_dma_operations', true)) else "0200" %}
{{ command_register }}0006,

; Revision ID (0x08), Programming Interface (0x09), Sub Class (0x0A), Base Class (0x0B)
{{ safe_attr(config_space, 'class_code', '00') | string }}{{ safe_attr(config_space, 'revision_id', '00') | string }},

; Cache Line Size (0x0C), Latency Timer (0x0D), Header Type (0x0E), BIST (0x0F)
00001010,

; Base Address Registers (0x10-0x27)
{% set bars = (bar_config.bars if (bar_config is defined and bar_config.bars is defined) else []) %}
{% set has_bars = (bars | length) > 0 %}

; BAR0 (0x10-0x13) - Memory BAR
{% if has_bars %}
{{ render_bar(0, bars[0]) }}
{% else %}
{{ render_bar(0) }}
{% endif %}

; BAR1 (0x14-0x17) - Upper 32 bits for 64-bit BAR or second BAR
{% if has_bars and (bars[0].is_64bit if bars|length > 0 and (bars[0] is not none) else False) %}
; BAR1: Upper 32 bits of 64-bit BAR0
FFFFFFFF,
{% elif has_bars and bars|length > 1 %}
{{ render_bar(1, bars[1]) }}
{% else %}
; BAR1: Disabled (not configured)
00000000,
{% endif %}

; BAR2 (0x18-0x1B) - I/O BAR or third memory BAR
{% if has_bars and bars|length > 2 %}
{{ render_bar(2, bars[2], true) }}
{% else %}
; BAR2: Disabled (not configured)
00000000,
{% endif %}

; BAR3 (0x1C-0x1F) - Fourth BAR
{% if has_bars and bars|length > 3 %}
{{ render_bar(3, bars[3]) }}
{% else %}
; BAR3: Disabled (not configured)
00000000,
{% endif %}

; BAR4 (0x20-0x23) - Fifth BAR
{% if has_bars and bars|length > 4 %}
{{ render_bar(4, bars[4]) }}
{% else %}
; BAR4: Disabled (not configured)
00000000,
{% endif %}

; BAR5 (0x24-0x27) - Sixth BAR
{% if has_bars and bars|length > 5 %}
{{ render_bar(5, bars[5]) }}
{% else %}
; BAR5: Disabled (not configured)
00000000,
{% endif %}

; Cardbus CIS Pointer (0x28-0x2B) - Unused
00000000,

; Subsystem Vendor ID (0x2C-0x2D) and Subsystem ID (0x2E-0x2F)
{% set has_device = device is defined %}
{% set has_subsys_device_id = has_device and hasattr(device, 'subsys_device_id') %}
{% set has_subsys_vendor_id = has_device and hasattr(device, 'subsys_vendor_id') %}
{% set valid_subsys_device_id = has_subsys_device_id and device.subsys_device_id != "0000" %}
{% set valid_subsys_vendor_id = has_subsys_vendor_id and device.subsys_vendor_id != "0000" %}
{# Subsystem IDs - use centralized helpers with proper fallbacks #}
{% set subsys_vid_str = get_subsystem_vendor_id(device_config, device, vendor_id_int) %}
{% set subsys_dev_str = get_subsystem_device_id(device_config, device, device_id_int) %}
{% if subsys_dev_str != '0000' and subsys_vid_str != '0000' %}
; Subsystem: {{ subsys_dev_str }}:{{ subsys_vid_str }}
{{ subsys_dev_str }}{{ subsys_vid_str }},
{% else %}
; Subsystem: Not configured
00000000,
{% endif %}

; Expansion ROM Base Address (0x30-0x33) - Disabled
00000000,

; Capabilities Pointer (0x34), Reserved (0x35-0x3B)
; Points to first capability at 0x40
{{ "%02X" % (CAP_OFFSET_PM | safe_int(0)) }}000000,

; Interrupt Line (0x3C), Interrupt Pin (0x3D), Min_Gnt (0x3E), Max_Lat (0x3F)
; Using INTA (0x01) for interrupt pin
0000010B,

; =====================================================================
; PCI Capabilities
; =====================================================================

; Power Management Capability ({{ CAP_OFFSET_PM }}-{{ CAP_OFFSET_PM + 7 }})
; Cap ID=0x01, Next=0x50, PMC=0x0003, PMCSR=0x0000
{% set next_cap = CAP_OFFSET_MSI %}
{% set pm_cap_header = "0003" ~ ("%02X" % (next_cap | safe_int(0))) ~ "01" %}
{{ pm_cap_header }},
00000000,

{# Define variables outside conditional blocks so they're always available #}
{% set msix_enabled = is_msix_supported() %}
{% set next_cap = CAP_OFFSET_PCIE %}
{% set msi_cap_header = "0080" ~ ("%02X" % (next_cap | safe_int(0))) ~ "05" %}
{% set msix_control = ("%04X" % ((msix_config.num_vectors - 1) | safe_int(0))) if (msix_config.num_vectors|default(0) > 0) else "0000" %}
{% set msix_cap_header = msix_control ~ ("%02X" % (next_cap | safe_int(0))) ~ "11" %}

; MSI Capability ({{ CAP_OFFSET_MSI }}-{{ CAP_OFFSET_MSI + 7 }})
{% if not msix_enabled %}
; Cap ID=0x05, Next=0x60, Message Control=0x0080 (64-bit capable)
{{ msi_cap_header }},
; Message Address Lower 32 bits
00000000,
{% else %}
; Reserved space when MSI-X is used
00000000,
00000000,
{% endif %}

; MSI-X Capability ({{ CAP_OFFSET_MSIX }}-{{ CAP_OFFSET_MSIX + 11 }})
{% if msix_enabled %}
{# Set default values if msix_config.table_offset or msix_config.pba_offset are not defined #}
{% set msix_table_offset = msix_config.table_offset|default(0x1000) %}
{% set msix_table_bir = msix_config.table_bir|default(0) %}
{% set msix_pba_offset = msix_config.pba_offset|default(0x800) %}
{% set msix_pba_bir = msix_config.pba_bir|default(0) %}

; Cap ID=0x11, Next=0x70, Message Control={{ "%04X" % ((msix_config.num_vectors - 1) | safe_int(0)) }}
{# Variables already defined above #}
{{ msix_cap_header }},

; Table Offset/BIR: Offset={{ "%08X" % (msix_table_offset | safe_int(0)) }}, BIR={{ msix_table_bir }}
{# Encode as [31:3]=offset, [2:0]=BIR; require 8-byte alignment #}
{% if (msix_table_offset | safe_int(0)) % 8 != 0 %}
; Error: MSI-X table offset must be 8-byte aligned
{%- error "MSI-X table offset must be 8-byte aligned" %}
{% endif %}
{# Encode as (offset - offset%8) + (bir%8) #}
{% set _tbl_off = (msix_table_offset | safe_int(0)) %}
{% set _tbl_bir = (msix_table_bir | safe_int(0)) %}
{% set table_offset_bir = (_tbl_off - (_tbl_off % 8)) + (_tbl_bir % 8) %}
{{ "%08X" % table_offset_bir }},

; PBA Offset/BIR: Offset={{ "%08X" % (msix_pba_offset | safe_int(0)) }}, BIR={{ msix_pba_bir }}
{# Encode as [31:3]=offset, [2:0]=BIR; require 8-byte alignment #}
{% if (msix_pba_offset | safe_int(0)) % 8 != 0 %}
; Error: MSI-X PBA offset must be 8-byte aligned
{%- error "MSI-X PBA offset must be 8-byte aligned" %}
{% endif %}
{# Encode as (offset - offset%8) + (bir%8) #}
{% set _pba_off = (msix_pba_offset | safe_int(0)) %}
{% set _pba_bir = (msix_pba_bir | safe_int(0)) %}
{% set pba_offset_bir = (_pba_off - (_pba_off % 8)) + (_pba_bir % 8) %}
{{ "%08X" % pba_offset_bir }},
{% else %}
; No MSI-X capability
00000000,
00000000,
00000000,
{% endif %}

; PCIe Capability ({{ CAP_OFFSET_PCIE }}-{{ CAP_OFFSET_PCIE + 63 }})
; Cap ID=0x10, Next=0x00 (end of chain), PCIe Capabilities=0x0002
{% set next_cap = CAP_OFFSET_AER if device_config.enable_advanced_features else 0 %}
{% set pcie_cap_header = "0002" ~ ("%02X" % (next_cap | safe_int(0))) ~ "10" %}
{{ pcie_cap_header }},

; Device Capabilities
00000000,
; Device Control and Status
00000000,
; Link Capabilities
00000000,
; Link Control and Status
00000000,
; Slot Capabilities (if applicable)
00000000,
; Slot Control and Status
00000000,
; Root Capabilities
00000000,
; Root Control and Status
00000000,
; Device Capabilities 2
00000000,
; Device Control 2 and Status 2
00000000,
; Link Capabilities 2
00000000,
; Link Control 2 and Status 2
00000000,
; Slot Capabilities 2
00000000,
; Slot Control 2 and Status 2
00000000,

{% if device_config.enable_advanced_features %}
; =====================================================================
; Advanced Error Reporting Capability ({{ CAP_OFFSET_AER }}-{{ CAP_OFFSET_AER + 63 }})
; =====================================================================
; Cap ID=0x01, Next=0x00, AER Capabilities=0x0000
00000001,
; Uncorrectable Error Status (latched events)
00000000,
; Uncorrectable Error Mask
{% if aer is not defined or not aer %}
; Warning: AER context missing - zeroing uncorrectable error mask
{% endif %}
{{ "%08X" % ((aer.uncorrectable_error_mask if (aer is defined and aer and (aer.uncorrectable_error_mask is defined)) else 0) | safe_int(0)) }},
; Uncorrectable Error Severity
{% if aer is not defined or not aer %}
; Warning: AER context missing - zeroing uncorrectable error severity
{% endif %}
{{ "%08X" % ((aer.uncorrectable_error_severity if (aer is defined and aer and (aer.uncorrectable_error_severity is defined)) else 0) | safe_int(0)) }},
; Correctable Error Status (latched events)
00000000,
; Correctable Error Mask
{% if aer is not defined or not aer %}
; Warning: AER context missing - zeroing correctable error mask
{% endif %}
{{ "%08X" % ((aer.correctable_error_mask if (aer is defined and aer and (aer.correctable_error_mask is defined)) else 0) | safe_int(0)) }},
; Advanced Error Capabilities and Control
{% if aer is not defined or not aer %}
; Warning: AER context missing - zeroing advanced error capabilities
{% endif %}
{{ "%08X" % ((aer.advanced_error_capabilities if (aer is defined and aer and (aer.advanced_error_capabilities is defined)) else 0) | safe_int(0)) }},
; Header Log (4 DWORDs)
00000000,
00000000,
00000000,
00000000,
{% if device_config.enable_error_injection %}
; Optional Error Injection Control (implementation dependent)
; This build enables error injection hooks in HDL (not represented here).
{% endif %}
; Root Error Command
00000000,
; Root Error Status
00000000,
; Error Source Identification
00000000,
; Reserved
00000000,
00000000,
00000000,
{% endif %}

{% if device_config and hasattr(device_config, 'has_manufacturing_variance') and device_config.has_manufacturing_variance %}
; =====================================================================
; Device-Specific Configuration based on Manufacturing Variance
; =====================================================================
{% if timing_config and hasattr(timing_config, 'timing_regularity') %}
{% if timing_config.timing_regularity > 0.8 %}
; High regularity device - optimized timing
{% elif timing_config.timing_regularity < 0.3 %}
; Low regularity device - conservative timing
{% else %}
; Medium regularity device - standard timing
{% endif %}
{% endif %}
{% endif %}

; =====================================================================
; Extended Configuration Space ({{ EXTENDED_CFG_START }}-{{ EXTENDED_CFG_END - 1 }})
; =====================================================================
; Mostly zeros for basic implementation
{% for i in range(EXTENDED_CFG_START, EXTENDED_CFG_END, 4) %}
{% if loop.index % 16 == 1 %}
; Offset {{ "%03X" % (i | safe_int(0)) }}
{% endif %}
00000000{% if not loop.last %},{% endif %}
{% endfor %};

; =====================================================================
; PCILeech-Specific Configuration Metadata
; =====================================================================
; This section contains device-specific configuration derived from behavior analysis
;
{% if device_config is defined and hasattr(device_config, 'behavior_profile') and device_config.behavior_profile %}
; Behavior Profile Summary:
; - Total Register Accesses: {{ device_config.total_register_accesses }}
; - Capture Duration: {{ device_config.capture_duration }}s
; - Timing Patterns: {{ device_config.timing_patterns_count }}
; - State Transitions: {{ device_config.state_transitions_count }}
{% endif %}
;
; PCILeech Configuration:
{% if not pcileech_config.command_timeout %}
{%- error "PCILeech command timeout is required - no fallback values allowed" %}
{% endif %}
; - Command Timeout: {{ pcileech_config.command_timeout }} cycles
{% if not pcileech_config.buffer_size %}
{%- error "PCILeech buffer size is required - no fallback values allowed" %}
{% endif %}
; - Buffer Size: {{ pcileech_config.buffer_size }} bytes
{% if pcileech_config.enable_dma is not defined %}
{%- error "PCILeech DMA operations setting is required - no fallback values allowed" %}
{% endif %}
; - DMA Operations: {{ pcileech_config.enable_dma }}
{% if pcileech_config.enable_scatter_gather is not defined %}
{%- error "PCILeech scatter-gather setting is required - no fallback values allowed" %}
{% endif %}
; - Scatter-Gather: {{ pcileech_config.enable_scatter_gather }}
;
; Timing Configuration:
{% if not timing_config.read_latency %}
{%- error "Timing read latency is required - no fallback values allowed" %}
{% endif %}
; - Read Latency: {{ timing_config.read_latency }} cycles
{% if not timing_config.write_latency %}
{%- error "Timing write latency is required - no fallback values allowed" %}
{% endif %}
; - Write Latency: {{ timing_config.write_latency }} cycles
{% if not timing_config.burst_length %}
{%- error "Timing burst length is required - no fallback values allowed" %}
{% endif %}
; - Burst Length: {{ timing_config.burst_length }}
{% if not timing_config.clock_frequency_mhz %}
{%- error "Timing clock frequency is required - no fallback values allowed" %}
{% endif %}
; - Clock Frequency: {{ timing_config.clock_frequency_mhz }} MHz
;
; BAR Configuration (using safe defaults when values are missing):
{# Use safe_attr to avoid TemplateObject attribute errors during migration #}
{% set primary_bar_index = safe_attr(bar_config, 'bar_index', 0) %}
; - Primary BAR Index: {{ primary_bar_index }}
{% set aperture_size = safe_attr(bar_config, 'aperture_size', 0) %}
; - Aperture Size: {{ aperture_size }} bytes
{% set bar_type = safe_attr(bar_config, 'bar_type', 0) %}
; - BAR Type: {{ bar_type }} (0=32-bit, 1=64-bit)
{% set prefetchable = safe_attr(bar_config, 'prefetchable', false) %}
; - Prefetchable: {{ prefetchable }}
