/*
 * Copyright (C) 2023 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ia_css_psys_static_storage_class.h"
#include "ia_css_psys_program_group_manifest.h"
#include "ia_css_rbm_manifest.h"

#ifndef IPU7_ERROR_MISSING_DISABLE_SECTION
#include "vied_nci_acb_route_type.h" /* only used for printing. */
#endif /* IPU7_ERROR_MISSING_DISABLE_SECTION */

/*
 * Functions to possibly inline
 */

#ifndef __IA_CSS_PSYS_STATIC_INLINE__
#include "ia_css_psys_program_group_manifest_impl.h"
#endif /* __IA_CSS_PSYS_STATIC_INLINE__ */

/*
 * Functions not to inline
 */

/*
 * We need to refactor those files in order to
 * build in the firmware only what is needed,
 * switches are put current to workaround compilation problems
 * in the firmware (for example lack of uint64_t support)
 * supported in the firmware
 */
#if !defined(__HIVECC)
size_t ia_css_sizeof_program_group_manifest(
    const uint8_t program_count,
    const uint8_t terminal_count,
    const uint8_t *program_needs_extension,
    const uint8_t *program_dependency_count,
    const uint8_t *terminal_dependency_count,
    const ia_css_terminal_type_t *terminal_type,
    const uint16_t *cached_in_param_section_count,
    const uint16_t *cached_out_param_section_count,
    const uint16_t *spatial_param_section_count,
    const uint16_t *fragment_param_section_count,
    const uint16_t *sliced_param_section_count,
    const uint16_t *sliced_out_param_section_count,
    const uint16_t *kernel_fragment_seq_count,
    const uint16_t *progctrlinit_load_section_counts,
    const uint16_t *progctrlinit_connect_section_counts)
{
    size_t size = 0;
    int i = 0;
    int j = 0;
    int k = 0;
    int l = 0;
    int m = 0;
    int n = 0;
    int o = 0;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_sizeof_program_group_manifest(): enter:\n");

    verifexit(program_count != 0);
    verifexit(program_dependency_count != NULL);
    verifexit(terminal_dependency_count != NULL);

    size += sizeof(ia_css_program_group_manifest_t);

    /* Private payload in the program group manifest */
    size += ceil_mul(sizeof(struct ia_css_psys_private_pg_data),
                sizeof(uint64_t));
    /* RBM manifest in the program group manifest */
    size += ceil_mul(sizeof(ia_css_rbm_manifest_t),
                sizeof(uint64_t));

    for (i = 0; i < (int)program_count; i++) {
        size += ia_css_sizeof_program_manifest(
                program_needs_extension[i],
                program_dependency_count[i],
                terminal_dependency_count[i]);
    }

    for (i = 0; i < (int)terminal_count; i++) {
        switch (terminal_type[i]) {
        case IA_CSS_TERMINAL_TYPE_PARAM_CACHED_IN:
            size += ia_css_param_terminal_manifest_get_size(
                    cached_in_param_section_count[j]);
            j++;
            break;
        case IA_CSS_TERMINAL_TYPE_PARAM_CACHED_OUT:
            size += ia_css_param_terminal_manifest_get_size(
                    cached_out_param_section_count[k]);
            k++;
            break;
        case IA_CSS_TERMINAL_TYPE_PARAM_SPATIAL_IN:
        case IA_CSS_TERMINAL_TYPE_PARAM_SPATIAL_OUT:
            size += ia_css_spatial_param_terminal_manifest_get_size(
                    spatial_param_section_count[l]);
            l++;
            break;
        case IA_CSS_TERMINAL_TYPE_PROGRAM:
            size += ia_css_program_terminal_manifest_get_size(
                    fragment_param_section_count[m],
                    kernel_fragment_seq_count[m]);
            m++;
            break;
        case IA_CSS_TERMINAL_TYPE_PROGRAM_CONTROL_INIT:
            size += ia_css_program_control_init_terminal_manifest_get_size(
                program_count,
                progctrlinit_load_section_counts,
                progctrlinit_connect_section_counts);
            break;
        case IA_CSS_TERMINAL_TYPE_DATA_IN:
        case IA_CSS_TERMINAL_TYPE_DATA_OUT:
            size += sizeof(ia_css_data_terminal_manifest_t);
            break;
        case IA_CSS_TERMINAL_TYPE_PARAM_SLICED_IN:
            size += ia_css_sliced_param_terminal_manifest_get_size(
                    sliced_param_section_count[n]);
            n++;
            break;
        case IA_CSS_TERMINAL_TYPE_PARAM_SLICED_OUT:
            size += ia_css_sliced_param_terminal_manifest_get_size(
                sliced_out_param_section_count[o]);
            o++;
            break;
        default:
            IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
                "ia_css_sizeof_program_group_manifest invalid argument\n");
        }
    }

EXIT:
    if (0 == program_count || 0 == terminal_count ||
        NULL == program_dependency_count ||
        NULL == terminal_dependency_count) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
            "ia_css_sizeof_program_group_manifest invalid argument\n");
    }
    return size;
}

