{{ header_comment }}
puts "Setting up PCILeech build environment..."
{%- from "_helpers.j2" import safe_attr, safe_name %}
# Set batch mode for automated builds
{%- set _build_jobs = (build.jobs if (build is defined and build.jobs is defined) else kwargs.get('build', {}).get('jobs', None) if kwargs is defined else None) -%}
{%- if batch_mode or _build_jobs is not none %}
set_param general.maxThreads {{ (_build_jobs if _build_jobs is not none else 1) }}
set_param synth.maxThreads {{ (_build_jobs if _build_jobs is not none else 1) }}
set_param place.maxThreads {{ (_build_jobs if _build_jobs is not none else 1) }}
set_param route.maxThreads {{ (_build_jobs if _build_jobs is not none else 1) }}
{%- endif %}

# Error handling configuration
set_msg_config -id {Common 17-55} -suppress
set_msg_config -id {Vivado 12-1387} -suppress
set_msg_config -id {Synth 8-3331} -suppress
set_msg_config -id {Synth 8-3332} -suppress
# End of error handling configuration

{%- set _proj_name = safe_name(project) -%}
{%- set _proj_dir = (project.dir if project is defined and project.dir is defined else project_dir|default('.')) -%}
{%- set _fpga_part = safe_attr(board, 'fpga_part', fpga_part|default('xc7a35t')) -%}
{%- set _board_name = safe_attr(board, 'name', board_name|default('generic')) -%}

