################################################################################
#
#   Main Script to buil any project in the repository
#
################################################################################
source functions.tcl -notrace
write_msg "INFO: Launching Vivado TCL mode" "1"

if { $::argc == 3 } {
    set target_path  [lindex $argv 0]
    set run_type  [lindex $argv 1]
    set output_path [lindex $argv 2]
} else {
    write_msg "ERROR: Bad call to tcl script build_project.tcl" "3"
    return 1
}

# Loading project specific config
source ${target_path}/tcl/project_cfg.tcl -notrace
set_param general.maxThreads ${max_threads}

# Set the project name
set _xil_proj_name_ ${project_name}
source ${target_path}/tcl/create_bd.tcl -notrace

# Create project
create_project ${_xil_proj_name_} ${output_path}/${_xil_proj_name_} -part ${reference_part}

# Source TCL FPGA Device
source common-ip/fpga_device/tcl/fpga_device.tcl
create_fpga_version "${_xil_proj_name_}" "common-ip/fpga_device/src/fpga_device.v" "${output_path}/${_xil_proj_name_}/fpga_device.v"
add_files -norecurse common-ip/fpga_device/src/dna_reader.v
add_files -norecurse ${output_path}/${_xil_proj_name_}/fpga_device.v

# Set Properties from the list
if [ info exist ::user_list(PROP_NAME) ] {
    set curr_project [ current_project ]
    set list_names [ get_list PROP_NAME ]
    set list_values [ get_list PROP_VAL ]
    set list_names_max_i [ get_list_size  PROP_NAME ]
    for { set i 0 } { $i < ${list_names_max_i} } { incr i } {
        set lname [ lindex ${list_names} ${i} ]
        set lvalue [ lindex ${list_values} ${i} ]
        write_msg "INFO: Set property $lname to $lvalue" "1"
        set_property -name $lname -value $lvalue -objects $curr_project
    }
}

# Add VHDL
if [ info exist ::user_list(SRC_VHDL) ] {
    set list_vhdl [ get_list SRC_VHDL ]
    set list_lib [ get_list LIB_VHDL ]
    set list_vhdl_max_i [ get_list_size  SRC_VHDL ]
    for { set i 0 } { $i < ${list_vhdl_max_i} } { incr i } {
        set vhdl_src [ lindex ${list_vhdl} ${i} ]
        set vhdl_lib [ lindex ${list_lib} ${i} ]
        write_msg "INFO: Adding VHLD file ${vhdl_src}" "1"
        read_vhdl -library ${vhdl_lib} ${target_path}/src/${vhdl_src}
    }
}

# Add VHDL08
if [ info exist ::user_list(SRC_VHDL08) ] {
    set list_vhdl [ get_list SRC_VHDL08 ]
    set list_lib [ get_list LIB_VHDL08 ]
    set list_vhdl_max_i [ get_list_size  SRC_VHDL08 ]
    for { set i 0 } { $i < ${list_vhdl_max_i} } { incr i } {
        set vhdl_src [ lindex ${list_vhdl} ${i} ]
        set vhdl_lib [ lindex ${list_lib} ${i} ]
        write_msg "INFO: Adding VHLD 2008 file ${vhdl_src}" "1"
        read_vhdl -library ${vhdl_lib} -2008 ${target_path}/src/${vhdl_src}
    }
}

# Add Verilog/SystemVerilog sources
if [ info exist ::user_list(SRC_VERILOG) ] {
    set list_ver [ get_list SRC_VERILOG ]
    set list_ver_max_i [ get_list_size  SRC_VERILOG ]
    for { set i 0 } { $i < ${list_ver_max_i} } { incr i } {
        set ver_src [ lindex ${list_ver} ${i} ]
        if { [ enable_sv_compilation ${ver_src} ] == 1 } {
            write_msg "INFO: Adding SystemVerilog file ${ver_src}" "1"
            read_verilog -library ${lib_default} -sv ${target_path}/src/${ver_src}
        } else {
            write_msg "INFO: Adding Verilog file ${ver_src}" "1"
            read_verilog -library ${lib_default} ${target_path}/src/${ver_src}
        }
    }
}

