% Joshua Mack, Sam Bellestri, Nia Simmonds IREECE 2015
% Fixed_FullCORDIC_Generic_tb:
%   Takes in a given test domain (varies from lower to upper with "lines" many test cases) along with the corresponding integer and fractional widths of the fixed-point format and number of iterations
%   And then generates a VHDL testbench for simulating a specific configuration of expanded hyperbolic CORDIC. The resulting file is saved to the current Matlab working directory
%   As "Fixed_FullCORDIC_Generic_tb.vhd". Has an additional parameter for whether the user wants to test rotational mode or vectoring mode

function [] = Fixed_FullCORDIC_Generic_tb(mode,lower,upper,lines,iterations,intWidth,fracWidth)
  % If rotational mode...
  if mode == 'r'

    % Declare some variables
    numBits = intWidth+fracWidth;
    iterWidth = floor(log2(iterations))+1;
    q = quantizer('fixed',[numBits fracWidth]);

    negIter = -5:1:0; posIter = 1:1:iterations;
    scalingFactor = prod(sqrt(1-(1-2.^(negIter-2)).^2)) * prod(sqrt(1-(2.^(-posIter)).^2)) *  0.998044956480943;

    % Write out a testbench file
    file = fopen('Fixed_FullCORDIC_Generic_tb.vhd', 'wt');
    fprintf(file,'library IEEE;\n');
    fprintf(file,'use IEEE.STD_LOGIC_1164.ALL;\n');
    fprintf(file,'use std.textio.all;\n');
    fprintf(file,'use ieee.std_logic_textio.all;\n');
    fprintf(file,'library std;\n');
    fprintf(file,'use std.env.all;\n');
    fprintf(file,'use ieee.std_logic_1164.all;\n');
    fprintf(file,'use ieee.numeric_std.all;\n\n');
    fprintf(file,'entity Fixed_FullCORDIC_Generic_tb is\nend Fixed_FullCORDIC_Generic_tb;\n\n');
    fprintf(file,['architecture Behavioral of Fixed_FullCORDIC_Generic_tb is\n', ...
        'component FXCordic_Expanded is\n', ...
        '\tGeneric ( filename1 : string; filename2 : string; dataWidth : integer; iterWidth : integer;\n\t\tN : integer; M : integer );\n',...
        '\tPort ( clk, start, mode : in STD_LOGIC;\n',...
            '\t\tx0 : in STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\ty0 : in STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\tz0 : in STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\txOut : out STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\tyOut : out STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\tzOut : out STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\tdone : out STD_LOGIC );\n']);
    fprintf(file,['end component;\n\n', ...
    'constant fileName1 : string := "%d_%dBitExpandedLUT_Fixed.txt";\n', ...
    'constant fileName2 : string := "%d_%dBitLUT_Fixed.txt";\n', ...
    'constant dataWidth : integer := %d;\n', ...
    'constant iterWidth : integer := %d;\n', ...
    'constant N : integer := %d;\n', ...
    'constant M : integer := %d;\n\n', ...
        'signal clk_tb, start_tb, mode_tb, done : std_logic;\n', ...
        'signal x0, y0, z0, xn, yn, zn : std_logic_vector (dataWidth-1 downto 0);\n\n', ...
        'begin\n',...
            '\tmyCORDIC : FXCordic_Expanded Generic Map(fileName1 => fileName1, fileName2 => fileName2,\n', ...
                    '\t\t\tdataWidth => dataWidth, iterWidth => iterWidth, M => M, N => N)\n', ...
            '\t\tPort Map(clk_tb, start_tb, mode_tb, x0, y0, z0, xn, yn, zn, done);\n\n', ...
            'clock : process begin\n',...
                '\tclk_tb <= ''0''; wait for 1 ns;\n',...
                '\tclk_tb <= ''1''; wait for 1 ns;\n',...
           'end process;\n\n',...
            'testProc : process\n',... 
             '\tFILE test_out_data1: TEXT open WRITE_MODE is "%diterations%dbits_cosh_fixed.txt";\n',...
             '\tFILE test_out_data2: TEXT open WRITE_MODE is "%diterations%dbits_sinh_fixed.txt";\n',...
             '\tvariable L1 : LINE;\n',...
             '\tvariable L2 : LINE;\n\n',...
         'begin\n\n',...
    '--------------------------Rotation Mode Tests-----------------------------\n',...
        '\tmode_tb <= ''0'';\n',...
        '\t-- The main pieces that need to be in place to get nonscaled, separated values of Cosh and Sinh.\n',...
        '\t-- x0 := %s;\n',...
        '\tx0 <= "%s";\n',...
        '\t-- y0 := 0\n',...
        '\ty0 <= "%s";\n\n\n'],intWidth,fracWidth,intWidth,fracWidth,numBits,iterWidth,iterations,5,iterations,numBits,iterations,numBits,num2str(1/scalingFactor),num2bin(q,1/scalingFactor),dec2bin(0,numBits));
    
    % Begin writing actual test cases
    x = linspace(lower,upper,lines);
    i = 1;
    while i <= lines
        %Perform conversion and record in file
        fprintf(file,'\t--z0 <= "%s";\n', num2str(x(i)));
        fprintf(file,'\tz0 <= "%s";\n', num2bin(q,x(i)));
        fprintf(file,'\tstart_tb <= ''1''; wait for 2 ns; start_tb <= ''0''; wait for 250 ns;\n');
        fprintf(file,'\twrite(L1,xn);\n');
        fprintf(file,'\twriteline(test_out_data1,L1);\n');
        fprintf(file,'\twrite(L2,yn);\n');
        fprintf(file,'\twriteline(test_out_data2,L2);\n\n');
        i = i + 1;
    end
    fprintf(file,['stop(0);\n',...
        'end process;\n',...
        'end Behavioral;\n']);
    
  fclose(file);
  end 
  
  % Otherwise, if mode is vectoring...
  if mode == 'v'

    % Declare some variables
    numBits = intWidth+fracWidth;
    iterWidth = floor(log2(fracWidth))+1;
    q = quantizer('fixed',[numBits fracWidth]);

    % Begin writing testbench file
    file = fopen('Fixed_FullCORDIC_Generic_tb.vhd', 'wt');
    fprintf(file,'library IEEE;\n');
    fprintf(file,'use IEEE.STD_LOGIC_1164.ALL;\n');
    fprintf(file,'use std.textio.all;\n');
    fprintf(file,'use ieee.std_logic_textio.all;\n');
    fprintf(file,'library std;\n');
    fprintf(file,'use std.env.all;\n');
    fprintf(file,'use ieee.std_logic_1164.all;\n');
    fprintf(file,'use ieee.numeric_std.all;\n\n');
    fprintf(file,'entity Fixed_FullCORDIC_Generic_tb is\n end Fixed_FullCORDIC_Generic_tb;\n\n');
    fprintf(file,['architecture Behavioral of Fixed_FullCORDIC_Generic_tb is\n', ...
        'component FXCordic_Expanded is\n', ...
        '\tGeneric ( filename1 : string; filename2 : string; dataWidth : integer; iterWidth : integer;\n\t\tN : integer; M : integer );\n',...
        '\tPort ( clk, start, mode : in STD_LOGIC;\n',...
            '\t\tx0 : in STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\ty0 : in STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\tz0 : in STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\txOut : out STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\tyOut : out STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\tzOut : out STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\tdone : out STD_LOGIC );\n']);
    fprintf(file,['end component;\n\n', ...
    'constant fileName1 : string := "%d_%dBitExpandedLUT_Fixed.txt";\n', ...
    'constant fileName2 : string := "%d_%dBitLUT_Fixed.txt";\n', ...
    'constant dataWidth : integer := %d;\n', ...
    'constant iterWidth : integer := %d;\n', ...
    'constant N : integer := %d;\n', ...
    'constant M : integer := %d;\n\n', ...
        'signal clk_tb, start_tb, mode_tb, done : std_logic;\n', ...
        'signal x0, y0, z0, xn, yn, zn : std_logic_vector (dataWidth-1 downto 0);\n\n', ...
        'begin\n',...
            '\tmyCORDIC : FXCordic_Expanded Generic Map(fileName1 => fileName1, fileName2 => fileName2,\n', ...
                    '\t\t\tdataWidth => dataWidth, iterWidth => iterWidth, M => M, N => N)\n', ...
            '\t\tPort Map(clk_tb, start_tb, mode_tb, x0, y0, z0, xn, yn, zn, done);\n\n', ...
            'clock : process begin\n',...
                '\tclk_tb <= ''0''; wait for 1 ns;\n',...
                '\tclk_tb <= ''1''; wait for 1 ns;\n',...
           'end process;\n\n',...
            'testProc : process\n',... 
             '\tFILE test_out_data1: TEXT open WRITE_MODE is "%diterations%dbits_atanh_fixed.txt";\n',...
             '\tvariable L1 : LINE;\n\n',...
         'begin\n\n',...
    '--------------------------Vectoring Mode Tests-----------------------------\n',...
        '\tmode_tb <= ''1'';\n',...
        '\t-- The main pieces that need to be in place to get atanh(y/x).\n',...
        '\t-- x0 := %d;\n',...
        '\tx0 <= "%s";\n',...
        '\t-- z0 := 0\n',...
        '\tz0 <= "%s";\n\n\n'],intWidth,fracWidth,intWidth,fracWidth,numBits,iterWidth,iterations,5,iterations,numBits,1,num2bin(q,1),num2bin(q,0));
    
    % Begin writing test cases
    x = linspace(lower,upper,lines);
    i = 1;
    while i <= lines
        %Perform conversion and record in file
        fprintf(file,'\t--y0 <= "%s";\n', num2str(x(i)));
        fprintf(file,'\ty0 <= "%s";\n', num2bin(q,x(i)));
        fprintf(file,'\tstart_tb <= ''1''; wait for 4 ns; start_tb <= ''0''; wait for 250 ns;\n');
        fprintf(file,'\twrite(L1,zn);\n');
        fprintf(file,'\twriteline(test_out_data1,L1);\n\n');
        i = i + 1;
    end
    fprintf(file,['\tstop(0);\n',...
        'end process;\n',...
        'end Behavioral;\n']);
    
  fclose(file);
  end 
  return;