/*
 * Currently, the design of XNR kernel inside the *_pregdc program group,
 * does not fit the exact model as is being asserted on in
 * ia_css_is_program_group_manifest_valid. We therefore disable some checks.
 * Further investigation is needed to determine whether *_pregdc program group
 * can be changed or that the model must be changed.
 * #define USE_SIMPLIFIED_GRAPH_MODEL 1 allows multiple programs to be
 * connected to the same terminal, and it allows a kernel be mapped over
 * multiple programs.
 */
#define USE_SIMPLIFIED_GRAPH_MODEL 1

/*
 * Model and/or check refinements
 * - Parallel programs do not yet have mutual exclusive alternatives
 * - The pgram dependencies do not need to be acyclic
 * - Parallel programs need to have an equal kernel requirement
 */
bool ia_css_is_program_group_manifest_valid(
    const ia_css_program_group_manifest_t *manifest)
{
    int i;
    bool is_valid = false;
    uint8_t terminal_count;
    uint8_t program_count;
    ia_css_kernel_bitmap_t total_bitmap;
    ia_css_kernel_bitmap_t check_bitmap;
    ia_css_kernel_bitmap_t terminal_bitmap;
    /*
     * Use a standard bitmap type for the minimum logic to check the DAG,
     * generic functions can be used for the kernel enable bitmaps; Later
     */
    vied_nci_resource_bitmap_t resource_bitmap;
    int terminal_bitmap_weight;
    int num_parameter_terminal_in = 0;
    int num_parameter_terminal_out = 0;
    int num_program_terminal = 0;
    int num_program_terminal_sequencer_info = 0;
    bool has_program_control_init_terminal = false;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_is_program_group_manifest_valid(): enter:\n");

    verifexit(manifest != NULL);
    verifexit(ia_css_program_group_manifest_get_size(manifest) != 0);
    verifexit(ia_css_program_group_manifest_get_alignment(manifest) != 0);
    verifexit(ia_css_program_group_manifest_get_program_group_ID(manifest) != 0);

    terminal_count =
        ia_css_program_group_manifest_get_terminal_count(manifest);
    program_count =
        ia_css_program_group_manifest_get_program_count(manifest);
    total_bitmap =
        ia_css_program_group_manifest_get_kernel_bitmap(manifest);
    check_bitmap = ia_css_kernel_bitmap_clear();
    resource_bitmap = vied_nci_bit_mask(VIED_NCI_RESOURCE_BITMAP_BITS);
    terminal_bitmap = ia_css_kernel_bitmap_clear();

    verifexit(program_count != 0);
    verifexit(terminal_count != 0);
    verifexit(!ia_css_is_kernel_bitmap_empty(total_bitmap));
    verifexit(vied_nci_is_bitmap_empty(resource_bitmap));

    /* Check the kernel bitmaps for terminals */
    for (i = 0; i < (int)terminal_count; i++) {
        ia_css_terminal_manifest_t *terminal_manifest_i =
            ia_css_program_group_manifest_get_term_mnfst(
                manifest, i);
        bool is_parameter_in =
            (IA_CSS_TERMINAL_TYPE_PARAM_CACHED_IN ==
            ia_css_terminal_manifest_get_type(
                terminal_manifest_i));
        bool is_parameter_out =
            (IA_CSS_TERMINAL_TYPE_PARAM_CACHED_OUT ==
            ia_css_terminal_manifest_get_type(
                terminal_manifest_i));
        bool is_data =
            ia_css_is_terminal_manifest_data_terminal(
                terminal_manifest_i);
        bool is_program =
            ia_css_is_terminal_manifest_program_terminal(
                terminal_manifest_i);
        bool is_spatial_param =
            ia_css_is_terminal_manifest_spatial_parameter_terminal(
                terminal_manifest_i);
        bool is_program_control_init =
            ia_css_is_terminal_manifest_program_control_init_terminal(
                terminal_manifest_i);

        if (is_parameter_in) {
            num_parameter_terminal_in = is_parameter_in;
        } else if (is_parameter_out) {
            num_parameter_terminal_out = is_parameter_out;
        } else if (is_data) {
            ia_css_data_terminal_manifest_t *dterminal_manifest_i =
                (ia_css_data_terminal_manifest_t *)
                terminal_manifest_i;
            ia_css_kernel_bitmap_t terminal_bitmap_i =
                ia_css_data_terminal_manifest_get_kernel_bitmap(
                    dterminal_manifest_i);
            /*
             * A terminal must depend on kernels that are a subset
             * of the total, correction, it can only depend on one
             * kernel
             */
            verifexit(!ia_css_is_kernel_bitmap_empty(
                    terminal_bitmap_i));
            verifexit(ia_css_is_kernel_bitmap_subset(
                    total_bitmap, terminal_bitmap_i));
            verifexit(ia_css_is_kernel_bitmap_onehot(
                    terminal_bitmap_i));
        } else if (is_program) {
            verifexit(terminal_manifest_i);
            num_program_terminal += is_program;
            num_program_terminal_sequencer_info +=
                ((ia_css_program_terminal_manifest_t *)
                terminal_manifest_i)->
            kernel_fragment_sequencer_info_manifest_info_count;
        } else if (is_program_control_init) {
            has_program_control_init_terminal = is_program_control_init;
        } else {
            const ia_css_spatial_param_terminal_manifest_t
                *spatial_param_man =
            (const ia_css_spatial_param_terminal_manifest_t *)
                terminal_manifest_i;
            verifexit(spatial_param_man);
            verifexit(is_spatial_param);

            terminal_bitmap =
                ia_css_kernel_bitmap_set(terminal_bitmap,
                spatial_param_man->kernel_id);
            verifexit(!ia_css_is_kernel_bitmap_empty(terminal_bitmap));
            verifexit(ia_css_is_kernel_bitmap_subset(
                    total_bitmap, terminal_bitmap));
        }
    }

    /* Check the kernel bitmaps for programs */
    for (i = 0; i < (int)program_count; i++) {
        int j;
        ia_css_program_manifest_t *program_manifest_i =
            ia_css_program_group_manifest_get_prgrm_mnfst(
                manifest, i);
        ia_css_program_type_t program_type_i =
            ia_css_program_manifest_get_type(program_manifest_i);
        ia_css_kernel_bitmap_t program_bitmap_i =
            ia_css_program_manifest_get_kernel_bitmap(
                program_manifest_i);
        uint8_t program_dependency_count_i =
            ia_css_program_manifest_get_program_dependency_count(
                program_manifest_i);
        uint8_t terminal_dependency_count_i =
            ia_css_program_manifest_get_terminal_dependency_count(
                program_manifest_i);
        uint8_t program_dependency_i0 =
            ia_css_program_manifest_get_program_dependency(
                program_manifest_i, 0);
        bool is_sub_i =
            ia_css_is_program_manifest_subnode_program_type(
                program_manifest_i);
        bool is_exclusive_sub_i =
            (program_type_i == IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUB);
        bool is_virtual_sub_i =
            (program_type_i == IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB);
        bool is_super_i =
            ia_css_is_program_manifest_supernode_program_type(
                program_manifest_i);

        /*
         * A program must have kernels that
         * are a subset of the total
         */
        verifexit(!ia_css_is_kernel_bitmap_empty(
                program_bitmap_i));
        verifexit(ia_css_is_kernel_bitmap_subset(
                total_bitmap, program_bitmap_i));
        verifexit((program_type_i != IA_CSS_N_PROGRAM_TYPES));
        verifexit((program_dependency_count_i + terminal_dependency_count_i) != 0);
        /*
         * Checks for subnodes
         * - Parallel subnodes cannot depend on terminals
         * - Exclusive subnodes must depend on
         *   fewer terminals than the supernode
         * - Subnodes only depend on a supernode of the same type
         * - Must have a subset of the supernode's kernels
         *   (but not equal)
         * - This tests only positive cases
         * Checks for singular or supernodes
         * - Cannot depend on exclusive subnodes
         * - No intersection between kernels
         *   (too strict for multiple instances ?)
         */
        if (is_sub_i) {
            /* Subnode */
            ia_css_program_manifest_t *program_manifest_k =
            ia_css_program_group_manifest_get_prgrm_mnfst(
                manifest, program_dependency_i0);
            ia_css_program_type_t program_type_k =
                ia_css_program_manifest_get_type(
                    program_manifest_k);
            ia_css_kernel_bitmap_t program_bitmap_k =
                ia_css_program_manifest_get_kernel_bitmap(
                    program_manifest_k);

            verifexit(program_dependency_count_i == 1);
            if (is_exclusive_sub_i || is_virtual_sub_i) {
                verifexit(terminal_dependency_count_i <=
                    ia_css_program_manifest_get_terminal_dependency_count(
                        program_manifest_k));
            } else{
                verifexit(terminal_dependency_count_i == 0);
            }
            verifexit(program_type_k ==
                (is_exclusive_sub_i ?
                    IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUPER :
                is_virtual_sub_i ?
                    IA_CSS_PROGRAM_TYPE_VIRTUAL_SUPER :
                    IA_CSS_PROGRAM_TYPE_PARALLEL_SUPER));
            verifexit(!ia_css_is_kernel_bitmap_equal(
                    program_bitmap_k, program_bitmap_i));
            verifexit(ia_css_is_kernel_bitmap_subset(
                    program_bitmap_k, program_bitmap_i));
        } else {
            /* Singular or Supernode */
            int k;
            ia_css_kernel_bitmap_t program_bitmap_k;

            for (k = 0; k < program_dependency_count_i; k++) {
                uint8_t program_dependency_k =
                ia_css_program_manifest_get_program_dependency(
                    program_manifest_i, k);
                ia_css_program_manifest_t *program_manifest_k =
                ia_css_program_group_manifest_get_prgrm_mnfst(
                manifest, (int)program_dependency_k);
                ia_css_program_type_t program_type_k =
                ia_css_program_manifest_get_type(
                    program_manifest_k);
                program_bitmap_k =
                ia_css_program_manifest_get_kernel_bitmap(
                    program_manifest_k);

                verifexit(program_dependency_k <
                    program_count);
                verifexit((program_type_k !=
                    IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUB) &&
                    (program_type_k !=
                    IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB));
                verifexit(USE_SIMPLIFIED_GRAPH_MODEL ||
                ia_css_is_kernel_bitmap_intersection_empty(
                    program_bitmap_i, program_bitmap_k));
            }
        }

        /* Check for relations */
        for (j = 0; j < (int)program_count; j++) {
            int k;
            ia_css_program_manifest_t *program_manifest_j =
            ia_css_program_group_manifest_get_prgrm_mnfst(
                manifest, j);
            ia_css_program_type_t program_type_j =
            ia_css_program_manifest_get_type(program_manifest_j);
            ia_css_kernel_bitmap_t program_bitmap_j =
            ia_css_program_manifest_get_kernel_bitmap(
                program_manifest_j);
            uint8_t program_dependency_count_j =
            ia_css_program_manifest_get_program_dependency_count(
                program_manifest_j);
            uint8_t program_dependency_j0 =
            ia_css_program_manifest_get_program_dependency(
                program_manifest_j, 0);
            bool is_sub_j =
            ia_css_is_program_manifest_subnode_program_type(
                program_manifest_j);
            bool is_super_j =
            ia_css_is_program_manifest_supernode_program_type(
                program_manifest_j);
            bool is_virtual_sub_j =
            (program_type_j == IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB);
            bool is_j_subset_i =
            ia_css_is_kernel_bitmap_subset(
                program_bitmap_i, program_bitmap_j);
            bool is_i_subset_j =
            ia_css_is_kernel_bitmap_subset(
                program_bitmap_j, program_bitmap_i);

            /* Test below would fail for i==j */
            if (i == j)
                continue;

            /* Empty sets are always subsets, but meaningless */
            verifexit(!ia_css_is_kernel_bitmap_empty(
                    program_bitmap_j));

            /*
             * Checks for mutual subnodes
             * - Parallel subnodes must have an equal
             *   set of kernels
             * - Exclusive and virtual subnodes must
             *   have an unequal set of kernels
             * Checks for subnodes
             * - Subnodes must have a subset of kernels
             */
            if (((program_type_i ==
                IA_CSS_PROGRAM_TYPE_PARALLEL_SUB) &&
                (program_type_j ==
                IA_CSS_PROGRAM_TYPE_PARALLEL_SUB)) ||
                ((program_type_i ==
                IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUB) &&
                (program_type_j ==
                IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUB)) ||
                ((program_type_i ==
                IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB) &&
                (program_type_j ==
                IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB))) {

                verifexit(program_dependency_count_j == 1);
                verifexit(program_dependency_i0 != i);
                verifexit(program_dependency_j0 != i);

                if (program_dependency_i0 ==
                    program_dependency_j0) {
                    verifexit(is_sub_i);
                    /*
                     * Subnodes are subsets,
                     * not for virtual nodes
                     */
                    if (!is_virtual_sub_i)
                        verifexit(
                            ((is_j_subset_i ||
                            is_i_subset_j)));
                    /*
                     * That must be equal for
                     * parallel subnodes,
                     * must be unequal for
                     * exclusive and virtual subnodes
                     */
                    verifexit(
                    ((is_j_subset_i && is_i_subset_j) ^
                    (is_exclusive_sub_i |
                    is_virtual_sub_i)));

                }
                if (is_j_subset_i || is_i_subset_j) {
                    /* One being subset of the other does not necessarily mean that they are part
                     * of the same "cluster" (i.e. having same super dependency).
                     */
                    /* verifexit(program_dependency_i0 ==
                     *    program_dependency_j0);
                     */
                }
                /* If subnodes are the same, they need different program dependency. */
                if (ia_css_is_kernel_bitmap_equal(program_bitmap_i, program_bitmap_j)) {
                    verifexit(program_dependency_i0 != program_dependency_j0);
                }
            }

            if (((program_type_i ==
                IA_CSS_PROGRAM_TYPE_PARALLEL_SUPER) &&
                (program_type_j ==
                IA_CSS_PROGRAM_TYPE_PARALLEL_SUB)) ||
                ((program_type_i ==
                IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUPER) &&
                (program_type_j ==
                IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUB)) ||
                ((program_type_i ==
                IA_CSS_PROGRAM_TYPE_VIRTUAL_SUPER) &&
                (program_type_j ==
                IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB))) {

                verifexit(program_dependency_count_j == 1);
                verifexit(!is_i_subset_j);

                if (program_dependency_j0 == i) {
                    verifexit(program_dependency_i0 !=
                        program_dependency_j0);
                    verifexit(is_super_i);
                    verifexit(is_j_subset_i);

                }
                if (is_j_subset_i) {
                    /* verifexit(program_dependency_j0 == i); */
                    /* A sub that is subset of a super, is not necessarily dependent to it. */
                }
            }

            /*
             * Checks for dependent nodes
             * - Cannot depend on exclusive subnodes
             * - No intersection between kernels
             *   (too strict for multiple instances ?)
             *   unless a subnode
             */
            for (k = 0; k < (int)program_dependency_count_j; k++) {
                uint8_t program_dependency_k =
                ia_css_program_manifest_get_program_dependency(
                    program_manifest_j, k);

                verifexit((program_dependency_k <
                    program_count));
                if (program_dependency_k == i) {
                    /* program[j] depends on program[i] */
                    verifexit((i != j));
                    verifexit((program_type_i !=
                    IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUB) &&
                    (program_type_i !=
                    IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB));
                    verifexit(USE_SIMPLIFIED_GRAPH_MODEL ||
                (ia_css_is_kernel_bitmap_intersection_empty(
                program_bitmap_i, program_bitmap_j) ^ is_sub_j));
                }
            }

            /*
             * Checks for supernodes and subnodes
             * - Detect nodes that kernel-wise are subsets,
             *   but not connected to the correct supernode
             * - We do not (yet) detect if programs properly
             *   depend on all parallel nodes
             */
            if (!ia_css_is_kernel_bitmap_intersection_empty(
                program_bitmap_i, program_bitmap_j)) {
                /*
                 * This test will pass if
                 * the program manifest is NULL,
                 * but that's no concern here
                 */
                verifexit(USE_SIMPLIFIED_GRAPH_MODEL ||
            !ia_css_is_program_manifest_singular_program_type(
                program_manifest_i));
                verifexit(USE_SIMPLIFIED_GRAPH_MODEL ||
            !ia_css_is_program_manifest_singular_program_type(
                program_manifest_j));
                if (!is_virtual_sub_j)
                    verifexit(USE_SIMPLIFIED_GRAPH_MODEL ||
                    (is_j_subset_i || is_i_subset_j));
                if (is_super_i) {
                    /* verifexit(is_sub_j); */
                    /* verifexit(program_dependency_j0 == i); */
                }
                if (is_super_j) {
                    /* verifexit(is_sub_i); */
                    /* verifexit(program_dependency_i0 == j); */
                }
                if (is_super_i && is_super_j) {
                    /* Allow two supernodes to intersect as long as they are different */
                    verifexit(!ia_css_is_kernel_bitmap_equal(program_bitmap_i, program_bitmap_j));
                }
                /* A bitmap intersect does not necessarily need to mean super and sub. */
                /* A sub that intersects with a super, is not necessarily dependent to it. */
            }
        }
        check_bitmap = ia_css_kernel_bitmap_union(
                    check_bitmap, program_bitmap_i);
        /*
         * A terminal can be bound to only a single
         * (of multiple concurrent) program(s),
         * i.e. the one that holds the iterator to control it
         * Only singular and super nodes can depend on a terminal.
         * This loop accumulates all terminal
         * dependencies over all programs
         */
        for (j = 0; j < (int)terminal_dependency_count_i; j++) {
            uint8_t terminal_dependency =
            ia_css_program_manifest_get_terminal_dependency(
                    program_manifest_i, j);

            verifexit(terminal_dependency < terminal_count);
            if ((program_type_i !=
                IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUB) &&
                (program_type_i !=
                IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB)) {
                /* If the subnode always came after the */
                /* supernode we could check for presence */
                resource_bitmap =
                    vied_nci_bit_mask_set_unique(
                        resource_bitmap,
                        terminal_dependency);
                verifexit(USE_SIMPLIFIED_GRAPH_MODEL ||
                    !vied_nci_is_bitmap_empty(
                        resource_bitmap));
            }
        }
    }
    verifexit(ia_css_is_kernel_bitmap_equal(
            total_bitmap, check_bitmap));

    terminal_bitmap_weight =
        vied_nci_bitmap_compute_weight(resource_bitmap);
    verifexit(terminal_bitmap_weight >= 0);
    if (num_parameter_terminal_in ||
        num_parameter_terminal_out ||
        num_program_terminal ||
        has_program_control_init_terminal) {
        int skip_terminal_count = 0;

        skip_terminal_count += num_parameter_terminal_in;
        skip_terminal_count += num_parameter_terminal_out;
        skip_terminal_count += num_program_terminal;
        skip_terminal_count -= num_program_terminal_sequencer_info;
        if (has_program_control_init_terminal) {
            skip_terminal_count++;
        }
        verifexit(USE_SIMPLIFIED_GRAPH_MODEL ||
            (terminal_bitmap_weight ==
            (terminal_count - skip_terminal_count)));
    } else
        verifexit((terminal_bitmap_weight == terminal_count));

    is_valid = true;
EXIT:
    if (is_valid == false) {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, ERROR,
            "ia_css_is_program_group_manifest_valid: failed\n");
    }
    return is_valid;
}

