/******************************************************************************/
/* Component Name   ICU-M COMM(PE) Driver                                     */
/******************************************************************************/
/* Product      : ICU-M Firmware                                              */
/******************************************************************************/
/*******************************************************************************
* Copyright(C) 2021-2023 Renesas Electronics Corporation.                       
*                                                                               
*          RENESAS ELECTRONICS CONFIDENTIAL AND PROPRIETARY                     
*                                                                               
* These instructions, statements, and programs are the confidential information 
* of Renesas Electronics Corporation. They must be used and modified solely for 
* the purpose for which it was furnished by Renesas Electronics Corporation.    
* All part of them must not be reproduced nor disclosed to others in any form,  
* without the prior written permission of Renesas Electronics Corporation.      
*******************************************************************************/

/**************************************************************************************/
/* Header files                                                                       */
/**************************************************************************************/
#include "r_icumif_api.h"
#include "r_icumif_pub.h"
#include "user_icumif_api_pub.h"
#include "icum_d_comm_pe_pub.h"
#include "icum_d_comm_pe.h"

/**************************************************************************************/
/* Local variables                                                                    */
/**************************************************************************************/
/* Initialization state information */
static uint32_t icumif_initialized[TOTAL_PE_NUM] = {0U};

static ICUM_COMM_PE_INFO_t pe_info[TOTAL_PE_NUM] =
{
    { &ICUM_CMDREGICUM_ICU2PES0, &ICUM_CMDREGICUM_PE2ICUFS0, &ICUM_CMDREGICUM_PE2ICUIE0,   /* PE0:Cortex R Core0 */
      &ICUM_CMDREGICUM_ICU2PEF0, &ICUM_CMDREGICUM_ICU2PEFC0, &ICUM_CMDREGICUM_ICU2PEIE0, &ICUM_CMDREGICUM_ICU2PEIS0,
      &ICUM_CMDREGICUM_SEMAPE04, &ICUM_CMDREGICUM_SEMAPE0E, INTICUP_PESEL_TO_PE0, PE_SECURE_MODE_PE0 }
   ,{ &ICUM_CMDREGICUM_ICU2PES0, &ICUM_CMDREGICUM_PE2ICUFS5,  &ICUM_CMDREGICUM_PE2ICUIE5,   /* PE1:Cortex-R Core1 */
      &ICUM_CMDREGICUM_ICU2PEF5, &ICUM_CMDREGICUM_ICU2PEFC5, &ICUM_CMDREGICUM_ICU2PEIE5, &ICUM_CMDREGICUM_ICU2PEIS5,
      &ICUM_CMDREGICUM_SEMAPE05, &ICUM_CMDREGICUM_SEMAPE0F, INTICUP_PESEL_TO_PE5, PE_SECURE_MODE_PE5 }
   ,{ &ICUM_CMDREGICUM_ICU2PES0, &ICUM_CMDREGICUM_PE2ICUFS6, &ICUM_CMDREGICUM_PE2ICUIE6,   /* PE2:Cortex-R Core2 */
      &ICUM_CMDREGICUM_ICU2PEF6, &ICUM_CMDREGICUM_ICU2PEFC6, &ICUM_CMDREGICUM_ICU2PEIE6, &ICUM_CMDREGICUM_ICU2PEIS6,
      &ICUM_CMDREGICUM_SEMAPE06, &ICUM_CMDREGICUM_SEMAPE10, INTICUP_PESEL_TO_PE6, PE_SECURE_MODE_PE6 }
   ,{ &ICUM_CMDREGICUM_ICU2PES0, &ICUM_CMDREGICUM_PE2ICUFS1, &ICUM_CMDREGICUM_PE2ICUIE1,   /* PE3:Cortex-A Core0 */
      &ICUM_CMDREGICUM_ICU2PEF1, &ICUM_CMDREGICUM_ICU2PEFC1, &ICUM_CMDREGICUM_ICU2PEIE1, &ICUM_CMDREGICUM_ICU2PEIS1,
      &ICUM_CMDREGICUM_SEMAPE00, &ICUM_CMDREGICUM_SEMAPE0A, INTICUP_PESEL_TO_PE1, PE_SECURE_MODE_PE1 }
   ,{ &ICUM_CMDREGICUM_ICU2PES0, &ICUM_CMDREGICUM_PE2ICUFS2, &ICUM_CMDREGICUM_PE2ICUIE2,   /* PE4:Cortex-A Core1 */
      &ICUM_CMDREGICUM_ICU2PEF2, &ICUM_CMDREGICUM_ICU2PEFC2, &ICUM_CMDREGICUM_ICU2PEIE2, &ICUM_CMDREGICUM_ICU2PEIS2,
      &ICUM_CMDREGICUM_SEMAPE01, &ICUM_CMDREGICUM_SEMAPE0B, INTICUP_PESEL_TO_PE2, PE_SECURE_MODE_PE2 }
   ,{ &ICUM_CMDREGICUM_ICU2PES0, &ICUM_CMDREGICUM_PE2ICUFS3, &ICUM_CMDREGICUM_PE2ICUIE3,   /* PE5:Cortex-A Core2 */
      &ICUM_CMDREGICUM_ICU2PEF3, &ICUM_CMDREGICUM_ICU2PEFC3, &ICUM_CMDREGICUM_ICU2PEIE3, &ICUM_CMDREGICUM_ICU2PEIS3,
      &ICUM_CMDREGICUM_SEMAPE02, &ICUM_CMDREGICUM_SEMAPE0C, INTICUP_PESEL_TO_PE3, PE_SECURE_MODE_PE3 }
   ,{ &ICUM_CMDREGICUM_ICU2PES0, &ICUM_CMDREGICUM_PE2ICUFS4, &ICUM_CMDREGICUM_PE2ICUIE4,   /* PE6:Cortex-A Core3 */
      &ICUM_CMDREGICUM_ICU2PEF4, &ICUM_CMDREGICUM_ICU2PEFC4, &ICUM_CMDREGICUM_ICU2PEIE4, &ICUM_CMDREGICUM_ICU2PEIS4,
      &ICUM_CMDREGICUM_SEMAPE03, &ICUM_CMDREGICUM_SEMAPE0D, INTICUP_PESEL_TO_PE4, PE_SECURE_MODE_PE4 }
};
/* Callback registration at interrupt occurrence */
static R_ICUMIF_CB_REGIST_t cb_regist_info[TOTAL_PE_NUM] = { {NULL} };

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0003]:[ICUMFW_UD_S4_D_COMM_PE_0003]
* Function name: d_COMM_Enqueue_Request
* Description  : Enqueue specified ISD to service request queue
* Arguments    : r_icumif_isd_t *p_isd : Address value of ISD to be passed to ICUP
*              : uint8_t *p_req_index  : Index of the request queue entry
* Return Value : uint32_t Enqueue processing result
*                   ER_OK              : Successful
*                   ER_D_COMM_QUE_FULL : Service request queue FULL
***************************************************************************************/
static uint32_t d_COMM_Enqueue_Request(r_icumif_isd_t *p_isd, uint8_t *p_req_index)
{
    uint32_t            ret_val = ER_OK;
    volatile uint32_t   *p_reg;
    ptr_manip_t         queptr;
    uint32_t            *p_queptr;
    int32_t             next_idx;
    ptr_manip_t         isdptr;
    uintptr_t           saved_psw;
    uint32_t            my_peid;
    volatile uint32_t   lul_dummy;
    uint32_t            vm_chk_result;
    uint32_t            secure_bit;

    /* 1. Get the PEID */
    my_peid = USER_ICUMIF_GetMyPEID();

    /* 2. For interrupt control between PEs, */
    /* Interrupt disable check */
    USER_ICUMIF_GetLock(&saved_psw);

    /* 3. Lower 24 bits of ICUM_PE2ICUS register are acquire and upper 8 bits are */
    /*    complemented to generate top address of service request queue           */
    secure_bit = pe_info[my_peid].secure_mode_bit;

    if ((PEID_PE0 == my_peid) || (PE_SECURE_MODE_BITOFF != (MEM_INFO_ICUM_SECUREMOD & secure_bit)))
    {
        p_reg = (volatile uint32_t *)pe_info[my_peid].p_semape;
    }
    else
    {
        p_reg = (volatile uint32_t *)pe_info[my_peid].p_semape_ns;
    }

    queptr.val = (*p_reg & QUE_ADDR_LOWER_24BITS) | (QUE_ADDR_UPPER_8BITS_VALUE & MEM_INFO_SERVICEQUE_1_ADDR);
    p_queptr = (uint32_t *)queptr.p_ptr;

    /* Get the index of the next request queue entry */
    /* 4. Check entry after one of entry index of the service request queue */

    ret_val = ER_D_COMM_QUE_FULL;

    /* 5. Invalidate of cache area ( service response queue area ) */
    USER_ICUMIF_InvalidateDCache((uint32_t)(queptr.val + SERV_REQUEST_QUEUE_AREA_SIZE), SERV_RESPONSE_QUEUE_AREA_SIZE);
    
    for (next_idx = 0; next_idx < (int32_t)REQUEST_QUEUE_LENGTH; next_idx++)
    {
        if (0U == (*(p_queptr + next_idx)))
        {
            /* 4-2. */
            /* Regist ISD to service request queue */
            isdptr.p_vlt_ptr = (volatile void *)p_isd;
            *(p_queptr + next_idx) = (uint32_t)isdptr.val;

            /* Set service request / response queue transition state in */
            /* ISD indicated by parameter p_isd                         */
            p_isd->req_res_status = R_ICUMIF_REQRES_PE_REQ_ENQUE;
            /* Dummy Read */
            lul_dummy = p_isd->req_res_status;
            (void)lul_dummy;
            /* Synchronize */
            USER_ICUMIF_Sync();

            /* Check if the count of queue requests for each VM has reached the specified count */
            d_COMM_PE_VmRequestCountCheck(p_queptr, p_isd->vm_id, &vm_chk_result);
            
            /* prevent to become full the request queue. */
            if ((((int32_t)REQUEST_QUEUE_LENGTH - 1) == next_idx) || (VM_REQ_QUE_CNT_CHECK_REACHED == vm_chk_result))
            {
                p_isd->req_nointerrupt = R_ICUMIF_REQRES_INTERRPUT;
                /* Dummy Read */
                lul_dummy = p_isd->req_nointerrupt;
                (void)lul_dummy;
                /* Synchronize */
                USER_ICUMIF_Sync();
            }
            else
            {
                /* Do nothing */
            }

            /* Clean and invalidate of cache area                       */
            /* ( ISD common parameters and service request queue area ) */
            USER_ICUMIF_FlushDCache((uint32_t)isdptr.val, (uint32_t)(sizeof(r_icumif_isd_t) - sizeof(p_isd->prm)));
            USER_ICUMIF_FlushDCache((uint32_t)queptr.val, SERV_REQUEST_QUEUE_AREA_SIZE);

            *p_req_index = (uint8_t)next_idx;
            ret_val = ER_OK;
            break;
        }
        else
        {
            /* Do nothing */
        }
    }

    /* 5. Interrupt enable check */
    USER_ICUMIF_ReleaseLock(saved_psw);

    /* 6. Return the enqueue processing result */
    return (ret_val);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0004]:[ICUMFW_UD_S4_D_COMM_PE_0004]
