#ifndef GLOBALS
#define GLOBALS 1

#ifndef NFACTOR
#define NFACTOR 10
#endif

#if NFACTOR == 1
#  define __NF__ 2u
#elif NFACTOR == 2
# define __NF__ 4u
#elif NFACTOR == 3
#  define __NF__ 8u
#elif NFACTOR == 4
#  define __NF__ 16u
#elif NFACTOR == 5
#  define __NF__ 32u
#elif NFACTOR == 6
#  define __NF__ 64u
#elif NFACTOR == 7
#  define __NF__ 128u
#elif NFACTOR == 8
#  define __NF__ 256u
#elif NFACTOR == 9
#  define __NF__ 512u
#elif NFACTOR == 10
#  define __NF__ 1024u
#elif NFACTOR == 11
#  define __NF__ 2048u
#elif NFACTOR == 12
#  define __NF__ 4096u
#elif NFACTOR == 13
#  define __NF__ 8192u
#elif NFACTOR == 14
#  define __NF__ 16384u
#elif NFACTOR == 15
#  define __NF__ 32768u
#elif NFACTOR == 16
#  define __NF__ 65536u
#elif NFACTOR == 17
#  define __NF__ 131072u
#elif NFACTOR == 18
#  define __NF__ 262144u
#elif NFACTOR == 19
#  define __NF__ 524288u
#elif NFACTOR == 20
#  define __NF__ 1048576u
#else
# define __NF__ 1024u
#endif

#define DEFNFACTOR(n) \
	const uint n = __NF__;

//	const uint n = (__NF__/LOOKUP_GAP+(__NF__%LOOKUP_GAP>0));


#define E0 0x00FF00FFU
#define E1 0xFF00FF00U

__constant uint K[] = {
	0x428a2f98U,
	0x71374491U,
	0xb5c0fbcfU,
	0xe9b5dba5U,
	0x3956c25bU,
	0x59f111f1U,
	0x923f82a4U,
	0xab1c5ed5U,
	0xd807aa98U,
	0x12835b01U,
	0x243185beU, // 10
	0x550c7dc3U,
	0x72be5d74U,
	0x80deb1feU,
	0x9bdc06a7U,
	0xe49b69c1U,
	0xefbe4786U,
	0x0fc19dc6U,
	0x240ca1ccU,
	0x2de92c6fU,
	0x4a7484aaU, // 20
	0x5cb0a9dcU,
	0x76f988daU,
	0x983e5152U,
	0xa831c66dU,
	0xb00327c8U,
	0xbf597fc7U,
	0xc6e00bf3U,
	0xd5a79147U,
	0x06ca6351U,
	0x14292967U, // 30
	0x27b70a85U,
	0x2e1b2138U,
	0x4d2c6dfcU,
	0x53380d13U,
	0x650a7354U,
	0x766a0abbU,
	0x81c2c92eU,
	0x92722c85U,
	0xa2bfe8a1U,
	0xa81a664bU, // 40
	0xc24b8b70U,
	0xc76c51a3U,
	0xd192e819U,
	0xd6990624U,
	0xf40e3585U,
	0x106aa070U,
	0x19a4c116U,
	0x1e376c08U,
	0x2748774cU,
	0x34b0bcb5U, // 50
	0x391c0cb3U,
	0x4ed8aa4aU,
	0x5b9cca4fU,
	0x682e6ff3U,
	0x748f82eeU,
	0x78a5636fU,
	0x84c87814U,
	0x8cc70208U,
	0x90befffaU,
	0xa4506cebU, // 60
	0xbef9a3f7U,
	0xc67178f2U,
	0x98c7e2a2U,
	0xfc08884dU,
	0xcd2a11aeU,
	0x510e527fU,
	0x9b05688cU,
	0xC3910C8EU,
	0xfb6feee7U,
	0x2a01a605U, // 70
	0x0c2e12e0U,
	0x4498517BU,
	0x6a09e667U,
	0xa4ce148bU,
	0x95F61999U,
	0xc19bf174U,
	0xBB67AE85U,
	0x3C6EF372U,
	0xA54FF53AU,
	0x1F83D9ABU, // 80
	0x5BE0CD19U
};


/*
	0x5C5C5C5CU,
	0x36363636U,
	0x80000000U,
//	0x000003FFU, //never used
	0x00000280U,
	0x000004a0U,
	0x00000300U
};
*/

#define FOURdeclare(myvar, v1, v2, v3, v4) uint myvar ## 1 = v1; \
                                           uint myvar ## 2 = v2; \
                                           uint myvar ## 3 = v3; \
                                           uint myvar ## 4 = v4;

