// -----------------------------------------------------------------------------
// (C) Bibix
// The content below includes confidential, proprietary information of
// Bibix. All use, disclosure, and/or reproduction is prohibited
// unless authorized in writing. All rights reserved.
// -----------------------------------------------------------------------------
// File         : tb_fft_r8_bf.cpp
// Description  : Testbench for 8-point (radix 2^3) FFT pipeline
// Author       : Sabih Gerez, Bibix
//                based on work by Rene Moll, DSE
// Creation date: October 27, 2011
// -----------------------------------------------------------------------------
// $Rev: 174 $
// $Author: sabih $
// $Date: 2011-11-03 23:03:29 +0100 (Thu, 03 Nov 2011) $
// $Log$
// -----------------------------------------------------------------------------

#include <stdlib.h>
#include <stdio.h>

#include "fft_r8_bf.h"

#define WORD_LENGTH 12
#define IWORD_LENGTH 6
#define POINTS 8

/*
 * bit_reverse8
 * 
 * Fast bit reversal function for 3 bits numbers (0-7)
 */

unsigned char bit_reverse8(unsigned char value)
{
   unsigned char result = 0;

   if ( value & 0x04 ) result |= 0x01;
   if ( value & 0x02 ) result |= 0x02;
   if ( value & 0x01 ) result |= 0x04;

   return result;
}

int main(int argc, char* argv[])
{
  FILE *pFileDec;		// input file for decimal input
  FILE *pFileIn;		// output file with input stream
  FILE *pFileOut;		// output file with output stream

  pFileDec = fopen("fft_r8_bf.dec", "r");

  if (pFileDec == NULL) {
    printf("Cannot open fft_r8_bf.dec for reading!\n");
    return 1;
  }

  pFileIn = fopen("fft_r8_bf.in", "w");

  if (pFileIn == NULL) {
    printf("Cannot open fft_r8_bf.in for writing!\n");

    fclose(pFileDec);
    return 1;
  }

  pFileOut = fopen("fft_r8_bf.ref", "w");

  if (pFileOut == NULL) {
    printf("Cannot open fft_r8_bf.ref for writing!\n");

    fclose(pFileIn);
    fclose(pFileDec);
    return 1;
  }

  // Create an intance of the DUV
  fft_r8_bf oDUV;

  // Initialize DUV
  oDUV.reset();

  // Input reading
  char cBuffer[80];
  int nXreal, nXimag;
  double dXreal, dXimag;

  // Output variables
  i32    nYreal,        nYimag;
  i32    nYbufReal[POINTS], nYbufImag[POINTS];
  double dYbufReal[POINTS], dYbufImag[POINTS];

  // control
  int i = 0;
  bool prologue = 1;

  // Iterate for each test vector
  while (fgets(cBuffer, 80, pFileDec) != NULL)  {
    // Read input
    sscanf(cBuffer, "%lf %lf", &dXreal, &dXimag);

    // Convert to signed
    to_signed(dXreal, nXreal, WORD_LENGTH, IWORD_LENGTH);
    to_signed(dXimag, nXimag, WORD_LENGTH, IWORD_LENGTH);

    // run one clock cycle of hardware
    oDUV.run(i32(nXreal), i32(nXimag), nYreal, nYimag);
    
    // dump inputs and outputs as integers on behalf of VHDL simulations
    // no bitreversal of output order here!
    fprintf(pFileIn,  "%d %d\n", nXreal, nXimag);
    fprintf(pFileOut, "%d %d\n", nYreal, nYimag);

    // control
    // skip the first POINTS+2 samples and then process in blocks of
    // POINTS
    if (prologue) {
       i = i+1;
       if (i >= (POINTS+2)) {
          prologue = false;
          i = 0;
       }
    }
    else {
       nYbufReal[i] = nYreal;
       nYbufImag[i] = nYimag;

       // convert to double
       dYbufReal[i] = signed_to_double(nYbufReal[i], WORD_LENGTH, IWORD_LENGTH);
       dYbufImag[i] = signed_to_double(nYbufImag[i], WORD_LENGTH, IWORD_LENGTH);

       // check for end of block
       if (i >= (POINTS-1)) {
          // Perform bit reversal
          double dYrealRev[POINTS], dYimagRev[POINTS];
          for (int j = 0; j< POINTS; j++) {
            int nIndex = bit_reverse8(j);

            dYrealRev[nIndex] = dYbufReal[j];
            dYimagRev[nIndex] = dYbufImag[j];
          }

          memcpy(dYbufReal, dYrealRev, sizeof(dYbufReal));
          memcpy(dYbufImag, dYimagRev, sizeof(dYbufImag));

          // Write output (floating point to screen)
          printf("\nNew output block:\n");
          for (int j = 0; j < POINTS; j++) 
            printf ("Bin[%d]: %+10.6f %+10.6fi; abs_val = %9.6f\n", j,
                    dYbufReal[j], 
                    dYbufImag[j],
                    sqrt(dYbufReal[j]*dYbufReal[j] + 
                         dYbufImag[j]*dYbufImag[j]));
          
         i = 0;
       }
       else {
         i = i + 1;
       }
    }
          
  }

  // close files
  fclose(pFileDec);
  fclose(pFileIn);
  fclose(pFileOut);

  printf("OK! End of input file reached. Stopping simulation.\n");
}