* Function name: d_COMM_PE_GetSemaphore
* Description  : Get the Semaphore register
* Arguments    : (IN)icum_comm_target_pe_t target_pe
*                    uint8_t request
* Return Value : ER_OK
*                PE_SEMAPHORE_ER_SYSTEM
*                PE_SEMAPHORE_ER_TIMEOUT
***************************************************************************************/
static uint32_t d_COMM_PE_GetSemaphore(uint8_t target_pe, uint8_t request)
{
    register volatile uint32_t *p_reg;
    uint32_t uiAuth;
    uint32_t uiIcusem;
    uint32_t err;
    uint32_t uiCount;
    uint32_t secure_bit;

    /* Get the Semaphore register address */
    secure_bit = pe_info[target_pe].secure_mode_bit;

    if ((PEID_PE0 == (uint32_t)target_pe) || (PE_SECURE_MODE_BITOFF != (MEM_INFO_ICUM_SECUREMOD & secure_bit)))
    {
        p_reg = (volatile uint32_t *)pe_info[target_pe].p_semape;
    }
    else
    {
        p_reg = (volatile uint32_t *)pe_info[target_pe].p_semape_ns;
    }

    err = PE_SEMAPHORE_ER_TIMEOUT;
    uiCount = 0U;

    /* Wait for the Semaphore */
    do {
        /* Try to get the Semaphore as step1 */
        uiIcusem = *p_reg;
        uiAuth   = uiIcusem & PE_SEMAPHORE_AUTH_MASK;

        if (PE_SEMAPHORE_AUTH_GET1ST == uiAuth)
        {
            /* Try to get the Semaphore as step2 */
            uiIcusem = *p_reg;
            uiAuth   = (uiIcusem & PE_SEMAPHORE_AUTH_MASK);

            if (PE_SEMAPHORE_AUTH_GET2ND != uiAuth)
            {
                /* Error case. retry to get the Semaphore */
                /* Do nothing */
            }
            else
            {
                /* Got the Semaphore */
                err = ER_OK;
                break;
            }
        }
        else if (PE_SEMAPHORE_AUTH_GET2ND == uiAuth)
        {
            /* Got the Semaphore */
            err = ER_OK;
            break;
        }
        else
        {
            /* Do nothing */
        }

        uiCount++;
    } while (uiCount < PE_SEMAPHORE_WAIT);

    /* Set Request bit in the Semaphore register */
    if ((ER_OK == err) && (PE_SEMAPHORE_ON == (uint32_t)request))
    {
        *p_reg |= PE_SEMAPHORE_REQ;
    }
    else
    {
        /* Do nothing */
    }

    USER_ICUMIF_Sync();

    return err;
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0005]:[ICUMFW_UD_S4_D_COMM_PE_0005]
* Function name: d_COMM_PE_FreeSemaphore
* Description  : Free the Semaphore register
* Arguments    : (IN)icum_comm_target_pe_t target_pe
*                    uint8_t response
* Return Value : ER_OK
***************************************************************************************/
static uint32_t d_COMM_PE_FreeSemaphore(uint8_t target_pe, uint8_t response)
{
    register volatile uint32_t *p_reg;
    uint32_t uiAuth;
    uint32_t secure_bit;

    /* Get the Semaphore register address */
    secure_bit = pe_info[target_pe].secure_mode_bit;

    if ((PEID_PE0 == (uint32_t)target_pe) || (PE_SECURE_MODE_BITOFF != (MEM_INFO_ICUM_SECUREMOD & secure_bit)))
    {
        p_reg = (volatile uint32_t *)pe_info[target_pe].p_semape;
    }
    else
    {
        p_reg = (volatile uint32_t *)pe_info[target_pe].p_semape_ns;
    }

    uiAuth   = (*p_reg & PE_SEMAPHORE_AUTH_MASK);

    /* Check the Semaphore register status */
    if (PE_SEMAPHORE_AUTH_GET2ND == uiAuth)
    {
        if (PE_SEMAPHORE_ON == (uint32_t)response)
        {
            /* Clear Request bit in the Semaphore register */
            *p_reg &= ~PE_SEMAPHORE_RES;
        }
        else
        {
            /* Do nothing */
        }

        /* Free the Semaphore */
        *p_reg &= ~PE_SEMAPHORE_AUTH_MASK;
    }
    else
    {
        /* Do nothing */
    }

    USER_ICUMIF_Sync();

    return ER_OK;
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0020]:[ICUMFW_UD_S4_D_COMM_PE_0020]
* Function name: d_COMM_PE_VmRequestCountCheck
* Description  : Check the count of queues per VM.
* Arguments    : (IN) uint32_t *p_queptr
*                (IN) r_icumif_vm_id_t vm_id
*                (OUT)uint32_t *p_chk_result
* Return Value : N/A
***************************************************************************************/
static void d_COMM_PE_VmRequestCountCheck(uint32_t *p_queptr, r_icumif_vm_id_t vm_id, uint32_t *p_chk_result)
{
    uint32_t       vm_id_cnt;
    uint32_t       queue_idx;
    ptr_manip_t    isdptr;
    r_icumif_isd_t *p_isd;
    
    vm_id_cnt = 0U;
    queue_idx = 0U;
    *p_chk_result = VM_REQ_QUE_CNT_CHECK_OK;
    
    /* Search for the number of ISDs with the same VM ID */
    for (queue_idx = 0U; REQUEST_QUEUE_LENGTH > queue_idx ;queue_idx++)
    {
        if (0U != (*(p_queptr + queue_idx)))
        {
            isdptr.val = *(p_queptr + queue_idx);
            p_isd = (r_icumif_isd_t *)isdptr.p_ptr;
            
            /* Found the VM ID to be searched */
            if (p_isd->vm_id == vm_id)
            {
                vm_id_cnt++;
                
                if (VM_QUEUE_LENGTH <= vm_id_cnt)
                {
                    /* Count of ISDs with the same VM ID has reached the upper limit */
                    *p_chk_result = VM_REQ_QUE_CNT_CHECK_REACHED;
                    break;
                }
                else
                {
                    /* Do nothing */
                }
            }
            else
            {
                /* Do nothing */
            }
        }
        else
        {
            break;
        }
    }
    
    return;
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0001]:[ICUMFW_UD_S4_D_COMM_PE_0001]
* Function name: D_COMM_PE_Init
* Description  : Initialize the COMM(PE) driver
* Arguments    : uint32_t *p_request_queue : Pointer to service request queue
* Return Value : uint32_t Driver initialization result
*                   ER_OK                      : Successful
*                   ER_D_COMM_PARAM_NOT_G_RAM  : Parameter is not shared RAM area
*                   ER_D_COMM_QUE_ALREADY_INIT : Service queue already initialization
*                   ER_D_COMM_QUE_NOT_ACCESS   : Can not get the Semaphore
*                   ER_D_COMM_MEMCHK_NG        : Invalid memory info
***************************************************************************************/
uint32_t D_COMM_PE_Init(uint32_t *p_request_queue)
{
    uint32_t            ret_val = ER_OK;
    volatile uint32_t   *p_reg;
    uint32_t            count;
    uint32_t            bit_position;
    ptr_manip_t         wkptr;
    uint32_t            my_peid;
    uint32_t            semaphore;
    uintptr_t           saved_psw;
    uint32_t            secure_bit;

    /* 1. Memory information check ( Service queue size )    */
    /*    In the case of check NG, the process is terminated */
    if ((TOTAL_SERVICE_QUEUE_AREA_SIZE * TOTAL_PE_NUM) > MEM_INFO_SERVICEQUE_1_SIZE)
    {
        ret_val = ER_D_COMM_MEMCHK_NG;
    }
    else
    {
        my_peid = USER_ICUMIF_GetMyPEID();
        bit_position = PE_QUE_INIT;

        /* 2. For interrupt control between PEs,                  */
        /*    Interrupt disable initialization state information */
        USER_ICUMIF_GetLock(&saved_psw);

        /* 3. Check the "service queue initialization" state */
        /*    of the initialization state information        */
        if (INIT_UNPROCESSED == (0x00000001U & (icumif_initialized[my_peid] >> bit_position)))
        {
            /* 3-1. Get the Semaphore to clear err bit in the Semaphore register */
            semaphore = d_COMM_PE_GetSemaphore((uint8_t)my_peid, PE_SEMAPHORE_OFF);

            if(ER_OK == semaphore)
            {
                /* 3-1-1. Get top address of service queue area from memory information */
                wkptr.val = (uintptr_t)MEM_INFO_SERVICEQUE_1_ADDR;
                wkptr.val = wkptr.val + (my_peid * TOTAL_SERVICE_QUEUE_AREA_SIZE);
                p_request_queue = wkptr.p_uint32_ptr;
                *(wkptr.p_vlt_ptr) = VALUE_FOR_RAM_AREA_CHECK;
                if (VALUE_FOR_RAM_AREA_CHECK == *(wkptr.p_vlt_ptr))
                {
                    /* 3-1-1-1. */
                    /* Set lower 24 bits of p_request_queue      */
                    /* to lower 24 bits of ICUM_PE2ICUS register */
                    secure_bit = pe_info[my_peid].secure_mode_bit;

                    if ((PEID_PE0 == my_peid) || (PE_SECURE_MODE_BITOFF != (MEM_INFO_ICUM_SECUREMOD & secure_bit)))
                    {
                        p_reg = (volatile uint32_t *)pe_info[my_peid].p_semape;
                    }
                    else
                    {
                        p_reg = (volatile uint32_t *)pe_info[my_peid].p_semape_ns;
                    }

                    *p_reg = (*p_reg & ~QUE_ADDR_LOWER_24BITS) | 
                            ((uint32_t)((uintptr_t)((volatile void *)p_request_queue)) & QUE_ADDR_LOWER_24BITS);

                    /* Clear Error bit in the Semaphore register */
                    *p_reg &= ~PE_SEMAPHORE_ERR;

                    /* Clear queue area from address specified by p_request_queue */
                    for (count = 0U; count < TOTAL_QUEUE_LENGTH; count++)
                    {
                        p_request_queue[count] = 0U;
                    }

                    cb_regist_info[my_peid].p_func_addr = NULL;

                    /* Clean and invalidate of cache area ( service queue area ) */
                    USER_ICUMIF_FlushDCache((uint32_t)wkptr.val, TOTAL_SERVICE_QUEUE_AREA_SIZE);

                    /* The "service queue initialization" state is set to "processed" */
                    icumif_initialized[my_peid] |= (uint32_t)(INIT_PROCESSED << bit_position);
                    /* Synchronize Pipeline Macro */
                    USER_ICUMIF_Sync();
                }
                else
                {
                    ret_val = ER_D_COMM_PARAM_NOT_G_RAM;
                }

                /* Free the Semaphore */
                (void)d_COMM_PE_FreeSemaphore((uint8_t)my_peid, PE_SEMAPHORE_OFF);
            }
            else
            {
                ret_val = ER_D_COMM_QUE_NOT_ACCESS;
            }
        }
        else
        {
            /* 3-2. */
            ret_val = ER_D_COMM_QUE_ALREADY_INIT;
        }

        /* 4. Interrupt enable initialization state information */
        USER_ICUMIF_ReleaseLock(saved_psw);
    }

    /* 5. Return the driver initialization result */
    return (ret_val);
}


