aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rtl/trng_csprng.v497
-rw-r--r--src/rtl/trng_csprng_fifo.v550
-rw-r--r--src/tb/tb_csprng.v309
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
+//======================================================================