##
##  Copyright(c) 2020-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
##
##  This program is free software; you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation; either version 2 of the License, or
##  (at your option) any later version.
##
##  This program is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##
##  You should have received a copy of the GNU General Public License
##  along with this program; if not, see <http://www.gnu.org/licenses/>.
##

hexagon_ss = ss.source_set()

hex_common_py = 'hex_common.py'
attribs_def = meson.current_source_dir() / 'attribs_def.h.inc'
gen_tcg_h = meson.current_source_dir() / 'gen_tcg.h'
gen_tcg_hvx_h = meson.current_source_dir() / 'gen_tcg_hvx.h'
idef_parser_dir = meson.current_source_dir() / 'idef-parser'

#
#  Step 1
#  We use a C program to create semantics_generated.pyinc
#
gen_semantics = executable(
    'gen_semantics',
    'gen_semantics.c',
    native: true, build_by_default: false)

semantics_generated = custom_target(
    'semantics_generated.pyinc',
    output: 'semantics_generated.pyinc',
    command: [gen_semantics, '@OUTPUT@'],
)
hexagon_ss.add(semantics_generated)

#
# Step 2
# We use Python scripts to generate the following files
#     shortcode_generated.h.inc
#     tcg_func_table_generated.c.inc
#     printinsn_generated.h.inc
#     op_regs_generated.h.inc
#     op_attribs_generated.h.inc
#     opcodes_def_generated.h.inc
#
shortcode_generated = custom_target(
    'shortcode_generated.h.inc',
    output: 'shortcode_generated.h.inc',
    depends: [semantics_generated],
    depend_files: [hex_common_py, attribs_def],
    command: [python, files('gen_shortcode.py'), semantics_generated, attribs_def, '@OUTPUT@'],
)
hexagon_ss.add(shortcode_generated)

tcg_func_table_generated = custom_target(
    'tcg_func_table_generated.c.inc',
    output: 'tcg_func_table_generated.c.inc',
    depends: [semantics_generated],
    depend_files: [hex_common_py, attribs_def],
    command: [python, files('gen_tcg_func_table.py'), semantics_generated, attribs_def, '@OUTPUT@'],
)
hexagon_ss.add(tcg_func_table_generated)

printinsn_generated = custom_target(
    'printinsn_generated.h.inc',
    output: 'printinsn_generated.h.inc',
    depends: [semantics_generated],
    depend_files: [hex_common_py, attribs_def],
    command: [python, files('gen_printinsn.py'), semantics_generated, attribs_def, '@OUTPUT@'],
)
hexagon_ss.add(printinsn_generated)

op_regs_generated = custom_target(
    'op_regs_generated.h.inc',
    output: 'op_regs_generated.h.inc',
    depends: [semantics_generated],
    depend_files: [hex_common_py, attribs_def],
    command: [python, files('gen_op_regs.py'), semantics_generated, attribs_def, '@OUTPUT@'],
)
hexagon_ss.add(op_regs_generated)

op_attribs_generated = custom_target(
    'op_attribs_generated.h.inc',
    output: 'op_attribs_generated.h.inc',
    depends: [semantics_generated],
    depend_files: [hex_common_py, attribs_def],
    command: [python, files('gen_op_attribs.py'), semantics_generated, attribs_def, '@OUTPUT@'],
)
hexagon_ss.add(op_attribs_generated)

opcodes_def_generated = custom_target(
    'opcodes_def_generated.h.inc',
    output: 'opcodes_def_generated.h.inc',
    depends: [semantics_generated],
    depend_files: [hex_common_py, attribs_def],
    command: [python, files('gen_opcodes_def.py'), semantics_generated, attribs_def, '@OUTPUT@'],
)
hexagon_ss.add(opcodes_def_generated)

#
# Step 3
# We use a C program to create iset.py which is imported into dectree.py
# to create the decode tree
#
gen_dectree_import = executable(
    'gen_dectree_import',
    'gen_dectree_import.c', opcodes_def_generated, op_regs_generated,
    native: true, build_by_default: false)