/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0002]:[ICUMFW_UD_S4_D_COMM_PE_0002]
* Function name: D_COMM_TriggerInterruptToICUP
* Description  : Issue an interrupt with channel number specified for ICUP
* Arguments    : icum_comm_int_to_channel_t channel : Bit pattern indicating ch number
*                r_icumif_isd_t             *p_isd  : Address value of ISD to ICUP
* Return Value : uint32_t Interrupt issue result
*                   ER_OK                  : Successful
*                   ER_PARAM               : Parameter error
*                   ER_D_COMM_QUE_NOT_INIT : Service queue initialization not yet
*                   ER_D_COMM_QUE_FULL     : Service request queue FULL
***************************************************************************************/
uint32_t D_COMM_TriggerInterruptToICUP(icum_comm_int_to_channel_t channel,
                                       r_icumif_isd_t *p_isd)
{
    uint32_t            ret_val = ER_OK;
    uint32_t            call_func_ret;
    volatile uint32_t  *p_reg;
    volatile uint32_t  *p_single_reg;
    uint32_t            semaphore;
    uint32_t            bit_position;
    uint32_t            my_peid;
    uint8_t             index;
    uintptr_t           saved_psw;

    /* 1. Get necessary bit of register according to PEID */
    my_peid = USER_ICUMIF_GetMyPEID();
    p_reg = (volatile uint32_t *)pe_info[my_peid].p_pe2icufs;
    p_single_reg = (volatile uint32_t *)&ICUM_CMDREGICUM_PE2ICUSFS;
    
    index = QUEUE_INDEX_MAX;

    /* 2. Each processing is executed according to the value of parameter channel */
    switch (channel)
    {
        case ICUM_COMM_ICH_TO_SERV_REQUEST:
            /* 2-1. Check the "service queue initialization" state of */
            /*      the initialization state information              */
            bit_position = PE_QUE_INIT;
            if (INIT_UNPROCESSED == (0x00000001U & (icumif_initialized[my_peid] >> bit_position)))
            {
                /* 2-1-1. Service queue initialization not yet */
                ret_val = ER_D_COMM_QUE_NOT_INIT;
            }
            else
            {
                /* For interrupt control between PEs,                 */
                /* Interrupt disable initialization state information */
                USER_ICUMIF_GetLock(&saved_psw);

                /* Get the Semaphore register to access the request queue*/
                semaphore = d_COMM_PE_GetSemaphore((uint8_t)my_peid, PE_SEMAPHORE_ON);

                if (ER_OK == semaphore)
                {
                    /* 2-1-2. */
                    /* Enqueue ISD specified by parameter p_isd to service request queue */
                    call_func_ret = d_COMM_Enqueue_Request(p_isd, &index);
                    if (ER_OK == call_func_ret)
                    {
                        if (R_ICUMIF_REQRES_INTERRPUT == (uint32_t)p_isd->req_nointerrupt)
                        {
                            if ((QUEUE_INDEX_FIRST == (uint32_t)index) &&
                                (SERVICE_01_AES_CMAC == p_isd->service_id) && 
                                ((r_icumif_service_priority_t)R_ICUMIF_SERV_PRIORITY_HIGHEST ==
                                    (uint32_t)p_isd->service_priority))
                            {
                                /* Set PEID status for INTPES interrupt */
                                (void)D_COMM_SetPEStatusInfo(ICUM_COMM_INF_PE_ST_PEID, (uint8_t)my_peid);
                                /* Issue service execution request single interrupt */
                                *p_single_reg = ICUM_COMM_ICH_TO_SINGLE_INTERRUPT;
                            }
                            else
                            {
                                /* 2-1-2-1. Issue service execution request interrupt */
                                *p_reg = channel;
                            }
                        }
                        else
                        {
                            /* Do nothing */
                        }
                    }
                    else
                    {
                    /* 2-1-2-2. Service request queue FULL */
                        ret_val = call_func_ret;
                    }
                    /* Free the Semaphore */
                    (void)d_COMM_PE_FreeSemaphore((uint8_t)my_peid, PE_SEMAPHORE_OFF);
                }
                else
                {
                    ret_val = ER_D_COMM_QUE_NOT_ACCESS;
                }

                /* Interrupt enable of service response queue */
                USER_ICUMIF_ReleaseLock(saved_psw);
            }
            break;
        case ICUM_COMM_ICH_TO_CF_PRG_NOTIFY:
        case ICUM_COMM_ICH_TO_DF_PRG_NOTIFY:
        case ICUM_COMM_ICH_TO_CF_PRG_ERROR:
        case ICUM_COMM_ICH_TO_DF_PRG_ERROR:
        case ICUM_COMM_ICH_TO_OPERATION_END:
            /* 2-2. Issue an interrupt with specified channel number */
            *p_reg = channel;
            break;
        default:
            /* 2-3. Parameter error */
            ret_val = ER_PARAM;
            break;
    }

    /* 3. Return the interrupt issue result */
    return (ret_val);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0006]:[ICUMFW_UD_S4_D_COMM_PE_0006]