#define FOURassign(myvar, v1, v2, v3, v4) myvar ## 1 = v1; \
                                          myvar ## 2 = v2; \
                                          myvar ## 3 = v3; \
                                          myvar ## 4 = v4;

#define FOURcopy(var1, var2) var1 ## 1 = var2 ## 1; \
                             var1 ## 2 = var2 ## 2; \
                             var1 ## 3 = var2 ## 3; \
                             var1 ## 4 = var2 ## 4;

#define FOURtovec(var1, var2) var1.x = var2 ## 1; \
                              var1.y = var2 ## 2; \
                              var1.z = var2 ## 3; \
                              var1.w = var2 ## 4;

#define FOURfromvec(var1, var2) var1 ## 1 = var2.x; \
                                var1 ## 2 = var2.y; \
                                var1 ## 3 = var2.z; \
                                var1 ## 4 = var2.w;

#define UNROLL_FACTOR 2


#define rotl(x,y) rotate(x,y)
#define Ch(x,y,z) bitselect(z,y,x)
#define Maj(x,y,z) Ch((x^z),y,z)

#define EndianSwapa(n) (Ch(E0, rotl(n, 8U), rotl(n, 24U)))
#define EndianSwapb(n) (rotl(n & E0, 24U)|rotl(n & E1, 8U))

#define Tr2(x)		(rotl(x, 30U) ^ rotl(x, 19U) ^ rotl(x, 10U))
#define Tr1(x)		(rotl(x, 26U) ^ rotl(x, 21U) ^ rotl(x, 7U))
#define Wr2(x)		(rotl(x, 25U) ^ rotl(x, 14U) ^ (x>>3U))
#define Wr1(x)		(rotl(x, 15U) ^ rotl(x, 13U) ^ (x>>10U))

#define RND(a, b, c, d, e, f, g, h, k)  \
	h += Tr1(e); 			\
	h += Ch(e, f, g); 		\
	h += k;				\
	d += h;				\
	h += Tr2(a); 			\
	h += Maj(a, b, c);

//#define zSIZE 8
//#define Coord(x,y,z) z+(x<<3)+((uint)(y*CONCURRENT_THREADS)<<3)
//#define Coord(x,y,z) (x<<3)+((y<<3)*CONCURRENT_THREADS)+z
//#define Coord(x,y,z) x*(z ## SIZE)+y*(CONCURRENT_THREADS)*(z ## SIZE)+z
#define Coord(x,y,z) x*(z ## SIZE)+y*(x ## SIZE)*(z ## SIZE)+z
#define CO Coord(x,y,z)

//#define Coord(x,y,z) x+y*(x ## SIZE)+z*(y ## SIZE)*(x ## SIZE)
//#define CO Coord(z,x,y)

__constant uint fixedWa[8] = {0x428a2f99,0xd807aa98,0xf59b89c2,0xb707775c,0xad87a3ea,0xc91b1417,0xe64fb6a2,0xe0a1adbe};
__constant uint fixedWb[8] = {0xf1374491,0x12835b01,0x73924787,0x0468c23f,0xbcb1d3a3,0xc359dce1,0xe84d923a,0x7c728e11};
__constant uint fixedWc[8] = {0xb5c0fbcf,0x243185be,0x23c6886e,0xe7e72b4c,0x7b993186,0xa83253a7,0xe93a5730,0x511c78e4};
__constant uint fixedWd[8] = {0xe9b5dba5,0x550c7dc3,0xa42ca65c,0x49e1f1a2,0x562b9420,0x3b13c12d,0x09837686,0x315b45bd};
__constant uint fixedWe[8] = {0x3956c25b,0x72be5d74,0x15ed3627,0x4b99c816,0xbff3ca0c,0x9d3d725d,0x078ff753,0xfca71413};
__constant uint fixedWf[8] = {0x59f111f1,0x80deb1fe,0x4d6edcbf,0x926d1570,0xda4b0c23,0xd9031a84,0x29833341,0xea28f96a};
__constant uint fixedWg[8] = {0x923f82a4,0x9bdc06a7,0xe28217fc,0xaa0fc072,0x6cd8711a,0xb1a03340,0xd5de0b7e,0x79703128};
__constant uint fixedWh[8] = {0xab1c5ed5,0xc19bf794,0xef02488f,0xadb36e2c,0x8f337caa,0x16f58012,0x6948ccf4,0x4e1ef848};
__constant uint sK[6] = {
    0x5C5C5C5CU, //82
    0x36363636U,
    0x80000000U,
//  0x000003FFU, //never used
    0x00000280U,
    0x000004a0U,
    0x00000300U
};

#define FOUND (0xFF)
#define SETFOUND(Xnonce) output[output[FOUND]++] = Xnonce

#endif