#if !defined(__HIVECC)
int ia_css_program_group_manifest_set_kernel_bitmap(
    ia_css_program_group_manifest_t *manifest,
    const ia_css_kernel_bitmap_t bitmap)
{
    int retval = -1;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_group_manifest_set_kernel_bitmap(): enter:\n");

    if (manifest != NULL) {
        manifest->kernel_bitmap = bitmap;
        retval = 0;
    } else {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
            "ia_css_program_group_manifest_set_kernel_bitmap invalid argument\n");
    }
    return retval;
}
#endif

ia_css_kernel_bitmap_t ia_css_program_group_manifest_get_kernel_bitmap(
    const ia_css_program_group_manifest_t *manifest)
{
    ia_css_kernel_bitmap_t bitmap = ia_css_kernel_bitmap_clear();

    IA_CSS_TRACE_0(PSYSAPI_STATIC, VERBOSE,
        "ia_css_program_group_manifest_get_kernel_bitmap(): enter:\n");

    if (manifest != NULL) {
        bitmap = manifest->kernel_bitmap;
    } else {
        IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
            "ia_css_program_group_manifest_get_kernel_bitmap invalid argument\n");
    }
    return bitmap;
}

#if !defined(__HIVECC)
void ia_css_program_group_manifest_init(
    ia_css_program_group_manifest_t *blob,
    const uint8_t program_count,
    const uint8_t terminal_count,
    const uint8_t *program_needs_extension,
    const uint8_t *program_dependencies,
    const uint8_t *terminal_dependencies,
    const ia_css_terminal_type_t *terminal_type,
    const uint16_t *cached_in_param_section_count,
    const uint16_t *cached_out_param_section_count,
    const uint16_t *spatial_param_section_count,
    const uint16_t *fragment_param_section_count,
    const uint16_t *sliced_in_param_section_count,
    const uint16_t *sliced_out_param_section_count,
    const uint16_t *kernel_fragment_seq_count,
    const uint16_t *progctrlinit_load_section_counts,
    const uint16_t *progctrlinit_connect_section_counts)
{
    int i = 0;
    int j = 0;
    int k = 0;
    int l = 0;
    int m = 0;
    int n = 0;
    int o = 0;
    int result;
    uint32_t offset = 0;
    char *prg_manifest_base, *terminal_manifest_base;
    size_t program_size = 0;

    /*
     * assert(blob != NULL);
     */
    COMPILATION_ERROR_IF(
        SIZE_OF_DATA_TERMINAL_MANIFEST_STRUCT_IN_BITS !=
            (CHAR_BIT * sizeof(ia_css_data_terminal_manifest_t)));
    COMPILATION_ERROR_IF(
        SIZE_OF_PROGRAM_GROUP_MANIFEST_STRUCT_IN_BITS !=
            (CHAR_BIT * sizeof(ia_css_program_group_manifest_t)));
    COMPILATION_ERROR_IF(
        SIZE_OF_PROGRAM_MANIFEST_STRUCT_IN_BITS !=
            (CHAR_BIT * sizeof(ia_css_program_manifest_t)));
    COMPILATION_ERROR_IF(
        SIZE_OF_PROGRAM_MANIFEST_EXT_STRUCT_IN_BYTES !=
            (CHAR_BIT * sizeof(ia_css_program_manifest_ext_t)));

    COMPILATION_ERROR_IF(0 != sizeof(ia_css_program_manifest_t)%sizeof(uint32_t));
    COMPILATION_ERROR_IF(0 != sizeof(ia_css_program_manifest_ext_t)%sizeof(uint32_t));

    IA_CSS_TRACE_0(PSYSAPI_STATIC, INFO,
        "ia_css_program_group_manifest_init(): enter:\n");

    for (i = 0; i < (int)program_count; i++) {
        program_size +=
            ia_css_sizeof_program_manifest(
                program_needs_extension[i],
                program_dependencies[i],
                terminal_dependencies[i]);
    }

    /* A program group ID cannot be zero */
    blob->ID = 1;
    blob->program_count = program_count;
    blob->terminal_count = terminal_count;
    blob->program_manifest_offset = sizeof(ia_css_program_group_manifest_t);
    blob->terminal_manifest_offset =
        (uint32_t)blob->program_manifest_offset + program_size;

    prg_manifest_base = (char *)
        (((char *)blob) + blob->program_manifest_offset);
    offset = blob->program_manifest_offset;
    for (i = 0; i < (int)program_count; i++) {
        ia_css_program_manifest_init(
            (ia_css_program_manifest_t *)prg_manifest_base,
            program_needs_extension[i],
            program_dependencies[i], terminal_dependencies[i]);
        ia_css_program_manifest_set_parent_offset(
            (ia_css_program_manifest_t *)prg_manifest_base, offset);
        program_size =
            ia_css_sizeof_program_manifest(
                program_needs_extension[i],
                program_dependencies[i],
                terminal_dependencies[i]);
        prg_manifest_base += program_size;
        offset += (uint32_t)program_size;
    }

    offset = blob->terminal_manifest_offset;
    terminal_manifest_base = (char *) (((char *)blob) + offset);
    for (i = 0; i < (int)terminal_count; i++) {
        size_t terminal_size = 0;
        ia_css_terminal_manifest_t *term_manifest =
            (ia_css_terminal_manifest_t *)terminal_manifest_base;

        ia_css_terminal_manifest_set_parent_offset(
                (ia_css_terminal_manifest_t *)
                terminal_manifest_base,
                offset);
        switch (terminal_type[i]) {
        case IA_CSS_TERMINAL_TYPE_PARAM_CACHED_IN:
            result = ia_css_param_terminal_manifest_init(
                (ia_css_param_terminal_manifest_t *)
                term_manifest,
                cached_in_param_section_count[j]);
            if (0 == result) {
                terminal_size =
                ia_css_param_terminal_manifest_get_size(
                    cached_in_param_section_count[j]);
                j++;
            } else {
                IA_CSS_TRACE_0(PSYSAPI_STATIC, ERROR,
                    "ia_css_param_terminal_manifest_init failed in cached in terminal\n");
            }
            break;
        case IA_CSS_TERMINAL_TYPE_PARAM_CACHED_OUT:
            result = ia_css_param_terminal_manifest_init(
                (ia_css_param_terminal_manifest_t *)
                term_manifest,
                cached_out_param_section_count[k]);
            if (0 == result) {
                terminal_size =
                ia_css_param_terminal_manifest_get_size(
                    cached_out_param_section_count[k]);
                k++;
            } else {
                IA_CSS_TRACE_0(PSYSAPI_STATIC, ERROR,
                    "ia_css_param_terminal_manifest_init failed\n");
            }
            break;
        case IA_CSS_TERMINAL_TYPE_PARAM_SPATIAL_IN:
        case IA_CSS_TERMINAL_TYPE_PARAM_SPATIAL_OUT:
            result = ia_css_spatial_param_terminal_manifest_init(
                (ia_css_spatial_param_terminal_manifest_t *)
                term_manifest,
                spatial_param_section_count[l]);
            if (0 == result) {
                terminal_size =
            ia_css_spatial_param_terminal_manifest_get_size(
                spatial_param_section_count[l]);
                l++;
            } else {
                IA_CSS_TRACE_0(PSYSAPI_STATIC, ERROR,
                    "ia_css_spatial_param_terminal_manifest_init failed in spatial terminal\n");
            }
            break;
        case IA_CSS_TERMINAL_TYPE_PROGRAM:
            result = ia_css_program_terminal_manifest_init(
                (ia_css_program_terminal_manifest_t *)
                term_manifest,
                fragment_param_section_count[m],
                kernel_fragment_seq_count[m]);
            if (0 == result) {
                terminal_size =
                ia_css_program_terminal_manifest_get_size(
                    fragment_param_section_count[m],
                    kernel_fragment_seq_count[m]);
                m++;
            } else {
                IA_CSS_TRACE_0(PSYSAPI_STATIC, ERROR,
                    "ia_css_program_terminal_manifest_init failed in program terminal\n");
            }
            break;
        case IA_CSS_TERMINAL_TYPE_PROGRAM_CONTROL_INIT:
            result = ia_css_program_control_init_terminal_manifest_init(
                (ia_css_program_control_init_terminal_manifest_t *)
                term_manifest,
                program_count,
                progctrlinit_load_section_counts,
                progctrlinit_connect_section_counts);
            if (0 == result) {
                terminal_size =
                ia_css_program_control_init_terminal_manifest_get_size(
                    program_count,
                    NULL,
                    NULL);
            } else {
                IA_CSS_TRACE_0(PSYSAPI_STATIC, ERROR,
                    "ia_css_program_control_init_terminal_manifest_init failed\n");
            }
            break;
        case IA_CSS_TERMINAL_TYPE_DATA_IN:
        case IA_CSS_TERMINAL_TYPE_DATA_OUT:
            terminal_size = sizeof(ia_css_data_terminal_manifest_t);
            break;
        case IA_CSS_TERMINAL_TYPE_PARAM_SLICED_IN:
            result = ia_css_sliced_param_terminal_manifest_init(
                (ia_css_sliced_param_terminal_manifest_t *)
                term_manifest,
                sliced_in_param_section_count[n]);
            if (0 == result) {
                terminal_size =
            ia_css_sliced_param_terminal_manifest_get_size(
                sliced_in_param_section_count[n]);
                n++;
            } else {
                IA_CSS_TRACE_0(PSYSAPI_STATIC, ERROR,
                    "ia_css_param_terminal_manifest_init in sliced terminal failed\n");
            }
            break;
        case IA_CSS_TERMINAL_TYPE_PARAM_SLICED_OUT:
            result = ia_css_sliced_param_terminal_manifest_init(
                (ia_css_sliced_param_terminal_manifest_t *)
                term_manifest,
                sliced_out_param_section_count[o]);
            if (0 == result) {
                terminal_size =
                ia_css_sliced_param_terminal_manifest_get_size(
                    sliced_out_param_section_count[o]);
                n++;
            } else {
                IA_CSS_TRACE_0(PSYSAPI_STATIC, ERROR,
                    "ia_css_param_terminal_manifest_init in sliced out terminal failed\n");
            }
            break;
        default:
            IA_CSS_TRACE_0(PSYSAPI_STATIC, WARNING,
                "ia_css_program_group_manifest_init invalid argument\n");
        }
        term_manifest->size = (uint16_t)terminal_size;
        /* index: i equal to terminal ID due to sorted of the terminals array */
        term_manifest->ID = i;
        term_manifest->terminal_type = terminal_type[i];
        terminal_manifest_base += terminal_size;
        offset += (uint32_t)terminal_size;
    }

    /* Set the private program group manifest blob offset */
    blob->private_data_offset = offset;
    offset += ceil_mul(sizeof(struct ia_css_psys_private_pg_data),
                sizeof(uint64_t));

    /* Set the RBM manifest blob offset */
    blob->rbm_manifest_offset = offset;
    offset += ceil_mul(sizeof(ia_css_rbm_manifest_t),
                sizeof(uint64_t));

    assert(offset <= UINT16_MAX);
    blob->size = (uint16_t)offset;
}
#endif

