Skip to content
Snippets Groups Projects
tb_sha256_hash_compression.sv 8.86 KiB
//-----------------------------------------------------------------------------
// SoC Labs Basic SHA-2 Hash Compression Testbench
// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
//
// Contributors
//
// David Mapstone (d.a.mapstone@soton.ac.uk)
//
// Copyright  2022, SoC Labs (www.soclabs.org)
//-----------------------------------------------------------------------------
`timescale 1ns/1ns
`include "sha256_hash_compression.sv"

module tb_sha256_hash_compression;
    
    logic clk;
    logic nrst;
    logic en;
    logic sync_rst;
    // Data In data and Handshaking
    logic [511:0] data_in;
    logic data_in_last;
    logic data_in_valid;
    logic data_in_ready;
    
    // Data Out data and Handshaking
    logic [255:0] data_out;
    logic data_out_valid;
    logic data_out_ready;
    logic data_out_last;
        
    sha256_hash_compression uut (
                  .clk (clk),
                  .nrst(nrst),
                  .en  (en),
                  .sync_rst(sync_rst),
                  .data_in(data_in),
                  .data_in_valid(data_in_valid),
                  .data_in_ready(data_in_ready),
                  .data_in_last(data_in_last),
                  .data_out(data_out),
                  .data_out_last(data_out_last),
                  .data_out_valid(data_out_valid),
                  .data_out_ready(data_out_ready));
    
    logic data_in_drive_en;
    logic data_out_drive_ready;
    
    logic [511:0] data_in_queue [$];
    logic data_in_last_queue    [$];
    int   data_in_gap_queue     [$];
    logic data_in_wait_queue;
    
    
    logic [255:0] data_out_queue [$];
    logic data_out_last_queue    [$];
    int   data_out_stall_queue   [$];
    logic data_out_wait_queue;
    
    // Handle Valid and Data for data_in
    always_ff @(posedge clk, negedge nrst) begin: data_in_valid_drive
        if (!nrst) begin
            data_in                 <= 512'd0;
            data_in_valid           <=   1'b0;
            data_in_last            <=   1'b0;
            data_in_gap             <=   0;
            data_in_wait_queue      <=   1'b1;
        end else if (data_in_drive_en) begin
            if (data_in_gap > 0) begin
                data_in_gap <= data_in_gap -1;
                data_in_valid <= 1'b0;
            end else begin
                data_in_valid <= 1'b1;
            end
            if (((data_in_valid == 1'b1) && (data_in_ready == 1'b1)) ||
                 (data_in_wait_queue == 1'b1)) begin
                // Data transfer just completed or transfers already up to date
                if ((data_in_queue.size() > 0) && (data_in_last_queue.size() > 0) && (data_in_gap_queue.size() > 0)) begin
                    data_in            <= data_in_queue.pop_front();
                    data_in_last       <= data_in_last_queue.pop_front();
                    if (data_in_gap_queue[0] == 0) begin
                        data_in_valid  <= 1'b1;
                    end else begin
                        data_in_valid  <= 1'b0;
                    end
                    data_in_gap        <= data_in_gap_queue.pop_front();
                    data_in_wait_queue <= 1'b0;
                end else begin
                    // No data currently avaiable in queue to write but transfers up to date
                    data_in_wait_queue <= 1'b1;
                    data_in_valid      <= 1'b0;
                end
            end
        end
    end
    
    
    logic [255:0] data_out_check;
    logic data_out_last_check;
    int   data_in_gap;
    int   data_out_stall;
    
    int   packet_num;
    
    // Handle Output Ready Signal Verification
    always @(posedge clk) begin
        // Check Override Control on Ready
        if (data_out_drive_ready) begin
            // Count down to zero before enabling Ready
            if (data_out_stall > 0) begin
                data_out_stall <= data_out_stall - 1;
                data_out_ready <= 1'b0;
            end else begin
                // Wait for handshake before updating stall value
                if ((data_out_valid == 1'b1) && (data_out_ready == 1'b1)) begin
                    if (data_out_stall_queue.size() > 0) begin
                        if (data_out_stall_queue[0] == 0) begin
                            data_out_ready <= 1'b1;
                        end else begin
                            data_out_ready <= 1'b0;
                        end
                        data_out_stall <= data_out_stall_queue.pop_front();
                    end
                // Keep Ready Asserted until handshake seen
                end else begin
                    data_out_ready <= 1'b1;
                end
            end
        end else begin
            data_out_ready <= 1'b0;
        end
    end
    
    // Handle Output Data Verification
    always @(posedge clk) begin
        // Check Data on Handshake
        if ((data_out_valid == 1'b1) && (data_out_ready == 1'b1)) begin
            assert (data_out == data_out_check) else begin
                $error("data_out missmatch! packet %d | recieve: %x != check: %x", packet_num, data_out, data_out_check);
                $finish;
            end
            if ($test$plusargs ("DEBUG")) $display("data_out match! packet %d | recieve: %x != check: %x", packet_num, data_out, data_out_check);
            assert (data_out_last == data_out_last_check) else begin
                $error("data_out_last missmatch! packet %d | recieve: %x != check: %x", packet_num, data_out_last, data_out_last_check);
                $finish;
            end
            if ($test$plusargs ("DEBUG")) $display("data_out_last match! packet %d | recieve: %x != check: %x", packet_num, data_out_last, data_out_last_check);
            if ((data_out_queue.size() > 0) && (data_out_last_queue.size() > 0)) begin
                data_out_check      <= data_out_queue.pop_front();
                data_out_last_check <= data_out_last_queue.pop_front();
                if (data_out_last_check == 1'b1) begin
                    packet_num <= packet_num + 1;
                end
            end else begin
                $display("Test Passes");
                $finish;
            end
        end
    end
    
    // File Reading Variables
    int fd; // File descriptor Handle
    
    logic [511:0] input_data; // Temporary Input Data Storage
    logic input_data_last;    // Temporary Input Data Last
    int   input_data_gap;     // Temporary Input Gap
    
    
    logic [255:0] output_data; // Temporary Output Data Storage
    logic output_data_last;    // Temporary Output Data Last
    int  output_data_stall;    // Temporary Output Stall 
    
    initial begin
        $dumpfile("sha256_hash_compression.vcd");
        if ($test$plusargs ("DEBUG")) begin
            $dumpvars(0, tb_sha256_hash_compression);
            for (int i = 0; i < 16; i++) begin
                $dumpvars(0, tb_sha256_hash_compression.uut.M[i]);
            end
            for (int i = 0; i < 8; i++) begin
                $dumpvars(0, tb_sha256_hash_compression.uut.H[i]);
                $dumpvars(0, tb_sha256_hash_compression.uut.next_H[i]);
            end
            for (int i = 0; i < 64; i++) begin
                $dumpvars(0, tb_sha256_hash_compression.uut.W[i]);
                $dumpvars(0, tb_sha256_hash_compression.uut.next_W[i]);
                $dumpvars(0, tb_sha256_hash_compression.uut.ssig1_next_W[i]);
            end
        end
        data_in_drive_en = 0;
        data_out_drive_ready = 0;
        
        // Read input data into Queue
        fd = $fopen("../stimulus/testbench/input_message_block_stim.csv", "r");
        while ($fscanf (fd, "%x,%b,%d", input_data, input_data_last, input_data_gap) == 3) begin
            data_in_queue.push_back(input_data);
            data_in_last_queue.push_back(input_data_last);
            data_in_gap_queue.push_back(input_data_gap);
        end
        $fclose(fd);
        
        // Read output data into Queue
        fd = $fopen("../stimulus/testbench/output_hash_ref.csv", "r");
        while ($fscanf (fd, "%x,%b,%d", output_data, output_data_last, output_data_stall) == 3) begin
            data_out_queue.push_back(output_data);
            data_out_last_queue.push_back(output_data_last);
            data_out_stall_queue.push_back(output_data_stall);
        end
        $fclose(fd);
        
        // Initialise First Checking Values
        data_out_check      = data_out_queue.pop_front();      
        data_out_last_check = data_out_last_queue.pop_front();
        data_out_stall      = data_out_stall_queue.pop_front();
        
        // Enable Hash Compression
        en = 1;
        
        // Defaultly set Sync Reset Low
        sync_rst  = 0;
        
        #20 nrst  = 1;
        #20 nrst  = 0;
        #20 nrst  = 1;
        #20 data_in_drive_en = 1;
       
        # 30 data_out_drive_ready = 1;
    end
    
    initial begin
        forever begin
            #10 clk = 0;
            #10 clk = 1;
        end
    end
    
endmodule