# Tcl script to automatically generate the SDB synthesis descriptor.
#
# Must be added to your top-level Manifest.py like this:
#
# syn_post_project_cmd = "$(TCL_INTERPRETER) [this_tcl_script] " +
#                         syn_tool + " $(PROJECT_FILE)"
#
# Notes:
#
# 1. $(TCL_INTERPRETER) and $(PROJECT_FILE) will be automatically
#    resolved inside the Makefile generated by hdlmake.
# 2. syn_tool is a Manifest.py variable, it should already be in your
#    tol-level Manifest.py.
# 3. [this_tcl_script] should be replaced by the full path to
#    this Tcl script. Relative paths should be with respect to
#    the location of the top-level Manifest.py.
# 4. Mind the spaces inside the quotes, before and after syn_tool.

# get current time
set time_now [clock seconds]

# set list of supported tools
set supported_tools [list ise]

# get synthesis tool from 1st command line argument
set syn_tool [lindex $argv 0]

# get project file from 2nd command-line argument
set project_file [lindex $argv 1]

# set file for all output
set out_file synthesis_descriptor.vhd

# short procedure for consistent reporting
proc report {level message} {
    puts "$level:$::argv0 - $message"
}

# procedure to make sure a given string has a certain length,
# necessary for embedding strings in SDB. If string is longer, it is
# trimmed, if it is shorter it is padded (by default with spaces).
#
# For the curious: https://en.wikipedia.org/wiki/Procrustes
proc str_procrustes {str limit {pad_char " "}} {
    set str_len [string length $str]
    if {[expr $str_len < $limit]} {
	set pad [string repeat $pad_char [expr $limit - $str_len]]
	return $str$pad
    } else {
	return [string range $str 0 [expr $limit - 1]]
    }
}

#-------------------------------------------------------------------------------
# STEP 1/7: Check that the synthesis tool is supported
#-------------------------------------------------------------------------------
if {[lsearch -exact $supported_tools $syn_tool] == -1} {
    report ERROR "$syn_tool is not (yet) supported, exiting."
    exit -1
}

#-------------------------------------------------------------------------------
# STEP 2/7: Check that project file exists
#-------------------------------------------------------------------------------

if {![file exists $project_file]} {
    report ERROR "Missing file $project_file, exiting."
    exit -1
}

#-------------------------------------------------------------------------------
# STEP 3/7: Open project file
#-------------------------------------------------------------------------------

if {$syn_tool == "ise"} {
    xilinx::project open $project_file
    # dummy call to project get name to ger rid of annoying error
    # regarding list of boards for ISim
    xilinx::project get name
}
report INFO "Opened project $project_file."

#-------------------------------------------------------------------------------
# STEP 4/7: Get necessary info from synthesis tool and Git
#-------------------------------------------------------------------------------

if {$syn_tool == "ise"} {
    set inf_project [xilinx::project get name]
    # ISE does not provide a tcl command to get version.
    # Possible ways include parsing the project file (not backward compatible)
    # or Xilinx AR#35500.
    # For now we hard-code, since anyway ISE is end-of-life at version 14.7.
    set inf_tool_version [format "%08d" "147"]
}
set inf_tool_name [string toupper $syn_tool]
set inf_commit_id [exec git log -1 --format=%H]
set inf_date [clock format $time_now -format "%A, %B %d %Y"]
set inf_date_ymd [clock format $time_now -format "%Y%m%d"]
set inf_user [exec git config user.name]
# next line could break if git remote is not called "origin"
set inf_repo_url [exec git remote get-url origin]

#-------------------------------------------------------------------------------
# STEP 5/7: Generate the output file
#-------------------------------------------------------------------------------

set fp [open $out_file w]

puts $fp [string repeat "-" 80]
puts $fp "-- SDB meta information for $project_file."
puts $fp "--"
puts $fp "-- This file was automatically generated by $argv0 on:"
puts $fp "-- $inf_date"
puts $fp "--"
puts $fp "-- $argv0 is part of OHWR general-cores:"
puts $fp "-- https://www.ohwr.org/projects/general-cores/wiki"
puts $fp "--"
puts $fp "-- For more information on SDB meta information, see also:"
puts $fp "-- https://www.ohwr.org/projects/sdb/wiki"
puts $fp [string repeat "-" 80]
puts $fp ""
puts $fp "library ieee;"
puts $fp "use ieee.std_logic_1164.all;"
puts $fp "use work.wishbone_pkg.all;"
puts $fp ""
puts $fp "package synthesis_descriptor is"
puts $fp ""
puts $fp "  constant c_sdb_synthesis_info : t_sdb_synthesis := ("
puts $fp "    syn_module_name  => \"[str_procrustes $inf_project 16]\","
puts $fp "    syn_commit_id    => \"[str_procrustes $inf_commit_id 32]\","
puts $fp "    syn_tool_name    => \"[str_procrustes $inf_tool_name 8]\","
puts $fp "    syn_tool_version => x\"$inf_tool_version\","
puts $fp "    syn_date         => x\"[str_procrustes $inf_date_ymd 8]\","
puts $fp "    syn_username     => \"[str_procrustes $inf_user 15]\");"
puts $fp ""
puts $fp "  constant c_sdb_repo_url : t_sdb_repo_url := ("
puts $fp "    repo_url => \"[str_procrustes $inf_repo_url 63]\");"
puts $fp ""
puts $fp "end package synthesis_descriptor;"

close $fp

#-------------------------------------------------------------------------------
# Step 6/7: Add the output file to the project
#-------------------------------------------------------------------------------

if {$syn_tool == "ise"} {
    xilinx::xfile add $out_file
}
report "INFO" "Added $out_file to $project_file."

#-------------------------------------------------------------------------------
# Step 7/7: Close project file
#-------------------------------------------------------------------------------

if {$syn_tool == "ise"} {
    xilinx::project close
}
report "INFO" "Closed project $project_file."