/* linearite.c
Vérifie par le calcul la propriété 
tGFSR32x4(A^B) = tGFSR32x4(A) ^ tGFSR32x4(B)  */

#include <stdio.h>

typedef unsigned long long int U64;
typedef unsigned int U32;
typedef   signed int S32;
typedef unsigned char U8;

U64 cycles=0;

#define CRC32_standard  0x04C11DB7UL

#define GFSR_MACRO2(current, last) { \
  S32 t;                             \
  current^=last;                     \
  t=((signed int)current) >> 31;     \
  current<<=1;                       \
  current^=t & CRC32_standard;  }

#define MACRO_tGFSR32x4_SHFT(current, last, ptr) \
  current ^= last;        \
  current ^= ptr;         \
  t = current;            \
  current >>= 1;          \
  t &= 0x01010101;        \
  current &= 0x7F7F7F7F;  \
  t <<= 4;                \
  current ^= t;           \
  t <<= 3;                \
  current ^= t;

/* génère des valeurs pseudo-aléatoires puis les signe
   Les deux premiers octets sont A et B
   Le troisième est A^B */

#define MACRO_TEST(U,V)                      \
    GFSR_MACRO2(g##U, g##V)                  \
    t=(g##U & 0xFFFF) |                      \
      (((g##U<<16) ^ (g##U<<8)) & 0xFF0000); \
    MACRO_tGFSR32x4_SHFT(r##U, r##V, t)      \
    t=(r##U>>16) ^ (((r##U>>8)^r##U)&255);   \
    if (t) {                                 \
      printf("Erreur au cycle %lld : %X\n",  \
            cycles,t);                       \
      return -1;                             \
    }

int main() {
/* état initial du tGFSR de signature */
  U32 r0= (0x8f0a | ((0x8f ^ 0x0a)<<16)),
      r1= (0xac5b | ((0xac ^ 0x5b)<<16)),
      r2= (0xdbb0 | ((0xdb ^ 0xb0)<<16)),
      r3= (0x5d38 | ((0x5d ^ 0x38)<<16)), t;
/* état initial du tGFSR de génération */
  U32 g0=0x81b68d18, g1=0x14441139,
      g2=0x912a6300, g3=0x4ad95b66;

  do {
    MACRO_TEST(0, 3)
    MACRO_TEST(1, 0)
    MACRO_TEST(2, 1)
    MACRO_TEST(3, 2)

    cycles++;
    if ((cycles & ((1UL<<24)-1)) == 0 ) {
      printf("%lld%c",cycles,0xD);
      fflush(stdout);
    }
  } while (1);

  return r0^t;
}
