//====================================================================== // // tb_systolic_multiplier.v // ----------------------------------------------------------------------------- // Testbench for systolic Montgomery multiplier. // // 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_systolic_multiplier; // // Test Vectors // `include "modexp_fpga_model_vectors.v"; // // Parameters // localparam NUM_WORDS_384 = 384 / 32; localparam NUM_WORDS_512 = 512 / 32; // // Model Settings // localparam NUM_ROUNDS = 1000; // // Clock (100 MHz) // reg clk = 1'b0; always #5 clk = ~clk; // // Inputs // reg rst_n; reg ena; reg [ 3: 0] n_num_words; // // Outputs // wire rdy; // // Integers // integer w; // // BRAM Interfaces // wire [ 3: 0] core_a_addr; wire [ 3: 0] core_b_addr; wire [ 3: 0] core_n_addr; wire [ 3: 0] core_n_coeff_addr; wire [ 3: 0] core_r_addr; wire [31: 0] core_a_data; wire [31: 0] core_b_data; wire [31: 0] core_n_data; wire [31: 0] core_n_coeff_data; wire [31: 0] core_r_data; wire core_r_wren; reg [ 3: 0] tb_abn_addr; reg [ 3: 0] tb_r_addr; reg [31:0] tb_a_data; reg [31:0] tb_b_data; reg [31:0] tb_n_data; reg [31:0] tb_n_coeff_data; wire [31:0] tb_r_data; reg tb_abn_wren; // // BRAMs // bram_1rw_1ro_readfirst #(.MEM_WIDTH(32), .MEM_ADDR_BITS(4)) bram_a (.clk(clk), .a_addr(tb_abn_addr), .a_wr(tb_abn_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(4)) bram_b (.clk(clk), .a_addr(tb_abn_addr), .a_wr(tb_abn_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(4)) bram_n (.clk(clk), .a_addr(tb_abn_addr), .a_wr(tb_abn_wren), .a_in(tb_n_data), .a_out(), .b_addr(core_n_addr), .b_out(core_n_data)); bram_1rw_1ro_readfirst #(.MEM_WIDTH(32), .MEM_ADDR_BITS(4)) bram_n_coeff (.clk(clk), .a_addr(tb_abn_addr), .a_wr(tb_abn_wren), .a_in(tb_n_coeff_data), .a_out(), .b_addr(core_n_coeff_addr), .b_out(core_n_coeff_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), .a_out(), .b_addr(tb_r_addr), .b_out(tb_r_data)); // // UUT // modexpa7_systolic_multiplier # ( .OPERAND_ADDR_WIDTH (4), // 32 * (2**4) = 512-bit operands .SYSTOLIC_ARRAY_POWER (2) // 2 ** 2 = 4-tap array ) uut ( .clk (clk), .rst_n (rst_n), .ena (ena), .rdy (rdy), .a_bram_addr (core_a_addr), .b_bram_addr (core_b_addr), .n_bram_addr (core_n_addr), .n_coeff_bram_addr (core_n_coeff_addr), .r_bram_addr (core_r_addr), .a_bram_out (core_a_data), .b_bram_out (core_b_data), .n_bram_out (core_n_data), .n_coeff_bram_out (core_n_coeff_data), .r_bram_in (core_r_data), .r_bram_wr (core_r_wren), .n_num_words (n_num_words) ); // // Script // initial begin rst_n = 1'b0; ena = 1'b0; #200; rst_n = 1'b1; #100; test_systolic_multiplier_384(M_384, N_384, N_COEFF_384, FACTOR_384, COEFF_384); test_systolic_multiplier_512(M_512, N_512, N_COEFF_512, FACTOR_512, COEFF_512); end // // Test Tasks // task test_systolic_multiplier_384; input [383:0] m; input [383:0] n; input [383:0] n_coeff; input [383:0] factor; input [383:0] coeff; reg [767:0] m_factor_full; reg [383:0] m_factor_modulo; reg [383:0] a; reg [383:0] b; reg [383:0] r; reg [767:0] ab_full; reg [383:0] ab_modulo; integer round; integer num_passed; integer num_failed; begin m_factor_full = m * factor; // m * factor m_factor_modulo = m_factor_full % n; // m * factor % n m_factor_full = m_factor_modulo * coeff; // m * factor * coeff m_factor_modulo = m_factor_full % n; // m * factor * coeff % n a = m_factor_modulo; // start with a = m_factor... b = m_factor_modulo; // ... and b = m_factor n_num_words = 4'd11; // set number of words num_passed = 0; // nothing tested so far num_failed = 0; // for (round=0; round