/*
 * oclh_hd_squad.clh
 *      Author: havock
 */
#ifndef _OCLH_OCL_COMPILER_
#define __global
#define __private
#define __kernel
#endif /* _OCLH_OCL_COMPILER_ */

#ifndef OPENCL_INC_OCLH_SQUAD_COMMON_HEADER_CLH_DECLS_
#define OPENCL_INC_OCLH_SQUAD_COMMON_HEADER_CLH_DECLS_ 1

#if defined(_OCLH_OCL_HOST_HEADERS_) || defined(_OCLH_OCL_COMPILER_)
#pragma pack(push,1)
typedef struct _SQT_SQUAD_VARIABLES {
    int32_t  i32Cmd; /* command */
    uint32_t u32Cnt; /* counter of begun tasks, used as task index */
    __global volatile uint32_t* pu32RptVals;
} _SQT_SQUAD_VARS;
#pragma pack(pop)
#endif /* defined(_OCLH_OCL_HOST_HEADERS_) || defined(_OCLH_OCL_COMPILER_) */

#ifdef _OCLH_OCL_COMPILER_

#define _SQCMD_DISMISS  (-1)
#define _SQCMD_WAIT     0

#pragma pack(push,1)
typedef struct _SQT_REPORT_BIT_AND_DATA {
    uint64_t u64ValIdx;
    uint64_t u64NofVals;
    uint32_t u32Bit;
    uint32_t u32FullVal;
    uint32_t u32LastFullVal;
} _SQT_RPT_BIT_N_DAT;
typedef struct _SQT_TROOPER_TECHNICAL_DATA {
              uint64_t u64MSN;      /* Military Service Number,
                                       the unique overall trooper index */
              uint64_t u64Role;     /* trooper index in squad */
              uint64_t u64SquadNum; /* squad index */
              uint64_t u64RegSz;    /* number of one squad */
              uint64_t u64TrBufSzB; /* size of a trooper memory in bytes */
    __global  uint8_t* pu8TrBuf;    /* pointer to a trooper memory in bytes */
    __global  uint8_t* pu8SqZeroBuf;/* pointer to memory
                                       of the zeroth trooper in squad */
    _SQT_RPT_BIT_N_DAT RptBitNDat;
} _SQT_TROOPER_TECHDAT;
#pragma pack(pop)

_SQT_TROOPER_TECHDAT _sqf_declPersRecWith(
    __private const uint64_t u64MSN,
    __private const uint64_t u64RegSz,
    __global  uint8_t* const d_pu8TrooperBuf,
    __private const uint64_t u64TrBufSzB);
int32_t _sqf_giveCmdNRstRpt(
    __global _SQT_SQUAD_VARS* const pSqDat,
    __private const _SQT_RPT_BIT_N_DAT RptBitNDat,
    __private const int32_t i32Cmd);
uint32_t _sqf_setPrivSeqBitToOneLE32(__private const uint64_t u64N);
int32_t _sqf_getRptBit(
    __global const _SQT_SQUAD_VARS* const pSqDat,
    __private _SQT_RPT_BIT_N_DAT RptBitNDat);
int32_t _sqf_setBitToOne(
    __global volatile uint32_t* pu32RptVals,
    __private const _SQT_RPT_BIT_N_DAT RptBitNDat);

#endif /* _OCLH_OCL_COMPILER_ */
#endif /* OPENCL_INC_OCLH_SQUAD_COMMON_HEADER_CLH_DECLS_ */

#ifdef _OCLH_OCL_COMPILER_
#ifndef OPENCL_INC_OCLH_SQUAD_COMMON_HEADER_CLH_IMPLS_
#define OPENCL_INC_OCLH_SQUAD_COMMON_HEADER_CLH_IMPLS_ 1

_SQT_TROOPER_TECHDAT _sqf_declPersRecWith(
    __private const uint64_t u64MSN,
    __private const uint64_t u64RegSz,
    __global uint8_t* const d_pu8TrooperBuf,
    __private const uint64_t u64TrBufSzB) {
    _SQT_TROOPER_TECHDAT PersRec;
    PersRec.u64MSN=u64MSN;
    PersRec.u64RegSz=u64RegSz;
    PersRec.u64Role=u64MSN%u64RegSz;
    PersRec.u64SquadNum=u64MSN/u64RegSz;
    PersRec.pu8SqZeroBuf=
        &d_pu8TrooperBuf[PersRec.u64SquadNum*u64TrBufSzB*u64RegSz];
    PersRec.pu8TrBuf=&d_pu8TrooperBuf[u64MSN*u64TrBufSzB];
    PersRec.u64TrBufSzB	=u64TrBufSzB;
    {
        PersRec.RptBitNDat.u64NofVals=
            (u64RegSz%32)?((u64RegSz/32)+1):(u64RegSz/32);
        PersRec.RptBitNDat.u64ValIdx=PersRec.u64Role/32;
        PersRec.RptBitNDat.u32Bit=
            _sqf_setPrivSeqBitToOneLE32(PersRec.u64Role%32);
        PersRec.RptBitNDat.u32FullVal=0;
        PersRec.RptBitNDat.u32FullVal=(~(PersRec.RptBitNDat.u32FullVal));
        PersRec.RptBitNDat.u32LastFullVal=0;
        if(u64RegSz%32) {
            uint64_t i=0;
            for(i=0;i<(u64RegSz%32);i++)
                PersRec.RptBitNDat.u32LastFullVal=
                    PersRec.RptBitNDat.u32LastFullVal^
                        _sqf_setPrivSeqBitToOneLE32(i);
        } else PersRec.RptBitNDat.u32LastFullVal=PersRec.RptBitNDat.u32FullVal;
    }
    return(PersRec);
}

int32_t _sqf_giveCmdNRstRpt(
    __global _SQT_SQUAD_VARS* const pSqDat,
    __private const _SQT_RPT_BIT_N_DAT RptBitNDat,
    __private const int32_t i32Cmd) {
    __private uint64_t i=0;
    atomic_xchg(&pSqDat->i32Cmd,i32Cmd);
    atomic_xchg(&pSqDat->u32Cnt,0);
    for(i=0;i<RptBitNDat.u64NofVals;i++)
        atomic_xchg(&pSqDat->pu32RptVals[i],0);
    return(0);
}

uint32_t _sqf_setPrivSeqBitToOneLE32(__private const uint64_t u64N) {
    __private uint32_t u32NewS=0;
    __private uint8_t* pu8B=&(((__private uint8_t*) &u32NewS)[u64N/8]);
    *pu8B=1<<(u64N%8);
    return(u32NewS);
}

int32_t _sqf_getRptBit(
    __global const _SQT_SQUAD_VARS* const pSqDat,
    __private _SQT_RPT_BIT_N_DAT	RptBitNDat) {
    __private uint32_t u32Val;
    u32Val=pSqDat->pu32RptVals[RptBitNDat.u64ValIdx];
    if((u32Val & RptBitNDat.u32Bit)==0) return(0);
    else return(1);
}

int32_t _sqf_setBitToOne(
    __global volatile uint32_t* pu32RptVals,
    __private const _SQT_RPT_BIT_N_DAT RptBitNDat) {
    atomic_or(&pu32RptVals[RptBitNDat.u64ValIdx],RptBitNDat.u32Bit);
    return(0);
}

#endif /* OPENCL_INC_OCLH_SQUAD_COMMON_HEADER_CLH_IMPLS_ */
#endif /* _OCLH_OCL_COMPILER_ */
