% Joshua Mack, Sam Bellestri, Nia Simmonds IREECE 2015
% Fixed_xToTheY_Generic_tb_Plotter:
%   Takes in a given test domain 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 x^y. The resulting file is saved to the current Matlab working directory
%   As "Fixed_xToTheY_Generic_tb.vhd".

% Note that, as opposed to the non-"plotter" version, this testbench generation script uses a rectangular x-y test domain
% To enable easy plotting of the results, as opposed to the other xToTheY testbench file that generates over a non-rectangular domain.

function [] = Fixed_xToTheY_Generic_tb(xLower, xUpper, yLower, yUpper, xPoints, yPoints, intWidth, fracWidth, iterations)

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

    % Begin writing output file.
    file = fopen('Fixed_xToTheY_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_xToTheY_Generic_tb is\n end Fixed_xToTheY_Generic_tb;\n\n');
    fprintf(file,['architecture Behavioral of Fixed_xToTheY_Generic_tb is\n', ...
        '\tcomponent Fixed_xToTheY is\n', ...
        '\t\tGeneric ( filename1, filename2 : string; intWidth, fracWidth, iterWidth, M, N : integer );\n',...
        '\t\tPort ( x, y, InverseScalingFactor : in std_logic_vector(intWidth+fracWidth-1 downto 0);\n'...
           '\t\t\tclk, start : in std_logic;\n'...
           '\t\t\toutput : out std_logic_vector(intWidth+fracWidth-1 downto 0);\n'...
           '\t\t\tdone : out std_logic );\n']);
    fprintf(file,['\tend component;\n\n', ...
    '\tconstant file1 : string := "%d_%dBitExpandedLUT_Fixed.txt";\n', ...
    '\tconstant file2 : string := "%d_%dBitLUT_Fixed.txt";\n', ...
    '\tconstant intWidth : integer := %d;\n', ...
    '\tconstant fracWidth : integer := %d;\n', ...
    '\tconstant iterWidth : integer := %d;\n', ...
    '\tconstant M : integer := %d;\n',...
    '\tconstant N : integer := %d;\n\n',...
        '\tsignal clk, start, done : std_logic;\n', ...
        '\tsignal x, y, InvScalFact, output : std_logic_vector (intWidth+fracWidth-1 downto 0);\n\n', ...
        '\tbegin\n\n',...
            '\t\tmyXToTheY : Fixed_xToTheY Generic Map(fileName1 => file1, fileName2 => file2,\n', ...
                    '\t\t\t\tintWidth => intWidth, fracWidth => fracWidth, iterWidth => iterWidth, M => M, N => N)\n', ...
            '\t\tPort Map(x => x, y => y, InverseScalingFactor => InvScalFact, clk => clk, start => start, output => output, done => done);\n\n', ...
            '\t\tclkProc : process begin\n',...
                '\t\t\tclk <= ''0''; wait for 1 ns;\n',...
                '\t\t\tclk <= ''1''; wait for 1 ns;\n',...
           '\t\tend process;\n\n',...
            '\ttestProc : process\n',... 
             '\t\tFILE test_out_data1: TEXT open WRITE_MODE is "%diterations%dbits_xToTheY_Fixed.txt";\n',...
             '\t\tvariable L1              : LINE;\n',...
         '\tbegin\n\n',...
         '\t\t--InvScalFact := %f\n',...
        '\t\tInvScalFact <= "%s";\n\n'],intWidth,fracWidth,intWidth,fracWidth,intWidth,fracWidth,iterWidth,5,iterations,iterations,numBits,1/scalingFactor,num2bin(q,1/scalingFactor));

    % Begin writing test cases.
    fprintf(file, '\t\t-------------------------Begin Testing----------------------------\n');
    iterNum = 1;
    x = linspace(xLower, xUpper, xPoints);
    % Note that y does not vary with x
    y = linspace(yLower, yUpper, yPoints);
    for i = 1:1:xPoints
        for j = 1:1:yPoints
            fprintf(file,'\t\t-- Iteration %d\n',iterNum);
            fprintf(file,'\t\t-- %f\n',x(i));
            fprintf(file,'\t\tx <= "%s";\n', num2bin(q, x(i)));
            fprintf(file,'\t\t-- %f\n',y(j));
            fprintf(file,'\t\ty <= "%s";\n', num2bin(q, y(j)));
            fprintf(file,'\t\tstart <= ''1''; wait for 2 ns; start <= ''0''; wait until done = ''1''; wait for 20 ns;\n');
            fprintf(file,'\t\twrite(L1, output);\n'); fprintf(file, '\t\twriteline(test_out_data1,L1);\n\n');
            iterNum = iterNum + 1;
        end
    end     
    
    fprintf(file,['\t\tstop(0);\n',...
        '\tend process;\n',...
        'end Behavioral;\n']);
    
  fclose(file);
end 