{# Safely compute build jobs if build object exists #}
{%- set _build_jobs = None -%}
{%- if build is defined and build is not none -%}
    {%- if build.jobs is defined -%}
        {%- set _build_jobs = build.jobs -%}
    {%- endif -%}
{%- endif -%}

# Project configuration
set project_name "{{ _proj_name }}"
set project_dir "{{ _proj_dir }}"
set fpga_part "{{ _fpga_part }}"
set board_name "{{ _board_name }}"

# Build strategies
set synthesis_strategy "{{ synthesis_strategy | default('default') }}"
set implementation_strategy "{{ implementation_strategy | default('default') }}"

# Open existing project
puts "Opening PCILeech project: $project_name"
if {[file exists [file join $project_dir "${project_name}.xpr"]]} {
    open_project [file join $project_dir "${project_name}.xpr"]
} else {
    puts "ERROR: Project file not found. Run project generation script first."
    exit 1
}

# Verify project is properly configured
if {[get_property PART [current_project]] != $fpga_part} {
    puts "ERROR: Project FPGA part mismatch. Expected: $fpga_part"
    exit 1
}

puts "Project opened successfully"
puts "FPGA Part: [get_property PART [current_project]]"
puts "Target Language: [get_property TARGET_LANGUAGE [current_project]]"

# Ensure all .sv files are treated as SystemVerilog
set sv_in_proj [get_files -of_objects [get_filesets sources_1] *.sv]
if {[llength $sv_in_proj] > 0} {
    puts "Setting file type=SystemVerilog for [llength $sv_in_proj] .sv files"
    set_property file_type SystemVerilog $sv_in_proj
    foreach sv_file $sv_in_proj {
        puts "  -> File type now: [get_property file_type [get_files $sv_file]] ($sv_file)"
    }
}

# Refresh compile order after file-type changes
update_compile_order -fileset sources_1

# Reset runs to ensure clean build
reset_run synth_1
reset_run impl_1

# Configure synthesis strategy
puts "Configuring synthesis strategy: $synthesis_strategy"
set_property strategy $synthesis_strategy [get_runs synth_1]

{%- if fpga_family == "ultrascale" or fpga_family == "ultrascale_plus" %}
# UltraScale-specific synthesis options
set_property -name {STEPS.SYNTH_DESIGN.ARGS.MORE OPTIONS} -value {-mode out_of_context} -objects [get_runs synth_1]
set_property -name {STEPS.SYNTH_DESIGN.ARGS.FLATTEN_HIERARCHY} -value {rebuilt} -objects [get_runs synth_1]
{%- else %}
# 7-Series synthesis options
set_property -name {STEPS.SYNTH_DESIGN.ARGS.FLATTEN_HIERARCHY} -value {rebuilt} -objects [get_runs synth_1]
set_property -name {STEPS.SYNTH_DESIGN.ARGS.GATED_CLOCK_CONVERSION} -value {off} -objects [get_runs synth_1]
{%- endif %}

# Configure implementation strategy
puts "Configuring implementation strategy: $implementation_strategy"
set_property strategy $implementation_strategy [get_runs impl_1]

# Advanced implementation options for PCILeech
set_property -name {STEPS.PLACE_DESIGN.ARGS.MORE OPTIONS} -value {-timing_summary} -objects [get_runs impl_1]
set_property -name {STEPS.ROUTE_DESIGN.ARGS.MORE OPTIONS} -value {-timing_summary} -objects [get_runs impl_1]

{%- if batch_mode %}
# Batch mode specific settings
set_property -name {STEPS.SYNTH_DESIGN.ARGS.MORE OPTIONS} -value {-no_iobuf} -objects [get_runs synth_1]
{%- endif %}

# Start synthesis
puts "Starting synthesis..."
puts "Strategy: $synthesis_strategy"
puts "Jobs: {{ _build_jobs if _build_jobs is not none else 1 }}"

launch_runs synth_1 -jobs {{ _build_jobs if _build_jobs is not none else 1 }}
wait_on_run synth_1

# Check synthesis results
if {[get_property PROGRESS [get_runs synth_1]] != "100%"} {
    puts "ERROR: Synthesis failed"
    exit 1
}

if {[get_property NEEDS_REFRESH [get_runs synth_1]] == 1} {
    puts "ERROR: Synthesis needs refresh"
    exit 1
}

puts "Synthesis completed successfully"

# Generate synthesis reports
puts "Generating synthesis reports..."
open_run synth_1 -name synth_1
report_timing_summary -delay_type min_max -report_unconstrained -check_timing_verbose -max_paths 10 -input_pins -routable_nets -file timing_synth.rpt
report_utilization -file utilization_synth.rpt
report_power -file power_synth.rpt

# Start implementation
puts "Starting implementation..."
puts "Strategy: $implementation_strategy"

launch_runs impl_1 -jobs {{ _build_jobs if _build_jobs is not none else 1 }}
wait_on_run impl_1

# Check implementation results
if {[get_property PROGRESS [get_runs impl_1]] != "100%"} {
    puts "ERROR: Implementation failed"
    exit 1
}

if {[get_property NEEDS_REFRESH [get_runs impl_1]] == 1} {
    puts "ERROR: Implementation needs refresh"
    exit 1
}

puts "Implementation completed successfully"

# Generate implementation reports
puts "Generating implementation reports..."
open_run impl_1
report_timing_summary -delay_type min_max -report_unconstrained -check_timing_verbose -max_paths 10 -input_pins -routable_nets -file timing_impl.rpt
report_utilization -file utilization_impl.rpt
report_power -file power_impl.rpt
report_drc -file drc.rpt
report_methodology -file methodology.rpt

# Check timing closure
set timing_met 0.0
set hold_met 0.0

catch {
    set timing_met [get_property STATS.WNS [get_runs impl_1]]
    set hold_met [get_property STATS.WHS [get_runs impl_1]]
}

puts "Timing Results:"
puts "  Setup (WNS): $timing_met ns"
puts "  Hold (WHS): $hold_met ns"

if {$timing_met < 0} {
    puts "WARNING: Setup timing not met (WNS: $timing_met ns)"
}

if {$hold_met < 0} {
    puts "WARNING: Hold timing not met (WHS: $hold_met ns)"
}

# Generate bitstream
puts "Starting bitstream generation..."

# Configure bitstream options
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 33 [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]

{%- if fpga_family == "7series" %}
# 7-Series specific bitstream options
set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design]
set_property BITSTREAM.STARTUP.STARTUPCLK CCLK [current_design]
{%- elif fpga_family == "ultrascale" or fpga_family == "ultrascale_plus" %}
# UltraScale specific bitstream options
set_property BITSTREAM.CONFIG.OVERTEMPSHUTDOWN Enable [current_design]
{%- endif %}

