//====================================================================== // // Copyright (c) 2019, 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_core_full_512; // // Headers // `include "../rtl/modexpng_parameters.vh" // // Test Vectors // localparam TB_MODULUS_LENGTH_N = 512; localparam TB_MODULUS_LENGTH_PQ = TB_MODULUS_LENGTH_N / 2; localparam TB_NUM_WORDS_PQ = TB_MODULUS_LENGTH_PQ / BUS_DATA_W; localparam TB_NUM_WORDS_N = TB_MODULUS_LENGTH_N / BUS_DATA_W; localparam CORE_NUM_WORDS_PQ = TB_MODULUS_LENGTH_PQ / WORD_W; localparam CORE_NUM_WORDS_N = TB_MODULUS_LENGTH_N / WORD_W; reg [31:0] M[0:TB_NUM_WORDS_N-1]; reg [31:0] N[0:TB_NUM_WORDS_N-1]; reg [31:0] N_FACTOR[0:TB_NUM_WORDS_N-1]; reg [31:0] N_COEFF[0:TB_NUM_WORDS_N]; reg [31:0] X[0:TB_NUM_WORDS_N-1]; reg [31:0] Y[0:TB_NUM_WORDS_N-1]; reg [31:0] P[0:TB_NUM_WORDS_PQ-1]; reg [31:0] Q[0:TB_NUM_WORDS_PQ-1]; reg [31:0] P_FACTOR[0:TB_NUM_WORDS_PQ-1]; reg [31:0] Q_FACTOR[0:TB_NUM_WORDS_PQ-1]; reg [31:0] P_COEFF[0:TB_NUM_WORDS_PQ]; reg [31:0] Q_COEFF[0:TB_NUM_WORDS_PQ]; reg [31:0] D[0:TB_NUM_WORDS_N-1]; reg [31:0] DP[0:TB_NUM_WORDS_PQ-1]; reg [31:0] DQ[0:TB_NUM_WORDS_PQ-1]; reg [31:0] QINV[0:TB_NUM_WORDS_PQ-1]; reg [31:0] XM[0:TB_NUM_WORDS_N-1]; reg [31:0] YM[0:TB_NUM_WORDS_N-1]; reg [31:0] S[0:TB_NUM_WORDS_N-1]; reg [31:0] XM_READBACK[0:TB_NUM_WORDS_N-1]; reg [31:0] YM_READBACK[0:TB_NUM_WORDS_N-1]; reg [31:0] S_READBACK[0:TB_NUM_WORDS_N-1]; initial begin M[ 0] = 32'h8d3b583b; M[ 1] = 32'hc370f07e; M[ 2] = 32'hb9078738; M[ 3] = 32'haf37f86c; M[ 4] = 32'h02f0e161; M[ 5] = 32'h0506a68a; M[ 6] = 32'h1ae65107; M[ 7] = 32'hcd3a97f1; M[ 8] = 32'hb27244b8; M[ 9] = 32'h9bc3c400; M[ 10] = 32'he4d5636e; M[ 11] = 32'h35187c07; M[ 12] = 32'h78a661c9; M[ 13] = 32'h1e7ec273; M[ 14] = 32'hcdc31041; M[ 15] = 32'h002291d8; N[ 0] = 32'hcb703101; N[ 1] = 32'h82bc8290; N[ 2] = 32'hdb2372c2; N[ 3] = 32'hdeeb692e; N[ 4] = 32'ha3ee352a; N[ 5] = 32'h81a711ba; N[ 6] = 32'h14ee23bd; N[ 7] = 32'h8ad351c0; N[ 8] = 32'h75ecd3d5; N[ 9] = 32'h51c9b22f; N[ 10] = 32'hc1d3496e; N[ 11] = 32'h48176f3e; N[ 12] = 32'hd2aca749; N[ 13] = 32'hf236cea9; N[ 14] = 32'h7f4525ed; N[ 15] = 32'hb4fc5067; N_FACTOR[ 0] = 32'he253bfbf; N_FACTOR[ 1] = 32'h8e0b26aa; N_FACTOR[ 2] = 32'h0480b661; N_FACTOR[ 3] = 32'h9a13f7a1; N_FACTOR[ 4] = 32'h464b7342; N_FACTOR[ 5] = 32'hfb6f8e41; N_FACTOR[ 6] = 32'h081208e4; N_FACTOR[ 7] = 32'h63d8328a; N_FACTOR[ 8] = 32'h604d2b71; N_FACTOR[ 9] = 32'hc987dabe; N_FACTOR[ 10] = 32'h8a474e35; N_FACTOR[ 11] = 32'hc053ba1c; N_FACTOR[ 12] = 32'h15b82dd9; N_FACTOR[ 13] = 32'h42c2bbfa; N_FACTOR[ 14] = 32'h1681e95d; N_FACTOR[ 15] = 32'h07dee5fa; N_COEFF[ 0] = 32'h730f30ff; N_COEFF[ 1] = 32'h50ed900a; N_COEFF[ 2] = 32'h0b9038c5; N_COEFF[ 3] = 32'h974ddd03; N_COEFF[ 4] = 32'he2c118c8; N_COEFF[ 5] = 32'hbe1bc7e1; N_COEFF[ 6] = 32'h224d548c; N_COEFF[ 7] = 32'h48ea2ee4; N_COEFF[ 8] = 32'heb379247; N_COEFF[ 9] = 32'had97b934; N_COEFF[ 10] = 32'hfc6dfd93; N_COEFF[ 11] = 32'h3a0246ef; N_COEFF[ 12] = 32'h1baa167c; N_COEFF[ 13] = 32'h7d7ee254; N_COEFF[ 14] = 32'h657f0a53; N_COEFF[ 15] = 32'hea9e7245; N_COEFF[ 16] = 32'h0000f88c; X[ 0] = 32'h2d532c22; X[ 1] = 32'h2d3c3b06; X[ 2] = 32'he2862a8f; X[ 3] = 32'he8616ce4; X[ 4] = 32'h5d77ee51; X[ 5] = 32'he609de07; X[ 6] = 32'hef718044; X[ 7] = 32'h82f35f8b; X[ 8] = 32'hcdb9dcfe; X[ 9] = 32'hff6ea364; X[ 10] = 32'h0994ae28; X[ 11] = 32'h409b369b; X[ 12] = 32'hcfabda4e; X[ 13] = 32'h5cd52bbc; X[ 14] = 32'hd90e1715; X[ 15] = 32'h00f4dcf2; Y[ 0] = 32'h34fff653; Y[ 1] = 32'h50f52544; Y[ 2] = 32'h0ebf96a7; Y[ 3] = 32'h98352265; Y[ 4] = 32'hbe372927; Y[ 5] = 32'h5b2f6394; Y[ 6] = 32'h9acfccb3; Y[ 7] = 32'h7b5bd4b2; Y[ 8] = 32'h79b09448; Y[ 9] = 32'h08f11fa6; Y[ 10] = 32'h8411d066; Y[ 11] = 32'h58ba5021; Y[ 12] = 32'h03c1cb72; Y[ 13] = 32'hacf0689d; Y[ 14] = 32'h983c65bd; Y[ 15] = 32'h29a39dcc; P[ 0] = 32'hebfc2433; P[ 1] = 32'ha2cfbc81; P[ 2] = 32'hea08812b; P[ 3] = 32'h0adf004f; P[ 4] = 32'hb987a8c6; P[ 5] = 32'h2860f873; P[ 6] = 32'haf2cfe12; P[ 7] = 32'hddd53c3a; Q[ 0] = 32'hdc1981fb; Q[ 1] = 32'h01184053; Q[ 2] = 32'h7ab8d640; Q[ 3] = 32'h62ba8a22; Q[ 4] = 32'h6cb226a1; Q[ 5] = 32'he1f08e16; Q[ 6] = 32'h13e990b5; Q[ 7] = 32'hd0dc7ce3; P_FACTOR[ 0] = 32'h043fb284; P_FACTOR[ 1] = 32'hcaab7ce3; P_FACTOR[ 2] = 32'h543c62ef; P_FACTOR[ 3] = 32'h8aa74942; P_FACTOR[ 4] = 32'hefa2ea7b; P_FACTOR[ 5] = 32'hdb8513b5; P_FACTOR[ 6] = 32'h0ea607a4; P_FACTOR[ 7] = 32'h6a59e5a7; Q_FACTOR[ 0] = 32'h089dcd43; Q_FACTOR[ 1] = 32'h5b23611b; Q_FACTOR[ 2] = 32'h02f0f47c; Q_FACTOR[ 3] = 32'h952ababd; Q_FACTOR[ 4] = 32'hc4ee13fe; Q_FACTOR[ 5] = 32'h3feb46fa; Q_FACTOR[ 6] = 32'h96b679df; Q_FACTOR[ 7] = 32'h831126dd; P_COEFF[ 0] = 32'h647c8905; P_COEFF[ 1] = 32'hcb7c6b7d; P_COEFF[ 2] = 32'h8053b8be; P_COEFF[ 3] = 32'hb28f33a7; P_COEFF[ 4] = 32'hb3207e05; P_COEFF[ 5] = 32'h4e3d416e; P_COEFF[ 6] = 32'h1911d8d9; P_COEFF[ 7] = 32'hd569156e; P_COEFF[ 8] = 32'h00003dd7; Q_COEFF[ 0] = 32'h5eee9ecd; Q_COEFF[ 1] = 32'h085153b0; Q_COEFF[ 2] = 32'h85326da6; Q_COEFF[ 3] = 32'h7521931a; Q_COEFF[ 4] = 32'h99e0eef1; Q_COEFF[ 5] = 32'ha219917b; Q_COEFF[ 6] = 32'he8e9087a; Q_COEFF[ 7] = 32'h5239d12b; Q_COEFF[ 8] = 32'h0000ed92; D[ 0] = 32'hf127ca41; D[ 1] = 32'hc4975ff0; D[ 2] = 32'h69ebbe13; D[ 3] = 32'h66fe0018; D[ 4] = 32'hf2089237; D[ 5] = 32'hfa3f05ab; D[ 6] = 32'h2ab183c4; D[ 7] = 32'h1e4b3c04; D[ 8] = 32'ha67974e8; D[ 9] = 32'ha6714d63; D[ 10] = 32'hfe5cd801; D[ 11] = 32'h13f2071a; D[ 12] = 32'h0b978309; D[ 13] = 32'hb0ddb4a0; D[ 14] = 32'ha437a2cc; D[ 15] = 32'h2391b2fb; DP[ 0] = 32'h3891ed91; DP[ 1] = 32'h775046c2; DP[ 2] = 32'h60180c26; DP[ 3] = 32'h5130700a; DP[ 4] = 32'hb13c8216; DP[ 5] = 32'h833fcf78; DP[ 6] = 32'h7ab89b12; DP[ 7] = 32'hb976758c; DQ[ 0] = 32'h28cc59ad; DQ[ 1] = 32'h3ce6ed45; DQ[ 2] = 32'ha1f53aeb; DQ[ 3] = 32'h06ca05e1; DQ[ 4] = 32'hc5195df6; DQ[ 5] = 32'h42cf91f8; DQ[ 6] = 32'h93d6f054; DQ[ 7] = 32'h3d3bc769; QINV[ 0] = 32'h50201af6; QINV[ 1] = 32'h85d97b7f; QINV[ 2] = 32'h4247e697; QINV[ 3] = 32'h9fd231fe; QINV[ 4] = 32'h21e98610; QINV[ 5] = 32'ha0bc58dc; QINV[ 6] = 32'ha86f266c; QINV[ 7] = 32'h838688c8; XM[ 0] = 32'hf9980f33; XM[ 1] = 32'hb444f483; XM[ 2] = 32'h0a6f8294; XM[ 3] = 32'h1c74da49; XM[ 4] = 32'h0aa4151f; XM[ 5] = 32'ha1dfb66f; XM[ 6] = 32'h1415da79; XM[ 7] = 32'had7d3272; XM[ 8] = 32'h43d7b612; XM[ 9] = 32'h56626cce; XM[ 10] = 32'ha65edef6; XM[ 11] = 32'h28c49eb8; XM[ 12] = 32'h5364b7f8; XM[ 13] = 32'hd170915e; XM[ 14] = 32'h5a4c960d; XM[ 15] = 32'h27cb1911; YM[ 0] = 32'h7640c2ca; YM[ 1] = 32'hf49d583a; YM[ 2] = 32'he4ae0f22; YM[ 3] = 32'ha3dad5ed; YM[ 4] = 32'hbe88ab4d; YM[ 5] = 32'h9fb50b38; YM[ 6] = 32'h223feceb; YM[ 7] = 32'hfc4893ff; YM[ 8] = 32'hb40556c2; YM[ 9] = 32'hb25b27fa; YM[ 10] = 32'h7e277535; YM[ 11] = 32'h42e1e9ab; YM[ 12] = 32'hebd55ef2; YM[ 13] = 32'h8b6d8c0b; YM[ 14] = 32'h4d91ad9a; YM[ 15] = 32'h0e8bf565; S[ 0] = 32'h2f89f059; S[ 1] = 32'hdbc41170; S[ 2] = 32'h1d7ea6c0; S[ 3] = 32'h1df9add6; S[ 4] = 32'ha619e2e1; S[ 5] = 32'h253fcd88; S[ 6] = 32'h6c03a351; S[ 7] = 32'h795b1df0; S[ 8] = 32'h2854a51a; S[ 9] = 32'h0245619b; S[ 10] = 32'hfb67ef8f; S[ 11] = 32'hcc5bdd4f; S[ 12] = 32'ha70f58bd; S[ 13] = 32'h31f15702; S[ 14] = 32'hd6f36259; S[ 15] = 32'h280e67e0; end // // Clocks // `define CLK_FREQUENCY_MHZ (100.0) `define CLK_PERIOD_NS (1000.0 / `CLK_FREQUENCY_MHZ) `define CLK_PERIOD_HALF_NS (0.5 * `CLK_PERIOD_NS) `define CLK_PERIOD_QUARTER_NS (0.5 * `CLK_PERIOD_HALF_NS) `define CLK_BUS_FREQUENCY_MHZ (25.0) `define CLK_BUS_PERIOD_NS (1000.0 / `CLK_BUS_FREQUENCY_MHZ) `define CLK_BUS_PERIOD_HALF_NS (0.5 * `CLK_BUS_PERIOD_NS) reg clk = 1'b1; reg clk_dly = 1'b0; wire clk_idle = clk & clk_dly; reg clk_bus = 1'b1; reg clk_bus_dly = 1'b0; wire clk_bus_idle = clk_bus & clk_bus_dly; always #`CLK_PERIOD_HALF_NS clk <= ~clk; always #`CLK_BUS_PERIOD_HALF_NS clk_bus <= ~clk_bus; always @(clk ) clk_dly <= #(`CLK_PERIOD_HALF_NS - `CLK_PERIOD_QUARTER_NS) clk; always @(clk_bus) clk_bus_dly <= #(`CLK_BUS_PERIOD_HALF_NS - `CLK_PERIOD_QUARTER_NS) clk_bus; // // Clock Sync // task sync_clk; while (clk_idle !== 1) _wait_quarter_clk_tick; endtask task sync_clk_bus; while (clk_bus_idle !== 1) _wait_quarter_clk_tick; endtask // // Reset // reg rst = 1'b1; wire rst_n = ~rst; // // Control / Status // reg [ 7:0] word_index_last_n; reg [ 7:0] word_index_last_pq; reg [11:0] bit_index_last_n; reg [11:0] bit_index_last_pq; reg core_next = 1'b0; wire core_valid; reg core_crt_mode; // // System Bus // reg bus_cs = 1'b0; reg bus_we = 1'b0; reg [11:0] bus_addr; reg [31:0] bus_data_wr; wire [31:0] bus_data_rd; wire [ 1:0] bus_addr_sel = bus_addr[11:10]; wire [ 2:0] bus_addr_bank = bus_addr[9:7]; wire [ 6:0] bus_addr_data = bus_addr[6:0]; // // UUT // modexpng_core_top uut ( .clk (clk), .clk_bus (clk_bus), .rst_n (rst_n), .next (core_next), .valid (core_valid), .crt_mode (core_crt_mode), .word_index_last_n (word_index_last_n), .word_index_last_pq (word_index_last_pq), .bit_index_last_n (bit_index_last_n), .bit_index_last_pq (bit_index_last_pq), .bus_cs (bus_cs), .bus_we (bus_we), .bus_addr (bus_addr), .bus_data_wr (bus_data_wr), .bus_data_rd (bus_data_rd) ); // // Bus Init Routine // task core_set_input; begin core_set_input_1; core_set_input_2; wait_clk_bus_ticks(10); $display("Core input banks written."); end endtask // // Script // initial main; // // Main Routine (Control/Status, Bus) // integer i, j, k; task main; begin sync_clk; // switch to fast core clock core_reset; // reset core core_set_params; // set parameters (modulus width, exponent length) sync_clk_bus; // switch to slow bus clock core_set_input; // write to core input banks /**//**/ sync_clk; // switch to fast core clock core_set_crt_mode(1); // enable CRT signing core_pulse_next; // assert 'next' bit for one cycle core_wait_valid; // wait till 'valid' bit gets asserted sync_clk_bus; // switch to slow bus clock core_get_output; // read from core output banks core_verify_output; // check, whether core output matches precomputed known good refrence values core_print_load; // /**//**/ sync_clk; // switch to fast core clock core_set_crt_mode(0); // disable CRT signing core_pulse_next; // assert 'next' bit for one cycle core_wait_valid; // wait till 'valid' bit gets asserted sync_clk_bus; // switch to slow bus clock core_get_output; // read from core output banks core_verify_output; // check, whether core output matches precomputed known good refrence values core_print_load; // /**//**/ end endtask task core_reset; begin wait_clk_ticks(100); rst = 1'b0; wait_clk_ticks(10); $display("Core reset finished."); end endtask task core_set_params; begin word_index_last_n = CORE_NUM_WORDS_N - 1; word_index_last_pq = CORE_NUM_WORDS_PQ - 1; bit_index_last_n = TB_MODULUS_LENGTH_N - 1; bit_index_last_pq = TB_MODULUS_LENGTH_N / 2 - 1; $display("Core parameters set."); end endtask task core_set_crt_mode; input _crt; begin core_crt_mode = _crt; if (_crt) $display("Enabled CRT mode."); else $display("Disabled CRT mode."); end endtask task core_pulse_next; begin core_next = 1'b1; wait_clk_tick; core_next = 1'b0; $display("Pulsed core 'next' control signal."); end endtask task core_wait_valid; begin while (!core_valid) wait_clk_tick; wait_clk_ticks(10); $display("Detected high core 'valid' status signal."); end endtask // // Variables // integer _w, _n; // // core_set_input_1 // task core_set_input_1; reg [9:0] _tn; begin _tn = BANK_IN_1_N_COEFF * 2 ** BUS_OP_ADDR_W + TB_NUM_WORDS_N; // trick to write extra trailer word for (_w=0; _w ", XM[_w] ^ XM_READBACK[_w]); $write("\n"); end // if (!ym_ok) // for (_w=0; _w ", YM[_w] ^ YM_READBACK[_w]); $write("\n"); end // if (!s_ok) // for (_w=0; _w ", S[_w] ^ S_READBACK[_w]); $write("\n"); end // $write("XM is "); if (xm_ok) $write("OK.\n"); else $write("WRONG!\n"); // $write("YM is "); if (ym_ok) $write("OK.\n"); else $write("WRONG!\n"); // $write("S is "); if (s_ok) $write("OK.\n"); else $write("WRONG!\n"); // end // endtask // // _bus_drive() // task _bus_drive; input cs; input we; input [11:0] addr; input [31:0] data; {bus_cs, bus_we, bus_addr, bus_data_wr} <= {cs, we, addr, data}; endtask // // bus_write() // task bus_write; input [ 1:0] sel; input [ 2:0] bank; input [ 6:0] addr; input [31:0] data; begin _bus_drive(1'b1, 1'b1, {sel, bank, addr}, data); wait_clk_bus_tick; _bus_drive(1'b0, 1'b0, 12'hXXX, 32'hXXXXXXXX); end endtask // // bus_read() // task bus_read; input [ 1:0] sel; input [ 2:0] bank; input [ 6:0] addr; output [31:0] data; begin _bus_drive(1'b1, 1'b0, {sel, bank, addr}, 32'hXXXXXXXX); wait_clk_bus_tick; data = bus_data_rd; _bus_drive(1'b0, 1'b0, 12'hXXX, 32'hXXXXXXXX); end endtask // // _wait_quarter_clk_tick() // task _wait_quarter_clk_tick; #`CLK_PERIOD_QUARTER_NS; endtask // // _wait_half_clk_tick() // task _wait_half_clk_tick; begin _wait_quarter_clk_tick; _wait_quarter_clk_tick; end endtask // // wait_clk_tick() // task wait_clk_tick; begin _wait_half_clk_tick; _wait_half_clk_tick; end endtask // // wait_clk_bus_tick() // task wait_clk_bus_tick; #`CLK_BUS_PERIOD_NS; endtask // // wait_clk_ticks() // task wait_clk_ticks; input integer num_ticks; for (_n=0; _n