# Add XDC Files
if [ info exist ::user_list(CONSTRAINT) ] {
    set list_xdc [ get_list CONSTRAINT ]
    set list_names_max_i [ get_list_size  CONSTRAINT ]
    for { set i 0 } { $i < ${list_names_max_i} } { incr i } {
        set file_xdc [ lindex ${list_xdc} ${i} ]
        write_msg "INFO: Adding XDC file ${file_xdc}" "1"
        read_xdc ${target_path}/constraints/${file_xdc}
    }
}

# Set the directory path for the new project
set proj_dir [get_property directory [current_project]]

# Create 'sources_1' fileset (if not found)
if {[string equal [get_filesets -quiet sources_1] ""]} {
    create_fileset -srcset sources_1
}

update_ip_catalog -rebuild

set obj [get_filesets sources_1]
set_property -name "top" -value ${entity_top} -objects $obj

# ##############################################################################
#   Create Block Design
# ##############################################################################
write_msg "INFO: Generating block design" "1"
create_block_design "" ${_xil_proj_name_} ${target_path}
update_compile_order -fileset sources_1

set_property IS_ENABLED "1" [ get_files ${_xil_proj_name_}.bd ]
set_property REGISTERED_WITH_MANAGER "1" [ get_files ${_xil_proj_name_}.bd ]
set_property SYNTH_CHECKPOINT_MODE "Hierarchical" [ get_files ${_xil_proj_name_}.bd ]

# ##############################################################################
#   Launch synthesis & implementation
# ##############################################################################
if { [ string equal ${run_type} "build" ] } {

    # Launch Synthesis
    write_msg "INFO: Launch Synthesis" "1"
    launch_runs synth_1 -jobs ${max_threads}
    wait_on_run synth_1
    set status_synth [ get_property STATUS [ get_runs synth_1 ] ]
    if { [ string equal ${status_synth} "synth_design Complete!" ] } {
        write_msg "INFO: ${status_synth}" "1"
    } else {
        write_msg "ERROR: Synthesis run failed" "3"
        write_msg "ERROR: ${status_synth}" "3"
        exit 1
    }

    # Set Implementation Properties
    set obj [ get_runs impl_1 ]
    set_property -name "steps.phys_opt_design.is_enabled" -value "1" -objects $obj

    # Launch Implementation & Bitstream
    write_msg "INFO: Launch Implementation & Bistream generation" "1"
    launch_runs impl_1 -to_step write_bitstream -jobs ${max_threads}
    wait_on_run impl_1
    set status_impl_1 [ get_property STATUS [ get_runs impl_1 ] ]
    if { [ string equal ${status_impl_1} "write_bitstream Complete!" ] } {
        write_msg "INFO: ${status_impl_1}" "1"
    } else {
        write_msg "ERROR: Implementation run failed" "3"
        write_msg "ERROR: ${status_impl_1}" "3"
        exit 1
    }

    # Copy Bitstream
    if { [ file exists ${output_path}/${_xil_proj_name_}/${_xil_proj_name_}.runs/impl_1/${entity_top}.bit ] } {
        write_msg "INFO: Copy Bistream" "1"
        file copy ${output_path}/${_xil_proj_name_}/${_xil_proj_name_}.runs/impl_1/${entity_top}.bit ${output_path}/${_xil_proj_name_}/${_xil_proj_name_}.bit
        write_msg "INFO: Generating XSA with bitstream ${output_path}/${_xil_proj_name_}/${_xil_proj_name_}.xsa" "1"
        write_hw_platform -force ${output_path}/${_xil_proj_name_}/${_xil_proj_name_}.xsa -fixed -include_bit
    } else {
        write_msg "ERROR: Failed Bistream Generation" "3"
        exit 1
    }

} else {

    # Generate XSA without bistream
    write_msg "INFO: Target Hardware Platform" "1"
    generate_target {synthesis implementation} [get_files ${output_path}/${_xil_proj_name_}/${_xil_proj_name_}.srcs/sources_1/bd/${_xil_proj_name_}/${_xil_proj_name_}.bd]
    write_msg "INFO: Generating XSA file ${output_path}/${_xil_proj_name_}/${_xil_proj_name_}.xsa" "1"
    write_hw_platform -force ${output_path}/${_xil_proj_name_}/${_xil_proj_name_}.xsa -fixed

}
exit 0
