diff options
-rw-r--r-- | src/rtl/trng_csprng.v | 497 | ||||
-rw-r--r-- | src/rtl/trng_csprng_fifo.v | 550 | ||||
-rw-r--r-- | src/tb/tb_csprng.v | 309 |
3 files changed, 1356 insertions, 0 deletions
diff --git a/src/rtl/trng_csprng.v b/src/rtl/trng_csprng.v new file mode 100644 index 0000000..4d472d2 --- /dev/null +++ b/src/rtl/trng_csprng.v @@ -0,0 +1,497 @@ +//====================================================================== +// +// trng_csprng.v +// ------------- +// CSPRNG for the TRNG. +// +// +// Author: Joachim Strombergson +// Copyright (c) 2014, 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. +// +//====================================================================== + +module trng_csprng( + // Clock and reset. + input wire clk, + input wire reset_n, + + // Control, config and status. + input debug_mode, + input wire [4 : 0] num_rounds, + input wire [63 : 0] num_blocks, + input wire seed, + input wire enable, + output wire more_seed, + output wire ready, + output wire error, + + // Seed input + input wire seed_syn, + input [511 : 0] seed_data, + output wire seed_ack, + + // Random data output + output wire rnd_syn, + output wire [31 : 0] rnd_data, + input wire rnd_ack + ); + + + //---------------------------------------------------------------- + // Internal constant and parameter definitions. + //---------------------------------------------------------------- + parameter CIPHER_KEYLEN256 = 1'b1; // 256 bit key. + parameter CIPHER_MAX_BLOCKS = 64'h1000000000000000; + + parameter CTRL_IDLE = 4'h0; + parameter CTRL_SEED0 = 4'h1; + parameter CTRL_SEED1 = 4'h2; + parameter CTRL_INIT0 = 4'h3; + parameter CTRL_INIT1 = 4'h4; + parameter CTRL_NEXT0 = 4'h5; + parameter CTRL_NEXT1 = 4'h6; + parameter CTRL_MORE = 4'h7; + parameter CTRL_CANCEL = 4'hf; + + + //---------------------------------------------------------------- + // Registers including update variables and write enable. + //---------------------------------------------------------------- + reg [255 : 0] cipher_key_reg; + reg [255 : 0] cipher_key_new; + reg cipher_key_we; + + reg [63 : 0] cipher_iv_reg; + reg [63 : 0] cipher_iv_new; + reg cipher_iv_we; + + reg [63 : 0] cipher_ctr_reg; + reg [63 : 0] cipher_ctr_new; + reg cipher_ctr_we; + + reg [511 : 0] cipher_block_reg; + reg [511 : 0] cipher_block_new; + reg cipher_block_we; + + reg [63 : 0] block_ctr_reg; + reg [63 : 0] block_ctr_new; + reg block_ctr_inc; + reg block_ctr_rst; + reg block_ctr_we; + reg block_ctr_max; + + reg error_reg; + reg error_new; + reg error_we; + + reg [3 : 0] csprng_ctrl_reg; + reg [3 : 0] csprng_ctrl_new; + reg csprng_ctrl_we; + + reg ready_reg; + reg ready_new; + reg ready_we; + + reg more_seed_reg; + reg more_seed_new; + + reg seed_ack_reg; + reg seed_ack_new; + + + //---------------------------------------------------------------- + // Wires. + //---------------------------------------------------------------- + reg cipher_init; + reg cipher_next; + + wire [511 : 0] cipher_data_out; + wire cipher_data_out_valid; + + reg discard_outputs; + + wire fifo_more_data; + reg fifo_discard; + wire fifo_rnd_syn; + wire [31 : 0] fifo_rnd_data; + reg fifo_cipher_data_valid; + + + //---------------------------------------------------------------- + // Concurrent connectivity for ports etc. + //---------------------------------------------------------------- + assign seed_ack = seed_ack_reg; + assign more_seed = more_seed_reg; + + assign ready = ready_reg; + assign error = error_reg; + + assign rnd_syn = fifo_rnd_syn; + assign rnd_data = fifo_rnd_data; + + + //---------------------------------------------------------------- + // core instantiation. + //---------------------------------------------------------------- + chacha_core cipher( + .clk(clk), + .reset_n(reset_n), + + .init(cipher_init), + .next(cipher_next), + + .key(cipher_key_reg), + .keylen(CIPHER_KEYLEN256), + .iv(cipher_iv_reg), + .ctr(cipher_ctr_reg), + .rounds(num_rounds), + + .data_in(cipher_block_reg), + .ready(cipher_ready), + + .data_out(cipher_data_out), + .data_out_valid(cipher_data_out_valid) + ); + + + trng_csprng_fifo fifo( + .clk(clk), + .reset_n(reset_n), + + .csprng_data(cipher_data_out), + .csprng_data_valid(fifo_cipher_data_valid), + .discard(fifo_discard), + .more_data(fifo_more_data), + + .rnd_syn(fifo_rnd_syn), + .rnd_data(fifo_rnd_data), + .rnd_ack(rnd_ack) + ); + + + //---------------------------------------------------------------- + // reg_update + // + // Update functionality for all registers in the core. + // All registers are positive edge triggered with synchronous + // active low reset. All registers have write enable. + //---------------------------------------------------------------- + always @ (posedge clk or negedge reset_n) + begin + if (!reset_n) + begin + cipher_key_reg <= {8{32'h00000000}}; + cipher_iv_reg <= {2{32'h00000000}}; + cipher_ctr_reg <= {2{32'h00000000}}; + cipher_block_reg <= {16{32'h00000000}}; + block_ctr_reg <= {2{32'h00000000}}; + more_seed_reg <= 0; + seed_ack_reg <= 0; + ready_reg <= 0; + error_reg <= 0; + csprng_ctrl_reg <= CTRL_IDLE; + end + else + begin + more_seed_reg <= more_seed_new; + seed_ack_reg <= seed_ack_new; + + if (cipher_key_we) + begin + cipher_key_reg <= cipher_key_new; + end + + if (cipher_iv_we) + begin + cipher_iv_reg <= cipher_iv_new; + end + + if (cipher_ctr_we) + begin + cipher_ctr_reg <= cipher_ctr_new; + end + + if (cipher_block_we) + begin + cipher_block_reg <= cipher_block_new; + end + + if (block_ctr_we) + begin + block_ctr_reg <= block_ctr_new; + end + + if (ready_we) + begin + ready_reg <= ready_new; + end + + if (error_we) + begin + error_reg <= error_new; + end + + if (csprng_ctrl_we) + begin + csprng_ctrl_reg <= csprng_ctrl_new; + end + end + end // reg_update + + + //---------------------------------------------------------------- + // block_ctr + // + // Logic to implement the block counter. This includes the + // ability to detect that maximum allowed number of blocks + // has been reached. Either as defined by the application + // or the hard coded CIPHER_MAX_BLOCKS value. + //---------------------------------------------------------------- + always @* + begin : block_ctr + block_ctr_new = 64'h0000000000000000; + block_ctr_we = 0; + block_ctr_max = 0; + + if (block_ctr_rst) + begin + block_ctr_new = 64'h0000000000000000; + block_ctr_we = 1; + end + + if (block_ctr_inc) + begin + block_ctr_new = block_ctr_reg + 1'b1; + block_ctr_we = 1; + end + + if ((block_ctr_reg == num_blocks) || (block_ctr_reg == CIPHER_MAX_BLOCKS)) + begin + block_ctr_max = 1; + end + end // block_ctr + + + //---------------------------------------------------------------- + // csprng_ctrl_fsm + // + // Control FSM for the CSPRNG. + //---------------------------------------------------------------- + always @* + begin : csprng_ctrl_fsm + cipher_key_new = {8{32'h00000000}}; + cipher_key_we = 0; + cipher_iv_new = {2{32'h00000000}}; + cipher_iv_we = 0; + cipher_ctr_new = {2{32'h00000000}}; + cipher_ctr_we = 0; + cipher_block_new = {16{32'h00000000}}; + cipher_block_we = 0; + cipher_init = 0; + cipher_next = 0; + block_ctr_rst = 0; + block_ctr_inc = 0; + ready_new = 0; + ready_we = 0; + error_new = 0; + error_we = 0; + discard_outputs = 0; + seed_ack_new = 0; + more_seed_new = 0; + fifo_discard = 0; + fifo_cipher_data_valid = 0; + csprng_ctrl_new = CTRL_IDLE; + csprng_ctrl_we = 0; + + case (csprng_ctrl_reg) + CTRL_IDLE: + begin + if (!enable) + begin + csprng_ctrl_new = CTRL_CANCEL; + csprng_ctrl_we = 1; + end + else if (fifo_more_data) + begin + more_seed_new = 1; + csprng_ctrl_new = CTRL_SEED0; + csprng_ctrl_we = 1; + end + end + + CTRL_SEED0: + begin + if ((!enable) || (seed)) + begin + csprng_ctrl_new = CTRL_CANCEL; + csprng_ctrl_we = 1; + end + else if (seed_syn) + begin + more_seed_new = 1; + seed_ack_new = 1; + cipher_block_new = seed_data; + cipher_block_we = 1; + csprng_ctrl_new = CTRL_SEED1; + csprng_ctrl_we = 1; + end + end + + CTRL_SEED1: + begin + if ((!enable) || (seed)) + begin + csprng_ctrl_new = CTRL_CANCEL; + csprng_ctrl_we = 1; + end + else if (seed_syn) + begin + seed_ack_new = 1; + cipher_key_new = seed_data[255 : 0]; + cipher_key_we = 1; + cipher_iv_new = seed_data[319 : 256]; + cipher_iv_we = 1; + cipher_ctr_new = seed_data[383 : 320]; + cipher_ctr_we = 1; + csprng_ctrl_new = CTRL_INIT0; + csprng_ctrl_we = 1; + end + else + begin + more_seed_new = 1; + end + end + + CTRL_INIT0: + begin + if ((!enable) || (seed)) + begin + csprng_ctrl_new = CTRL_CANCEL; + csprng_ctrl_we = 1; + end + else + begin + cipher_init = 1; + block_ctr_rst = 1; + csprng_ctrl_new = CTRL_INIT1; + csprng_ctrl_we = 1; + end + end + + CTRL_INIT1: + begin + if ((!enable) || (seed)) + begin + csprng_ctrl_new = CTRL_CANCEL; + csprng_ctrl_we = 1; + end + else if (cipher_ready) + begin + csprng_ctrl_new = CTRL_NEXT0; + csprng_ctrl_we = 1; + end + end + + CTRL_NEXT0: + begin + if ((!enable) || (seed)) + begin + csprng_ctrl_new = CTRL_CANCEL; + csprng_ctrl_we = 1; + end + else + begin + cipher_next = 1; + csprng_ctrl_new = CTRL_NEXT1; + csprng_ctrl_we = 1; + end + end + + CTRL_NEXT1: + if ((!enable) || (seed)) + begin + csprng_ctrl_new = CTRL_CANCEL; + csprng_ctrl_we = 1; + end + else if (cipher_ready) + begin + block_ctr_inc = 1; + fifo_cipher_data_valid = 1; + csprng_ctrl_new = CTRL_MORE; + csprng_ctrl_we = 1; + end + + CTRL_MORE: + begin + if ((!enable) || (seed)) + begin + csprng_ctrl_new = CTRL_CANCEL; + csprng_ctrl_we = 1; + end + else if (fifo_more_data) + begin + if (block_ctr_max) + begin + more_seed_new = 1; + csprng_ctrl_new = CTRL_SEED0; + csprng_ctrl_we = 1; + end + else + begin + csprng_ctrl_new = CTRL_NEXT0; + csprng_ctrl_we = 1; + end + end + end + + CTRL_CANCEL: + begin + fifo_discard = 1; + cipher_key_new = {8{32'h00000000}}; + cipher_key_we = 1; + cipher_iv_new = {2{32'h00000000}}; + cipher_iv_we = 1; + cipher_ctr_new = {2{32'h00000000}}; + cipher_ctr_we = 1; + cipher_block_new = {16{32'h00000000}}; + cipher_block_we = 1; + block_ctr_rst = 1; + discard_outputs = 1; + csprng_ctrl_new = CTRL_IDLE; + csprng_ctrl_we = 1; + end + + endcase // case (cspng_ctrl_reg) + end // csprng_ctrl_fsm + +endmodule // trng_csprng + +//====================================================================== +// EOF trng_csprng.v +//====================================================================== diff --git a/src/rtl/trng_csprng_fifo.v b/src/rtl/trng_csprng_fifo.v new file mode 100644 index 0000000..4d908f9 --- /dev/null +++ b/src/rtl/trng_csprng_fifo.v @@ -0,0 +1,550 @@ +//====================================================================== +// +// trng_csprng_fifo.v +// ------------------ +// Output FIFO for the CSPRNG in the TRNG. +// +// +// Author: Joachim Strombergson +// Copyright (c) 2014, 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. +// +//====================================================================== + +module trng_csprng_fifo( + // Clock and reset. + input wire clk, + input wire reset_n, + + input wire [511 : 0] csprng_data, + input wire csprng_data_valid, + input wire discard, + output wire more_data, + + output wire rnd_syn, + output wire [31 : 0] rnd_data, + input wire rnd_ack + ); + + + //---------------------------------------------------------------- + // Internal constant and parameter definitions. + //---------------------------------------------------------------- + parameter FIFO_DEPTH = 32; + parameter FIFO_MAX = FIFO_DEPTH - 1; + + parameter WR_IDLE = 0; + parameter WR_WAIT = 1; + parameter WR_WRITE = 2; + parameter WR_DISCARD = 7; + + parameter RD_IDLE = 0; + parameter RD_ACK = 1; + parameter RD_DISCARD = 7; + + + //---------------------------------------------------------------- + // Registers including update variables and write enable. + //---------------------------------------------------------------- + reg [31 : 0] fifo_mem [0 : FIFO_MAX]; + reg fifo_mem_we; + + reg [3 : 0] mux_data_ptr_reg; + reg [3 : 0] mux_data_ptr_new; + reg mux_data_ptr_inc; + reg mux_data_ptr_rst; + reg mux_data_ptr_we; + + reg [7 : 0] wr_ptr_reg; + reg [7 : 0] wr_ptr_new; + reg wr_ptr_inc; + reg wr_ptr_rst; + reg wr_ptr_we; + + reg [7 : 0] rd_ptr_reg; + reg [7 : 0] rd_ptr_new; + reg rd_ptr_inc; + reg rd_ptr_rst; + reg rd_ptr_we; + + reg [31 : 0] rnd_data_reg; + + reg rnd_syn_reg; + reg rnd_syn_new; + reg rnd_syn_we; + + reg [2 : 0] wr_ctrl_reg; + reg [2 : 0] wr_ctrl_new; + reg wr_ctrl_we; + + reg [2 : 0] rd_ctrl_reg; + reg [2 : 0] rd_ctrl_new; + reg rd_ctrl_we; + + reg [5 : 0] fifo_ctr_reg; + reg [5 : 0] fifo_ctr_new; + reg fifo_ctr_inc; + reg fifo_ctr_dec; + reg fifo_ctr_rst; + reg fifo_ctr_we; + reg fifo_empty; + reg fifo_full; + + reg more_data_reg; + reg more_data_new; + reg more_data_we; + + + //---------------------------------------------------------------- + // Wires. + //---------------------------------------------------------------- + reg [31 : 0] muxed_data; + + + //---------------------------------------------------------------- + // Concurrent connectivity for ports etc. + //---------------------------------------------------------------- + assign rnd_data = rnd_data_reg; + assign rnd_syn = rnd_syn_reg; + assign more_data = more_data_reg; + + + //---------------------------------------------------------------- + // reg_update + //---------------------------------------------------------------- + always @ (posedge clk or negedge reset_n) + begin + if (!reset_n) + begin + fifo_mem[00] <= 32'h00000000; + fifo_mem[01] <= 32'h00000000; + fifo_mem[02] <= 32'h00000000; + fifo_mem[03] <= 32'h00000000; + fifo_mem[04] <= 32'h00000000; + fifo_mem[05] <= 32'h00000000; + fifo_mem[06] <= 32'h00000000; + fifo_mem[07] <= 32'h00000000; + fifo_mem[08] <= 32'h00000000; + fifo_mem[09] <= 32'h00000000; + fifo_mem[10] <= 32'h00000000; + fifo_mem[11] <= 32'h00000000; + fifo_mem[12] <= 32'h00000000; + fifo_mem[13] <= 32'h00000000; + fifo_mem[14] <= 32'h00000000; + fifo_mem[15] <= 32'h00000000; + fifo_mem[16] <= 32'h00000000; + fifo_mem[17] <= 32'h00000000; + fifo_mem[18] <= 32'h00000000; + fifo_mem[19] <= 32'h00000000; + fifo_mem[20] <= 32'h00000000; + fifo_mem[21] <= 32'h00000000; + fifo_mem[22] <= 32'h00000000; + fifo_mem[23] <= 32'h00000000; + fifo_mem[24] <= 32'h00000000; + fifo_mem[25] <= 32'h00000000; + fifo_mem[26] <= 32'h00000000; + fifo_mem[27] <= 32'h00000000; + fifo_mem[28] <= 32'h00000000; + fifo_mem[29] <= 32'h00000000; + fifo_mem[30] <= 32'h00000000; + fifo_mem[31] <= 32'h00000000; + + mux_data_ptr_reg <= 4'h0; + wr_ptr_reg <= 8'h00; + rd_ptr_reg <= 8'h00; + fifo_ctr_reg <= 6'h00; + rnd_data_reg <= 32'h00000000; + rnd_syn_reg <= 0; + more_data_reg <= 0; + wr_ctrl_reg <= 3'h0; + rd_ctrl_reg <= 3'h0; + end + else + begin + rnd_data_reg <= fifo_mem[rd_ptr_reg]; + + if (rnd_syn_we) + begin + rnd_syn_reg <= rnd_syn_new; + end + + if (fifo_mem_we) + begin + fifo_mem[wr_ptr_reg] <= muxed_data; + end + + if (mux_data_ptr_we) + begin + mux_data_ptr_reg <= mux_data_ptr_new; + end + + if (wr_ptr_we) + begin + wr_ptr_reg <= wr_ptr_new; + end + + if (rd_ptr_we) + begin + rd_ptr_reg <= rd_ptr_new; + end + + if (fifo_ctr_we) + begin + fifo_ctr_reg <= fifo_ctr_new; + end + + if (more_data_we) + begin + more_data_reg <= more_data_new; + end + + if (wr_ctrl_we) + begin + wr_ctrl_reg <= wr_ctrl_new; + end + + if (rd_ctrl_we) + begin + rd_ctrl_reg <= rd_ctrl_new; + end + end + end // reg_update + + + //---------------------------------------------------------------- + // data_mux + //---------------------------------------------------------------- + always @* + begin : data_mux + case(mux_data_ptr_reg) + 00: muxed_data = csprng_data[031 : 000]; + 01: muxed_data = csprng_data[063 : 032]; + 02: muxed_data = csprng_data[095 : 064]; + 03: muxed_data = csprng_data[127 : 096]; + 04: muxed_data = csprng_data[159 : 128]; + 05: muxed_data = csprng_data[191 : 160]; + 06: muxed_data = csprng_data[223 : 192]; + 07: muxed_data = csprng_data[255 : 224]; + 08: muxed_data = csprng_data[287 : 256]; + 09: muxed_data = csprng_data[313 : 282]; + 10: muxed_data = csprng_data[351 : 320]; + 11: muxed_data = csprng_data[383 : 351]; + 12: muxed_data = csprng_data[415 : 384]; + 13: muxed_data = csprng_data[447 : 416]; + 14: muxed_data = csprng_data[479 : 448]; + 15: muxed_data = csprng_data[511 : 480]; + endcase // case (mux_data_ptr_reg) + end // data_mux + + + //---------------------------------------------------------------- + // mux_data_ptr + //---------------------------------------------------------------- + always @* + begin : mux_data_ptr + mux_data_ptr_new = 4'h0; + mux_data_ptr_we = 0; + + if (mux_data_ptr_rst) + begin + mux_data_ptr_new = 4'h0; + mux_data_ptr_we = 1; + end + + if (mux_data_ptr_inc) + begin + mux_data_ptr_new = mux_data_ptr_reg + 1'b1; + mux_data_ptr_we = 1; + end + end // mux_data_ptr + + + //---------------------------------------------------------------- + // fifo_rd_ptr + //---------------------------------------------------------------- + always @* + begin : fifo_rd_ptr + rd_ptr_new = 8'h00; + rd_ptr_we = 0; + + if (rd_ptr_rst) + begin + rd_ptr_new = 8'h00; + rd_ptr_we = 1; + end + + if (rd_ptr_inc) + begin + if (rd_ptr_reg == FIFO_MAX) + begin + rd_ptr_new = 8'h00; + rd_ptr_we = 1; + end + else + begin + rd_ptr_new = rd_ptr_reg + 1'b1; + rd_ptr_we = 1; + end + end + end // fifo_rd_ptr + + + //---------------------------------------------------------------- + // fifo_wr_ptr + //---------------------------------------------------------------- + always @* + begin : fifo_wr_ptr + wr_ptr_new = 8'h00; + wr_ptr_we = 0; + + if (wr_ptr_rst) + begin + wr_ptr_new = 8'h00; + wr_ptr_we = 1; + end + + if (wr_ptr_inc) + begin + if (wr_ptr_reg == FIFO_MAX) + begin + wr_ptr_new = 8'h00; + wr_ptr_we = 1; + end + else + begin + wr_ptr_new = wr_ptr_reg + 1'b1; + wr_ptr_we = 1; + end + end + end // fifo_wr_ptr + + + //---------------------------------------------------------------- + // fifo_ctr + // + // fifo counter tracks the number of elements and provides + // signals for full and empty fifo. + //---------------------------------------------------------------- + always @* + begin : fifo_ctr + fifo_empty = 0; + fifo_full = 0; + fifo_ctr_new = 6'h00; + fifo_ctr_we = 0; + + if (fifo_ctr_reg == FIFO_DEPTH) + begin + fifo_full = 1; + end + + if (fifo_ctr_reg < 6'h0f) + begin + fifo_empty = 1; + end + + if (fifo_ctr_inc) + begin + fifo_ctr_new = fifo_ctr_reg + 1'b1; + fifo_ctr_we = 1; + end + + if (fifo_ctr_dec) + begin + fifo_ctr_new = fifo_ctr_reg - 1'b1; + fifo_ctr_we = 1; + end + + if (fifo_ctr_rst) + begin + fifo_ctr_new = 6'h00; + fifo_ctr_we = 1; + end + end // fifo_ctr + + + //---------------------------------------------------------------- + // rd_ctrl + //---------------------------------------------------------------- + always @* + begin : rd_ctrl + fifo_ctr_dec = 0; + rnd_syn_new = 0; + rnd_syn_we = 0; + rd_ptr_inc = 0; + rd_ptr_rst = 0; + rd_ctrl_new = RD_IDLE; + rd_ctrl_we = 0; + + case (rd_ctrl_reg) + RD_IDLE: + begin + if (discard) + begin + rd_ctrl_new = RD_DISCARD; + rd_ctrl_we = 1; + end + else + begin + if (!fifo_empty) + begin + rnd_syn_new = 1; + rnd_syn_we = 1; + rd_ctrl_new = RD_ACK; + rd_ctrl_we = 1; + end + end + end + + RD_ACK: + begin + if (discard) + begin + rd_ctrl_new = RD_DISCARD; + rd_ctrl_we = 1; + end + else + begin + if (rnd_ack) + begin + fifo_ctr_dec = 1; + rd_ptr_inc = 1; + rnd_syn_new = 0; + rnd_syn_we = 1; + rd_ctrl_new = RD_IDLE; + rd_ctrl_we = 1; + end + end + end + + RD_DISCARD: + begin + rnd_syn_new = 0; + rnd_syn_we = 1; + rd_ptr_rst = 1; + rd_ctrl_new = RD_IDLE; + rd_ctrl_we = 1; + + end + + endcase // case (rd_ctrl_reg) + + end // rd_ctrl + + + //---------------------------------------------------------------- + // wr_ctrl + //---------------------------------------------------------------- + always @* + begin : wr_ctrl + more_data_new = 0; + more_data_we = 0; + mux_data_ptr_rst = 0; + mux_data_ptr_inc = 0; + wr_ptr_inc = 0; + wr_ptr_rst = 0; + fifo_mem_we = 0; + fifo_ctr_inc = 0; + fifo_ctr_rst = 0; + wr_ctrl_new = WR_IDLE; + wr_ctrl_we = 0; + + case (wr_ctrl_reg) + WR_IDLE: + begin + if (discard) + begin + wr_ctrl_new = WR_DISCARD; + wr_ctrl_we = 1; + end + else if (!fifo_full) + begin + more_data_new = 1; + more_data_we = 1; + wr_ctrl_new = WR_WAIT; + wr_ctrl_we = 1; + end + end + + WR_WAIT: + begin + if (discard) + begin + wr_ctrl_new = WR_DISCARD; + wr_ctrl_we = 1; + end + else if (csprng_data_valid) + begin + more_data_new = 0; + more_data_we = 1; + mux_data_ptr_rst = 1; + wr_ctrl_new = WR_WRITE; + wr_ctrl_we = 1; + end + end + + WR_WRITE: + begin + if (discard) + begin + wr_ctrl_new = WR_DISCARD; + wr_ctrl_we = 1; + end + else if (!fifo_full) + begin + fifo_mem_we = 1; + wr_ptr_inc = 1; + mux_data_ptr_inc = 1; + fifo_ctr_inc = 1; + + if (mux_data_ptr_new == 4'h0) + begin + wr_ctrl_new = WR_IDLE; + wr_ctrl_we = 1; + end + end + end + + WR_DISCARD: + begin + fifo_ctr_rst = 1; + more_data_new = 0; + more_data_we = 1; + mux_data_ptr_rst = 1; + wr_ptr_rst = 1; + wr_ctrl_new = WR_IDLE; + wr_ctrl_we = 1; + end + endcase // case (wr_ctrl_reg) + + end // wr_ctrl + +endmodule // trng_csprng_fifo + +//====================================================================== +// EOF trng_csprng_fifo.v +//====================================================================== diff --git a/src/tb/tb_csprng.v b/src/tb/tb_csprng.v new file mode 100644 index 0000000..10a7992 --- /dev/null +++ b/src/tb/tb_csprng.v @@ -0,0 +1,309 @@ +//====================================================================== +// +// tb_csprng.v +// ----------- +// Testbench for the csprng module in the trng. +// +// +// Author: Joachim Strombergson +// Copyright (c) 2014, 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. +// +//====================================================================== + +//------------------------------------------------------------------ +// Simulator directives. +//------------------------------------------------------------------ +`timescale 1ns/100ps + + +//------------------------------------------------------------------ +// Test module. +//------------------------------------------------------------------ +module tb_csprng(); + + //---------------------------------------------------------------- + // Internal constant and parameter definitions. + //---------------------------------------------------------------- + parameter DEBUG = 1; + + parameter CLK_HALF_PERIOD = 1; + parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD; + + + //---------------------------------------------------------------- + // Register and Wire declarations. + //---------------------------------------------------------------- + reg [31 : 0] cycle_ctr; + reg [31 : 0] error_ctr; + reg [31 : 0] tc_ctr; + + reg tb_clk; + reg tb_reset_n; + reg tb_debug_mode; + reg [4 : 0] tb_num_rounds; + reg [63 : 0] tb_num_blocks; + reg tb_seed; + reg tb_enable; + wire tb_ready; + wire tb_more_seed; + wire tb_error; + reg tb_seed_syn; + reg [511 : 0] tb_seed_data; + wire tb_seed_ack; + wire tb_rnd_syn; + wire [31: 0] tb_rnd_data; + reg tb_rnd_ack; + + + //---------------------------------------------------------------- + // Device Under Test. + //---------------------------------------------------------------- + trng_csprng dut( + .clk(tb_clk), + .reset_n(tb_reset_n), + + .debug_mode(tb_debug_mode), + .num_rounds(tb_num_rounds), + .num_blocks(tb_num_blocks), + .seed(tb_seed), + .enable(tb_enable), + .more_seed(tb_more_seed), + .ready(tb_ready), + .error(tb_error), + + .seed_syn(tb_seed_syn), + .seed_data(tb_seed_data), + .seed_ack(tb_seed_ack), + + .rnd_syn(tb_rnd_syn), + .rnd_data(tb_rnd_data), + .rnd_ack(tb_rnd_ack) + ); + + + //---------------------------------------------------------------- + // clk_gen + // + // Always running clock generator process. + //---------------------------------------------------------------- + always + begin : clk_gen + #CLK_HALF_PERIOD; + tb_clk = !tb_clk; + end // clk_gen + + + //---------------------------------------------------------------- + // sys_monitor() + // + // An always running process that creates a cycle counter and + // conditionally displays information about the DUT. + //---------------------------------------------------------------- + always + begin : sys_monitor + cycle_ctr = cycle_ctr + 1; + + #(CLK_PERIOD); + + if (DEBUG) + begin + dump_dut_state(); + end + end + + + //---------------------------------------------------------------- + // dump_dut_state() + // + // Dump the state of the dump when needed. + //---------------------------------------------------------------- + task dump_dut_state(); + begin + $display("cycle: 0x%016x", cycle_ctr); + $display("State of DUT"); + $display("------------"); + $display("Inputs:"); + $display("debug_mode = 0x%01x, seed = 0x%01x, enable = 0x%01x", + dut.debug_mode, dut.seed, dut.enable); + $display("ready = 0x%01x, error = 0x%01x", + dut.ready, dut.error); + $display("num_rounds = 0x%02x, num_blocks = 0x%016x", + dut.num_rounds, dut.num_blocks); + $display("seed_syn = 0x%01x, seed_ack = 0x%01x, seed_data = 0x%064x", + dut.seed_syn, dut.seed_ack, dut.seed_data); + $display(""); + + $display("Internal states:"); + $display("cipher_key = 0x%032x", dut.cipher_key_reg); + $display("cipher_iv = 0x%08x, cipher_ctr = 0x%08x", + dut.cipher_iv_reg, dut.cipher_ctr_reg); + $display("cipher_block = 0x%064x", dut.cipher_block_reg); + $display("csprng_ctrl = 0x%02x", dut.csprng_ctrl_reg); + $display(""); + $display("Cipher states:"); + $display("cipher init: 0x%01x, cipher next: 0x%01x", + dut.cipher.init, dut.cipher.next); + $display("cipher ctrl: 0x%01x, qr ctr: 0x%01x, dr ctr: 0x%02x", + dut.cipher.chacha_ctrl_reg, dut.cipher.qr_ctr_reg, dut.cipher.dr_ctr_reg); + $display("cipher ready: 0x%01x, cipher data out valid: 0x%01x", + dut.cipher.ready, dut.cipher.data_out_valid); + $display("cipher data out: 0x%064x", dut.cipher.data_out); + $display(""); + $display("Cipher states:"); + $display("mux ctr: 0x%02x, fifo ctr: 0x%02x, fifo_wr_ptr = 0x%02x, fifo_rd_ptr = 0x%02x", + dut.fifo.mux_data_ptr_reg, dut.fifo.fifo_ctr_reg, dut.fifo.wr_ptr_reg, dut.fifo.rd_ptr_reg,); + $display("fifo wr ctrl: 0x%02x, fifo rd ctrl: 0x%02x", dut.fifo.wr_ctrl_reg, dut.fifo.rd_ctrl_reg); + $display(""); + + $display("Outputs:"); + $display("rnd_syn = 0x%01x, rnd_ack = 0x%01x, rnd_data = 0x%08x", + dut.rnd_syn, dut.rnd_ack, dut.rnd_data); + $display(""); + end + endtask // dump_dut_state + + + //---------------------------------------------------------------- + // reset_dut() + // + // Toggle reset to put the DUT into a well known state. + //---------------------------------------------------------------- + task reset_dut(); + begin + $display("*** Toggle reset."); + tb_reset_n = 0; + + #(2 * CLK_PERIOD); + tb_reset_n = 1; + $display(""); + end + endtask // reset_dut + + + //---------------------------------------------------------------- + // display_test_results() + // + // Display the accumulated test results. + //---------------------------------------------------------------- + task display_test_results(); + begin + if (error_ctr == 0) + begin + $display("*** All %02d test cases completed successfully", tc_ctr); + end + else + begin + $display("*** %02d tests completed - %02d test cases did not complete successfully.", + tc_ctr, error_ctr); + end + end + endtask // display_test_results + + + //---------------------------------------------------------------- + // init_sim() + // + // Initialize all counters and testbed functionality as well + // as setting the DUT inputs to defined values. + //---------------------------------------------------------------- + task init_sim(); + begin + cycle_ctr = 0; + error_ctr = 0; + tc_ctr = 0; + + tb_clk = 0; + tb_reset_n = 1; + tb_debug_mode = 0; + tb_num_rounds = 5'h00; + tb_num_blocks = 64'h0000000000000000; + tb_seed = 0; + tb_enable = 0; + tb_seed_syn = 0; + tb_seed_data = {16{32'h00000000}}; + tb_rnd_ack = 0; + end + endtask // init_sim + + + //---------------------------------------------------------------- + // tc1_test_init_cipher() + // + // TC1: Test that the DUT automatically starts initialize when + // enable is set. + //---------------------------------------------------------------- + task tc1_test_init_cipher(); + begin + $display("*** TC1: Test automatic init of cipher started."); + tb_num_blocks = 64'h0000000000000004; + tb_seed_syn = 1; + tb_seed_data = {8{64'haaaaaaaa55555555}}; + tb_enable = 1; + tb_num_rounds = 5'h08; + tb_rnd_ack = 1; + + #(2000 * CLK_PERIOD); + + $display("*** TC1: Test automatic init of cipher done."); + + end + endtask // tc1_test_init_cipher + + + //---------------------------------------------------------------- + // csprng_test + // + // The main test functionality. + //---------------------------------------------------------------- + initial + begin : csprng_test + + $display(" -= Testbench for csprng started =-"); + $display(" ================================"); + $display(""); + + init_sim(); + dump_dut_state(); + reset_dut(); + dump_dut_state(); + + // Test code goes here. + tc1_test_init_cipher(); + + display_test_results(); + + $display(""); + $display("*** CSPRNG simulation done. ***"); + $finish; + end // csprng_test +endmodule // tb_csprng + +//====================================================================== +// EOF tb_csprng.v +//====================================================================== |