#########################################################################
# Helper file contains procs to support tcl scripts for FPGA classes
#########################################################################

# Variables Declaration
variable language
variable platform
variable tcName
variable demoOrLab
variable projName
variable lastStep
variable verbose
variable sourceList
variable run_synth
variable run_impl

# Initialize the variables
set language  undefined
set platform  undefined
set lastStep  notStarted

# used to indicate that the helper.tcl was loaded
set helper loaded

##################################################
# proc for doing wide range of configurable items
##################################################
proc use {thing} {
  variable language
  variable platform   
   
 # Initialize the variable, if it is not yet in use 
 if {[info exists language] == 0}  { set language  undefined }   
 if {[info exists platform] == 0}  { set platform  undefined }     
   
 # Selects the platform and language that is being used
 if { [string compare -nocase $thing "KC705"] == 0 } {
		set platform KC705
   } elseif { [string compare -nocase $thing "KCU105"] == 0 } {
		set platform KCU105
   } elseif { [string compare -nocase $thing "KC7xx"] == 0 } {
		set platform KC7xx
   } elseif {[string compare -nocase $thing "VHDL"] == 0} {
		set language VHDL
   } elseif {[string compare -nocase $thing "Verilog"] == 0} {
		set language Verilog
   } elseif {[string compare -nocase $thing "netlist"] == 0} {
		set language netlist
   } else {
		puts "Unknown use item! $thing"
		return
   }
 }

############################################
# proc for creating a New Vivado Project
############################################
proc projectCreate {} {  
 # Defining the variables
   variable language
   variable platform
   variable tcName
   variable demoOrLab
   variable projName
   variable verbose  
   
   if {$verbose == 1} { puts "completer_helper: projectCreate"; }   
   
   # Close the project if one is open
   set pjs [get_projects]
   if {[llength $pjs] > 0} {
      close_project
   }   
    # Check if both a language and platform has been selected   
   set isLangNotSelected [string compare -nocase $language "undefined"]
   set isPlatNotSelected [string compare -nocase $platform "undefined"]
   set isKCU105     [string compare -nocase $platform "KCU105"]
   set isKC705      [string compare -nocase $platform "KC705"]
   set isKC7xx      [string compare -nocase $platform "KC7xx"]
   set isVerilog    [string compare -nocase $language "Verilog"]
   set isVHDL       [string compare -nocase $language "VHDL"]
   
   # Ensure that the language has been selected
    if {$isLangNotSelected} {
       puts "Please type: use VHDL | Verilog"
       puts "   then rerun the projectCreate"
    } 
	if {$isPlatNotSelected} {
       puts "Please type: use KCU105 | KC705 | KC7xx"
       puts "   then rerun the projectCreate"
    }    
	   # Create the new project based on the specified board
	  if {$isKCU105 == 0} {
         create_project $projName C:/training/$tcName/$demoOrLab/$platform/$language -part xcku040-ffva1156-2-e
         set_property board_part xilinx.com:kcu105:part0:1.2 [current_project]
	     } elseif {$isKC705 == 0} {
         create_project $projName C:/training/$tcName/$demoOrLab/$platform/$language -part xc7k325tffg900-2
		 set_property board_part xilinx.com:kc705:part0:1.5 [current_project] 
	     } elseif {$isKC7xx == 0} {
         create_project $projName C:/training/$tcName/$demoOrLab/$platform/$language -part xc7k70tfbg484-2 
	     } 
	  # With the project now open, set the default language
      set_property target_language $language [current_project]
    markLastStep projectCreated
 }

##########################################
# proc for adding .v/.vhd source files
##########################################
proc sourcesAdd {} {
    variable tcName
    variable demoOrLab
    variable language
    variable platform
	variable verbose
	variable projName
              
  if {$verbose == 1} { puts "completer_helper: sourcesAdd sourceList"; }  
  # checks the project name and picks the source files based on the language choosen 
  # uart_led design
  if {$projName == "uart_led"} {
   if {$language == "VHDL"} {
    set sourceList [list led_ctl.vhd meta_harden.vhd uart_baud_gen.vhd uart_led.vhd uart_led_pkg.vhd uart_rx.vhd uart_rx_ctl.vhd]
   } elseif {$language == "Verilog"} {
	 set sourceList [list led_ctl.v meta_harden.v uart_baud_gen.v uart_led.v uart_rx.v uart_rx_ctl.v]
	} 
   } elseif {$projName == "wave_gen"} {
   # wave_gen design
   if {$language == "VHDL"} {
	set sourceList [list clk_div.vhd clk_gen.vhd clkx_bus.vhd cmd_parse.vhd dac_spi.vhd debouncer.vhd lb_ctl.vhd meta_harden.vhd out_ddr_flop.vhd reset_bridge.vhd resp_gen.vhd rst_gen.vhd samp_gen.vhd samp_ram.vhd to_bcd.vhd uart_baud_gen.vhd uart_rx.vhd uart_rx_ctl.vhd uart_tx.vhd uart_tx_ctl.vhd wave_gen.vhd string_utilities_synth_pkg.vhd wave_gen_pkg.vhd]
	} elseif {$language == "Verilog"} {
	 set sourceList [list clk_div.v clk_gen.v clkx_bus.v clogb2.txt cmd_parse.v dac_spi.v debouncer.v lb_ctl.v meta_harden.v out_ddr_flop.v reset_bridge.v resp_gen.v rst_gen.v samp_gen.v samp_ram.v to_bcd.v uart_baud_gen.v uart_rx.v uart_rx_ctl.v uart_tx.v uart_tx_ctl.v wave_gen.v]
	}
   } else {
     puts "Other Design"
	}
#Imports the source files from project directory	
  foreach i $sourceList {
   puts "Adding RTL file $i"
   import_files -fileset sources_1 -norecurse C:/training/$tcName/$demoOrLab/$platform/$language/$i
  }   
 markLastStep sourcesFilesAdded
}

