// +FHDR------------------------------------------------------------
//                 Copyright (c) 2022 SmartLogic.
//                       ALL RIGHTS RESERVED
// -----------------------------------------------------------------
// Filename      : spu_hw_queue.s.c
// Author        : lishuang.xie
// Created On    : 2023-02-06
// Last Modified :
// -----------------------------------------------------------------
// Description:
//
//
// -FHDR------------------------------------------------------------
#include "app_interface.h"
#include "ucp_printf.h"
#include "ucp_utility.h"
#include "hwque.h"

/*********************************************************/
typedef struct ECS_MSG_QUEUE_STRUCT
{
    uint16_t que_id;    /* queue index */
    uint16_t de_idx;    /* deep index */
    uint16_t dep;       /* deep */
    uint16_t mask;      /* mask */
}ecs_msg_que;

#define ECS_APE_MSG_NUM         (682)           /* message num: 682 --> 0x2AA */
#define ECS_APE_MSG_SIG_SIZE    (512)           /* one message:512 --> 0x200 */

ecs_msg_que g_ecs_msg_que;

uint32_t g_spu_rfm_ddr_msg_addr[] = {0x102AA000,    /* PET RFM0 */
                                     0x102FF400,    /* PET RFM1 */
                                     0x10354800,    /* ECS RFM0 */
                                     0x103A9C00};   /* ECS RFM1 */

#ifdef UCP_OSP_DBG_HW_CNT_ENABLE
static uint32_t gu32_app_sendto_que0_ok = 0;    // #0
static uint32_t gu32_app_sendto_que1_ok = 0;
static uint32_t gu32_app_sendto_que2_ok = 0;
static uint32_t gu32_app_sendto_que3_ok = 0;
static uint32_t gu32_app_sendto_que4_ok = 0;
static uint32_t gu32_app_sendto_que5_ok = 0;
static uint32_t gu32_app_sendto_que6_ok = 0;
static uint32_t gu32_app_sendto_que7_ok = 0;
static uint32_t gu32_app_sendto_que8_ok = 0;
static uint32_t gu32_app_sendto_que9_ok = 0;
static uint32_t gu32_app_sendto_que10_ok = 0;
static uint32_t gu32_app_sendto_que11_ok = 0;

static uint32_t gu32_app_sendto_que0_ng = 0;    // #12
static uint32_t gu32_app_sendto_que1_ng = 0;
static uint32_t gu32_app_sendto_que2_ng = 0;
static uint32_t gu32_app_sendto_que3_ng = 0;
static uint32_t gu32_app_sendto_que4_ng = 0;
static uint32_t gu32_app_sendto_que5_ng = 0;
static uint32_t gu32_app_sendto_que6_ng = 0;
static uint32_t gu32_app_sendto_que7_ng = 0;
static uint32_t gu32_app_sendto_que8_ng = 0;
static uint32_t gu32_app_sendto_que9_ng = 0;
static uint32_t gu32_app_sendto_que10_ng = 0;
static uint32_t gu32_app_sendto_que11_ng = 0;

static uint32_t gu32_app_recv_que0 = 0;     // #24
static uint32_t gu32_app_recv_que1 = 0;
static uint32_t gu32_app_recv_que2 = 0;
static uint32_t gu32_app_recv_que3 = 0;
static uint32_t gu32_app_recv_que4 = 0;
static uint32_t gu32_app_recv_que5 = 0;
static uint32_t gu32_app_recv_que6 = 0;
static uint32_t gu32_app_recv_que7 = 0;
static uint32_t gu32_app_recv_que8 = 0;
static uint32_t gu32_app_recv_que9 = 0;
static uint32_t gu32_app_recv_que10 = 0;
static uint32_t gu32_app_recv_que11 = 0;
#endif

#define APP_PALLADIUM_TEST
#ifdef APP_PALLADIUM_TEST
typedef struct ECS_APP_IFC_STRUCT
{
    uint32_t ecs_msg_deque_num;
    uint32_t ecs_msg_deque_par_err;
    uint32_t ecs_msg_alloc_size_err;
    uint32_t ecs_msg_deque_err;
    uint32_t ecs_msg_send_num;
    uint32_t ecs_msg_InQue_err;
    uint32_t ecs_msg_get_info_empty_num;
    uint32_t ecs_msg_get_info_OutQue_err;
    uint32_t ecs_msg_get_info_num;
}ecs_app_dbg_info;