* Function name: D_COMM_GetResponseISD
* Description  : Dequeue ISD from head of the service response queue for its self PE
* Arguments    : r_icumif_isd_t **p_isd : The store address of ISD
* Return Value : uint32_t ISD acquire result
*                   ER_OK                  : Successful
*                   ER_D_COMM_QUE_NOT_INIT : Service queue initialization not yet
*                   ER_D_COMM_NO_ISD       : There is no ISD in service response queue
***************************************************************************************/
uint32_t D_COMM_GetResponseISD(r_icumif_isd_t **p_isd)
{
    uint32_t            ret_val = ER_OK;
    volatile uint32_t   *p_reg;
    ptr_manip_t         queptr;
    uint32_t            *p_queptr;
    int32_t             next_idx;
    ptr_manip_t         isdptr;
    uint32_t            my_peid;
    uint32_t             semaphore;
    uintptr_t           saved_psw;
    volatile uint32_t   lul_dummy;
    uint32_t            secure_bit;

    /* 2. Check the "service queue initialization" state of */
    /*    the initialization state information              */
    my_peid = USER_ICUMIF_GetMyPEID();
    if (INIT_UNPROCESSED == (0x00000001U & (icumif_initialized[my_peid] >> PE_QUE_INIT)))
    {
        /* 2-1. Service queue initialization not yet */
        ret_val = ER_D_COMM_QUE_NOT_INIT;
    }
    else
    {
        /* 2-2. */
        /* For interrupt control between PEs,       */
        /* Interrupt disable of service response queue */
        USER_ICUMIF_GetLock(&saved_psw);

        /* Get the Semaphore register to access the respnse queue */
        semaphore = d_COMM_PE_GetSemaphore((uint8_t)my_peid, PE_SEMAPHORE_OFF);

        if (ER_OK == semaphore)
        {
            secure_bit = pe_info[my_peid].secure_mode_bit;

            if ((PEID_PE0 == my_peid) || (PE_SECURE_MODE_BITOFF != (MEM_INFO_ICUM_SECUREMOD & secure_bit)))
            {
                p_reg = (volatile uint32_t *)pe_info[my_peid].p_semape;
            }
            else
            {
                p_reg = (volatile uint32_t *)pe_info[my_peid].p_semape_ns;
            }

            /* Lower 24 bits of Semaphore register are acquire and upper 8 bits */
            /* are complemented to generate top address of service request queue   */
            queptr.val = (*p_reg & QUE_ADDR_LOWER_24BITS) | (QUE_ADDR_UPPER_8BITS_VALUE & MEM_INFO_SERVICEQUE_1_ADDR);
            p_queptr = (uint32_t *)queptr.p_ptr;

            ret_val = ER_D_COMM_NO_ISD;
            p_queptr += RESPONSE_QUEUE_OFST;
            
            /* Invalidate of cache area ( service response queue area ) */
            queptr.val += SERV_REQUEST_QUEUE_AREA_SIZE;
            USER_ICUMIF_InvalidateDCache((uint32_t)queptr.val, SERV_RESPONSE_QUEUE_AREA_SIZE);

            for (next_idx = 0; next_idx < (int32_t)RESPONSE_QUEUE_LENGTH; next_idx++)
            {
                /* Check entry after one of entry index of the service request queue */
                if (0U != (*(p_queptr + next_idx)))
                {
                    if (ret_val != ER_OK)
                    {
                        /* 2-2-2. */
                        /* Acquire the address of ISD */
                        isdptr.val = *(p_queptr + next_idx);
                        *p_isd = (r_icumif_isd_t *)isdptr.p_ptr;
                        /* Invalidate of cache area ( ISD common_parameters ) */
                        USER_ICUMIF_InvalidateDCache((uint32_t)isdptr.val, (uint32_t)(sizeof(r_icumif_isd_t) - sizeof((*p_isd)->prm)));
                        /* free the entry in service response queue */
                        *(p_queptr + next_idx) = 0U;
                        /* Set service request / response queue transition state in acquired ISD */
                        (*p_isd)->req_res_status = R_ICUMIF_REQRES_PE_RES_DEQUE;
                        /* Dummy Read */
                        lul_dummy = (*p_isd)->req_res_status;
                        (void)lul_dummy;
                        /* Synchronize */
                        USER_ICUMIF_Sync();
                        /* Clean and invalidate of cache area                       */
                        /* ( ISD common_parameters and service request queue area ) */
                        USER_ICUMIF_FlushDCache((uint32_t)isdptr.val, (uint32_t)(sizeof(r_icumif_isd_t) - sizeof((*p_isd)->prm)));
                        ret_val = ER_OK;
                    }
                    else
                    {
                        ret_val = ER_D_COMM_EXIST_ISD;
                        break;
                    }
                }
                else
                {
                    /* Do nothing */
                }
            }
            
            queptr.val -= SERV_REQUEST_QUEUE_AREA_SIZE;
            USER_ICUMIF_FlushDCache((uint32_t)queptr.val, SERV_REQUEST_QUEUE_AREA_SIZE);
            /* when the error bit of the semaphore register is be set */
            if (PE_SEMAPHORE_ERR == (*p_reg & PE_SEMAPHORE_ERR))
            {
                /* error occurred */
                ret_val = ER_D_COMM_QUE_NOT_ACCESS;
                *p_reg &= ~PE_SEMAPHORE_ERR;
            }
            else
            {
                /* Do nothing */
            }

            /* Free the Semaphore */
            (void)d_COMM_PE_FreeSemaphore((uint8_t)my_peid, PE_SEMAPHORE_OFF);
        }
        else
        {
            ret_val = ER_D_COMM_QUE_NOT_ACCESS;
        }

        /* 2-3. Interrupt enable of service response queue */
        USER_ICUMIF_ReleaseLock(saved_psw);
    }

    /* 3. Return the ISD acquire result */
    return (ret_val);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0007]:[ICUMFW_UD_S4_D_COMM_PE_0007]