int ia_css_program_group_manifest_print(
    const ia_css_program_group_manifest_t *manifest,
    void *fid)
{
    int retval = -1;
    int i;
    uint8_t program_count, terminal_count;
    ia_css_kernel_bitmap_t bitmap;
    struct ia_css_psys_private_pg_data *priv_data;
    ia_css_rbm_manifest_t *rbm_manifest;

    IA_CSS_TRACE_0(PSYSAPI_STATIC, INFO,
        "ia_css_program_group_manifest_print(): enter:\n");

    NOT_USED(fid);

    verifexit(manifest != NULL);

    IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO,
        "sizeof(manifest) = %d\n",
        (int)ia_css_program_group_manifest_get_size(manifest));
    IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO,
        "alignment(manifest) = %d\n",
        (int)ia_css_program_group_manifest_get_alignment(manifest));

    IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO,
        "program group ID = %d\n",
        (int)ia_css_program_group_manifest_get_program_group_ID(
            manifest));

    program_count =
        ia_css_program_group_manifest_get_program_count(manifest);
    terminal_count =
        ia_css_program_group_manifest_get_terminal_count(manifest);

    bitmap = ia_css_program_group_manifest_get_kernel_bitmap(manifest);
    verifexit(ia_css_kernel_bitmap_print(bitmap, fid) == 0);

    IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO,
        "%d program manifests\n", (int)program_count);
    for (i = 0; i < (int)program_count; i++) {
        ia_css_program_manifest_t *program_manifest =
            ia_css_program_group_manifest_get_prgrm_mnfst(
                manifest, i);

        retval = ia_css_program_manifest_print(program_manifest, fid);
        verifjmpexit(retval == 0);
    }
    IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO,
        "%d terminal manifests\n", (int)terminal_count);
    for (i = 0; i < (int)terminal_count; i++) {
        ia_css_terminal_manifest_t *terminal_manifest =
            ia_css_program_group_manifest_get_term_mnfst(
                manifest, i);

        retval = ia_css_terminal_manifest_print(
                terminal_manifest, fid);
        verifjmpexit(retval == 0);
    }

    priv_data =
        (struct ia_css_psys_private_pg_data *)
        ia_css_program_group_manifest_get_private_data(manifest);
    IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO,
        "private_data_offset %d\n", manifest->private_data_offset);

    for (i = 0; i < IPU_DEVICE_GP_PSA_MUX_NUM_MUX; i++) {
        IA_CSS_TRACE_2(PSYSAPI_STATIC, INFO,
            "PSA MUX id %d mux val %d\n", i,
            priv_data->psa_mux_conf[i]);

    }

    for (i = 0; i < IPU_DEVICE_GP_ISA_STATIC_MUX_NUM_MUX; i++) {
        IA_CSS_TRACE_2(PSYSAPI_STATIC, INFO,
            "ISA MUX id %d mux val %d\n", i,
            priv_data->isa_mux_conf[i]);

    }

