//====================================================================== // // tb_expoentiator.v // ----------------------------------------------------------------------------- // Testbench for Montgomery modular exponentiation block. // // Authors: Pavel Shatov // // Copyright (c) 2017, NORDUnet A/S All rights reserved. // // 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_exponentiator; // // Test Vectors // `include "modexp_fpga_model_vectors.v"; // // Parameters // localparam NUM_WORDS_384 = 384 / 32; localparam NUM_WORDS_512 = 512 / 32; // // Clock (100 MHz) // reg clk = 1'b0; always #5 clk = ~clk; // // Inputs // reg rst_n; reg ena; reg [ 3: 0] n_num_words; reg [ 8: 0] d_num_bits; // // Outputs // wire rdy; // // Integers // integer w; // // BRAM Interfaces // wire [ 3: 0] core_m_addr; wire [ 3: 0] core_d_addr; wire [ 3: 0] core_n1_addr; wire [ 3: 0] core_n2_addr; wire [ 3: 0] core_n_coeff1_addr; wire [ 3: 0] core_n_coeff2_addr; wire [ 3: 0] core_r_addr; wire [31: 0] core_m_data; wire [31: 0] core_d_data; wire [31: 0] core_n1_data; wire [31: 0] core_n2_data; wire [31: 0] core_n_coeff1_data; wire [31: 0] core_n_coeff2_data; wire [31: 0] core_r_data_in; wire core_r_wren; reg [ 3: 0] tb_mdn_addr; reg [ 3: 0] tb_r_addr; reg [31:0] tb_m_data; reg [31:0] tb_d_data; reg [31:0] tb_n_data; reg [31:0] tb_n_coeff_data; wire [31:0] tb_r_data; reg tb_mdn_wren; // // BRAMs // bram_1rw_1ro_readfirst #(.MEM_WIDTH(32), .MEM_ADDR_BITS(4)) bram_m (.clk(clk), .a_addr(tb_mdn_addr), .a_wr(tb_mdn_wren), .a_in(tb_m_data), .a_out(), .b_addr(core_m_addr), .b_out(core_m_data)); bram_1rw_1ro_readfirst #(.MEM_WIDTH(32), .MEM_ADDR_BITS(4)) bram_d (.clk(clk), .a_addr(tb_mdn_addr), .a_wr(tb_mdn_wren), .a_in(tb_d_data), .a_out(), .b_addr(core_d_addr), .b_out(core_d_data)); bram_1rw_1ro_readfirst #(.MEM_WIDTH(32), .MEM_ADDR_BITS(4)) bram_n1 (.clk(clk), .a_addr(tb_mdn_addr), .a_wr(tb_mdn_wren), .a_in(tb_n_data), .a_out(), .b_addr(core_n1_addr), .b_out(core_n1_data)); bram_1rw_1ro_readfirst #(.MEM_WIDTH(32), .MEM_ADDR_BITS(4)) bram_n2 (.clk(clk), .a_addr(tb_mdn_addr), .a_wr(tb_mdn_wren), .a_in(tb_n_data), .a_out(), .b_addr(core_n2_addr), .b_out(core_n2_data)); bram_1rw_1ro_readfirst #(.MEM_WIDTH(32), .MEM_ADDR_BITS(4)) bram_n_coeff1 (.clk(clk), .a_addr(tb_mdn_addr), .a_wr(tb_mdn_wren), .a_in(tb_n_coeff_data), .a_out(), .b_addr(core_n_coeff1_addr), .b_out(core_n_coeff1_data)); bram_1rw_1ro_readfirst #(.MEM_WIDTH(32), .MEM_ADDR_BITS(4)) bram_n_coeff2 (.clk(clk), .a_addr(tb_mdn_addr), .a_wr(tb_mdn_wren), .a_in(tb_n_coeff_data), .a_out(), .b_addr(core_n_coeff2_addr), .b_out(core_n_coeff2_data)); bram_1rw_1ro_readfirst #(.MEM_WIDTH(32), .MEM_ADDR_BITS(4)) bram_r (.clk(clk), .a_addr(core_r_addr), .a_wr(core_r_wren), .a_in(core_r_data_in), .a_out(), .b_addr(tb_r_addr), .b_out(tb_r_data)); // // UUT // modexpa7_exponentiator # ( .OPERAND_ADDR_WIDTH (4), // 32 * (2**4) = 512-bit operands .SYSTOLIC_ARRAY_POWER (2) // 2 ** 2 = 4-tap systolic array ) uut ( .clk (clk), .rst_n (rst_n), .ena (ena), .rdy (rdy), .m_bram_addr (core_m_addr), .d_bram_addr (core_d_addr), .n1_bram_addr (core_n1_addr), .n2_bram_addr (core_n2_addr), .n_coeff1_bram_addr (core_n_coeff1_addr), .n_coeff2_bram_addr (core_n_coeff2_addr), .r_bram_addr (core_r_addr), .m_bram_out (core_m_data), .d_bram_out (core_d_data), .n1_bram_out (core_n1_data), .n2_bram_out (core_n2_data), .n_coeff1_bram_out (core_n_coeff1_data), .n_coeff2_bram_out (core_n_coeff1_data), .r_bram_in (core_r_data_in), .r_bram_wr (core_r_wren), .n_num_words (n_num_words), .d_num_bits (d_num_bits) ); // // Script // initial begin rst_n = 1'b0; ena = 1'b0; #200; rst_n = 1'b1; #100; test_exponent_384(M_FACTOR_384, D_384, N_384, N_COEFF_384, S_384); //test_exponent_512(M_512); end // // Test Tasks // task test_exponent_384; // input [383:0] m; input [383:0] d; input [383:0] n; input [383:0] n_coeff; input [383:0] s; reg [383:0] r; // integer i; // begin // n_num_words = 4'd11; // set number of words d_num_bits = 9'd383; // set number of bits // write_memory_384(m, d, n, n_coeff); // fill memory ena = 1; // start operation #10; // ena = 0; // clear flag while (!rdy) #10; // wait for operation to complete read_memory_384(r); // get result from memory $display(" calculated: %x", r); // display result $display(" expected: %x", s); // // check calculated value if (r === s) begin $display(" OK"); $display("SUCCESS: Test passed."); end else begin $display(" ERROR"); $display("FAILURE: Test not passed."); end // end // endtask /* task test_factor_512; // input [511:0] n; reg [511:0] f; reg [511:0] factor; integer i; // begin // calc_factor_512(n, f); // calculate factor on-the-fly // make sure, that the value matches the one saved in the include file if (f !== FACTOR_512) begin $display("ERROR: Calculated factor value differs from the one in the test vector!"); $finish; end n_num_words = 4'd15; // set number of words write_memory_512(n); // fill memory ena = 1; // start operation #10; // ena = 0; // clear flag while (!rdy) #10; // wait for operation to complete read_memory_512(factor); // get result from memory $display(" calculated: %x", factor); // display result $display(" expected: %x", f); // // check calculated value if (f === factor) begin $display(" OK"); $display("SUCCESS: Test passed."); end else begin $display(" ERROR"); $display("FAILURE: Test not passed."); end // end // endtask */ // // write_memory_384 // task write_memory_384; // input [383:0] m; input [383:0] d; input [383:0] n; input [383:0] n_coeff; reg [383:0] m_shreg; reg [383:0] d_shreg; reg [383:0] n_shreg; reg [383:0] n_coeff_shreg; // begin // tb_mdn_wren = 1; // start filling memories m_shreg = m; // preload shift register d_shreg = d; // preload shift register n_shreg = n; // preload shift register n_coeff_shreg = n_coeff; // preload shift register // for (w=0; w