% Joshua Mack, Sam Bellestri, Nia Simmonds IREECE 2015
% FloP_eToTheX_Generic_tb:
%   Takes in a given test domain along with the corresponding exponent and fractional widths of the floating-point format and number of iterations
%   And then generates a VHDL testbench for simulating a specific configuration of e^x. The resulting file is saved to the current Matlab working directory
%   As "FloP_eToTheX_Generic_tb.vhd".

function [] = Fixed_eToTheX_Generic_tb(lower,upper,lines,iterations,intWidth,fracWidth)

    % 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;

    % The easiest way to see what's going on here is basically just to run the script and look at the output.
    % It should be formatted relatively nicely.
    file = fopen('Fixed_eToTheX_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_eToTheX_Generic_tb is\nend Fixed_eToTheX_Generic_tb;\n\n');
    fprintf(file,['architecture Behavioral of Fixed_eToTheX_Generic_tb is\n', ...
        'component Fixed_eToTheX is\n', ...
        '\tGeneric ( filename1, filename2 : string; dataWidth, iterWidth, M, N : integer );\n',...
        '\tPort ( clk, start : in STD_LOGIC;\n',...
            '\t\tinput, InverseScalingFactor : in STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\toutput : out STD_LOGIC_VECTOR (dataWidth-1 downto 0);\n',...
            '\t\tdone : out STD_LOGIC );\n']);
    fprintf(file,['end component;\n\n', ...
    'constant file1 : string := "%d_%dBitExpandedLUT_Fixed.txt";\n', ...
    'constant file2 : string := "%d_%dBitLUT_Fixed.txt";\n', ...
    'constant dataWidth : integer := %d;\n', ...
    'constant iterWidth : integer := %d;\n', ...
    'constant M : integer := %d;\n', ...
    'constant N : integer := %d;\n\n', ...
        'signal clk_tb, start_tb, done_tb : std_logic;\n', ...
        'signal input_tb, InvScalFact, output_tb : std_logic_vector (dataWidth-1 downto 0);\n\n', ...
        'begin\n',...
            '\tmyCORDIC : Fixed_eToTheX Generic Map(fileName1 => file1, fileName2 => file2,\n', ...
                    '\t\t\tdataWidth => dataWidth, iterWidth => iterWidth, M => M, N => N)\n', ...
            '\t\tPort Map(clk_tb, start_tb, input_tb, InvScalFact, output_tb, done_tb);\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_eToTheX_fixed.txt";\n',...
             '\tvariable L1 : LINE;\n\n',...
         'begin\n\n',...
    '--------------------------Begin Tests-----------------------------\n',...
        '\t-- The main pieces that need to be in place to get standard, nonscaled e^x values\n',...
        '\t-- InvScalFact := %s;\n',...
        '\tInvScalFact <= "%s";\n\n\n'],intWidth,fracWidth,intWidth,fracWidth,numBits,iterWidth,5,iterations,iterations,numBits,num2str(1/scalingFactor),num2bin(q,1/scalingFactor));
    
    % Begin writing test cases to the file.
    x = linspace(lower,upper,lines);
    i = 1;
    while i <= lines
        %Perform conversion and record in file
        fprintf(file,'\t--input <= "%s";\n', num2str(x(i)));
        fprintf(file,'\tinput_tb <= "%s";\n', num2bin(q,x(i)));
        fprintf(file,'\tstart_tb <= ''1''; wait for 2 ns; start_tb <= ''0''; wait until done_tb = ''1''; wait for 20 ns;\n');
        fprintf(file,'\twrite(L1,output_tb);\n');
        fprintf(file,'\twriteline(test_out_data1,L1);\n\n');
        i = i + 1;
    end
    fprintf(file,['stop(0);\n',...
        'end process;\n',...
        'end Behavioral;\n']);

    fclose(file); 
return;