/*
   fichier test_crc16-64.c
   version du 16 janvier 2007 :
     portage sous UltraSparc, separation du banc de test

   compiler avec :
   $ gcc -Os -W -Wall -momit-leaf-frame-pointer -fomit-frame-pointer \
        -ansi -march=pentium3 test_compaction.c
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "def64.h"
#include "lfsr4.c" /* genere la table de constantes à signer */

/* Directives de vorbosage */
/* à définir à la compilation, en ligne de commande
#define PRINTCRC
#define PRINTLFSR
#define PRINTCRC2
#define TESTS_TABLE
*/

#ifndef TAILLE_CST
#define TAILLE_CST 5000
#endif

void print_table(U64 *t); /* prototype */
#include "crc16-64.c"

/* Quelques fonctions utiles... */

void print_table(U64 *t) {
  int i;
  for (i=0; i<16; i+=4) {
    printf("%016llX %016llX %016llX %016llX\n",
    t[i], t[i+1], t[i+2], t[i+3]);
  }
  printf("\n");
}

/* effectue la rotation inverse pour
 faciliter les comparaisons de signatures */
void rotate_registers(int rotr) {
  int j, rotl;
  U64 a,b;
  U64 t[16];

  if (rotr!=0) {
    rotr<<=3;
    rotl=64-rotr;

    for (j=0; j<16; j++) {
      a=CRC16_64_table[j];
      b=CRC16_64_table[(j+1)&15];
      t[j]= LOCAL_SHRr(a,rotr) | LOCAL_SHLr(b,rotl);
    }
    memcpy(CRC16_64_table,t,16*8);
  }
}

U8 constant_block[TAILLE_CST];

void init_LFSR() {
  unsigned int i;
  for (i=0; i<sizeof(constant_block); i++)
#ifndef PRINTLFSR
    constant_block[i] = (lfsr4() << 4) | lfsr4();
#else
    printf("%02X", constant_block[i] = (lfsr4() << 4) | lfsr4());
  printf("\n\n");
#endif
}

int main() {

#ifndef test_unalignedCRC16
  /* vérifie que aligned_CRC16_64() et unaligned_CRC16_64() sont équivalents,
   par un test exhaustif de tous les alignement et de toutes les tailles */
  U64 tmp_reg[16];
  unsigned int i, j=0;
  unsigned char *c=calloc(sizeof(constant_block)+10,1);

  init_LFSR();

  rotation_table(); /* initialise les 8 rotations */

  /* boucle en taille */
  do {
    j+=1;
    #ifdef PRINTCRC
      printf("\n -- taille=%d\n",j);
    #endif
    aligned_CRC16_64(j,(void*)(&constant_block[0]));
    memcpy(tmp_reg, CRC16_64_table, 16*8);

    /* boucle en alignement */
    for (i=0; i<8; i++) {
      #ifdef PRINTCRC
        printf("\n* taille=%d, alignement=%d\n",j,i);
      #endif
      memcpy(c+i, constant_block,j);
      unaligned_CRC16_64(j,c+i);
      rotate_registers(i); /* compense l'alignement */
      if (memcmp(CRC16_64_table, tmp_reg, 16*8))
      { 
        printf("\n##### erreur pour taille=%d, alignement=%d\n",j, i);
        printf("table originale :\n");
        print_table(tmp_reg);
        printf("table recalculée :\n");
        print_table(CRC16_64_table);
        return -1;
      }
    }
  } while (j<sizeof(constant_block));
  printf("\nOK\n");

#endif

#ifdef test_aligned

LE RESTE EST POURRI ET VIEUX, IL RESTE LA EN CAS DE REGRESSION

  /* vérifie que aligned_CRC16_64() et aligned_CRC16_64_2() sont équivalents */

  U64 tmp_reg[16];
  int i=42000*8*16, /* taille du bloc à tester */
      j=0;
  char *c=calloc(i+15,1);

  do {
    j+=128;
    aligned_CRC16_64(j,(void*)(&constant_block[0]));
    memcpy(tmp_reg, CRC16_64_table, 16*8);
    aligned_CRC16_64_2(j,(void*)(&constant_block[0]));
    if (memcmp(CRC16_64_table, tmp_reg, 16*8)) {
      printf("erreur dans cst_block avec j=%d\n",j);
      return -1;
    }
  } while (j<sizeof(constant_block));

  j=0;
  do {
    j+=128;
    if ((j%16384)==0) {
      printf("%c%d  ",0XD,j);
      fflush(stdout);
    }
    aligned_CRC16_64(j,(U64*)c);
    memcpy(tmp_reg, CRC16_64_table, 16*8);
    aligned_CRC16_64_2(j,(U64*)c);
    if (memcmp(CRC16_64_table, tmp_reg, 16*8)) {
      printf("erreur avec j=%d\n",j);
      return -2;
    }
  } while (j<i);
  printf("\nOK\n");
#endif

#ifdef test_periode_rebouclage
/* mesure la longueur de rebouclage effectif */
  int j=0;
  char *c=calloc(16,1);

  do {
    j+=8;
    if ((j%16384)==0) {
      printf("%c%d ",0XD,j);
      fflush(stdout);
    }
    aligned_CRC16_64(j,(U64*)c);
  } while (memcmp(CRC16_64_const, CRC16_64_table,16*8));
  printf(" j=%d\n",j);
#endif

  return 0;
}