launch_runs impl_1 -to_step write_bitstream -jobs {{ _build_jobs if _build_jobs is not none else 1 }}
wait_on_run impl_1

# Check bitstream generation
if {[get_property PROGRESS [get_runs impl_1]] != "100%"} {
    puts "ERROR: Bitstream generation failed"
    exit 1
}

puts "Bitstream generation completed successfully"

# Copy output files to root directory
set bit_file [file join $project_dir "${project_name}.runs" "impl_1" "*.bit"]
set ltx_file [file join $project_dir "${project_name}.runs" "impl_1" "*.ltx"]

# Find and copy bitstream file
set bit_files [glob -nocomplain $bit_file]
if {[llength $bit_files] > 0} {
    set source_bit [lindex $bit_files 0]
    set dest_bit "${board_name}.bit"
    file copy -force $source_bit $dest_bit
    puts "Bitstream copied to: $dest_bit"
    
    # Get file size for validation
    set bit_size [file size $dest_bit]
    set bit_size_mb [expr {$bit_size / 1024.0 / 1024.0}]
    puts "Bitstream size: [format "%.2f" $bit_size_mb] MB"
    
    if {$bit_size_mb < 0.5} {
        puts "WARNING: Bitstream size is unusually small"
    }
} else {
    puts "ERROR: Bitstream file not found"
    exit 1
}

# Copy debug probes file if it exists
set ltx_files [glob -nocomplain $ltx_file]
if {[llength $ltx_files] > 0} {
    set source_ltx [lindex $ltx_files 0]
    set dest_ltx "${board_name}.ltx"
    file copy -force $source_ltx $dest_ltx
    puts "Debug probes copied to: $dest_ltx"
}

# Generate MCS file for flash programming
puts "Generating MCS file for flash programming..."
set mcs_file "${board_name}.mcs"

{%- if fpga_family == "7series" %}
write_cfgmem -format mcs -size 16 -interface SPIx4 -loadbit "up 0x0 $dest_bit" -file $mcs_file
{%- elif fpga_family == "ultrascale" or fpga_family == "ultrascale_plus" %}
write_cfgmem -format mcs -size 32 -interface SPIx4 -loadbit "up 0x0 $dest_bit" -file $mcs_file
{%- endif %}

if {[file exists $mcs_file]} {
    puts "MCS file generated: $mcs_file"
} else {
    puts "WARNING: MCS file generation failed"
}

# Final build summary
puts ""
puts "========================================="
puts "PCILeech Build Summary"
puts "========================================="
puts "Board: $board_name"
puts "FPGA: $fpga_part"
puts "Project: $project_name"
puts "Synthesis Strategy: $synthesis_strategy"
puts "Implementation Strategy: $implementation_strategy"
puts "Setup Timing (WNS): $timing_met ns"
puts "Hold Timing (WHS): $hold_met ns"
puts "Output Files:"
puts "  Bitstream: $dest_bit ([format "%.2f" $bit_size_mb] MB)"
if {[file exists $mcs_file]} {
    puts "  Flash File: $mcs_file"
}
if {[file exists $dest_ltx]} {
    puts "  Debug Probes: $dest_ltx"
}
puts "========================================="

if {$timing_met >= 0 && $hold_met >= 0} {
    puts "BUILD SUCCESSFUL - All timing constraints met"
} else {
    puts "BUILD COMPLETED - WARNING: Timing constraints not met"
}

# Close project
close_project

puts "PCILeech build completed!"