ecs_app_dbg_info g_ecs_app_debug_info;
#endif

int8_t ecs_msg_que_init(uint16_t core_id)
{
    memset(&g_ecs_msg_que, 0, sizeof(g_ecs_msg_que));
#ifdef APP_PALLADIUM_TEST
    memset(&g_ecs_app_debug_info, 0, sizeof(g_ecs_app_debug_info));
#endif
    g_ecs_msg_que.que_id = (uint16_t)core_id - 8;
    g_ecs_msg_que.de_idx = 0;
    g_ecs_msg_que.dep    = ECS_APE_MSG_NUM;
    g_ecs_msg_que.mask   = ECS_APE_MSG_NUM -1;

    debug_write(DBG_DDR_COMMON_IDX(core_id, 8), core_id);
    return 0;
}

int32_t ecs_msg_que_deque(uint32_t *pvalue)
{
#ifdef APP_PALLADIUM_TEST
    int32_t core_id = get_core_id();
#endif
    uint32_t base_value = 0;

    /* check */
    if (NULL == pvalue)
    {
#ifdef APP_PALLADIUM_TEST
        g_ecs_app_debug_info.ecs_msg_deque_par_err++;
        debug_write(DBG_DDR_COMMON_IDX(core_id, 9), g_ecs_app_debug_info.ecs_msg_deque_par_err);
#endif
        return -1;
    }

    base_value = g_spu_rfm_ddr_msg_addr[g_ecs_msg_que.que_id];

    *pvalue = ((g_ecs_msg_que.de_idx << 9) + base_value);

    if ((g_ecs_msg_que.de_idx + 1) == g_ecs_msg_que.mask)
    {
        g_ecs_msg_que.de_idx = 0;
    }
    else
    {
        g_ecs_msg_que.de_idx = (g_ecs_msg_que.de_idx +1);
    }
#ifdef APP_PALLADIUM_TEST
    g_ecs_app_debug_info.ecs_msg_deque_num++;
    debug_write(DBG_DDR_COMMON_IDX(core_id, 10), g_ecs_app_debug_info.ecs_msg_deque_num);
#endif
    return 0;
}

/* malloc message buffer */
char *osp_alloc_msg(int32_t size)
{
#ifdef APP_PALLADIUM_TEST
    int32_t core_id = get_core_id();
#endif
    uint32_t addr = 0;
    int32_t  ret  = 0;

    if ((size+ECS_MSG_HEAD_LEN) > ECS_APE_MSG_SIG_SIZE)
    {
        UCP_PRINT_ERROR("ecs_alloc_msg: error (size = 0x%08x)\r\n", size);
#ifdef APP_PALLADIUM_TEST
        g_ecs_app_debug_info.ecs_msg_alloc_size_err++;
        debug_write(DBG_DDR_COMMON_IDX(core_id, 11), g_ecs_app_debug_info.ecs_msg_alloc_size_err);
#endif
        return NULL;
    }

    ret = ecs_msg_que_deque(&addr);
    if (0 != ret)
    {
        /* no buffer */
        UCP_PRINT_ERROR("ecs_alloc_msg: error (no addr)\r\n");
#ifdef APP_PALLADIUM_TEST
        g_ecs_app_debug_info.ecs_msg_deque_err++;
        debug_write(DBG_DDR_COMMON_IDX(core_id, 12), g_ecs_app_debug_info.ecs_msg_deque_err);
#endif
        return NULL;
    }
    return (char*)((uint32_t)addr + (uint32_t)ECS_MSG_HEAD_LEN);
}

