// -----------------------------------------------------------------------------
// (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_cordic_pipe.cpp
// Description  : Testbench for CORDIC 
// Author       : Sabih Gerez, Bibix
//                based on work by Rene Moll, DSE
// Creation date: July 13, 2011
// -----------------------------------------------------------------------------
// $Rev: 146 $
// $Author: sabih $
// $Date: 2011-08-18 23:57:22 +0200 (Thu, 18 Aug 2011) $
// $Log$
// -----------------------------------------------------------------------------

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

#include "arx_util.h"
#include "cordic_pipe.h"

int main(int argc, char* argv[])
{
  // both input and output data stream will be written from testbench
  // open file for input stream
  FILE *infile;

  infile = fopen("cordic_pipe.in", "wt");
  if (infile == NULL)
     printf("Cannot open cordic_pipe.in for reading!\n");
  assert(infile != NULL);

  // open file for output stream
  FILE *outfile;

  outfile = fopen("cordic_pipe.out", "wt");
  if (outfile == NULL)
     printf("Cannot open cordic_pipe.out for writing!\n");
  assert(outfile != NULL);
  
  // word lengths
  const int wld_in  = 10;
  const int wld_out = 11;
  const int wlp_in  = 10;

  // derived constants
  const i32 max_data_in  =  pow(2, wld_in-1) - 1;
  const i32 max_phase    =  pow(2, wlp_in-1) - 1;
  const i32 phase_corr   =  pow(2, wlp_in);
  
  // Create an intance of the DUV
  cordic_pipe oDUV;
  
  // phase accumulator
  i32 phase_acc = 0;

  // phase step in case of 10-bit phase: 
  // 1024 corresponds to 360 degrees
  // so a step of 10 corresponsd roughly to  4 degrees
  // so a step of 40 corresponsd roughly to 15 degrees
  i32 phase_step;
  
  // Output variables
  // - X, Y coordinates
  i32    nXout, nYout, nPout;
  double dYout, dXout, dPout;
  
  // Output helper
  char cBuffer[80];

  // initialize with spaces
  for (int i = 0; i < 79; i++)
    cBuffer[i] = ' ';

  cBuffer[79] = '\n';
  
  printf("**** Generating sine and cosine using rotation mode. ****\n");
  
  // Initialize DUV
  oDUV.reset();

  // let the phase step be constant, then increasing, then constant
  for (int i = 0; i < 240; i++)  {
    if (i < 100)
       phase_step = 10;
    else if (i < 140)
       phase_step = i - 90;
    else
       phase_step = 40;

    // Apply input to DUV
    oDUV.run(max_data_in, 0, phase_acc, 0, nXout, nYout, nPout);
    
    // Write input and output to file
    fprintf(infile, "%d %d %d %d\n", max_data_in, 0, phase_acc, 0);
    fprintf(outfile, "%d %d %d\n", nXout, nYout, nPout);

    // Perform output conversion
    dXout = signed_to_double(nXout, wld_out, 2);
    dYout = signed_to_double(nYout, wld_out, 2);
    
    // print the output to stdout using "ASCII art"
    //
    int xpos = 40 + 40/1.7 * dXout;
    int ypos = 40 + 40/1.7 * dYout;

    cBuffer[xpos] = '*';
    cBuffer[ypos] = '+';
    
    printf("%s", cBuffer);

    cBuffer[xpos] = ' ';
    cBuffer[ypos] = ' ';

    // calculate new phase
    phase_acc = phase_acc + phase_step;
    if (phase_acc > max_phase)
       phase_acc = phase_acc - phase_corr;
  }

  printf("**** Get phase form sine and cosine using vectoring mode. ****\n");
  
  // Initialize DUV
  // oDUV.reset();

  // let the phase step be constant, then increasing, then constant
  for (int i = 0; i < 240; i++)  {
    if (i < 100)
       phase_step = 10;
    else if (i < 140)
       phase_step = i - 90;
    else
       phase_step = 40;

    // convert phase into an angle in radians
    double angle = 1.0 * phase_acc/max_phase * 3.1415926535;

    // Apply input to DUV
    oDUV.run(i32(cos(angle) * max_data_in),
             i32(sin(angle) * max_data_in),
             0,
             1, // vectoring mode!
             nXout, nYout, nPout);
    
    // Write input and output to file
    fprintf(infile, "%d %d %d %d\n", 
            i32(cos(angle) * max_data_in),
            i32(sin(angle) * max_data_in),
            0, 
            1); // vectoring mode!
    fprintf(outfile, "%d %d %d\n", nXout, nYout, nPout);

    // Perform output conversion
    dPout = signed_to_double(nPout, wlp_in, 1);
    
    // print the output to stdout using "ASCII art"
   
    int ppos = 40 + 40 * dPout;

    cBuffer[ppos] = '*';
    
    printf("%s", cBuffer);

    cBuffer[ppos] = ' ';

    // calculate new phase
    phase_acc = phase_acc + phase_step;
    if (phase_acc > max_phase)
       phase_acc = phase_acc - phase_corr;
  }
  
  fclose(infile);
  fclose(outfile);
  
  printf("OK! End of simulation.\n");
}