iset_py = custom_target(
    'iset.py',
    output: 'iset.py',
    command: [gen_dectree_import, '@OUTPUT@'],
)
hexagon_ss.add(iset_py)

#
# Step 4
# Generate the input to the QEMU decodetree.py script
#
normal_decode_generated = custom_target(
    'normal_decode_generated',
    output: 'normal_decode_generated',
    depends: [iset_py, semantics_generated],
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files('gen_decodetree.py'), semantics_generated, 'NORMAL', '@OUTPUT@'],
)
hexagon_ss.add(normal_decode_generated)

hvx_decode_generated = custom_target(
    'hvx_decode_generated',
    output: 'hvx_decode_generated',
    depends: [iset_py, semantics_generated],
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files('gen_decodetree.py'), semantics_generated, 'EXT_mmvec', '@OUTPUT@'],
)
hexagon_ss.add(hvx_decode_generated)

subinsn_a_decode_generated = custom_target(
    'subinsn_a_decode_generated',
    output: 'subinsn_a_decode_generated',
    depends: [iset_py, semantics_generated],
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_A', '@OUTPUT@'],
)
hexagon_ss.add(subinsn_a_decode_generated)

subinsn_l1_decode_generated = custom_target(
    'subinsn_l1_decode_generated',
    output: 'subinsn_l1_decode_generated',
    depends: [iset_py, semantics_generated],
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_L1', '@OUTPUT@'],
)
hexagon_ss.add(subinsn_l1_decode_generated)

subinsn_l2_decode_generated = custom_target(
    'subinsn_l2_decode_generated',
    output: 'subinsn_l2_decode_generated',
    depends: [iset_py, semantics_generated],
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_L2', '@OUTPUT@'],
)
hexagon_ss.add(subinsn_l2_decode_generated)

subinsn_s1_decode_generated = custom_target(
    'subinsn_s1_decode_generated',
    output: 'subinsn_s1_decode_generated',
    depends: [iset_py, semantics_generated],
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_S1', '@OUTPUT@'],
)
hexagon_ss.add(subinsn_s1_decode_generated)

subinsn_s2_decode_generated = custom_target(
    'subinsn_s2_decode_generated',
    output: 'subinsn_s2_decode_generated',
    depends: [iset_py, semantics_generated],
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_S2', '@OUTPUT@'],
)
hexagon_ss.add(subinsn_s2_decode_generated)

#
# Run the QEMU decodetree.py script to produce the instruction decoder
#
decodetree_py = meson.current_source_dir() / '../../scripts/decodetree.py'
decode_normal_generated = custom_target(
    'decode_normal_generated.c.inc',
    output: 'decode_normal_generated.c.inc',
    input: normal_decode_generated,
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files(decodetree_py), normal_decode_generated, '--static-decode=decode_normal', '-o', '@OUTPUT@'],
)
hexagon_ss.add(decode_normal_generated)

decode_hvx_generated = custom_target(
    'decode_hvx_generated.c.inc',
    output: 'decode_hvx_generated.c.inc',
    input: hvx_decode_generated,
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files(decodetree_py), hvx_decode_generated, '--static-decode=decode_hvx', '-o', '@OUTPUT@'],
)
hexagon_ss.add(decode_hvx_generated)

decode_subinsn_a_generated = custom_target(
    'decode_subinsn_a_generated.c.inc',
    output: 'decode_subinsn_a_generated.c.inc',
    input: subinsn_a_decode_generated,
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files(decodetree_py), subinsn_a_decode_generated, ['--static-decode=decode_subinsn_a', '--insnwidth=16'], '-o', '@OUTPUT@'],
)
hexagon_ss.add(decode_subinsn_a_generated)

