"""
disassemble.py <optimization flag>

Description:
   Script to assist students running the GNU disassembly tool for the APU_NEON (FP_and_SIMD) lab
   where <optimization_flag> is a text string corrolating to the optimization string, typically O0, O2

Note:
   Vitis Unified IDE uses Python2 - make sure your coding style matches! (needs verification)

Usage:
   this script doesn't require any argument, but it does rely on having the gnu disassembly tools
   in the standard location.
   *** Linux ONLY ***

Debugging:
   source /opt/amd/Vitis/2024.1/settings64.sh
   cd ~/training/apu_neon/support
   vitis -s disassemble_O0.py > results_file.txt; gedit results_file.txt

History:
  2024/09/22 - RS - removed tkinter parts
  2024/02/14 - WK - initial - based on the tcl script of the same name
"""

import os
import platform
import sys
import subprocess
import vitis

run_results = []


def clean_exit(msg: str) -> None:
    """
    :param msg: message to display in the pop-up box
    :return: None
    """
    print(msg)
    vitis.dispose()  # shut down the vitis tool
    exit(1)


def run(cmd, use_shell=False):
    """
    @descr: runs the passed command string
            important note: this launches the application and WAITS/SUSPENDS for the app to close!
    @usage: run results are copied to global variable run_results so that these results can be recovered
            if the run command is passed through a thread
    @param cmd: command to execute with arguments as a single string
    @param use_shell:
    @return: os return code, stdout msg, error message
    """
    global run_results
    try:
        cmd_list = cmd.split(' ')
        child = subprocess.Popen(cmd_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=use_shell)
        (out, err) = child.communicate()
        stdout = f"custEd_utils.py:run({cmd}): {out}"
        stderr = f"custEd_utils.py:run({cmd}: {err}"
        run_results = [child.returncode, stdout, stderr]
        return [child.returncode, stdout, stderr]
    except OSError as e:
        print("OSError: " + str(e))
        return [e.errno, "", str(e)]
    except:
        print(f"Something bad happened in run: {cmd}")
        print("Error > ", sys.exc_info()[0])
        return [-1, "", sys.exc_info()[0]]


if __name__ == '__main__':
    # get the name of the script
    script_name = sys.argv[0]
    if len(sys.argv) >= 2:
        optimization_flag = sys.argv[1]
    else:
        print(f"Usage: {script_name} [optimization flag]")
        print(f"\tif optimization flag is not specified, O0 is assumed.")
        optimization_flag = "O0"

    # grab the one environment variable that points to the lab area
    training_path = os.environ['TRAINING_PATH']
    if len(training_path) == 0:
        print("Can't continue until the environment variable for TRAINING_PATH is set\nAborting!")
        exit(1)
    print(f"Using {training_path} as the location of the training directory")

    # set up the necessary paths
    work_dir: str = f"{training_path}/apu_neon/lab"
    vitis_path: str = "/opt/amd/Vitis/2024.1"  # uses global variable substitution for <!...!>
    if vitis_path[:-1] == '/':  # if the last character is a slash, then...
        vitis_path = vitis_path[:-1]  # remove the slash

    # identify the host OS so that we know what relative path to use
    host_os = platform.system()
    if host_os.lower() == "windows":  # if this is a Windows environment, then look in the Windows hiding place...
        clean_exit("This script doesn't currently support Windows")
        exit(1)
        # disassembler_tool_location: str = f"{vitis_path}/gnu/aarch64/nt/aarch64-none/bin"
    elif host_os.lower() == "linux":   # if it's Linux, then look in its hiding place
        print("debug: we found that this is running under Linux")
        disassembler_tool_location: str = f"{vitis_path}gnu/aarch64/lin/aarch64-none/bin"
    else:
        clean_exit("I can't identify what OS this is running on.\nAborting!")

    # define shorthand
    project_name = "apu_neon_app"
    output_name = f"{project_name}_{optimization_flag}.s"
    elf_file = f"{work_dir}/{project_name}/build/{project_name}.elf"

    # Welcome the user
    print(f"Disassembling {project_name} with {optimization_flag}")

    # identify the dis-assembler for this OS
    disassembler_tool: str = ""
    if host_os.lower() == "windows":
        # should never get here! this code is here for future capability
        disassembler_tool_location: str = f"{vitis_path}/gnu/aarch64/nt/aarch64-none/bin"
        disassembler_tool = f"{disassembler_tool_location}/aarch64-none-elf-objdump.exe"
    elif host_os.lower() == "linux":
        disassembler_tool_location: str = f"{vitis_path}/gnu/aarch64/lin/aarch64-none/bin"
        disassembler_tool = f"{disassembler_tool_location}/aarch64-none-elf-objdump"
        
    # check that the elf file exists 
    if os.path.isfile(elf_file):
        print("elf found\n")
    else:
        print("elf not found: {elf_file}\n")

    # if the disassembler was found, then run it
    if os.path.isfile(disassembler_tool):
        [exit_code, stdout, stderr] = run(f"{disassembler_tool} -D {elf_file}")
        print(f"dissassmbly exit code: {exit_code}")
        if exit_code != 0:
            print(f"Disassembler exited with some issue: {exit_code}")
            print(f"from the stdout: {stdout}\n\nfrom the stderr: {stderr}\n")
        else:
            output_file = f"{work_dir}/disassemble_{optimization_flag}"
            print(f"disassembly completed successfully - saving to {output_file}")
            cleaned_message = stdout.replace("\\n", '\n')
            cleaned_message = cleaned_message.replace("\\t", '\t')
            start = cleaned_message.index("Disassembly of section")
            cleaned_message = cleaned_message[start:]
            f = open(output_file, 'w')
            f.write(cleaned_message)
            f.close()
    else:
        clean_exit(f"Cannot find this disassembler: {disassembler_tool}")

    # Done
    clean_exit(
        f"Successfully completed running {script_name}.\n"
        f"Disassembled file is located in the {work_dir} directory with the name {output_name}\n")

#
# <copyright-disclaimer-start>
#<copyright-disclaimer-start>
#  **************************************************************************************************************
#  * © 2024 Advanced Micro Devices, Inc. All rights reserved.                                                   *
#  * DISCLAIMER                                                                                                 *
#  * The information contained herein is for informational purposes only, and is subject to change              *
#  * without notice. While every precaution has been taken in the preparation of this document, it              *
#  * may contain technical inaccuracies, omissions and typographical errors, and AMD is under no                *
#  * obligation to update or otherwise correct this information.  Advanced Micro Devices, Inc. makes            *
#  * no representations or warranties with respect to the accuracy or completeness of the contents of           *
#  * this document, and assumes no liability of any kind, including the implied warranties of noninfringement,  *
#  * merchantability or fitness for particular purposes, with respect to the operation or use of AMD            *
#  * hardware, software or other products described herein.  No license, including implied or                   *
#  * arising by estoppel, to any intellectual property rights is granted by this document.  Terms and           *
#  * limitations applicable to the purchase or use of AMD’s products are as set forth in a signed agreement     *
#  * between the parties or in AMD's Standard Terms and Conditions of Sale. GD-18                               *
#  *                                                                                                            *
#  **************************************************************************************************************
#<copyright-disclaimer-end>
# <copyright-disclaimer-end>
#