####################################
# proc for adding constraint files
####################################
proc constraintFilesAdd {} {
   variable language
   variable platform   
   variable tcName
   variable verbose
   variable demoOrLab
   variable projName
    if {$verbose == 1} { puts "adding constraint file"}
 # checks for the design and adds respected xdc file from project directory
     if {$projName == "uart_led"} {
	 import_files -fileset [get_filesets constrs_1] C:/training/$tcName/$demoOrLab/$platform/$language/uart_led.xdc
    } elseif {$projName == "wave_gen"} {
	 import_files -fileset [get_filesets constrs_1] C:/training/$tcName/$demoOrLab/$platform/$language/wave_gen_pins.xdc
	 import_files -fileset [get_filesets constrs_1] C:/training/$tcName/$demoOrLab/$platform/$language/wave_gen_timing.xdc
  } 
 markLastStep constraintAdded
}

####################################
# proc for adding ip files
####################################
proc ipFilesAdd {} {
 variable tcName
 variable platform
 variable demoOrLab
 variable language
 variable verbose
 if {$verbose == 1} { puts "adding constraint file"}
 #Adds the ip files based on board choosen
 if {$platform == "KC705"} {
  import_files -norecurse C:/training/$tcName/$demoOrLab/$platform/$language/clk_core.xci
}
markLastStep ipFilesAdded
}

####################################
# proc to run synthesis process
####################################
proc synthesisRun {run_synth} {
 variable verbose   
 if {$verbose == 1} { puts "Running Synthesis" } 
  if {$run_synth == 1} {
   launch_runs synth_1 -jobs 4
 # waiting for synthesis to complete and opens the synthesized design
    wait_on_run synth_1
    open_run synth_1 -name synth_1 
    } else {
    open_run synth_1 -name synth_1 
   }
   markLastStep synthComplete
 }

#######################################
# proc to run implementation process
#######################################
proc implementationRun {run_impl} {
 variable verbose   
 variable language
  if {$verbose == 1} { puts "Running Implementation" } 
  
  if {$run_impl == 1} {
  if {$language != "netlist"} {
	reset_run synth_1
  }		
  launch_runs impl_1 -jobs 4
  # waiting for implementation to complete and opens the implemented design
  wait_on_run impl_1
  open_run impl_1 -name impl_1  
  } else {
  open_run impl_1 -name impl_1
  }
markLastStep implComplete
}

####################################
# proc to generate bitstream
####################################
proc bitstreamRun {} {
 variable verbose   
  if {$verbose == 1} { puts "Generating Bitstream" } 
  # Test if there is already a bitstream
  set status [get_property status [current_run]]
  set implementationCompleteMessage "route_design Complete!"
  set bitstreamCompleteMessage      "write_bitstream Complete!"
     
  if {[string compare $status $bitstreamCompleteMessage] != 0} {
  launch_runs impl_1 -to_step write_bitstream -jobs 4
  if {$verbose == 1} { puts "\t waiting for bitstream generation to complete"; }
  wait_on_run impl_1
  } else {
	puts "Bitstream has already been run!"
  }
 markLastStep bitstreamGenerated
}

##############################################################
# proc to download the bitstream to the board with probe file
##############################################################
proc deviceProgram {} {
 variable tcName
 variable platform
 variable demoOrLab
 variable language
 variable verbose
 variable projName 
 set projName.runs {append $projName .runs}
 set projName.bit {append $projName .bit}
 
 if {$verbose == 1} { puts "opening hardware manager"}
 # start the hardware session
   open_hw
   connect_hw_server
   open_hw_target
   
 # program the device from the provided bitstream
 if {$platform == "KCU105"} {
   set_property PROGRAM.FILE C:/training/$tcName/$demoOrLab/$platform/$language/$projName.runs/impl_1/$projName.bit [get_hw_devices xcku040_0]
   set_property PROBES.FILE C:/training/$tcName/$demoOrLab/$platform/$language/$projName.runs/impl_1/debug_nets.ltx [get_hw_devices xcku040_0]  
   program_hw_devices [get_hw_devices xcku040_0]
   refresh_hw_device [lindex [get_hw_devices xcku040_0] 0]
 } elseif {$platform == "KC705"} {
   set_property PROGRAM.FILE C:/training/$tcName/$demoOrLab/$platform/$language/$projName.runs/impl_1/$projName.bit [get_hw_devices xc7k325t_0]
   set_property PROBES.FILE C:/training/$tcName/$demoOrLab/$platform/$language/$projName.runs/impl_1/debug_nets.ltx [get_hw_devices xc7k325t_0]  
   program_hw_devices [get_hw_devices xc7k325t_0]
   refresh_hw_device [lindex [get_hw_devices xc7k325t_0] 0]
  }
 markLastStep deviceProgrammed
}

##########################################################
# proc for marking the step that was just completed
##########################################################
proc markLastStep {lastStepName} {
 variable lastStep
 set lastStep $lastStepName
}