decode_subinsn_l1_generated = custom_target(
    'decode_subinsn_l1_generated.c.inc',
    output: 'decode_subinsn_l1_generated.c.inc',
    input: subinsn_l1_decode_generated,
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files(decodetree_py), subinsn_l1_decode_generated, ['--static-decode=decode_subinsn_l1', '--insnwidth=16'], '-o', '@OUTPUT@'],
)
hexagon_ss.add(decode_subinsn_l1_generated)

decode_subinsn_l2_generated = custom_target(
    'decode_subinsn_l2_generated.c.inc',
    output: 'decode_subinsn_l2_generated.c.inc',
    input: subinsn_l2_decode_generated,
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files(decodetree_py), subinsn_l2_decode_generated, ['--static-decode=decode_subinsn_l2', '--insnwidth=16'], '-o', '@OUTPUT@'],
)
hexagon_ss.add(decode_subinsn_l2_generated)

decode_subinsn_s1_generated = custom_target(
    'decode_subinsn_s1_generated.c.inc',
    output: 'decode_subinsn_s1_generated.c.inc',
    input: subinsn_s1_decode_generated,
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files(decodetree_py), subinsn_s1_decode_generated, ['--static-decode=decode_subinsn_s1', '--insnwidth=16'], '-o', '@OUTPUT@'],
)
hexagon_ss.add(decode_subinsn_s1_generated)

decode_subinsn_s2_generated = custom_target(
    'decode_subinsn_s2_generated.c.inc',
    output: 'decode_subinsn_s2_generated.c.inc',
    input: subinsn_s2_decode_generated,
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files(decodetree_py), subinsn_s2_decode_generated, ['--static-decode=decode_subinsn_s2', '--insnwidth=16'], '-o', '@OUTPUT@'],
)
hexagon_ss.add(decode_subinsn_s2_generated)

#
# Generate the trans_* functions that the decoder will use
#
decodetree_trans_funcs_generated = custom_target(
    'decodetree_trans_funcs_generated.c.inc',
    output: 'decodetree_trans_funcs_generated.c.inc',
    depends: [iset_py, semantics_generated],
    env: {'PYTHONPATH': meson.current_build_dir()},
    command: [python, files('gen_trans_funcs.py'), semantics_generated, '@OUTPUT@'],
)
hexagon_ss.add(decodetree_trans_funcs_generated)

hexagon_ss.add(files(
    'cpu.c',
    'translate.c',
    'op_helper.c',
    'gdbstub.c',
    'genptr.c',
    'reg_fields.c',
    'decode.c',
    'iclass.c',
    'opcodes.c',
    'printinsn.c',
    'arch.c',
    'fma_emu.c',
    'mmvec/decode_ext_mmvec.c',
    'mmvec/system_ext_mmvec.c',
))