* Function name: D_COMM_GetICUStatusAddr
* Description  : Acquire address value of status information of ICU-M Firmware
* Arguments    : None
* Return Value : r_icumif_sts_t * Address value of ICU-M Firmware status information
***************************************************************************************/
r_icumif_sts_t *D_COMM_GetICUStatusAddr(void)
{
    r_icumif_sts_t  *p_reg;
    ptr_manip_t     regptr;
    uint32_t        my_peid;

    /* 1. Return the address value of ICUM_ICU2PES register as function return value */
    my_peid = USER_ICUMIF_GetMyPEID();
    regptr.p_vlt_ptr = pe_info[my_peid].p_icu2pes;
    p_reg = (r_icumif_sts_t *)regptr.p_ptr;

    return (p_reg);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0008]:[ICUMFW_UD_S4_D_COMM_PE_0008]
* Function name: D_COMM_SetPEStatusInfo
* Description  : Set status information of the specified PE
* Arguments    : icum_com_info_pe_status_t info      : Status information of PE to set
*                uint8_t                   set_value : Value of status information
* Return Value : uint32_t Status information setting result
*                   ER_OK    : Successful
*                   ER_PARAM : Parameter error
***************************************************************************************/
uint32_t D_COMM_SetPEStatusInfo(icum_com_info_pe_status_t info, uint8_t set_value)
{
    uint32_t            ret_val = ER_OK;
    volatile uint32_t   *p_reg;
    uint32_t            bit_pattern;
    uint32_t            mask_pattern;
    uintptr_t           saved_psw;
    volatile uint32_t   lul_dummy;

    /* 2. For interrupt control between PEs,      */
    /*    Interrupt disable of PE state information */
    USER_ICUMIF_GetLock(&saved_psw);

    p_reg = (volatile uint32_t *)&ICUM_CMDREGICUM_PE2ICUS0;

    /* 3. Each processing is executed according to the value of parameter info */
    switch (info)
    {
        case ICUM_COMM_INF_PE_ST_FACIACCDIS:
            /* 3-1. */
            /* Generate bit pattern so that value of least significant bit of  */
            /* parameter set_value can be set as state of                      */
            /* inhibiting the data flash access state of PE status information */
            bit_pattern = ((INFO_PE_ST_FACIACCDIS_BIT & (uint32_t)set_value) << info) << INFO_PE_ST_POSITION;

            /* Set generate bit pattern to upper 8 bits of ICUM_PE2ICUS register */
            mask_pattern = ~(((uint32_t)(INFO_PE_ST_FACIACCDIS_BIT << info)) << INFO_PE_ST_POSITION);
            *p_reg = (*p_reg & mask_pattern) | bit_pattern;
            /* Dummy Read */
            lul_dummy = *p_reg;
            (void)lul_dummy;
            /* Synchronize */
            USER_ICUMIF_Sync();
            break;
        case ICUM_COMM_INF_PE_ST_FLS_OPRN:
            /* 3-2. */
            /* Generate bit pattern so that value of least significant bit of  */
            /* parameter set_value can be set as state of                      */
            /* inhibiting the data flash access state of PE status information */
            bit_pattern = ((INFO_PE_ST_FLS_OPRN_BIT & (uint32_t)set_value) << info) << INFO_PE_ST_POSITION;

            /* Set generate bit pattern to upper 8 bits of ICUM_PE2ICUS register */
            mask_pattern = ~(((uint32_t)(INFO_PE_ST_FLS_OPRN_BIT << info)) << INFO_PE_ST_POSITION);
            *p_reg = (*p_reg & mask_pattern) | bit_pattern;
            /* Dummy Read */
            lul_dummy = *p_reg;
            (void)lul_dummy;
            /* Synchronize */
            USER_ICUMIF_Sync();
            break;
        case ICUM_COMM_INF_PE_ST_PEID:
            /* 3-3. */
            /* Generate bit pattern so that value of least significant bit of  */
            /* parameter set_value can be set PEID information for INTPES interrupt */
            bit_pattern = (PEID_MASK & (uint32_t)set_value);

            /* Set generate bit pattern to upper 8 bits of ICUM_PE2ICUS register */
            mask_pattern = ~(PEID_MASK);
            *p_reg = (*p_reg & mask_pattern) | bit_pattern;
            /* Dummy Read */
            lul_dummy = *p_reg;
            (void)lul_dummy;
            /* Synchronize */
            USER_ICUMIF_Sync();
            break;
        case ICUM_COMM_INF_PE_ST_FLS_DF_PRG:
            /* 3-4. */
            /* Generate bit pattern so that value of least significant bit of  */
            /* parameter set_value can be set as state of data flash prograimming */
            bit_pattern = ((INFO_PE_ST_FLS_DF_PRG_BIT & (uint32_t)set_value) << info) << INFO_PE_ST_POSITION;

            /* Set generate bit pattern to upper 8 bits of ICUM_PE2ICUS register */
            mask_pattern = ~(((uint32_t)(INFO_PE_ST_FLS_DF_PRG_BIT << info)) << INFO_PE_ST_POSITION);
            *p_reg = (*p_reg & mask_pattern) | bit_pattern;
            /* Dummy Read */
            lul_dummy = *p_reg;
            (void)lul_dummy;
            /* Synchronize */
            USER_ICUMIF_Sync();
            break;
        case ICUM_COMM_INF_PE_ST_FLS_CF_PRG:
            /* 3-5. */
            /* Generate bit pattern so that value of least significant bit of  */
            /* parameter set_value can be set as state of code flash prograimming */
            bit_pattern = ((INFO_PE_ST_FLS_CF_PRG_BIT & (uint32_t)set_value) << info) << INFO_PE_ST_POSITION;

            /* Set generate bit pattern to upper 8 bits of ICUM_PE2ICUS register */
            mask_pattern = ~(((uint32_t)(INFO_PE_ST_FLS_CF_PRG_BIT << info)) << INFO_PE_ST_POSITION);
            *p_reg = (*p_reg & mask_pattern) | bit_pattern;
            /* Dummy Read */
            lul_dummy = *p_reg;
            (void)lul_dummy;
            /* Synchronize */
            USER_ICUMIF_Sync();
            break;
        default:
            /* 3-6. Parameter error */
            ret_val = ER_PARAM;
            break;
    }

    /* 4. Interrupt enable of PE state information */
    USER_ICUMIF_ReleaseLock(saved_psw);

    /* 5. Return Status information setting result */
    return (ret_val);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0009]:[ICUMFW_UD_S4_D_COMM_PE_0009]
