
/*
Currently this module implements some form of frequency test.
It produces Error if the number of 1's is not within |N/2 +- d| for some small d. 
N is the number of random bits: set to 1M.
d = 50K (i.e., 5% deviation from 50% bits 1s.
Note: this is not an efficient reference design.
*/

// Replace this module for the required statistical test
`define SAMPLE_SIZE 20'd1000000
//`define SAMPLE_SIZE 20'd192       // Use this for simulation

module statistical_test(clk, stat_trng_rst, 
                        enable_TRO, random_reg, rng_ready, 
                        stat_error, done,
                        debug_out);

input clk;
input stat_trng_rst;    // When statistical test is performed, this is 0
output reg enable_TRO;      // This module generates this signal to enable the random bit generator
input [63:0] random_reg; // 64 random bits from the random bit generator
input rng_ready;         // When this signal is 1, random_reg is used by this module for statistical calculation 

output reg stat_error;  // This signal is 1 when the stastical test fails 
output done;            // This signal becomes 1 after the statistical test is complete.

output [63:0] debug_out; // optional signal

reg [19:0] num_of_1s;
reg rng_ready_d0, rng_ready_d1;
wire [8:0] Hamming_weight;
wire num_of_1s_deviation_significant;
reg [19:0] rng_word_counter;

assign Hamming_weight = random_reg[0]+random_reg[1]+random_reg[2]+random_reg[3]+random_reg[4]+random_reg[5]+random_reg[6]+random_reg[7]+random_reg[8]+random_reg[9]+random_reg[10]+random_reg[11]+random_reg[12]+random_reg[13]+random_reg[14]+random_reg[15]+random_reg[16]+random_reg[17]+random_reg[18]+random_reg[19]+random_reg[20]+random_reg[21]+random_reg[22]+random_reg[23]+random_reg[24]+random_reg[25]+random_reg[26]+random_reg[27]+random_reg[28]+random_reg[29]+random_reg[30]+random_reg[31]+random_reg[32]+random_reg[33]+random_reg[34]+random_reg[35]+random_reg[36]+random_reg[37]+random_reg[38]+random_reg[39]+random_reg[40]+random_reg[41]+random_reg[42]+random_reg[43]+random_reg[44]+random_reg[45]+random_reg[46]+random_reg[47]+random_reg[48]+random_reg[49]+random_reg[50]+random_reg[51]+random_reg[52]+random_reg[53]+random_reg[54]+random_reg[55]+random_reg[56]+random_reg[57]+random_reg[58]+random_reg[59]+random_reg[60]+random_reg[61]+random_reg[62]+random_reg[63];

always @(posedge clk)
begin
	rng_ready_d0 <= rng_ready;
	rng_ready_d1 <= rng_ready_d0;
end

always @(posedge clk)
begin
    if(stat_trng_rst)
        enable_TRO <= 1'b0;
    else if(done)
        enable_TRO <= 1'b0;
    else
        enable_TRO <= 1'b1;
end
     
always @(posedge clk)
begin
    if(stat_trng_rst)
        num_of_1s <= 20'd0;
	else if(rng_ready_d1==1'b0 && rng_ready_d0==1'b1)
        num_of_1s <= num_of_1s + Hamming_weight;
    else     
        num_of_1s <= num_of_1s;
end

assign num_of_1s_deviation_significant = ((num_of_1s > (20'd500000 - 20'd1000)) && (num_of_1s < (20'd500000 + 20'd1000))) ? 1'b0 : 1'b1  ;


always @(posedge clk)
begin
    if(stat_trng_rst)
        rng_word_counter <= 20'd0;
	else if(rng_ready_d1==1'b0 && rng_ready_d0==1'b1 && done!=1)
        rng_word_counter <= rng_word_counter + 1;
    else     
        rng_word_counter <= rng_word_counter;
end

always @(posedge clk)
begin
    if(done==1'b1)
        stat_error <= num_of_1s_deviation_significant;
    else
        stat_error <= stat_error;    
end


assign done = (rng_word_counter == (`SAMPLE_SIZE>>6)) ? 1'b1 : 1'b0; // One word is 64 bits.

assign debug_out = num_of_1s;

endmodule 