#
# Step 4.5
# We use flex/bison based idef-parser to generate TCG code for a lot
# of instructions. idef-parser outputs
#     idef-generated-emitter.c
#     idef-generated-emitter.h.inc
#     idef-generated-enabled-instructions
#
idef_parser_enabled = get_option('hexagon_idef_parser')
if idef_parser_enabled and 'hexagon-linux-user' in target_dirs
    idef_parser_input_generated = custom_target(
        'idef_parser_input.h.inc',
        output: 'idef_parser_input.h.inc',
        depends: [semantics_generated],
        depend_files: [hex_common_py],
        command: [python, files('gen_idef_parser_funcs.py'), semantics_generated, attribs_def, '@OUTPUT@'],
    )

    preprocessed_idef_parser_input_generated = custom_target(
        'idef_parser_input.preprocessed.h.inc',
        output: 'idef_parser_input.preprocessed.h.inc',
        input: idef_parser_input_generated,
        depend_files: [idef_parser_dir / 'macros.inc'],
        command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' + idef_parser_dir, '-o', '@OUTPUT@'],
    )

    flex = generator(
        find_program('flex'),
        output: ['@BASENAME@.yy.c', '@BASENAME@.yy.h'],
        arguments: ['-o', '@OUTPUT0@', '--header-file=@OUTPUT1@', '@INPUT@']
    )

    bison = generator(
        find_program('bison', version: '>=3.0'),
        output: ['@BASENAME@.tab.c', '@BASENAME@.tab.h'],
        arguments: ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@']
    )

    glib_dep = dependency('glib-2.0', native: true)

    idef_parser = executable(
        'idef-parser',
        [flex.process(idef_parser_dir / 'idef-parser.lex'),
         bison.process(idef_parser_dir / 'idef-parser.y'),
         idef_parser_dir / 'parser-helpers.c'],
        include_directories: ['idef-parser', '../../include/'],
        dependencies: [glib_dep],
        native: true
    )

    idef_generated_tcg = custom_target(
        'idef-generated-tcg',
        output: ['idef-generated-emitter.c',
                 'idef-generated-emitter.h.inc',
                 'idef-generated-enabled-instructions'],
        input: preprocessed_idef_parser_input_generated,
        depend_files: [hex_common_py],
        command: [idef_parser, '@INPUT@', '@OUTPUT0@', '@OUTPUT1@', '@OUTPUT2@']
    )

    indent = find_program('indent', required: false)
    if indent.found()
        idef_generated_tcg_c = custom_target(
            'indent',
            input: idef_generated_tcg[0],
            output: 'idef-generated-emitter.indented.c',
            command: [indent, '-linux', '@INPUT@', '-o', '@OUTPUT@']
        )
    else
        idef_generated_tcg_c = custom_target(
            'copy',
            input: idef_generated_tcg[0],
            output: 'idef-generated-emitter.indented.c',
            command: ['cp', '@INPUT@', '@OUTPUT@']
        )
    endif

    idef_generated_list = idef_generated_tcg[2].full_path()

    hexagon_ss.add(idef_generated_tcg_c)

    # Setup input and dependencies for the next step, this depends on whether or
    # not idef-parser is enabled
    helper_dep = [semantics_generated, idef_generated_tcg_c, idef_generated_tcg]
    helper_in = [semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, idef_generated_list]
else
    # Setup input and dependencies for the next step, this depends on whether or
    # not idef-parser is enabled
    helper_dep = [semantics_generated]
    helper_in = [semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h]
endif

#
# Step 5
# We use Python scripts to generate the following files
#     helper_protos_generated.h.inc
#     helper_funcs_generated.c.inc
#     tcg_funcs_generated.c.inc
#
helper_protos_generated = custom_target(
    'helper_protos_generated.h.inc',
    output: 'helper_protos_generated.h.inc',
    depends: helper_dep,
    depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
    command: [python, files('gen_helper_protos.py'), helper_in, '@OUTPUT@'],
)
hexagon_ss.add(helper_protos_generated)

helper_funcs_generated = custom_target(
    'helper_funcs_generated.c.inc',
    output: 'helper_funcs_generated.c.inc',
    depends: helper_dep,
    depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
    command: [python, files('gen_helper_funcs.py'), helper_in, '@OUTPUT@'],
)
hexagon_ss.add(helper_funcs_generated)

tcg_funcs_generated = custom_target(
    'tcg_funcs_generated.c.inc',
    output: 'tcg_funcs_generated.c.inc',
    depends: helper_dep,
    depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
    command: [python, files('gen_tcg_funcs.py'), helper_in, '@OUTPUT@'],
)
hexagon_ss.add(tcg_funcs_generated)

analyze_funcs_generated = custom_target(
    'analyze_funcs_generated.c.inc',
    output: 'analyze_funcs_generated.c.inc',
    depends: helper_dep,
    depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
    command: [python, files('gen_analyze_funcs.py'), helper_in, '@OUTPUT@'],
)
hexagon_ss.add(analyze_funcs_generated)

target_arch += {'hexagon': hexagon_ss}