Hog v9.50.0
launch.tcl
Go to the documentation of this file.
1 #!/usr/bin/env tclsh
2 # @file
3 # Copyright 2018-2025 The University of Birmingham
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 
18 # Launch Xilinx Vivado or ISE implementation and possibly write bitstream in text mode
19 
20 set default_commands {
21 
22  \^L(IST)?$ {
23  Msg Status "\n** The projects in this repository are:"
24  ListProjects $repo_path $list_all
25  Msg Status "\n"
26  exit 0
27  # NAME*: LIST or L
28  # DESCRIPTION: List the projects in the repository. To show hidden projects use the -all option
29  # OPTIONS: all, verbose
30  }
31 
32  \^H(ELP)?$ {
33  puts "$usage"
34  exit 0
35  # NAME: HELP or H
36  # DESCRIPTION: Display this help message or specific help for each directive
37  # OPTIONS:
38  }
39 
40  \^C(REATE)?$ {#
41  set do_create 1
42  set recreate 1
43  # NAME*: CREATE or C
44  # DESCRIPTION: Create the project, replace it if already existing.
45  # OPTIONS: ext_path.arg, lib.arg, verbose
46  }
47 
48  \^I(MPL(EMENT(ATION)?)?)?$ {#
49  set do_implementation 1
50  set do_bitstream 1
51  set do_compile 1
52  # NAME: IMPLEMENTATION or I
53  # DESCRIPTION: Runs only the implementation, the project must already exist and be synthesised.
54  # OPTIONS: check_syntax, ext_path.arg, njobs.arg, no_bitstream, no_reset, recreate, verbose
55  }
56 
57  \^SYNT(H(ESIS(E)?)?)? {#
58  set do_synthesis 1
59  set do_compile 1
60  # NAME: SYNTH
61  # DESCRIPTION: Run synthesis only, create the project if not existing.
62  # OPTIONS: check_syntax, ext_path.arg, njobs.arg, recreate, verbose
63  }
64 
65  \^S(IM(ULAT(ION|E)?)?)?$ {#
66  set do_simulation 1
67  set do_create 1
68  # NAME*: SIMULATION or S
69  # DESCRIPTION: Simulate the project, creating it if not existing, unless it is a GHDL simulation.
70  # OPTIONS: check_syntax, ext_path.arg, lib.arg, recreate, simset.arg, verbose
71  }
72 
73  \^W(ORK(FLOW)?)?$ {#
74  set do_implementation 1
75  set do_synthesis 1
76  set do_bitstream 1
77  set do_compile 1
78  # NAME*: WORKFLOW or W
79  # DESCRIPTION: Runs the full workflow, creates the project if not existing.
80  # OPTIONS: check_syntax, ext_path.arg, impl_only, njobs.arg, no_bitstream, recreate, synth_only, verbose
81  }
82 
83  \^(CREATEWORKFLOW|CW)?$ {#
84  set do_implementation 1
85  set do_synthesis 1
86  set do_bitstream 1
87  set do_compile 1
88  set recreate 1
89  # NAME: CREATEWORKFLOW or CW
90  # DESCRIPTION: Creates the project -even if existing- and launches the complete workflow.
91  # OPTIONS: check_syntax, ext_path.arg, njobs.arg, no_bitstream, synth_only, verbose
92  }
93 
94  \^(CHECKSYNTAX|CS)?$ {#proj
95  set do_check_syntax 1
96  # NAME: CECHSYNTAX or CS
97  # DESCRIPTION: Check the syntax of the project. Only for Vivado, Quartus and Libero projects.
98  # OPTIONS: ext_path.arg, recreate, verbose
99  }
100 
101  \^X(ML)?$ {#proj
102  set do_ipbus_xml 1
103  # NAME: XML or X
104  # DESCRIPTION: Copy, check or create the IPbus XMLs for the project.
105  # OPTIONS: dst_dir.arg, generate, verbose
106  }
107 
108  \^V(IEW)?$ {#proj
109  set do_list_file_parse 1
110  # NAME*: VIEW or V
111  # DESCRIPTION: Print Hog list file contents in a tree-like fashon.
112  # OPTIONS: verbose
113  }
114 
115  \^(CHECKYAML|YML)?$ {
116  set min_n_of_args -1
117  set max_n_of_args 1
118  set do_check_yaml_ref 1
119  # NAME: CHECKYML or YML
120  # DESCRIPTION: Check that the ref to Hog repository in the .gitlab-ci.yml file, matches the one in Hog submodule.
121  # OPTIONS: verbose
122  }
123 
124  \^B(UTTONS)?$ {#
125  set min_n_of_args -1
126  set max_n_of_args 1
127  set do_buttons 1
128  # NAME: BUTTONS or B
129  # DESCRIPTION: Add Hog buttons to the Vivado GUI, to check and recreate Hog list and configuration files.
130  # OPTIONS: verbose
131  }
132 
133  \^(CHECKLIST|CL)?$ {#proj
134  set do_check_list_files 1
135  # NAME: CHECKLIST or CL
136  # DESCRIPTION: Check that list and configuration files on disk match what is on the project.
137  # OPTIONS: ext_path.arg, verbose
138  }
139 
140  \^COMPSIM(LIB)?$ {
141  set do_compile_lib 1
142  set argument_is_no_project 1
143  # NAME: COMPSIMLIB or COMPSIM
144  # DESCRIPTION: Compiles the simulation library for the chosen simulator with Vivado.
145  # OPTIONS: dst_dir.arg, verbose
146  }
147 
148  \^SIG(ASI)?$ {#
149  set do_sigasi 1
150  # NAME: SIGASI or SIG
151  # DESCRIPTION: Create a .csv file to be used in Sigasi.
152  # OPTIONS: verbose
153  }
154 
155  default {
156  if {$directive != ""} {
157  Msg Status "ERROR: Unknown directive $directive.\n\n"
158  puts $usage
159  exit 1
160  } else {
161  puts "$usage"
162  exit 0
163  }
164  }
165 }
166 
167 # Add this bit above!
168 # \^NEW_DIRECTIVE?$ {
169 # set do_new_directive 1
170 # }
171 
172 
173 #parsing command options
174 set parameters {
175  {no_bitstream "If set, the bitstream file will not be produced."}
176  {recreate "If set, the project will be re-created if it already exists."}
177  {no_reset "If set, runs (synthesis and implementation) won't be reset before launching them."}
178  {check_syntax "If set, the HDL syntax will be checked at the beginning of the workflow."}
179  {njobs.arg 4 "Number of jobs. Default: 4"}
180  {ext_path.arg "" "Sets the absolute path for the external libraries."}
181  {lib.arg "" "Simulation library path, compiled or to be compiled"}
182  {synth_only "If set, only the synthesis will be performed."}
183  {impl_only "If set, only the implementation will be performed. This assumes synthesis should was already done."}
184  {simset.arg "" "Simulation sets, separated by commas, to be run."}
185  {all "List all projects, including test projects. Test projects have #test on the second line of hog.conf."}
186  {generate "For IPbus XMLs, it will re create the VHDL address decode files."}
187  {dst_dir.arg "" "For reports, IPbus XMLs, set the destination folder (default is in the ./bin folder)."}
188  {verbose "If set, launch the script in verbose mode"}
189 }
190 
191 set tcl_path [file normalize "[file dirname [info script]]"]
192 source $tcl_path/hog.tcl
193 source $tcl_path/create_project.tcl
194 # Quartus needs extra packages and treats the argv in a different way
195 if {[IsQuartus]} {
196  load_package report
197  set argv $quartus(args)
198 }
199 
200 Msg Debug "s: $::argv0 a: $argv"
201 
202 set commands_path [file normalize "$tcl_path/../../hog-commands/"]
203 ### CUSTOM COMMANDS ###
204 set custom_commands [GetCustomCommands $commands_path 1]
205 set custom_usage [GetCustomCommands $commands_path]
206 # append usage "\n** Options:"
207 
208 lassign [InitLauncher $::argv0 $tcl_path $parameters $default_commands $argv $custom_usage] directive project project_name group_name repo_path old_path bin_dir top_path usage short_usage cmd ide list_of_options
209 array set options $list_of_options
210 Msg Debug "Returned by InitLauncher: \
211 $project $project_name $group_name $repo_path $old_path $bin_dir $top_path $cmd"
212 
213 set ext_path ""
214 if { $options(ext_path) != ""} {
215  set ext_path $options(ext_path)
216 }
217 set simlib_path ""
218 
219 
220 ######## DEFAULTS #########
221 set do_implementation 0; set do_synthesis 0; set do_bitstream 0;
222 set do_create 0; set do_compile 0; set do_simulation 0; set recreate 0;
223 set do_reset 1; set do_list_all 2; set do_check_syntax 0;
224 
225 ### Hog stand-alone directives ###
226 # The following directives are used WITHOUT ever calling the IDE, they are run in tclsh
227 # A place holder called new_directive can be followed to add new commands
228 
229 set do_ipbus_xml 0
230 set do_list_file_parse 0;
231 set do_check_yaml_ref 0;
232 set do_buttons 0;
233 set do_check_list_files 0;
234 set do_compile_lib 0;
235 set do_sigasi 0;
236 
237 Msg Debug "Looking for a $directive in : $default_commands $custom_commands"
238 switch -regexp -- $directive "$default_commands $custom_commands"
239 
240 if { $options(all) == 1 } {
241  set do_list_all 1
242 } else {
243  set do_list_all 2
244 }
245 
246 if {$options(dst_dir) == "" && ($do_ipbus_xml ==1 || $do_check_list_files == 1)} {
247  # Getting all the versions and SHAs of the repository
248  lassign [GetRepoVersions [file normalize $repo_path/Top/$group_name/$project] \
249  $repo_path $ext_path] commit version hog_hash hog_ver top_hash top_ver libs hashes vers \
250  cons_ver cons_hash ext_names ext_hashes xml_hash xml_ver user_ip_repos \
251  user_ip_hashes user_ip_vers
252 
253  set describe [GetHogDescribe $commit $repo_path]
254  set dst_dir [file normalize "bin/$group_name/$project\-$describe"]
255 }
256 
257 if {$cmd == -1} {
258 #This is if the project was not found
259  Msg Status "\n\nPossible projects are:"
260  ListProjects $repo_path $do_list_all
261  Msg Status "\n"
262  exit 1
263 } elseif {$cmd == -2} {
264  # Project not given but needed
265  Msg Status "ERROR: You must specify a project with directive $directive."
266  # \n\n[cmdline::usage $parameters $usage]"
267  Msg Status "Possible projects are:"
268  ListProjects $repo_path $do_list_all
269  exit 1
270 
271 } elseif {$cmd == 0} {
272  #This script was launched within the IDE,: Vivado, Quartus, etc
273  Msg Info "$::argv0 was launched from the IDE."
274 
275 } else {
276  # This script was launched with Tclsh, we need to check the arguments
277  # and if everything is right launch the IDE on this script and return
278 
279 
280 
281  #### Directives to be handled in tclsh should be here ###
282  ### IMPORTANT: Each if block should either end with "exit 0" or
283  ### set both $ide and $cmd to be executed when this script is run again
284 
285  if {$do_ipbus_xml == 1} {
286  Msg Info "Handling IPbus XMLs for $project_name..."
287 
288  set proj_dir $repo_path/Top/$project_name
289 
290  if { $options(generate) == 1 } {
291  set xml_gen 1
292  } else {
293  set xml_gen 0
294  }
295 
296 
297  set xml_dst "$dst_dir/xml"
298 
299 
300  if {[llength [glob -nocomplain $proj_dir/list/*.ipb]] > 0 } {
301  if {![file exists $xml_dst]} {
302  Msg Info "$xml_dst directory not found, creating it..."
303  file mkdir $xml_dst
304  }
305  } else {
306  Msg Error "No .ipb files found in $proj_dir/list/"
307  exit
308  }
309 
310  set ret [GetRepoVersions $proj_dir $repo_path ""]
311  set sha [lindex $ret 13]
312  set hex_ver [lindex $ret 14]
313 
314  set ver [HexVersionToString $hex_ver]
315  CopyIPbusXMLs $proj_dir $repo_path $xml_dst $ver $sha 1 $xml_gen
316 
317  exit 0
318  }
319 
320  if {$do_list_file_parse == 1} {
321  set proj_dir $repo_path/Top/$project_name
322  set proj_list_dir $repo_path/Top/$project_name/list
323  GetHogFiles -print_log -list_files {.src,.con,.sim,.ext,.sim,.ipb} $proj_list_dir $repo_path
324  Msg Status " "
325  Msg Info "All Done."
326  exit 0
327  }
328 
329  if {$do_check_yaml_ref == 1 } {
330  Msg Info "Checking if \"ref\" in .gitlab-ci.yml actually matches the included yml file in Hog submodule"
331  CheckYmlRef $repo_path false
332  exit 0
333  }
334 
335  if {$do_buttons == 1 } {
336  Msg Info "Adding Hog buttons to Vivado bar (will use the vivado currently in PATH)..."
337  set ide vivado
338  set cmd "vivado -mode batch -notrace -source $repo_path/Hog/Tcl/utils/add_hog_custom_button.tcl"
339  }
340 
341  if {$do_compile_lib == 1} {
342  if {$project eq ""} {
343  Msg Error "You need to specify a simulator as first argument."
344  exit 1
345  } else {
346  set simulator $project
347  Msg Info "Selecting $simulator simulator..."
348  }
349  if { $options(dst_dir) != "" } {
350  set output_dir $options(dst_dir)
351  } else {
352  Msg Info "No destination directory defined. Using default: SimulationLib/"
353  set output_dir "SimulationLib"
354  }
355 
356  set ide vivado
357  set cmd "vivado -mode batch -notrace -source $repo_path/Hog/Tcl/utils/compile_simlib.tcl -tclargs -simulator $simulator -output_dir $output_dir"
358  }
359 
360  set simsets ""
361  if {$do_simulation == 1} {
362  # Get all simsets in the project that run with GHDL
363  set ghdl_simsets [GetSimSets $project_name $repo_path "$options(simset)" 1]
364  set ghdl_import 0
365  dict for {simset_name simset_dict} $ghdl_simsets {
366  if {$ghdl_import == 0} {
367  ImportGHDL $project_name $repo_path $simset_name $simset_dict $ext_path
368  set ghdl_import 1
369  }
370  LaunchGHDL $project_name $repo_path $simset_name $simset_dict $ext_path
371  # dict unset simsets_dict $simset_name
372  }
373  set ide_simsets [GetSimSets $project_name $repo_path $options(simset) 0 1]
374 
375  if {[dict size $ide_simsets] == 0} {
376  # All simulations have been run, exiting
377  Msg Info "All simulations have been run, exiting..."
378  exit 0
379  }
380 
381  }
382 
383  # if {$do_new_directive ==1 } {
384  #
385  # # Do things here
386  #
387  # exit 0
388  #}
389 
390  #### END of tclsh commands ####
391  Msg Info "Launching command: $cmd..."
392 
393  # Check if the IDE is actually in the path...
394  set ret [catch {exec which $ide}]
395  if {$ret != 0} {
396  Msg Error "$ide not found in your system. Make sure to add $ide to your PATH enviromental variable."
397  exit $ret
398  }
399 
400  if {[string first libero $cmd] >= 0} {
401  # The SCRIPT_ARGS: flag of libero makes tcl crazy...
402  # Let's pipe the command into a shell script and remove it later
403  set libero_script [open "launch-libero-hog.sh" w]
404  puts $libero_script "#!/bin/sh"
405  puts $libero_script $cmd
406  close $libero_script
407  set cmd "sh launch-libero-hog.sh"
408  }
409 
410  set ret [catch {exec -ignorestderr {*}$cmd >@ stdout} result]
411 
412  if {$ret != 0} {
413  Msg Error "IDE returned an error state."
414  } else {
415  Msg Info "All done."
416  exit 0
417  }
418 
419  if {[string first libero $cmd] >= 0} {
420  file delete "launch-libero-hog.sh"
421  }
422 
423  exit $ret
424 }
425 
426 #After this line, we are in the IDE
427 ##################################################################################
428 
429 # We need to Import tcllib if we are using Libero
430 if {[IsLibero] || [IsDiamond]} {
431  if {[info exists env(HOG_TCLLIB_PATH)]} {
432  lappend auto_path $env(HOG_TCLLIB_PATH)
433  } else {
434  puts "ERROR: To run Hog with Microsemi Libero SoC or Lattice Diamond,\
435  you need to define the HOG_TCLLIB_PATH variable."
436  return
437  }
438 }
439 
440 if {[catch {package require cmdline} ERROR] || [catch {package require struct::matrix} ERROR]} {
441  puts "$ERROR\n Tcllib not found. If you are running this script on tclsh for debuggin purpose ONLY, you can fix this by installing 'tcllib'"
442  exit 1
443 }
444 
445 set run_folder [file normalize "$repo_path/Projects/$project_name/$project.runs/"]
446 if {[IsLibero]} {
447  set run_folder [file normalize "$repo_path/Projects/$project_name/"]
448 }
449 
450 #Only for quartus, not used otherwise
451 set project_path [file normalize "$repo_path/Projects/$project_name/"]
452 
453 
454 if { $options(no_bitstream) == 1 } {
455  set do_bitstream 0
456  set do_compile 0
457 }
458 
459 if { $options(recreate) == 1 } {
460  set recreate 1
461 }
462 
463 if { $options(synth_only) == 1} {
464  set do_implementation 0
465  set do_synthesis 1
466  set do_bitstream 0
467  set do_create 1
468  set do_compile 1
469 }
470 
471 if { $options(impl_only) == 1} {
472  set do_implementation 1
473  set do_synthesis 0
474  set do_bitstream 0
475  set do_create 0
476  set do_compile 1
477 }
478 
479 
480 if { $options(no_reset) == 1 } {
481  set do_reset 0
482 }
483 
484 if { $options(check_syntax) == 1 } {
485  set do_check_syntax 1
486 }
487 
488 
489 
490 
491 if {$options(lib)!= ""} {
492  set lib_path [file normalize $options(lib)]
493 } else {
494  if {[info exists env(HOG_SIMULATION_LIB_PATH)]} {
495  set lib_path $env(HOG_SIMULATION_LIB_PATH)
496  } else {
497  if {[file exists "$repo_path/SimulationLib"]} {
498  set lib_path [file normalize "$repo_path/SimulationLib"]
499  } else {
500  set lib_path ""
501  }
502  }
503 }
504 
505 
506 
507 if { $options(verbose) == 1 } {
508  variable ::DEBUG_MODE 1
509 }
510 
511 # Msg Info "Number of jobs set to $options(njobs)."
512 
513 ############## Quartus ########################
514 set argv ""
515 
516 ############# CREATE or OPEN project ############
517 if {[IsISE]} {
518  cd $tcl_path
519  set project_file [file normalize $repo_path/Projects/$project_name/$project.ppr]
520 } elseif {[IsVivado]} {
521  cd $tcl_path
522  set project_file [file normalize $repo_path/Projects/$project_name/$project.xpr]
523 } elseif {[IsQuartus]} {
524  if { [catch {package require ::quartus::project} ERROR] } {
525  Msg Error "$ERROR\n Can not find package ::quartus::project"
526  cd $old_path
527  return 1
528  } else {
529  Msg Info "Loaded package ::quartus::project"
530  load_package flow
531  }
532  set project_file "$project_path/$project.qpf"
533 } elseif {[IsLibero]} {
534  set project_file [file normalize $repo_path/Projects/$project_name/$project.prjx]
535 } elseif {[IsDiamond]} {
536  sys_install version
537  set project_file [file normalize $repo_path/Projects/$project_name/$project.ldf]
538 }
539 
540 if {[file exists $project_file]} {
541  Msg Info "Found project file $project_file for $project_name."
542  set proj_found 1
543 } else {
544  Msg Info "Project file not found for $project_name."
545  set proj_found 0
546 }
547 
548 if {($proj_found == 0 || $recreate == 1)} {
549  Msg Info "Creating (possibly replacing) the project $project_name..."
550  lassign [GetConfFiles $repo_path/Top/$project_name] conf sim pre post
551 
552  if {[file exists $conf]} {
553  #Still not sure of the difference between project and project_name
554  CreateProject -simlib_path $lib_path $project_name $repo_path
555  } else {
556  Msg Error "Project $project_name is incomplete: no hog.conf file found, please create one..."
557  }
558 } else {
559  Msg Info "Opening existing project file $project_file..."
560  if {[IsXilinx]} {
561  file mkdir "$repo_path/Projects/$project_name/$project.gen/sources_1"
562  }
563  OpenProject $project_file $repo_path
564 }
565 
566 
567 ########## CHECK SYNTAX ###########
568 if { $do_check_syntax == 1 } {
569  Msg Info "Checking syntax for project $project_name..."
570  CheckSyntax $project_name $repo_path $project_file
571 }
572 
573 ######### LaunchSynthesis ########
574 if {$do_synthesis == 1} {
575  LaunchSynthesis $do_reset $do_create $run_folder $project_name $repo_path $ext_path $options(njobs)
576 }
577 
578 if {$do_implementation == 1 } {
579  LaunchImplementation $do_reset $do_create $run_folder $project_name $repo_path $options(njobs) $do_bitstream
580 }
581 
582 
583 if {$do_bitstream == 1 && ![IsXilinx] } {
584  GenerateBitstream $run_folder $repo_path $options(njobs)
585 }
586 
587 if {$do_simulation == 1} {
588  # set simsets $options(simset)
589  set simsets [GetSimSets $project_name $repo_path $options(simset)]
590  LaunchSimulation $project_name $lib_path $simsets $repo_path
591 }
592 
593 
594 if {$do_check_list_files} {
595  Msg Info "Running list file checker..."
596 
597  #if {![file exists $dst_dir]} {
598  # Msg Info "$dst_dir directory not found, creating it..."
599  # file mkdir $dst_dir
600  # }
601 
602 
603 set argv0 check_list_files
604  if {$ext_path ne ""} {
605  set argv [list "-ext_path" "$ext_path" "-outDir" "$dst_dir" "-pedantic"]
606  } else {
607  set argv [list "-outDir" "$dst_dir" "-pedantic"]
608  }
609 
610  source $tcl_path/utils/check_list_files.tcl
611 }
612 
613 
614 if {$do_sigasi} {
615  Msg Info "Creating Sigasi file for $project..."
616 
617  #Simulation
618  set csv_name "${project}_sigasi_sim.csv"
619  #Create IPs here
620  Msg Info "Generating IP targets for simulations..."
621  foreach ip [get_ips] {
622  set targets [list_targets [get_files [file tail [get_property IP_FILE $ip]]]]
623  if { [ lsearch -exact $targets simulation] >= 0 } {
624  generate_target simulation $ip
625  } else {
626  Msg Warning "IP $ip is not a simulation target, skipping..."
627  }
628  }
629 
630 
631  set source_files [get_files -filter {(FILE_TYPE == VHDL || FILE_TYPE == "VHDL 2008" || FILE_TYPE == "VHDL 2019" || FILE_TYPE == VERILOG || FILE_TYPE == SYSTEMVERILOG) && USED_IN_SIMULATION == 1 } ]
632  if {$options(dst_dir) == ""} {
633  set dst_path "$repo_path"
634  } else {
635  set dst_path $repo_path/$options(dst_dir)
636  if {![file exists $dst_path]} {
637  Msg Info "Creating $dst_path..."
638  file mkdir $dst_path
639  }
640  }
641 
642  Msg Info "Creating sigasi csv file for simulation $dst_path/$csv_name..."
643  set csv_file [open $dst_path/$csv_name w]
644 
645  foreach source_file $source_files {
646  puts $csv_file [ concat [ get_property LIBRARY $source_file ] "," $source_file ]
647  }
648  close $csv_file
649 
650  #Synthesis
651  set csv_name "${project}_sigasi_synth.csv"
652  Msg Info "Generating IP targets for synthesis..."
653  foreach ip [get_ips] {
654  generate_target synthesis $ip
655  }
656 
657  set source_files [get_files -filter {(FILE_TYPE == VHDL || FILE_TYPE == "VHDL 2008" || FILE_TYPE == "VHDL 2019" || FILE_TYPE == VERILOG || FILE_TYPE == SYSTEMVERILOG) && USED_IN_SYNTHESIS == 1 } ]
658  Msg Info "Creating sigasi csv file for synthesis $dst_path/$csv_name..."
659  set csv_file [open $dst_path/$csv_name w]
660  foreach source_file $source_files {
661  puts $csv_file [ concat [ get_property LIBRARY $source_file ] "," $source_file ]
662  }
663  close $csv_file
664 
665 }
666 
667 ## CLOSE Project
669 
670 Msg Info "All done."
671 cd $old_path