/* send msg into hw_queue */
int32_t osp_send_msg(uint32_t msg_addr,
                         uint32_t msg_len,
                         uint8_t  msg_type,
                         uint8_t  src_core_id,
                         uint8_t  dst_core_id,
                         uint8_t  src_task_id,
                         uint8_t  dst_task_id)
{
    ecs_msg_head *pmsg_head = NULL;
    ecs_msg_head st_msg_head;
    int32_t  ret_queue = -1;

#ifdef APP_PALLADIUM_TEST
    g_ecs_app_debug_info.ecs_msg_send_num++;
    int32_t core_id = get_core_id();
#endif
    pmsg_head = (ecs_msg_head*)((uint32_t)msg_addr - (uint32_t)ECS_MSG_HEAD_LEN);
    st_msg_head.msg_size = msg_len;
    st_msg_head.msg_type = msg_type;
    st_msg_head.msg_type_oam = 0x00;
    st_msg_head.src_core_id = src_core_id;
    st_msg_head.dst_core_id = dst_core_id;
    st_msg_head.src_task_id = src_task_id;
    st_msg_head.dst_task_id = dst_task_id;

    memcpy_ucp((void*)pmsg_head, (void*)&st_msg_head, ECS_MSG_HEAD_LEN);
    __ucps2_synch(0);

    UCP_PRINT_LOG("ecs_send_msg: dst_que_id = 0x%08x, addr = 0x%08x\r\n", dst_core_id, msg_addr);
    ret_queue = smart_in_que(dst_core_id, msg_addr);
    if (0 != ret_queue)
    {
        UCP_PRINT_ERROR("ecs_send_msg: error(smart_in_que) que_id = 0x%08x addr = 0x%08x\r\n", dst_core_id, msg_addr);
#ifdef APP_PALLADIUM_TEST
        g_ecs_app_debug_info.ecs_msg_InQue_err++;
        debug_write(DBG_DDR_COMMON_IDX(core_id, 13), g_ecs_app_debug_info.ecs_msg_InQue_err);
        debug_write(DBG_DDR_ERR_IDX(core_id, 19), ret_queue);
#endif

#ifdef UCP_OSP_DBG_HW_CNT_ENABLE
        switch (dst_core_id)
        {
            case 0:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 12), ++gu32_app_sendto_que0_ng);
                break;
            }
            case 1:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 13), ++gu32_app_sendto_que1_ng);
                break;
            }
            case 2:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 14), ++gu32_app_sendto_que2_ng);
                break;
            }
            case 3:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 15), ++gu32_app_sendto_que3_ng);
                break;
            }
            case 4:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 16), ++gu32_app_sendto_que4_ng);
                break;
            }
            case 5:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 17), ++gu32_app_sendto_que5_ng);
                break;
            }
            case 6:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 18), ++gu32_app_sendto_que6_ng);
                break;
            }
            case 7:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 19), ++gu32_app_sendto_que7_ng);
                break;
            }
            case 8:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 20), ++gu32_app_sendto_que8_ng);
                break;
            }
            case 9:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 21), ++gu32_app_sendto_que9_ng);
                break;
            }
            case 10:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 22), ++gu32_app_sendto_que10_ng);
                break;
            }
            case 11:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 23), ++gu32_app_sendto_que11_ng);
                break;
            }
            default:
            {
                break;
            }
        }
#endif
    }
#ifdef APP_PALLADIUM_TEST
    debug_write(DBG_DDR_COMMON_IDX(core_id, 14), g_ecs_app_debug_info.ecs_msg_send_num);
#endif

#ifdef UCP_OSP_DBG_HW_CNT_ENABLE
    switch (dst_core_id)
    {
        case 0:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 0), ++gu32_app_sendto_que0_ok);
            break;
        }
        case 1:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 1), ++gu32_app_sendto_que1_ok);
            break;
        }
        case 2:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 2), ++gu32_app_sendto_que2_ok);
            break;
        }
        case 3:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 3), ++gu32_app_sendto_que3_ok);
            break;
        }
        case 4:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 4), ++gu32_app_sendto_que4_ok);
            break;
        }
        case 5:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 5), ++gu32_app_sendto_que5_ok);
            break;
        }
        case 6:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 6), ++gu32_app_sendto_que6_ok);
            break;
        }
        case 7:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 7), ++gu32_app_sendto_que7_ok);
            break;
        }
        case 8:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 8), ++gu32_app_sendto_que8_ok);
            break;
        }
        case 9:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 9), ++gu32_app_sendto_que9_ok);
            break;
        }
        case 10:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 10), ++gu32_app_sendto_que10_ok);
            break;
        }
        case 11:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 11), ++gu32_app_sendto_que11_ok);
            break;
        }
        default:
        {
            break;
        }
    }
