/*
   file mds_crc16_tsterr.c
   created Mon Oct 24 03:47:48 CEST 2005 by Yann GUIDON <whygee@f-cpu.org>
   version Sat Oct 29 04:01:56 CEST 2005 : paperbag-class ultrabugS found /o\

   This program exercises the CRC16 routines on 4K-blocks as used by the MDS container.

   The "fault model" includes pseudo-random bit toggles.
   This version is quite extremist as it flips up to _all_ the bits...
   And it can leave the CRC out of the block (not modified) if you want to compare.

   compile with
     gcc -Os -fomit-frame-pointer -march=pentium3 -o ext mds_crc16_tst.c

   Parameters :
     -DRND_LUT : the CRC16 LUT if filled with pseudo-random numbers
     -DCRC_inside : puts the CRC inside the modified block
     -DCRC16_NEGATE : CRC is stored negated
*/

#ifdef RND_LUT
#define CRC16_SMALL_FOOTPRINT
#endif

#include "mds_crc16.c"
#include "lfsr4.c"

#include <stdio.h> /* printf etc. */
#include <strings.h> /* memset */

unsigned char z[4096]; /* the 4K zone of (t)error ! */
unsigned char err_offset[4096]; /* index of all toggled bits */
unsigned short int err[32768]; /* histogram */
#ifndef LOOPS
#define LOOPS 50
#endif

int main() {
  unsigned int i, j, k, l, m;
  LFSR_reg = 0xBDE54527;
  unsigned long int nb_err=0, nb_crc=0, nb_odd=0, nb_even=0;

#ifdef CRC_inside
#define crc_res ( * (unsigned short int *) (&z[4094]) )
#define CRC_length 4094
#else
  unsigned short int crc_res;
#define CRC_length 4096
#endif

#ifdef RND_LUT
  for (i=0; i<256; i++) {
    CRC16_LUT[i] = ( lfsr4() | (lfsr4()<< 4) | (lfsr4()<< 8) | (lfsr4()<< 12) ) ;
  }
#endif

  for (i=0; i<LOOPS; i++) {

/* create the 4K-2 block */
    for (j=0; j<CRC_length; j++)
      z[j]=lfsr4() | (lfsr4()<< 4);

/* compute the CRC16 */
    crc_res = CRC16(z, CRC_length);

    memset(err_offset,0,sizeof(err_offset));
/* incrementally add errors */
    j=1;

    do {
      /* computes bit position + offset in the array */
      k=32767 & ( lfsr4() | (lfsr4()<< 4) | (lfsr4()<< 8) | (lfsr4()<< 12) ) ;

      /* verify that it was not used already */
      l=k>>3;
      while (err_offset[l] == 0xFF)
        l= (l+1) & 4095;

      m=k&7;
      while (err_offset[l] & (1<<m))
        m= (m+1) & 7;

      /* register the new index */
      err_offset[l] |= 1 << m;
      /* toggles said bit: */
      z[l] ^= 1 << m;

      if (crc_res == CRC16(z, 4096)) {
        err[j]++;
        nb_err++;
        if (j & 1)
          nb_odd++;
        else
          nb_even++;
      }
      nb_crc++;
      j++;
    } while (j<32765);

    if ((i&63) == 2) {
      printf("block #%d / %d : ",i,LOOPS);
      printf("%d erreurs (%d impaires et %d paires) pour %d CRC ", nb_err, nb_odd, nb_even, nb_crc);

#ifdef RND_LUT
      printf("(RND LUT) ");
#else
      printf("(LUT normale) ");
#endif

#ifdef CRC_inside
      printf("{CRC inside}");
#else
      printf("{CRC outside}");
#endif

#ifdef CRC16_NEGATE
      printf("[CRC inversé]\n");
#else
      printf("[CRC non inversé]\n");
#endif

      fflush(NULL);
    }
  }

  printf("========FINI=!=========\n");
  for (j=1; j<32768; j++)
    if (err[j])
      printf("%d %d\n",j, err[j]);

  printf("\n%d erreurs (%d impaires et %d paires) pour %d CRC\n", nb_err, nb_odd, nb_even, nb_crc);
  if (nb_err)
    printf("%d / %d = 1 erreur pour %d CRC.\n",nb_crc,nb_err,nb_crc/nb_err);

#ifdef RND_LUT
      printf("(RND LUT) ");
#else
      printf("(LUT normale) ");
#endif

#ifdef CRC_inside
      printf("{CRC inside}");
#else
      printf("{CRC outside}");
#endif

#ifdef CRC16_NEGATE
      printf("[CRC inversé]\n");
#else
      printf("[CRC non inversé]\n");
#endif

  fflush(NULL);
  return 0;
}
