summaryrefslogblamecommitdiff
path: root/bench/tb_modular_multiplier.v
blob: bd7599fe50dc66e0f543b32dd8e945cbf17ebbfb (plain) (tree)






















































































































































































































































































                                                                                                         
//------------------------------------------------------------------------------
//
// tb_modular_multiplier.v
// -----------------------------------------------------------------------------
// Testbench for Curve25519 modular multiplier.
//
// Authors: Pavel Shatov
//
// Copyright (c) 2018, NORDUnet A/S
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// - Neither the name of the NORDUnet nor the names of its contributors may be
//   used to endorse or promote products derived from this software without
//   specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
`timescale 1ns / 1ps
//------------------------------------------------------------------------------

module tb_modular_multiplier;


        //
        // Test Vectors
        //
    localparam A1 = 256'h216936d3_cd6e53fe_c0a4e231_fdd6dc5c_692cc760_9525a7b2_c9562d60_8f25d51a;   // GX
    localparam B1 = 256'h66666666_66666666_66666666_66666666_66666666_66666666_66666666_66666658;   // GY


        //
        // Core Parameters
        //
    localparam  WORD_COUNTER_WIDTH  = 3;
    localparam  OPERAND_NUM_WORDS   = 8;


        //
        // Clock (100 MHz)
        //
`define CLOCK_PERIOD        10.0
`define CLOCK_HALF_PERIOD   (0.5 * `CLOCK_PERIOD)

    reg clk = 1'b0;
    always #`CLOCK_HALF_PERIOD clk = ~clk;


        //
        // Inputs, Outputs
        //
    reg     rst_n;
    reg     ena;
    wire    rdy;


        //
        // Buffers (A, B, P)
        //
    wire    [WORD_COUNTER_WIDTH-1:0]    core_a_addr;
    wire    [WORD_COUNTER_WIDTH-1:0]    core_b_addr;
    wire    [WORD_COUNTER_WIDTH-1:0]    core_p_addr;
    
    wire                                core_p_wren;
    
    wire    [                32-1:0]    core_a_data;
    wire    [                32-1:0]    core_b_data;
    wire    [                32-1:0]    core_p_data;
    
    reg     [WORD_COUNTER_WIDTH-1:0]    tb_ab_addr;
    reg     [WORD_COUNTER_WIDTH-1:0]    tb_p_addr;
    
    reg                                 tb_ab_wren;
    
    reg     [                32-1:0]    tb_a_data;
    reg     [                32-1:0]    tb_b_data;
    wire    [                32-1:0]    tb_p_data;
    
    bram_1rw_1ro_readfirst # (.MEM_WIDTH(32), .MEM_ADDR_BITS(WORD_COUNTER_WIDTH))
    bram_a
    (   .clk(clk),
        .a_addr(tb_ab_addr),  .a_wr(tb_ab_wren), .a_in(tb_a_data), .a_out(),
        .b_addr(core_a_addr), .b_out(core_a_data)
    );

    bram_1rw_1ro_readfirst # (.MEM_WIDTH(32), .MEM_ADDR_BITS(WORD_COUNTER_WIDTH))
    bram_b
    (   .clk(clk),
        .a_addr(tb_ab_addr),  .a_wr(tb_ab_wren), .a_in(tb_b_data), .a_out(),
        .b_addr(core_b_addr), .b_out(core_b_data)
    );
        
    bram_1rw_1ro_readfirst # (.MEM_WIDTH(32), .MEM_ADDR_BITS(WORD_COUNTER_WIDTH))
    bram_p
    (   .clk(clk),
        .a_addr(core_p_addr), .a_wr(core_p_wren), .a_in(core_p_data), .a_out(),
        .b_addr(tb_p_addr),   .b_out(tb_p_data)
    );
    
    
        //
        // UUT
        //
    ed25519_modular_multiplier uut
    (
        .clk        (clk),
        .rst_n      (rst_n),
        
        .ena        (ena),
        .rdy        (rdy),
        
        .a_addr     (core_a_addr),
        .b_addr     (core_b_addr),
        .p_addr     (core_p_addr),
        
        .p_wren     (core_p_wren),
        
        .a_din      (core_a_data),
        .b_din      (core_b_data),
        .p_dout     (core_p_data)
    );
        
        
        //
        // Testbench Routine
        //
    reg ok = 1;
    initial begin
        
            /* initialize control inputs */
        rst_n   = 0;
        ena     = 0;
        
            /* wait for some time */
        #200;
        
            /* de-assert reset */
        rst_n   = 1;
        
            /* wait for some time */
        #100;
        
            /* run tests */
        $display("1. A1*B1=P1...");
        test_modular_multiplier(A1, B1);
        
            /* print result */
        if (ok) $display("tb_modular_multiplier: SUCCESS");
        else    $display("tb_modular_multiplier: FAILURE");
        //
        #10000;
        //
        //$finish;
        //
    end
    
    
        //
        // Test Task
        //  
    task test_modular_multiplier;
    
        input   [255:0] a;
        input   [255:0] b;
        
        reg     [255:0] a_shreg;
        reg     [255:0] b_shreg;
        reg     [255:0] p_shreg;
        reg             p_ok;
        
        integer         w;

        begin
        
                /* initialize result */
            p_ok = 0;

                /* initialize shift registers */
            a_shreg = a;
            b_shreg = b;

                /* start filling memories */
            tb_ab_wren = 1;
            
                /* write all the words */
            for (w=0; w<OPERAND_NUM_WORDS; w=w+1) begin
                
                    /* set addresses */
                tb_ab_addr = w[WORD_COUNTER_WIDTH-1:0];
                
                    /* set data words */
                tb_a_data = a_shreg[31:0];
                tb_b_data = b_shreg[31:0];
                
                    /* shift inputs */
                a_shreg = {{32{1'bX}}, a_shreg[255:32]};
                b_shreg = {{32{1'bX}}, b_shreg[255:32]};
                
                    /* wait for 1 clock tick */
                #`CLOCK_PERIOD;
                
            end
            
                /* stop filling memories */
            tb_ab_wren = 0;

                /* wipe addresses */
            tb_ab_addr = {WORD_COUNTER_WIDTH{1'bX}};
            
                /* wipe data words */
            tb_a_data = {32{1'bX}};
            tb_b_data = {32{1'bX}};
                        
                /* start operation */
            ena = 1;
            
                /* clear flag */
            #`CLOCK_PERIOD ena = 0;
            
                /* wait for operation to complete */
            while (!rdy) #`CLOCK_PERIOD;
            
//                /* read result */
//            for (w=0; w<OPERAND_NUM_WORDS; w=w+1) begin
//                
//                    /* set address */
//                tb_qxy_addr = w[WORD_COUNTER_WIDTH-1:0];
//                
//                    /* wait for 1 clock tick */
//                #10;
//                
//                    /* store data word */
//                qx_shreg = {tb_qx_data, qx_shreg[255:32]};
//                qy_shreg = {tb_qy_data, qy_shreg[255:32]};
//
//            end
//            
//                /* compare */
//            q_ok =  (qx_shreg == qx) &&
//                        (qy_shreg == qy);
//
                /* display results */
            if (p_ok) $display("test_modular_multiplier(): CORRECT RESULT");
            else      $display("test_modular_multiplier(): WRONG RESULT");
            
                /* update global flag */
            ok = ok & p_ok;
        
        end
        
    endtask
    
endmodule


//------------------------------------------------------------------------------
// End-of-File
//------------------------------------------------------------------------------