#endif
    return ret_queue;
}

int32_t osp_send_msg_oam(uint32_t msg_addr,
                         uint32_t msg_len,
                         uint8_t  msg_type,
                         uint8_t  src_core_id,
                         uint8_t  dst_core_id,
                         uint8_t  src_task_id,
                         uint8_t  dst_task_id)
{
    ecs_msg_head *pmsg_head = NULL;
    ecs_msg_head st_msg_head;
    int32_t  ret_queue = -1;

#ifdef APP_PALLADIUM_TEST
    g_ecs_app_debug_info.ecs_msg_send_num++;
    int32_t core_id = get_core_id();
#endif
    pmsg_head = (ecs_msg_head*)((uint32_t)msg_addr - (uint32_t)ECS_MSG_HEAD_LEN);
    st_msg_head.msg_size = msg_len;
    //st_msg_head.msg_type = ;
    st_msg_head.msg_type_oam = msg_type; 
    st_msg_head.src_core_id = src_core_id;
    st_msg_head.dst_core_id = dst_core_id;
    st_msg_head.src_task_id = src_task_id;
    st_msg_head.dst_task_id = dst_task_id;

    memcpy_ucp((void*)pmsg_head, (void*)&st_msg_head, ECS_MSG_HEAD_LEN);

    ret_queue = smart_in_que(dst_core_id, msg_addr);
    if (0 != ret_queue)
    {
        UCP_PRINT_ERROR("ecs_send_msg: error(smart_in_que) que_id = 0x%08x addr = 0x%08x\r\n", dst_core_id, msg_addr);
#ifdef APP_PALLADIUM_TEST
        g_ecs_app_debug_info.ecs_msg_InQue_err++;
        debug_write(DBG_DDR_COMMON_IDX(core_id, 13), g_ecs_app_debug_info.ecs_msg_InQue_err);
        debug_write(DBG_DDR_ERR_IDX(core_id, 19), ret_queue);
#endif

#ifdef UCP_OSP_DBG_HW_CNT_ENABLE
        switch (dst_core_id)
        {
            case 0:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 12), ++gu32_app_sendto_que0_ng);
                break;
            }
            case 1:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 13), ++gu32_app_sendto_que1_ng);
                break;
            }
            case 2:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 14), ++gu32_app_sendto_que2_ng);
                break;
            }
            case 3:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 15), ++gu32_app_sendto_que3_ng);
                break;
            }
            case 4:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 16), ++gu32_app_sendto_que4_ng);
                break;
            }
            case 5:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 17), ++gu32_app_sendto_que5_ng);
                break;
            }
            case 6:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 18), ++gu32_app_sendto_que6_ng);
                break;
            }
            case 7:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 19), ++gu32_app_sendto_que7_ng);
                break;
            }
            case 8:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 20), ++gu32_app_sendto_que8_ng);
                break;
            }
            case 9:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 21), ++gu32_app_sendto_que9_ng);
                break;
            }
            case 10:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 22), ++gu32_app_sendto_que10_ng);
                break;
            }
            case 11:
            {
                debug_write(OSP_DEBUG_HW_POT(core_id, 23), ++gu32_app_sendto_que11_ng);
                break;
            }
            default:
            {
                break;
            }
        }
#endif
    }
#ifdef APP_PALLADIUM_TEST
    debug_write(DBG_DDR_COMMON_IDX(core_id, 14), g_ecs_app_debug_info.ecs_msg_send_num);
#endif

