% Joshua Mack, Sam Bellestri, Nia Simmonds IREECE 2015
% FloP_eToTheX_Generic_tb:
%   Takes in a given test domain (varies from lower to upper with "numPts" many test cases) 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 [] = FloP_eToTheX_Generic_tb(lower,upper,numPts,iterations,expWidth,fracWidth)
    
    % Declare some variables
    numBits = expWidth+fracWidth+1;
    iterWidth = floor(log2(iterations))+1;
    q = quantizer('float',[numBits expWidth]);

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

    % Begin writing to output file. Easiest way to understand this piece is to run it and look at the output.
    file = fopen('FloP_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 FloP_eToTheX_Generic_tb is\nend FloP_eToTheX_Generic_tb;\n\n');
    fprintf(file,['architecture Behavioral of FloP_eToTheX_Generic_tb is\n', ...
        'component FloP_eToTheX is\n', ...
        '\tGeneric ( fileName1 : string := "%dBitExpandedLUT.txt"; fileName2 : string := "%dBitLUT.txt"; \n\t\texpWidth : integer := %d; fracWidth : integer := %d; iterWidth : integer := %d; N : integer := %d );\n',...
        '\tPort ( input, InverseScalingFactor : in std_logic_vector(expWidth+fracWidth downto 0);\n',...
               '\t\tM : in std_logic_vector(iterWidth-1 downto 0);\n',...
               '\t\tclk, start : in std_logic;\n',...
               '\t\toutput : out std_logic_vector(expWidth+fracWidth downto 0);\n',...
               '\t\tdone : out std_logic );\n'],numBits,numBits,expWidth,fracWidth,iterWidth,iterations);
    fprintf(file,['end component;\n\n', ...
    'constant fileName1 : string := "%dBitExpandedLUT.txt";\n', ...
    'constant fileName2 : string := "%dBitLUT.txt";\n', ...
    'constant expWidth : integer := %d;\n', ...
    'constant fracWidth : integer := %d;\n', ...
    'constant iterWidth : integer := %d;\n', ...
    'constant N : integer := %d;\n', ...
    'constant invScalFact : std_logic_vector(expWidth+fracWidth downto 0) := "%s";\n\n',...
        'signal input_tb, output_tb : std_logic_vector(expWidth+fracWidth downto 0);\n',...
        'signal M : std_logic_vector(iterWidth-1 downto 0);\n',...
        'signal clk_tb, start_tb, done_tb : std_logic;\n\n', ...
        'begin\n',...
            '\tmyExp : FloP_eToTheX Generic Map(fileName1 => fileName1, fileName2 => fileName2,\n', ...
                    '\t\t\texpWidth => expWidth, fracWidth => fracWidth, iterWidth => iterWidth, N => N)\n', ...
            '\t\tPort Map(input_tb, invScalFact, M, clk_tb, start_tb, 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.txt";\n',...
             '\tvariable L1 : LINE;\n\n',...
         'begin\n\n',...
         '\t--M = "%d"\n',...
         '\tM <= "%s";\n\n'],numBits,numBits,expWidth,fracWidth,iterWidth,iterations,num2bin(q,1/scalingFactor),iterations,numBits,5,dec2bin(5,iterWidth));
    % Prep work done, begin writing test cases
    x = linspace(lower,upper,numPts);
    i = 1;
    while i <= numPts
        %Perform conversion and record in file
        fprintf(file,'-- Iteration %d\n', i);
        fprintf(file,'-- %f\n', 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 for 250 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);
  end 