% Joshua Mack, Sam Bellestri, Nia Simmonds IREECE 2015
% UltimateTestScript_NaturalLogX:
%   Acts as a completely autonomous test script for testing floating-point ln(x).
%   After establishing the test domain for each case and the arrays specifying the cases that need testing, 
%   The script simply iterates through each combination, generates LUTs, generates a testbench, executes the Vivado simulation,
%   analyzes the results, and proceeds to the next test case. Requires some directories to be manually specified by hand, though, 
%   and it can be a bit tricky working around (1) Matlab's hatred of double quotation marks (") and (2) unix's hatred of spaces. 
%   If you're careful, though, and only replace the path names between the single and double quotes, it should transfer to other machines fine.

function [] = UltimateTestScript_NaturalLogX()

    % Define the test domain for each simulation to test over
    % xMax_Restricted and xMax_Unrestricted are temporary measures put in place due to the fixed-point formats we needed to test.
    % xMax_Unrestricted required at least our 24-bit format to fully represent, but we still needed to test the 16 and 20 bit formats fairly.
    xMin = 0.000001;
    xMax_Restricted = 4290000000;
    xMax_Unrestricted = 62153937022.4645;
    xPts = 1000;
    
    % Define the configurations to be tested. Note that the simulation tests bitWidth vs numIter where bitWidth(i) = 1 + expArr(i) + fracArr(i) and numIter(j) = iterArr(j).
    fracArr = [9 13 16 20 23 26 30 34 37 41 44 48 52];
    expArr = [6 6 7 7 8 9 9 9 10 10 11 11 11];
    iterArr = [8 12 16 20 24 28 32 36 40 44 48 52];

    % Filename that PSNR results will be saved to at the end of the script.
    fileName = ['NaturalLogX_PSNR_', num2str(length(fracArr)*length(iterArr)), '_Cases_', num2str(xMin, 2), '_to_', num2str(xMax_Unrestricted, 2), '_', datestr(datetime('today')), '.txt'];
    
    % Name of the VHDL testbench file
    tbName = 'FloP_NaturalLogX_Generic_tb.vhd';
    % Path to testbench directory -- directory where you want the generated VHDL testbench to be stored.
    VHDLPath = '"C:/Data/College Stuff/IREECE 2015/Cylinder Pressure Estimation/VHDL/NaturalLogX/NaturalLogX.srcs/sim_1/new/"';
    % Path to Matlab directory -- the current working directory for Matlab. Surely can be replaced by some usage of "pwd"
    MatlabPath = '"C:/Data/College Stuff/IREECE 2015/Cylinder Pressure Estimation/Matlab Files/';
    
    % Clear the results directory of any previously generated files
    % It enabled us to be sure that the results we were getting were, in fact, from this test run. Otherwise, for example, a given configuration's simulation may fail
    % (say, 40 bits, 24 iterations), in which case the script hands control from the Vivado simulator back to Matlab, and the only way that the script knows the simulation failed
    % is if it cannot find the resulting simulation file (or if it doesn't have xPts results in it). 
    unix('rm ./FloP_NaturalLogX_VivadoResults/*');

    myPSNR = zeros(length(fracArr), length(iterArr));
    h1 = figure();
    for i = 1:1:length(fracArr)
        for j = 1:1:length(iterArr)
            if iterArr(j) <= fracArr(i)
                % Assign the parameters for this execution
                expWidth = expArr(i); fracWidth = fracArr(i); numIterations = iterArr(j);
                % Print out some helpful information for the person watching this script execute
                fprintf('\n----------------------\n');
                fprintf('%d bits, %d iterations', expWidth+fracWidth+1, numIterations);
                fprintf('\n----------------------\n'); 

                if expWidth+fracWidth+1 < 24
                    xMax = xMax_Restricted;
                else
                    xMax = xMax_Unrestricted;
                end

                % Path to simulation results -- varies depending on test case, so must be reconstructed with each iteration.
                % First just establish the basic path. Essentially just the path to the testbench file.
                simuResultsPath = '"C:/Data/College Stuff/IREECE 2015/Cylinder Pressure Estimation/VHDL/NaturalLogX/NaturalLogX.sim/sim_1/behav/';
                % Then concatenate the filename of the simulation results
                simuResultsPath = [simuResultsPath, num2str(numIterations), 'iterations', num2str(fracWidth+expWidth+1), 'bits_NaturalLogX.txt"'];

                % Generate testbench
                FloP_NaturalLogX_Generic_tb(xMin, xMax, xPts, numIterations, expWidth, fracWidth);
                % Copy it to the vivado project
                unix(['cp ./', tbName, ' ', VHDLPath]);

                % Generate CORDIC LUTs
                [fileName1, fileName2] = generateLUTs(numIterations,expWidth,fracWidth);
                projectPathStr = '"C:/Data/College Stuff/IREECE 2015/Cylinder Pressure Estimation/VHDL/NaturalLogX/NaturalLogX.srcs/sources_1/new/"';
                unix(['mv ', fileName1, ' ', fileName2, ' ', projectPathStr]);

                % Start vivado and call the script to automate the simulation process
                unix('C:/Xilinx/Vivado/2015.1/bin/vivado -mode tcl -source ./TCL_Files/NaturalLogXSim.tcl');

                % Copy the results back to matlab directory into PSNR folder
                % Requires the companion tcl script to be inside the "TCL_Files" directory located inside Matlab's current working directory.
                unix(['cp ', simuResultsPath, ' ', MatlabPath, 'FloP_NaturalLogX_VivadoResults/"']);

                % Call the matlab PSNR script
                myPSNR(i, j) = convertPlotAndPSNR_NaturalLogX(xMin, xMax, xPts, expWidth, fracWidth, numIterations);

                % Repeat the simulation if the Vivado simulator failed.
                while myPSNR(i, j) == -123456
                    unix('C:/Xilinx/Vivado/2015.1/bin/vivado -mode tcl -source ./TCL_Files/NaturalLogXSim.tcl');
                    unix(['cp ', simuResultsPath, ' ', MatlabPath, 'FloP_NaturalLogX_VivadoResults/"']);
                    myPSNR(i, j) = convertPlotAndPSNR_NaturalLogX(xMin, xMax, xPts, expWidth, fracWidth, numIterations);
                end
            else
                % Keep each sample equal in length regardless of cases run
                figure(h1);
                myPSNR(i, j:1:length(iterArr)) = myPSNR(i, j-1);
            end
        end
        % Plot the results
        myPlots(i) = plot(iterArr, myPSNR(i, :), 'd-'); hold all;
    end
    % Add some legends and a title to make it look nice
    for i = 1:1:length(fracArr)
       legendStrs{i} = [num2str(fracArr(i) + expArr(i) + 1), ' bits'];
    end
    legend(myPlots, legendStrs);
    title(['$\ln{x}$ PSNR vs Number of Iterations, ', ...
            num2str(xMin), ' $\leq$ x $\leq$ ', num2str(xMax)], 'Interpreter', 'laTex');
    
    % And write the results to a file because why not?
    myFile = fopen(['./PSNR_Output/', fileName], 'w');
    fprintf(myFile, 'xMin = %f, xMax = %f, xPts = %d', xMin, xMax, xPts);
    for i = 1:1:length(myPSNR)
        for j = 1:1:length(myPSNR(1, :))
            fprintf(myFile, 'Exp Width: %d, Frac Width: %d, Num Iterations: %d\n', expArr(i), fracArr(i), iterArr(j));
            fprintf(myFile, '%f\n', myPSNR(i, j));
        end
    end
    fclose(myFile);
    
end