* Function name: D_COMM_SetInterruptEnable
* Description  : Enable interrupt of ICUP --> PE (INTICUP)
* Arguments    : None
* Return Value : None
***************************************************************************************/
void D_COMM_SetInterruptEnable(void)
{
    volatile uint32_t   *p_reg;
    uint32_t            pesel_value;
    uint32_t            ie_value;
    uint32_t            my_peid;
    ICUM_COMM_PE_INFO_t *p_pe_info;
    uintptr_t           saved_psw;

    /* Get the PEID */
    my_peid = USER_ICUMIF_GetMyPEID();

    /* 1. For interrupt control between PEs,                  */
    /*    Interrupt disable of initialization state information */
    USER_ICUMIF_GetLock(&saved_psw);

    /* 2. Check the state of "ICU2PEI initialization" of self PE */
    /*    in initialization state information                    */
    p_pe_info = &pe_info[my_peid];
    if (INIT_UNPROCESSED == (0x00000001U & (icumif_initialized[my_peid] >> PE_ICU2PEI_INIT)))
    {
        /* 2-1. */
        /* Set Interrupt destination selection */
        pesel_value  = p_pe_info->inticup_pesel_to_pe;
        p_reg = (volatile uint32_t *)p_pe_info->p_icu2peis;
        *p_reg = pesel_value;

        /* Set Interrupt enable */
        p_reg = (volatile uint32_t *)p_pe_info->p_icu2peie;
        ie_value = (1U << ICUM_COMM_ICH_FM_SYS_INTERRUPT) | (1U << ICUM_COMM_ICH_FM_SERV_RESPONSE);
        *p_reg = ie_value;

        /* The "ICU2PEI initialization" state is set to "processed" */
        icumif_initialized[my_peid] |= (uint32_t)(INIT_PROCESSED << PE_ICU2PEI_INIT);
        /* Synchronize Pipeline Macro */
        USER_ICUMIF_Sync();
    }
    else
    {
        /* Do nothing */
    }

    /* 3. Interrupt enable of initialization state information */
    USER_ICUMIF_ReleaseLock(saved_psw);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0010]:[ICUMFW_UD_S4_D_COMM_PE_0010]