#ifndef IPU7_ERROR_MISSING_DISABLE_SECTION
    for (i = 0; i < IPU_DEVICE_ACB_NUM_ACB; i++) {

        if (priv_data->acb_route[i].in_select !=
            NCI_ACB_PORT_INVALID) {

            assert(priv_data->acb_route[i].in_select !=
                NCI_ACB_PORT_INVALID &&
                priv_data->acb_route[i].out_select !=
                NCI_ACB_PORT_INVALID);

            IA_CSS_TRACE_3(PSYSAPI_STATIC, INFO,
                "Route Cell id %d In %d Out %d\n", i,
                priv_data->acb_route[i].in_select,
                priv_data->acb_route[i].out_select);
        }

    }
#endif /* IPU7_ERROR_MISSING_DISABLE_SECTION */

    for (i = 0; i < MAX_INPUT_BUFFER; i++) {
        IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO, "Input Buffer: link_id = %d\n",
                priv_data->input_buffer_info[i].link_id);
        IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO, "Input Buffer: buffer_base_addr 0x%x\n",
                priv_data->input_buffer_info[i].buffer_base_addr);
        IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO, "Input Buffer: bpe = %d\n",
                priv_data->input_buffer_info[i].bpe);
        IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO, "Input Buffer: buffer_width = %d\n",
                priv_data->input_buffer_info[i].buffer_width);
        IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO, "Input Buffer: buffer_height = %d\n",
                priv_data->input_buffer_info[i].buffer_height);
        IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO, "Input Buffer: num_of_buffers = %d\n",
                priv_data->input_buffer_info[i].num_of_buffers);
        IA_CSS_TRACE_1(PSYSAPI_STATIC, INFO, "Input Buffer: dfm_port_addr = 0x%x\n",
                priv_data->input_buffer_info[i].dfm_port_addr);
        IA_CSS_TRACE_0(PSYSAPI_STATIC, INFO, "======== Input Buffer: end ===========\n");
    }

    rbm_manifest = ia_css_program_group_manifest_get_rbm_manifest((ia_css_program_group_manifest_t *)manifest);
    ia_css_rbm_manifest_print(rbm_manifest);

    retval = 0;
EXIT:
    if (retval != 0) {
        IA_CSS_TRACE_1(PSYSAPI_STATIC, ERROR,
            "ia_css_program_group_manifest_print failed (%i)\n",
            retval);
    }
    return retval;
}
#endif /* !defined(__HIVECC) */
