# Tcl script for iverilog simulation
namespace eval sim_iverilog {
  # Help information for this script
  proc print_help {} {
    variable script_file "run_iverilog.tcl"
    puts "\nDescription:"
    puts "Runs the iverilog simulation.\n"
    puts "Syntax:"
    puts "$script_file"
    puts "$script_file \[action\] \[args\]"
    puts "Usage:"
    puts "Name                   Description"
    puts "-------------------------------------------------------------------------"
    puts "\[action\]             Determine the action to be performed. Default value: help\n"
    puts "                       Current actions: help, clean\n"
    puts "\[args\]               Arguments related to the action.\n"
    puts "                       --root 
 changes the root reference for the project.\n"
    puts "-------------------------------------------------------------------------\n"
    exit 0
  }
  proc main {} {
    variable root_dir
    # Set the reference directory to where the script is
    #set root_dir [file dirname [info script]]
    # Set the reference directory for source file relative paths (by default the value is script directory path)
    set root_dir "."
    if { [info exists ::root_dir_loc] } {
      set root_dir $::root_dir_loc
    }
    if { $::argc > 0 } {
      set root_dir [lindex $::argv 0]
    }
    puts "Starting simulation using iverilog. The root dir is: $root_dir"
    #   variable root [file dirname [file normalize [info script]]]
    #   variable root [file dirname [file dirname [info script]]]
    variable root $root_dir
    variable source_path $root/src/verilog
    variable sources {counter.v}
    variable tb_path $root/tests/verilog
    variable test_benches {counter_tb.v}
    proc append_path {root list} {
      set l {}
      foreach f $list {
        lappend l $root/$f
      }
      return $l
    }
    variable sources_full_path [append_path $source_path $sources]
    variable tb_full_path [append_path $tb_path $test_benches]
    variable output_dir $root/runs/sim/iverilog
    variable additional_options "-D VCD_DUMP"
    proc run_sim {tb} {
      set name [file rootname $tb]
      puts "Running test bench $name"
      puts "Cleaning files..."
      #    file delete [glob -nocomplain $sim_iverilog::output_dir/*]
      puts "Recreating path..."
      file mkdir $sim_iverilog::output_dir
      set iverilog_args "$sim_iverilog::additional_options -g2012 -Wall -I $sim_iverilog::source_path -Y .sv -y $sim_iverilog::source_path -o $sim_iverilog::output_dir/$name.vvp $sim_iverilog::tb_path/$tb $sim_iverilog::sources_full_path"
      try {
        set results [exec iverilog {*}$iverilog_args]
        set status 0
      } trap CHILDSTATUS {results options} {
        set status [lindex [dict get $options -errorcode] 2]
      }
      if {$status != 0} {
        puts "Problem running iverilog :"
        puts $results
        return
      }
      # output iverilog result
      puts $results
      set cwd [pwd]
      puts "Running vvp..."
      set vvp_cmd "vvp $name.vvp -lxt2"
      cd $sim_iverilog::output_dir
      #puts [pwd]
      set results [exec {*}$vvp_cmd]
      # output vvp result
      puts $results
      cd $cwd
      puts "All done..."
    }
    foreach tb $test_benches {
      run_sim $tb
    }
    exit 0
  }
  # run main
  main
}