* Function name: D_COMM_SetSystemCallBackFunc
* Description  : Register the function to call back when receiving system interrupt
* Arguments    : R_ICUMIF_CB_REGIST_t *p_regist_info : Pointer to registration info
* Return Value : uint32_t Callback registration result
*                   ER_OK : Successful
***************************************************************************************/
uint32_t D_COMM_SetSystemCallBackFunc(R_ICUMIF_CB_REGIST_t *p_regist_info)
{
    uint32_t my_peid;

    /* Get the PEID */
    my_peid = USER_ICUMIF_GetMyPEID();

    /* 1. Save CallBack Function Address */
    cb_regist_info[my_peid].p_func_addr = p_regist_info->p_func_addr;

    /* 2. Return the callback registration result */
    return (ER_OK);
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0012]:[ICUMFW_UD_S4_D_COMM_PE_0012]
* Function name: D_COMM_GetICUMemCheckErrInfo
* Description  : Get the result of memory check error
* Arguments    : uint8_t *p_error : Pointer to memory check info
* Return Value : uint32_t return the result of API
*                   ER_OK    : Successful
*                   ER_PARAM : Parameter error
***************************************************************************************/
uint32_t D_COMM_GetICUMemCheckErrInfo(uint8_t *p_error)
{
    volatile uint32_t   *p_reg;
    uint32_t            my_peid;
    uint32_t            ret_val = ER_OK;
    uintptr_t           saved_psw;
    uint32_t            secure_bit;

    if(p_error != NULL)
    {
        /* Get the PEID */
        my_peid = USER_ICUMIF_GetMyPEID();

        /* For interrupt control between PEs,                 */
        /* Interrupt disable initialization state information */
        USER_ICUMIF_GetLock(&saved_psw);

        (void)d_COMM_PE_GetSemaphore((uint8_t)my_peid, PE_SEMAPHORE_OFF);

        /*  get semaphore register according to the PEID of the self PE */
        secure_bit = pe_info[my_peid].secure_mode_bit;

        if ((PEID_PE0 == my_peid) || (PE_SECURE_MODE_BITOFF != (MEM_INFO_ICUM_SECUREMOD & secure_bit)))
        {
            p_reg = (volatile uint32_t *)pe_info[my_peid].p_semape;
        }
        else
        {
            p_reg = (volatile uint32_t *)pe_info[my_peid].p_semape_ns;
        }

        /* when the error bit of the semaphore register is be set*/
        if (PE_SEMAPHORE_ERR == (*p_reg & PE_SEMAPHORE_ERR))
        {
            /* memory check error to be set in *p_error */
            *p_error = ICUM_COMM_MEMCHECK_ERROR;
            *p_reg &= ~PE_SEMAPHORE_ERR;
        }
        else
        {
            /* memory check OK to be set in *p_error */
            *p_error = ICUM_COMM_MEMCHECK_OK;
        }

        (void)d_COMM_PE_FreeSemaphore((uint8_t)my_peid, PE_SEMAPHORE_OFF);

        /* Interrupt enable of PE state information */
        USER_ICUMIF_ReleaseLock(saved_psw);
    }
    else
    {
        ret_val = ER_PARAM;
    }

    return (ret_val);
}

