/*
fichier crc16-32.c
créé le 21 février 2007 par Yann Guidon - whygee@f-cpu.org

principe : 4 tGFSR parallèles de 4x8 bits, poly=144

    5592405 itérations pour MMUL=142/150/166/178/180/198 et 3 registres
  286260975 itérations pour MMUL=128+(7/16/41)=144 et 4 registres,
      ( quelle que soit la valeur signée )
*/

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>

#define INIT 67

#ifndef MMUL
  #define MMUL (128|16)
#endif

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

#define MACRO_CRC16_32_C_MUL(current, last, ptr) \
  current ^= last;        \
  current ^= ptr;         \
  t = current;            \
  current >>= 1;          \
  t &= 0x01010101;        \
  current &= 0x7F7F7F7F;  \
  t *= MMUL;              \
  current ^= t;

#ifndef MACRO_CRC16_32
#define MACRO_CRC16_32 MACRO_CRC16_32_C_SHL
#endif

int dummy[4];

volatile unsigned long int compteur;
volatile int flag;

int test_CRC32_SHL(int *p) {
  register unsigned int
   r0=0, r1=0, r2=0, r3=INIT, t;

  do {
    MACRO_CRC16_32_C_SHL(r0, r3, p[0])
    MACRO_CRC16_32_C_SHL(r1, r0, p[1])
    MACRO_CRC16_32_C_SHL(r2, r1, p[2])
    MACRO_CRC16_32_C_SHL(r3, r2, p[3])
/*    p=(int *) ((((long)p)+4) & -4); */
    compteur++;
  } while (!flag);

  return r0+r1+r2+r3; /* empêche l'optimiseur d'effacer le code */
}

int test_CRC32_MUL(int *p) {
  register unsigned int
   r0=0, r1=0, r2=0, r3=INIT, t;

  do {
    MACRO_CRC16_32_C_MUL(r0, r3, p[0])
    MACRO_CRC16_32_C_MUL(r1, r0, p[1])
    MACRO_CRC16_32_C_MUL(r2, r1, p[2])
    MACRO_CRC16_32_C_MUL(r3, r2, p[3])
/*    p=(int *) ((((long)p)+4) & -4);*/
    compteur++;
  } while (!flag);

  return r0+r1+r2+r3; /* empêche l'optimiseur d'effacer le code */
}

void timer_handler(int i) {
  flag=i;  
}


int main() {
  unsigned long long int t;
  struct itimerval itv;
  itv.it_interval.tv_sec=0;
  itv.it_interval.tv_usec=0;
  itv.it_value.tv_sec=4;
  itv.it_value.tv_usec=0;

  signal(SIGVTALRM,timer_handler);

/* test avec la version à décalages */
  compteur=0;
  flag=0;
  printf("Mesure de vitesse : 4 secondes avec code à décalage\n");  
  fflush(stdout);
  
  setitimer(ITIMER_VIRTUAL,&itv,NULL);
  test_CRC32_SHL(dummy);
  t=compteur;
  t<<=2;
  printf("%lld octets par seconde\n",t);


/* test avec la version à multiplications */
  compteur=0;
  flag=0;
  printf("Mesure de vitesse : 4 secondes avec code à multiplication\n");  
  fflush(stdout);
  
  setitimer(ITIMER_VIRTUAL,&itv,NULL);
  test_CRC32_MUL(dummy);
  t=compteur;
  t<<=2;
  printf("%lld octets par seconde\n",t);

  return 0;
}
/*gcc -W -Wall -march=pentium3 -Os -fomit-frame-pointer -o time_crc16-32 time_crc16-32.c && ./time_crc16-32  */
