/*************************************************************************
* Copyright (C) 2019 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.
*************************************************************************/

#ifndef STATUS_H
#define STATUS_H

#include <crypto_mb/defs.h>

typedef int32u mbx_status;
typedef int64u mbx_status16;

// error statuses and manipulators
#define MBX_STATUS_OK                  (0)
#define MBX_STATUS_MISMATCH_PARAM_ERR  (1)
#define MBX_STATUS_NULL_PARAM_ERR      (2)
#define MBX_STATUS_LOW_ORDER_ERR       (4)
#define MBX_STATUS_SIGNATURE_ERR       (8)
#define MBX_STATUS_UNSUPPORTED_ISA_ERR (10)

__MBX_INLINE mbx_status MBX_SET_STS(mbx_status status, int numb, mbx_status sttVal)
{
    numb &= 7; /* 0 <= numb < 8 */
    status &= (mbx_status)(~(0xF << (numb * 4)));
    return status |= (sttVal & 0xF) << (numb * 4);
}

__MBX_INLINE mbx_status MBX_GET_STS(mbx_status status, int numb)
{
    return (status >> (numb * 4)) & 0xF;
}

// Construct mb8 mbx_status from _lo and _hi mb4 statuses
__MBX_INLINE mbx_status MBX_COMBINE_STS_MB4(mbx_status status_lo, mbx_status status_hi)
{
    return status_lo | ((status_hi << 4 * 4) & 0xFFFF0000);
}

__MBX_INLINE mbx_status MBX_SET_STS_ALL(mbx_status stsVal)
{
    return (stsVal << 4 * 7) | (stsVal << 4 * 6) | (stsVal << 4 * 5) | (stsVal << 4 * 4) |
           (stsVal << 4 * 3) | (stsVal << 4 * 2) | (stsVal << 4 * 1) | stsVal;
}

__MBX_INLINE mbx_status MBX_SET_STS_BY_MASK(mbx_status status, int8u mask, mbx_status sttVal)
{
    int numb;

    for (numb = 0; numb < 8; numb++) {
        mbx_status buf_stt = ((mbx_status)(0 - ((mask >> numb) & 1)) & sttVal);
        status             = MBX_SET_STS(status, numb, buf_stt);
    }
    return status;
}

__MBX_INLINE int MBX_IS_ANY_0_TO_3_OK_STS(const mbx_status status)
{
    const int ret =
        MBX_STATUS_OK == MBX_GET_STS(status, 0) || MBX_STATUS_OK == MBX_GET_STS(status, 1) ||
        MBX_STATUS_OK == MBX_GET_STS(status, 2) || MBX_STATUS_OK == MBX_GET_STS(status, 3);
    return ret;
}

__MBX_INLINE int MBX_IS_ANY_4_TO_7_OK_STS(const mbx_status status)
{
    const int ret =
        MBX_STATUS_OK == MBX_GET_STS(status, 4) || MBX_STATUS_OK == MBX_GET_STS(status, 5) ||
        MBX_STATUS_OK == MBX_GET_STS(status, 6) || MBX_STATUS_OK == MBX_GET_STS(status, 7);
    return ret;
}

__MBX_INLINE int MBX_IS_ANY_OK_STS(mbx_status status)
{
    const int ret = MBX_IS_ANY_0_TO_3_OK_STS(status) || MBX_IS_ANY_4_TO_7_OK_STS(status);
    return (int)ret;
}

/*
// Helpers for 64-bit status mbx_status16
*/

/* Accessors for the low and high part of 64-bit status */
__MBX_INLINE mbx_status MBX_GET_HIGH_PART_STS16(mbx_status16 status16)
{
    return ((mbx_status)(((mbx_status16)(status16) >> 32) & 0xFFFFFFFF));
}

__MBX_INLINE mbx_status MBX_GET_LOW_PART_STS16(mbx_status16 status16)
{
    return ((mbx_status)(status16));
}

__MBX_INLINE mbx_status16 MBX_SET_STS16_ALL(mbx_status16 stsVal)
{
    return (stsVal << 4 * 15) | (stsVal << 4 * 14) | (stsVal << 4 * 13) | (stsVal << 4 * 12) |
           (stsVal << 4 * 11) | (stsVal << 4 * 10) | (stsVal << 4 * 9) | (stsVal << 4 * 8) |
           (stsVal << 4 * 7) | (stsVal << 4 * 6) | (stsVal << 4 * 5) | (stsVal << 4 * 4) |
           (stsVal << 4 * 3) | (stsVal << 4 * 2) | (stsVal << 4 * 1) | stsVal;
}

__MBX_INLINE mbx_status16 MBX_SET_STS16(mbx_status16 status, int numb, mbx_status16 sttVal)
{
    numb &= 15; /* 0 <= numb < 16 */
    status &= (mbx_status16)(~((int64u)0xF << (numb * 4)));
    return status |= (sttVal & 0xF) << (numb * 4);
}

__MBX_INLINE mbx_status16 MBX_SET_STS16_BY_MASK(mbx_status16 status,
                                                int16u mask,
                                                mbx_status16 sttVal)
{
    int numb;
    for (numb = 0; numb < 16; numb++) {
        mbx_status16 buf_stt = (mbx_status16)((0 - ((mask >> numb) & 1))) & sttVal;
        status               = MBX_SET_STS16(status, numb, buf_stt);
    }
    return status;
}

__MBX_INLINE int MBX_IS_ANY_OK_STS16(mbx_status16 status)
{
    return MBX_IS_ANY_OK_STS(MBX_GET_HIGH_PART_STS16(status)) ||
           MBX_IS_ANY_OK_STS(MBX_GET_LOW_PART_STS16(status));
}

#endif /* STATUS_H */