/**************************************************************************************/
/* Interrupt handler functions                                                        */
/**************************************************************************************/

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0014]:[ICUMFW_UD_S4_D_COMM_PE_0014]
* Function name: d_COMM_Sys_Interrupt
* Description  : Execute process of system interrupt from ICU-M
* Arguments    : None
* Return Value : None
***************************************************************************************/
static void d_COMM_Sys_Interrupt(void)
{
    uint32_t my_peid;

    /* Get the PEID */
    my_peid = USER_ICUMIF_GetMyPEID();

    /* 1. Check registration state of function to call back */
    /*    when system interrupt is received                 */
    if (NULL != cb_regist_info[my_peid].p_func_addr)
    {
        /* 1-1. Call registered callback function */
        (*cb_regist_info[my_peid].p_func_addr)();
    }
    else
    {
        /* Do nothing */
    }

    return;
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0019]:[ICUMFW_UD_S4_D_COMM_PE_0019]
* Function name: D_COMM_IRQ_Handler
* Description  : Execute interrupt process of ICUP --> PE (INTICUP)
* Arguments    : None
* Return Value : None
***************************************************************************************/
void D_COMM_IRQ_Handler(void)
{
    volatile uint32_t   *p_reg;
    uint32_t            work_icu2pef;
    uint32_t            i;
    uint32_t            my_peid;
    volatile uint32_t   lul_dummy;

    /* 1. Get necessary bit of register according to PEID */
    my_peid = USER_ICUMIF_GetMyPEID();
    p_reg = (volatile uint32_t *)pe_info[my_peid].p_icu2pef;
    work_icu2pef = *p_reg;

    p_reg = (volatile uint32_t *)pe_info[my_peid].p_icu2pefc;

    /* Clear interrupt factor of the non set PESELs */
    if (0x00000000U != (work_icu2pef & INTICUP_ICH_MASK))
    {
        *p_reg = (work_icu2pef & INTICUP_ICH_MASK);
        work_icu2pef &= ~INTICUP_ICH_MASK;
    }
    else
    {
        /* Do nothing */
    }

    /* 2. Check value of bits 0 to 2 of work_icu2pef bit by bit in order */
    /*    to determine occurred interrupt                                 */
    for (i = 0U; ((INTICUP_EACH_PE_BIT_WIDTH > i) && (0U != work_icu2pef)); i++)
    {
        /* 2-1. Check the value of least significant bit of work_icu2pef */
        if (0x00000001U == (0x00000001U & work_icu2pef))
        {
            /* 2-1-1. */
            /* Clear interrupt factor */
            *p_reg = (1U << i);
            lul_dummy = *p_reg;
            (void)lul_dummy;
            /* Synchronize */
            USER_ICUMIF_Sync();

            switch (i)
            {
                case ICUM_COMM_ICH_FM_SYS_INTERRUPT:
                    /* 2-1-1-1. Execute system interrupt handling process */
                    d_COMM_Sys_Interrupt();
                    break;
                case ICUM_COMM_ICH_FM_SERV_RESPONSE:
                    /* 2-1-1-2. Execute service execution response interrupt */
                    /*          handling process                             */
                    (void)R_ICUMIF_ServiceResponse();
                    break;
                default:
                    /* 2-1-1-4. Do nothing */
                    break;
            }
        }
        else
        {
            /* Do nothing */
        }

        /* 2-2. Update work_icu2pef right shifted by 1 bit */
        work_icu2pef >>= 1U;
    }

    return;
}

/***************************************************************************************
* Function ID  : [ICUMFW_CD_S4_D_COMM_PE_0028]:[ICUMFW_UD_S4_D_COMM_PE_0028]
* Function name: D_COMM_PE_CheckMemorySharedRAM
* Description  : Check the memory 
* Arguments    :(IN)uint32_t start_addr: start address
*               (IN)uint32_t size: check memory size
* Return Value : ER_OK
*                ER_PARAM
*                ER_D_COMM_MEMCHK_NG
*                ER_D_COMM_ALIGN_NG
***************************************************************************************/
uint32_t D_COMM_PE_CheckMemorySharedRAM(uint32_t start_addr, uint32_t size)
{
    int32_t     ret_val    = ER_OK;
    uint32_t    addr_valid = 0U;

    /* 1. Address alignment check                            */
    /*    In the case of check NG, the process is terminated */
    if (0U != (start_addr & ALIGNMENT_64BYTE_CHECK_PATTERN))
    {
        ret_val = ER_D_COMM_ALIGN_NG;
    }
    else
    {
        /* 2. Address range check                                */
        /*    In the case of check NG, the process is terminated */
        if (size <= MEM_INFO_SERVICEQUE_1_SIZE)
        {
            if ((MEM_INFO_SERVICEQUE_1_ADDR <= start_addr) &&
                ((MEM_INFO_SERVICEQUE_1_ADDR + MEM_INFO_SERVICEQUE_1_SIZE - size) >= start_addr))
            {
                addr_valid = 1U;
            }
            else
            {
                /* Do nothing */
            }
        }
        else
        {
            /* Do nothing */
        }
        if ((0U == addr_valid) && (size <= MEM_INFO_SHAREDMEM_1_SIZE))
        {
            if ((MEM_INFO_SHAREDMEM_1_ADDR <= start_addr) && 
                ((MEM_INFO_SHAREDMEM_1_ADDR + MEM_INFO_SHAREDMEM_1_SIZE - size) >= start_addr))
            {
                addr_valid = 1U;
            }
            else
            {
                /* Do nothing */
            }
        }
        else
        {
            /* Do nothing */
        }
        if ((0U == addr_valid) && (size <= MEM_INFO_SHAREDMEM_2_SIZE))
        {
            if ((MEM_INFO_SHAREDMEM_2_ADDR <= start_addr) && 
                ((MEM_INFO_SHAREDMEM_2_ADDR + MEM_INFO_SHAREDMEM_2_SIZE - size) >= start_addr))
            {
                addr_valid = 1U;
            }
            else
            {
                /* Do nothing */
            }
        }
        else
        {
            /* Do nothing */
        }
        if ((0U == addr_valid) && (size <= MEM_INFO_SHAREDMEM_3_SIZE))
        {
            if ((MEM_INFO_SHAREDMEM_3_ADDR <= start_addr) && 
                ((MEM_INFO_SHAREDMEM_3_ADDR + MEM_INFO_SHAREDMEM_3_SIZE - size) >= start_addr))
            {
                addr_valid = 1U;
            }
            else
            {
                /* Do nothing */
            }
        }
        else
        {
            /* Do nothing */
        }
        if (0U == addr_valid)
        {
            ret_val = ER_D_COMM_MEMCHK_NG;
        }
        else
        {
            /* Do nothing */
        }
    }

    /* 3. Return the address check result */
    return (uint32_t)ret_val;
}
