################################################################################
#
#   Author: alen.arias.vazquez@cern.ch
#   Date: 10/05/2022
#
################################################################################

# Get Git Hash
proc get_git_hash {} {
    return [ exec git rev-parse --short=40 HEAD ]
}

# Get Git Tag
proc get_git_tag {} {
    set git_tag_check [ catch { exec git describe --tags --abbrev=0 --dirty=D } msg ]
    if { $git_tag_check == 1 } {
        write_yellow "Any tag has not been defined yet in the current repository"
        return "v0.0.0"
    } else {
        return $msg
    }
}

# Conver Git Tag to number:
#   bits 31-24: major number
#   bits 23-16: minor number
#   bits 15-00: patch number
proc convert_tag_to_number { tag } {
    # Highest v255.255.65535
    if { [ string range $tag 0 0 ] == "v" } {
        # Remove v
        set tag [ string range $tag 1 end ]
        if { [ string range $tag end end ] == "D" } {
            # Remove Dirty
            set tag [ string range $tag 0 end-1 ]
        }
        set list_num [ split $tag {.} ]
        if { [ llength $list_num ] == 3 } {
            set major [ format %02X [ lindex $list_num 0 ] ]
            set minor [ format %02X [ lindex $list_num 1 ] ]
            set patch [ format %04X [ lindex $list_num 2 ] ]
            return [ concat $major$minor$patch ]
        } else {
            return 0
        }
    } else {
        return 0
    }
}

# Convert String to Hex String
proc convert_string_to_hex { str size } {
    while { $size > [ string length $str ] } {
        set str [ concat -$str ]
    }
    binary scan $str H* hex
    return $hex
}

# Generate UUID
proc generate_uuid {} {
    set str [ info hostname ]
    binary scan $str H* hex_value
    set    uuid [ format %2.2x [ clock seconds ]]
    append uuid [ string range [ format %2.2x [ clock clicks ] ] 0 3 ]
    append uuid [ string range [ format %2.2x [ clock clicks ] ] 2 5 ]
    append uuid [ string range [ format %2.2x [ clock clicks ] ] 4 7 ]
    append uuid [ string range $hex_value 0 11]
    return $uuid
}

proc print_uuid { hex_uuid } {
    return [ concat [ string range $hex_uuid 0 7 ]-[ string range $hex_uuid 8 11 ]-[ string range $hex_uuid 12 15 ]-[ string range $hex_uuid 16 19 ]-[ string range $hex_uuid 20 end ] ]
}

proc create_fpga_version { name ref target } {

    # Parameters that are Constants:
    set vendor_id "FF000000"
    set device_id "44494F5A"
    set byte_ord "FFFE0000"
    set cap_mask "AAAAAAAA"

    # IP CORE ID
    set core_id "46504741"

    # Get git parameters
    set git_hash [ get_git_hash ]
    set git_tag [ get_git_tag ]

    # Get DATE
    set build_date [ clock seconds ]

    # Cut Commit hash
    set source_id [ string range $git_hash 8 end ]

    # UUID
    set uuid [ generate_uuid ]

    # Convert string to hex
    set name_hex [ convert_string_to_hex $name 8 ]
    set git_tag_hex [ convert_string_to_hex $git_tag 8 ]
    set num_version [ convert_tag_to_number $git_tag ]

    # Open input and output file
    set r_file [open $ref r]
    set w_file [open $target w]

    # Map for replace strings
    set map {}
    lappend map "parameter g_VENDOR_ID                   = 32'h0," "parameter g_VENDOR_ID                   = 32'h$vendor_id,"
    lappend map "parameter g_DEVICE_ID                   = 32'h0," "parameter g_DEVICE_ID                   = 32'h$device_id,"
    lappend map "parameter g_VERSION                     = 32'h0," "parameter g_VERSION                     = 32'h$num_version,"
    lappend map "parameter g_BYTE_ORD_MARK               = 32'h0," "parameter g_BYTE_ORD_MARK               = 32'h$byte_ord,"
    lappend map "parameter g_SOURCE_ID                   = 128'h0," "parameter g_SOURCE_ID                   = 128'h$source_id,"
    lappend map "parameter g_CAP_MASK                    = 32'h0," "parameter g_CAP_MASK                    = 32'h$cap_mask,"
    lappend map "parameter g_VENDOR_UUID                 = 128'h0," "parameter g_VENDOR_UUID                 = 128'h$uuid,"
    lappend map "parameter g_CORE_ID                     = 32'h0," "parameter g_CORE_ID                     = 32'h$core_id,"
    lappend map "parameter g_NAME                        = 64'h0," "parameter g_NAME                        = 64'h$name_hex,"
    lappend map "parameter g_BUILD_DATE                  = 32'd0," "parameter g_BUILD_DATE                  = 32'd$build_date,"
    lappend map "parameter g_HASH                        = 160'h0," "parameter g_HASH                        = 160'h$git_hash,"
    lappend map "parameter g_TAG                         = 64'h0," "parameter g_TAG                         = 64'h$git_tag_hex,"

    write_green ""
    write_green "Fpga Device Generation:"
    write_green "Vendor ID: 0x$vendor_id"
    write_green "Device ID: 0x$device_id"
    write_green "Number Version: 0x$num_version"
    write_green "Byte Order Mark: 0x$byte_ord"
    write_green "Source ID: $source_id"
    write_green "Capability Mask: 0x$cap_mask"
    write_green "Vendor UUID: [ print_uuid $uuid ]"
    write_green "IP Core ID: 0x$core_id"
    write_green "Project name: $name"
    write_green "Build Date: [ clock format $build_date -format "%Y-%m-%d %H:%M:%S" ]"
    write_green "Git Hash: $git_hash"
    write_green "Git Tag: $git_tag"
    write_green ""

    # Copy files
    while { [ gets $r_file r_line ] >= 0 } {
        set w_line [ string map $map $r_line]
        puts $w_file $w_line
    }

    # Closes files
    close $r_file
    close $w_file
}
