Files
embedded-autobuild/platform/xilinx/util.tcl
T
2024-10-26 00:49:32 +08:00

397 lines
14 KiB
Tcl
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package require json
# Helper procedure for formatted messages
proc _info {message} {
puts [format "INFO: %s" $message]
}
proc _warn {message} {
puts [format "WARN: %s" $message]
}
proc _error {message details} {
error [format "ERROR: %s. Details: %s" $message $details]
}
# Helper procedure to create hardware platform
proc _prepare_platform {hw_file platform_name is_vitis} {
if {![file exists $hw_file]} {
_error "Hardware design file does not exist" $hw_file
}
_info "Creating hardware platform: $platform_name"
if {$is_vitis} {
platform create -name $platform_name -hw $hw_file
_info "Platform '$platform_name' created successfully for Vitis."
} else {
sdk createhw -name $platform_name -hwspec $hw_file
_info "Hardware platform '$platform_name' created successfully for Xilinx SDK."
}
}
# Helper procedure for BSP configuration
proc _configure_bsp {bsp_name bsp_config platform_name is_vitis} {
set cpu [dict get $bsp_config target_cpu]
set os [dict get $bsp_config os]
# Create Domain/BSP
_info "Creating BSP: $bsp_name for CPU: $cpu and OS: $os"
if {$is_vitis} {
platform active $platform_name
domain create -name $bsp_name -os $os -proc $cpu
domain active $bsp_name
_info "BSP '$bsp_name' created for Vitis."
} else {
sdk createbsp -name $bsp_name -hwproject $platform_name -proc $cpu -os $os
_info "BSP '$bsp_name' created for Xilinx SDK."
}
# Apply BSP library configurations if they exist
if {[dict exists $bsp_config libs]} {
_info "Configuring BSP libraries..."
dict for {lib_name lib_info} [dict get $bsp_config libs] {
if {$is_vitis} {
bsp setlib -name $lib_name -ver [dict get $lib_info version]
} else {
setlib -bsp $bsp_name -lib $lib_name -ver [dict get $lib_info version]
}
_info "Applied library '$lib_name' version '[dict get $lib_info version]' for BSP '$bsp_name'."
if {[dict exists $lib_info config]} {
dict for {param value} [dict get $lib_info config] {
if {$is_vitis} {
bsp config $param $value
} else {
configbsp -bsp $bsp_name $param $value
}
_info "Configured library '$lib_name': $param = $value"
}
}
}
}
# Apply BSP configurations if they exist
if {[dict exists $bsp_config config]} {
_info "Configuring BSP options..."
dict for {param value} [dict get $bsp_config config] {
if {$is_vitis} {
bsp config $param $value
} else {
configbsp -bsp $bsp_name $param $value
}
_info "Applied BSP configuration: $param = $value for $bsp_name"
}
}
if {$is_vitis} {
bsp regenerate
} else {
regenbsp -bsp $bsp_name
projects -build -type bsp -name $bsp_name
}
_info "BSP '$bsp_name' successfully configured and regenerated."
return $bsp_name
}
# Helper procedure to handle source files: link or copy based on LINK_SRCS
proc _handle_sources {app_name sources} {
# Check environment variable LINK_SRCS
set link_srcs "y"
if {[info exists ::env(LINK_SRCS)]} {
set link_srcs $::env(LINK_SRCS)
}
foreach source_file $sources {
set source_path [file normalize $::root/$source_file]
set target_path [file join $::ws $app_name [file tail $source_path]]
# Delete existing symbolic link or file if it exists
if {[file exists $target_path]} {
file delete -force $target_path
_warn "Deleted existing link or file: $target_path"
}
# Handle source based on the value of LINK_SRCS
switch $link_srcs {
"y" {
# Create symbolic link
file link -symbolic $target_path $source_path
_info "Created symbolic link: $target_path -> $source_path"
}
"n" {
# Copy the source file
file copy $source_path $target_path
_info "Copied source file: $source_path to $target_path"
}
default {
_error "Unknown value for LINK_SRCS: ${link_srcs}."
}
}
}
}
proc _update_app_mem_layout {app_name mem_layout} {
# Update heap and stack sizes in linker script if specified
set lscript_path "$::ws/$app_name/src/lscript.ld"
if {[file exists $lscript_path]} {
set file_content {}
set file_id [open $lscript_path r]
while {[gets $file_id line] >= 0} {
if {[regexp {^_HEAP_SIZE =} $line] && [dict exists $mem_layout heap_size]} {
set heap_size [dict get $mem_layout heap_size]
if {$heap_size ne ""} {
set line "_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : $heap_size;"
_info "Updating _HEAP_SIZE in linker script to $heap_size"
} else {
_warn "Empty `heap_size` config, _HEAP_SIZE not updated."
}
} elseif {[regexp {^_STACK_SIZE =} $line] && [dict exists $mem_layout stack_size]} {
set stack_size [dict get $mem_layout stack_size]
if {$stack_size ne ""} {
set line "_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : $stack_size;"
_info "Updating _STACK_SIZE in linker script to $stack_size"
} else {
_warn "Empty `stack_size` config, _STACK_SIZE not updated."
}
}
lappend file_content $line
}
close $file_id
set file_id [open $lscript_path w]
puts $file_id [join $file_content \n]
close $file_id
} else {
_warn "Linker script $lscript_path not found for application: $app_name"
}
}
proc _update_app_build_config {app_name build_type build_config is_vitis} {
set build_types {"debug" "release"}
if {[lsearch $build_types $build_type] == -1} {
_error "Invalid config type: $build_type" "available types: $build_types"
}
set cmd [list]
if {$is_vitis} {
lappend cmd app config -name
} else {
lappend cmd sdk configapp -app
}
_info "Setting build configuration for '$app_name' as $build_type."
eval $cmd $app_name -set build-config $build_type
dict for {param value} $build_config {
switch -exact -- $param {
"include-path" {
foreach path $value {
eval $cmd $app_name include-path "../$path"
_info "Append included path: $path for $app_name."
}
}
"define-compiler-symbols" -
"undef-compiler-symbols" -
"libraries" -
"library-search-path" {
foreach item $value {
eval $cmd $app_name $param $item
_info "Append parameter $param: $item for $app_name."
}
}
"assembler-flags" -
"compiler-misc" -
"compiler-optimization" -
"linker-misc" -
"linker-script" {
if {$value ne ""} {
eval $cmd $app_name -set $param $value
_info "Set $param: $value for $app_name."
}
}
default {
_error "Unsupported app build-config option" $param
}
}
}
}
# Helper procedure for application configuration
proc _create_app {app_name app_config platform_name is_vitis} {
set cpu [dict get $app_config target_cpu]
set os [dict get $app_config os]
set lang [dict get $app_config language]
set sources [dict get $app_config sources]
set bsp_name "${os}_${cpu}"
# Configure BSP/Domain for application
if {[dict exists $app_config bsp] && [dict get $app_config bsp] ne ""} {
set bsp_name [dict get $app_config bsp]
} else {
set bsp_config [dict create]
set bsp_config [dict set bsp_config target_cpu $cpu]
set bsp_config [dict set bsp_config os $os]
if {[dict exists $app_config bsp_lib]} {
set bsp_lib [dict get $app_config bsp_lib]
set bsp_config [dict merge $bsp_config [dict create libs $bsp_lib]]
}
if {[dict exists $app_config bsp_config]} {
set bsp_cfg [dict get $app_config bsp_config]
set bsp_config [dict merge $bsp_config [dict create config $bsp_cfg]]
}
_configure_bsp $bsp_name $bsp_config $platform_name $is_vitis
}
# Create application
_info "Creating application: $app_name"
if {$is_vitis} {
app create -name $app_name \
-platform $platform_name \
-domain $bsp_name \
-proc $cpu \
-os $os \
-lang $lang \
-sysproj $::project_name \
-template "Empty Application($lang)"
_info "Application '$app_name' created for Vitis."
} else {
sdk createapp -name $app_name \
-hwproject $platform_name \
-bsp $bsp_name \
-proc $cpu \
-os $os \
-lang $lang \
-app "Empty Application"
_info "Application '$app_name' created for Xilinx SDK."
}
# Handle source files if present
if {[llength $sources] > 0} {
_info "Handling sources for application: $app_name"
_handle_sources $app_name $sources
} else {
_warn "No source files specified for application: $app_name"
}
# Configure application if additional configs exist
_info "Configuring application: $app_name"
if {[dict exists $app_config build_config]} {
dict for {build_type build_config} [dict get $app_config build_config] {
_update_app_build_config $app_name $build_type $build_config $is_vitis
}
}
# Update memory layout in linker script if specified
_info "Updating memory layout for application: $app_name"
if {[dict exists $app_config mem_layout]} {
set mem_layout [dict get $app_config mem_layout]
_update_app_mem_layout $app_name $mem_layout
}
}
# Apply FSBL patches if specified
# TODO:
proc _apply_fsbl_patches {patches} {
_info "Applying FSBL patches."
dict for {target_file patch_file} $patches {
set target_path "$::ws/fsbl/src/$target_file"
set patch_path "$::root/$patch_file"
file copy -force $patch_path $target_path
if {[file exists $patch_path]} {
_info "Patched $target_file with $patch_file"
} else {
_warn "FSBL patch file $patch_path not found, new file $patch_file "
}
}
}
# Main procedures
proc create_project {} {
cd $::ws
setws $::ws
_info "Workspace set to $::ws."
set is_vitis [expr {[string first ".hdf" $::hw_file] == -1}]
set platform_name "${::project_name}_platform"
# Prepare hardware platform
_prepare_platform $::hw_file $platform_name $is_vitis
# Process each bsp
dict for {bsp_name bsp_config} [dict get $::config bsps] {
_configure_bsp $bsp_name $bsp_config $platform_name $is_vitis
}
# Process each application
dict for {app_name app_config} [dict get $::config apps] {
_create_app $app_name $app_config $platform_name $is_vitis
}
}
proc build_project {} {
setws $::ws
set is_vitis [expr {[string first ".hdf" $::hw_file] == -1}]
if {$is_vitis} {
# paltform file can be deleted by clean operation ahead
platform active ${::project_name}_platform
platform generate
}
# Determine build type from environment
set build_type "debug"
if {[info exists ::env(RELEASE)] && $::env(RELEASE) == "y"} {
set build_type "release"
}
_info "Build type: $build_type"
dict for {app_name app_config} [dict get $::config apps] {
_info "Building application: $app_name"
if {$is_vitis} {
app config -name $app_name -set build-config $build_type
app build -name $app_name
_info "Application '$app_name' built for Vitis."
} else {
sdk configapp -app $app_name -set build-config $build_type
projects -build -type app -name $app_name
_info "Application '$app_name' built for Xilinx SDK."
}
}
}
proc clean_project {} {
setws $::ws
_info "Cleaning project in workspace: $::ws."
set is_vitis [expr {[string first ".hdf" $::hw_file] == -1}]
dict for {app_name app_config} [dict get $::config apps] {
_info "Cleaning application: $app_name"
if {$is_vitis} {
app clean -name $app_name
} else {
projects -clean -type app -name $app_name
}
_info "Application '$app_name' cleaned."
}
}
# Main execution
set function [lindex $argv 0]
set config_file [lindex $argv 1]
set ws [file normalize [lindex $argv 2]]
_info "Working at $ws"
# Load and parse configuration
set config_file_id [open $config_file r]
set config_data [read $config_file_id]
close $config_file_id
set root [file dirname [file normalize $config_file]]
set config [json::json2dict $config_data]
set project_name [dict get $config project_name]
set hw_file [file normalize [file join [file dirname $config_file] [dict get $config hw_design]]]
_info "Starting process: $function"
_info "Project name: $project_name"
_info "Hardware design file: $hw_file"
# Execute requested function
$function
_info "Process $function completed."