% Joshua Mack, Sam Bellestri, Nia Simmonds IREECE 2015
% UltimateTestScript_xToTheY:
%   Acts as a completely autonomous test script for testing floating-point x^y.
%   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_xToTheY()

    % Define the domain being tested over
    % |y * ln(x)| <= 12.42644
    % Testing over the range s.t. y can be greater than or equal to 1.
    % => |1 * ln(x)| <= 12.42644
    % => -12.42644 <= ln(x) <= 12.42644
    % => exp(-12.42644) <= x <= exp(12.42644) 
    xMin = exp(-12.42644);
    xMax = exp(12.42644);
    xPts = 150; yPts = 10;
    
    % Define the configurations being tested.
    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];

    % Define the filename that results will be saved to at the end of the script.
    fileName = ['xToTheY_PSNR_', num2str(length(fracArr)*length(iterArr)), '_Cases_', num2str(xMin, 2), '_to_', num2str(xMax, 2), '_', datestr(datetime('today')), '.txt'];
    
    % Name of the VHDL testbench file
    tbName = 'FloP_xToTheY_Generic_tb.vhd';
    % Path to directory that will contain testbench file
    VHDLPath = '"C:/Data/College Stuff/IREECE 2015/Cylinder Pressure Estimation/VHDL/xToTheY/xToTheY.srcs/sim_1/new/"';
    % Path to Matlab directory -- the current working directory for Matlab. Can surely 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*yPts results in it). 
    unix ('rm ./FloP_xToTheY_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 diagnostic information about which configuration is being tested.
                fprintf('\n----------------------\n');
                fprintf('%d bits, %d iterations', expWidth+fracWidth+1, numIterations);
                fprintf('\n----------------------\n'); 

                % Path to simulation results
                % First just establish the basic path
                simuResultsPath = '"C:/Data/College Stuff/IREECE 2015/Cylinder Pressure Estimation/VHDL/xToTheY/xToTheY.sim/sim_1/behav/';
                % Then concatenate the filename of the simulation results
                simuResultsPath = [simuResultsPath, num2str(numIterations), 'iterations', num2str(fracWidth+expWidth+1), 'bits_xToTheY.txt"'];

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

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

                % Start vivado and call the script to automate the simulation process
                % Requires the companion tcl script to be inside the "TCL_Files" directory located inside Matlab's current working directory.
                unix('C:/Xilinx/Vivado/2015.1/bin/vivado -mode tcl -source ./TCL_Files/xToTheYSim.tcl');

                % Copy the results back to matlab directory into PSNR folder
                unix(['cp ', simuResultsPath, ' ', MatlabPath, '/FloP_xToTheY_VivadoResults/"']);

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

                % Whenever Vivado fails, keep repeating the simuation until it works
                while myPSNR(i, j) == -123456
                    unix('C:/Xilinx/Vivado/2015.1/bin/vivado -mode tcl -source ./TCL_Files/xToTheYSim.tcl');
                    unix(['cp ', simuResultsPath, ' ', MatlabPath, '/FloP_xToTheY_VivadoResults/"']);
                    myPSNR(i, j) = convertPlotAndPSNR_xToTheY(xMin, xMax, xPts, yPts, expWidth, fracWidth, numIterations);
                end
            else
                % Keep each sample equal in length regardless of cases run
                myPSNR(i, j:1:length(iterArr)) = myPSNR(i, j-1);
            end
        end
        % Plot the results
        figure(h1);
        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(['${X}^{Y}$ 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, yPts = %d\n', xMin, xMax, xPts, yPts);
    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