#ifdef UCP_OSP_DBG_HW_CNT_ENABLE
    switch (dst_core_id)
    {
        case 0:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 0), ++gu32_app_sendto_que0_ok);
            break;
        }
        case 1:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 1), ++gu32_app_sendto_que1_ok);
            break;
        }
        case 2:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 2), ++gu32_app_sendto_que2_ok);
            break;
        }
        case 3:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 3), ++gu32_app_sendto_que3_ok);
            break;
        }
        case 4:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 4), ++gu32_app_sendto_que4_ok);
            break;
        }
        case 5:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 5), ++gu32_app_sendto_que5_ok);
            break;
        }
        case 6:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 6), ++gu32_app_sendto_que6_ok);
            break;
        }
        case 7:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 7), ++gu32_app_sendto_que7_ok);
            break;
        }
        case 8:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 8), ++gu32_app_sendto_que8_ok);
            break;
        }
        case 9:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 9), ++gu32_app_sendto_que9_ok);
            break;
        }
        case 10:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 10), ++gu32_app_sendto_que10_ok);
            break;
        }
        case 11:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 11), ++gu32_app_sendto_que11_ok);
            break;
        }
        default:
        {
            break;
        }
    }
#endif

    return ret_queue;
}

uint8_t ecs_hw_que_get_info(uint8_t que_id, uint32_t* pmsg_addr, uint32_t* pmsg_size)
{
    int ret = -1;
    uint32_t u32addr = 0;
#ifdef APP_PALLADIUM_TEST
    int32_t core_id = get_core_id();
#endif

    /* 查询是否有数据 */
    ret = smart_que_is_empty(que_id);
    if (0 != ret)
    {
#ifdef APP_PALLADIUM_TEST
        g_ecs_app_debug_info.ecs_msg_get_info_empty_num++;
        debug_write(DBG_DDR_COMMON_IDX(core_id, 15), g_ecs_app_debug_info.ecs_msg_get_info_empty_num);
#endif
        return 1;   /* 无数据 */
    }
    /* 取出数据 */
    ret = smart_out_que(que_id, &u32addr);
    if (0 != ret)
    {
#ifdef APP_PALLADIUM_TEST
        g_ecs_app_debug_info.ecs_msg_get_info_OutQue_err++;
        debug_write(DBG_DDR_COMMON_IDX(core_id, 16), g_ecs_app_debug_info.ecs_msg_get_info_OutQue_err);
#endif
        return 2;   /* 取不出数据 */
    }

    ecs_msg_head *pmsg_head = NULL;
    uint32_t u32msg_size    = 0;
    pmsg_head = (ecs_msg_head*)((uint32_t)u32addr - (uint32_t)ECS_MSG_HEAD_LEN);
    u32msg_size = do_read((char*)(&pmsg_head->msg_size));
    *pmsg_addr = u32addr;
    *pmsg_size = u32msg_size;

#ifdef UCP_OSP_DBG_HW_CNT_ENABLE
    uint8_t src_core_id = do_read_byte((char*)(&pmsg_head->src_core_id));
    //__ucps2_synch(0);

    switch (src_core_id)
    {
        case 0:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 24), ++gu32_app_recv_que0);
            break;
        }
        case 1:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 25), ++gu32_app_recv_que1);
            break;
        }
        case 2:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 26), ++gu32_app_recv_que2);
            break;
        }
        case 3:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 27), ++gu32_app_recv_que3);
            break;
        }
        case 4:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 28), ++gu32_app_recv_que4);
            break;
        }
        case 5:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 29), ++gu32_app_recv_que5);
            break;
        }
        case 6:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 30), ++gu32_app_recv_que6);
            break;
        }
        case 7:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 31), ++gu32_app_recv_que7);
            break;
        }
        case 8:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 32), ++gu32_app_recv_que8);
            break;
        }
        case 9:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 33), ++gu32_app_recv_que9);
            break;
        }
        case 10:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 34), ++gu32_app_recv_que10);
            break;
        }
        case 11:
        {
            debug_write(OSP_DEBUG_HW_POT(core_id, 35), ++gu32_app_recv_que11);
            break;
        }
        default:
        {
            break;
        }
    }
#endif


#ifdef APP_PALLADIUM_TEST
    g_ecs_app_debug_info.ecs_msg_get_info_num++;
    debug_write(DBG_DDR_COMMON_IDX(core_id, 17), g_ecs_app_debug_info.ecs_msg_get_info_num);
#endif

    return 0;
}


