Hog Hog2025.2-3
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] \
209 directive project project_name group_name repo_path old_path bin_dir top_path usage short_usage cmd ide list_of_options
210 
211 array set options $list_of_options
212 Msg Debug "Returned by InitLauncher: \
213 $project $project_name $group_name $repo_path $old_path $bin_dir $top_path $cmd"
214 
215 set ext_path ""
216 if {$options(ext_path) != ""} {
217  set ext_path $options(ext_path)
218 }
219 set simlib_path ""
220 
221 
222 ######## DEFAULTS #########
223 set do_implementation 0; set do_synthesis 0; set do_bitstream 0
224 set do_create 0; set do_compile 0; set do_simulation 0; set recreate 0
225 set do_reset 1; set do_list_all 2; set do_check_syntax 0
226 
227 ### Hog stand-alone directives ###
228 # The following directives are used WITHOUT ever calling the IDE, they are run in tclsh
229 # A place holder called new_directive can be followed to add new commands
230 
231 set do_ipbus_xml 0
232 set do_list_file_parse 0
233 set do_check_yaml_ref 0
234 set do_buttons 0
235 set do_check_list_files 0
236 set do_compile_lib 0
237 set do_sigasi 0
238 
239 Msg Debug "Looking for a $directive in : $default_commands $custom_commands"
240 switch -regexp -- $directive "$default_commands $custom_commands"
241 
242 if {$options(all) == 1} {
243  set do_list_all 1
244 } else {
245  set do_list_all 2
246 }
247 
248 if {$options(dst_dir) == "" && ($do_ipbus_xml == 1 || $do_check_list_files == 1) && $project != ""} {
249  # Getting all the versions and SHAs of the repository
250  lassign [GetRepoVersions [file normalize $repo_path/Top/$group_name/$project] \
251  $repo_path $ext_path] commit version hog_hash hog_ver top_hash top_ver libs hashes vers \
252  cons_ver cons_hash ext_names ext_hashes xml_hash xml_ver user_ip_repos \
253  user_ip_hashes user_ip_vers
254  cd $repo_path
255 
256  set describe [GetHogDescribe $commit $repo_path]
257  set dst_dir [file normalize "$repo_path/bin/$group_name/$project\-$describe"]
258 }
259 
260 if {$cmd == -1} {
261  #This is if the project was not found
262  Msg Status "\n\nPossible projects are:"
263  ListProjects $repo_path $do_list_all
264  Msg Status "\n"
265  exit 1
266 } elseif {$cmd == -2} {
267  # Project not given but needed
268  Msg Status "ERROR: You must specify a project with directive $directive."
269  # \n\n[cmdline::usage $parameters $usage]"
270  Msg Status "Possible projects are:"
271  ListProjects $repo_path $do_list_all
272  exit 1
273 } elseif {$cmd == 0} {
274  #This script was launched within the IDE,: Vivado, Quartus, etc
275  Msg Info "$::argv0 was launched from the IDE."
276 } else {
277  # This script was launched with Tclsh, we need to check the arguments
278  # and if everything is right launch the IDE on this script and return
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,.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  # if {$do_new_directive ==1 } {
383  #
384  # # Do things here
385  #
386  # exit 0
387  #}
388 
389  #### END of tclsh commands ####
390  Msg Info "Launching command: $cmd..."
391 
392  # Check if the IDE is actually in the path...
393  set ret [catch {exec which $ide}]
394  if {$ret != 0} {
395  Msg Error "$ide not found in your system. Make sure to add $ide to your PATH enviromental variable."
396  exit $ret
397  }
398 
399  if {[string first libero $cmd] >= 0} {
400  # The SCRIPT_ARGS: flag of libero makes tcl crazy...
401  # Let's pipe the command into a shell script and remove it later
402  set libero_script [open "launch-libero-hog.sh" w]
403  puts $libero_script "#!/bin/sh"
404  puts $libero_script $cmd
405  close $libero_script
406  set cmd "sh launch-libero-hog.sh"
407  }
408 
409  set ret [catch {exec -ignorestderr {*}$cmd >@ stdout} result]
410 
411  if {$ret != 0} {
412  Msg Error "IDE returned an error state."
413  } else {
414  Msg Info "All done."
415  exit 0
416  }
417 
418  if {[string first libero $cmd] >= 0} {
419  file delete "launch-libero-hog.sh"
420  }
421 
422  exit $ret
423 }
424 
425 #After this line, we are in the IDE
426 ##################################################################################
427 
428 # We need to Import tcllib if we are using Libero
429 if {[IsLibero] || [IsDiamond]} {
430  if {[info exists env(HOG_TCLLIB_PATH)]} {
431  lappend auto_path $env(HOG_TCLLIB_PATH)
432  } else {
433  puts "ERROR: To run Hog with Microsemi Libero SoC or Lattice Diamond,\
434  you need to define the HOG_TCLLIB_PATH variable."
435  return
436  }
437 }
438 
439 if {[catch {package require cmdline} ERROR] || [catch {package require struct::matrix} ERROR]} {
440  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'"
441  exit 1
442 }
443 
444 set run_folder [file normalize "$repo_path/Projects/$project_name/$project.runs/"]
445 if {[IsLibero]} {
446  set run_folder [file normalize "$repo_path/Projects/$project_name/"]
447 }
448 
449 #Only for quartus, not used otherwise
450 set project_path [file normalize "$repo_path/Projects/$project_name/"]
451 
452 
453 if {$options(no_bitstream) == 1} {
454  set do_bitstream 0
455  set do_compile 0
456 }
457 
458 if {$options(recreate) == 1} {
459  set recreate 1
460 }
461 
462 if {$options(synth_only) == 1} {
463  set do_implementation 0
464  set do_synthesis 1
465  set do_bitstream 0
466  set do_create 1
467  set do_compile 1
468 }
469 
470 if {$options(impl_only) == 1} {
471  set do_implementation 1
472  set do_synthesis 0
473  set do_bitstream 0
474  set do_create 0
475  set do_compile 1
476 }
477 
478 
479 if {$options(no_reset) == 1} {
480  set do_reset 0
481 }
482 
483 if {$options(check_syntax) == 1} {
484  set do_check_syntax 1
485 }
486 
487 
488 if {$options(lib) != ""} {
489  set lib_path [file normalize $options(lib)]
490 } else {
491  if {[info exists env(HOG_SIMULATION_LIB_PATH)]} {
492  set lib_path $env(HOG_SIMULATION_LIB_PATH)
493  } else {
494  if {[file exists "$repo_path/SimulationLib"]} {
495  set lib_path [file normalize "$repo_path/SimulationLib"]
496  } else {
497  set lib_path ""
498  }
499  }
500 }
501 
502 
503 if {$options(verbose) == 1} {
504  variable ::DEBUG_MODE 1
505 }
506 
507 # Msg Info "Number of jobs set to $options(njobs)."
508 
509 ############## Quartus ########################
510 set argv ""
511 
512 ############# CREATE or OPEN project ############
513 if {[IsISE]} {
514  cd $tcl_path
515  set project_file [file normalize $repo_path/Projects/$project_name/$project.ppr]
516 } elseif {[IsVivado]} {
517  cd $tcl_path
518  set project_file [file normalize $repo_path/Projects/$project_name/$project.xpr]
519 } elseif {[IsQuartus]} {
520  if {[catch {package require ::quartus::project} ERROR]} {
521  Msg Error "$ERROR\n Can not find package ::quartus::project"
522  cd $old_path
523  return 1
524  } else {
525  Msg Info "Loaded package ::quartus::project"
526  load_package flow
527  }
528  set project_file "$project_path/$project.qpf"
529 } elseif {[IsLibero]} {
530  set project_file [file normalize $repo_path/Projects/$project_name/$project.prjx]
531 } elseif {[IsDiamond]} {
532  sys_install version
533  set project_file [file normalize $repo_path/Projects/$project_name/$project.ldf]
534 }
535 
536 if {[file exists $project_file]} {
537  Msg Info "Found project file $project_file for $project_name."
538  set proj_found 1
539 } else {
540  Msg Info "Project file not found for $project_name."
541  set proj_found 0
542 }
543 
544 if {($proj_found == 0 || $recreate == 1)} {
545  Msg Info "Creating (possibly replacing) the project $project_name..."
546  lassign [GetConfFiles $repo_path/Top/$project_name] conf sim pre post
547 
548  if {[file exists $conf]} {
549  #Still not sure of the difference between project and project_name
550  CreateProject -simlib_path $lib_path $project_name $repo_path
551  } else {
552  Msg Error "Project $project_name is incomplete: no hog.conf file found, please create one..."
553  }
554 } else {
555  Msg Info "Opening existing project file $project_file..."
556  if {[IsXilinx]} {
557  file mkdir "$repo_path/Projects/$project_name/$project.gen/sources_1"
558  }
559  OpenProject $project_file $repo_path
560 }
561 
562 
563 ########## CHECK SYNTAX ###########
564 if {$do_check_syntax == 1} {
565  Msg Info "Checking syntax for project $project_name..."
566  CheckSyntax $project_name $repo_path $project_file
567 }
568 
569 ######### LaunchSynthesis ########
570 if {$do_synthesis == 1} {
571  LaunchSynthesis $do_reset $do_create $run_folder $project_name $repo_path $ext_path $options(njobs)
572 }
573 
574 if {$do_implementation == 1} {
575  LaunchImplementation $do_reset $do_create $run_folder $project_name $repo_path $options(njobs) $do_bitstream
576 }
577 
578 
579 if {$do_bitstream == 1 && ![IsXilinx]} {
580  GenerateBitstream $run_folder $repo_path $options(njobs)
581 }
582 
583 if {$do_simulation == 1} {
584  # set simsets $options(simset)
585  set simsets [GetSimSets $project_name $repo_path $options(simset)]
586  LaunchSimulation $project_name $lib_path $simsets $repo_path
587 }
588 
589 
590 if {$do_check_list_files} {
591  Msg Info "Running list file checker..."
592 
593  #if {![file exists $dst_dir]} {
594  # Msg Info "$dst_dir directory not found, creating it..."
595  # file mkdir $dst_dir
596  # }
597 
598 
599  set argv0 check_list_files
600  if {$ext_path ne ""} {
601  set argv [list "-ext_path" "$ext_path" "-outDir" "$dst_dir" "-pedantic"]
602  } else {
603  set argv [list "-outDir" "$dst_dir" "-pedantic"]
604  }
605 
606  source $tcl_path/utils/check_list_files.tcl
607 }
608 
609 
610 if {$do_sigasi} {
611  Msg Info "Creating Sigasi file for $project..."
612 
613  #Simulation
614  set csv_name "${project}_sigasi_sim.csv"
615  #Create IPs here
616  Msg Info "Generating IP targets for simulations..."
617  foreach ip [get_ips] {
618  set targets [list_targets [get_files [file tail [get_property IP_FILE $ip]]]]
619  if {[lsearch -exact $targets simulation] >= 0} {
620  generate_target simulation $ip
621  } else {
622  Msg Warning "IP $ip is not a simulation target, skipping..."
623  }
624  }
625 
626  # tclint-disable-next-line line-length
627  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 }]
628  if {$options(dst_dir) == ""} {
629  set dst_path "$repo_path"
630  } else {
631  set dst_path $repo_path/$options(dst_dir)
632  if {![file exists $dst_path]} {
633  Msg Info "Creating $dst_path..."
634  file mkdir $dst_path
635  }
636  }
637 
638  Msg Info "Creating sigasi csv file for simulation $dst_path/$csv_name..."
639  set csv_file [open $dst_path/$csv_name w]
640 
641  foreach source_file $source_files {
642  puts $csv_file [concat [get_property LIBRARY $source_file] "," $source_file]
643  }
644  close $csv_file
645 
646  #Synthesis
647  set csv_name "${project}_sigasi_synth.csv"
648  Msg Info "Generating IP targets for synthesis..."
649  foreach ip [get_ips] {
650  generate_target synthesis $ip
651  }
652  # tclint-disable-next-line line-length
653  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 }]
654  Msg Info "Creating sigasi csv file for synthesis $dst_path/$csv_name..."
655  set csv_file [open $dst_path/$csv_name w]
656  foreach source_file $source_files {
657  puts $csv_file [concat [get_property LIBRARY $source_file] "," $source_file]
658  }
659  close $csv_file
660 }
661 
662 ## CLOSE Project
664 
665 Msg Info "All done."
666 cd $old_path