diff options
-rw-r--r-- | src/rtl/trng.v | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/src/rtl/trng.v b/src/rtl/trng.v new file mode 100644 index 0000000..f296ce5 --- /dev/null +++ b/src/rtl/trng.v @@ -0,0 +1,539 @@ +//====================================================================== +// +// trng.v +// -------- +// Top level wrapper for the True Random Number Generator. +// +// +// 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( + // Clock and reset. + input wire clk, + input wire reset_n, + + input wire avalanche_noise, + + input wire cs, + input wire we, + input wire [7 : 0] address, + input wire [31 : 0] write_data, + output wire [31 : 0] read_data, + output wire error, + + output wire security_error + ); + + + //---------------------------------------------------------------- + // Internal constant and parameter definitions. + //---------------------------------------------------------------- + parameter ADDR_NAME0 = 8'h00; + parameter ADDR_NAME1 = 8'h01; + parameter ADDR_VERSION = 8'h02; + + parameter ADDR_TRNG_CTRL = 8'h10; + parameter TRNG_CTRL_ENABLE_BIT = 0; + parameter TRNG_CTRL_ENT0_ENABLE_BIT = 1; + parameter TRNG_CTRL_ENT1_ENABLE_BIT = 2; + parameter TRNG_CTRL_ENT2_ENABLE_BIT = 3; + parameter TRNG_CTRL_SEED_BIT = 8; + + parameter ADDR_TRNG_STATUS = 8'h11; + + parameter ADDR_TRNG_RND_DATA = 8'h20; + parameter ADDR_TRNG_RND_DATA_VALID = 8'h21; + parameter TRNG_RND_VALID_BIT = 0; + + parameter ADDR_CSPRNG_NUM_ROUNDS = 8'h30; + parameter ADDR_CSPRNG_NUM_BLOCKS_LOW = 8'h31; + parameter ADDR_CSPRNG_NUM_BLOCKS_HIGH = 8'h32; + + parameter ADDR_ENTROPY0_RAW = 8'h40; + parameter ADDR_ENTROPY0_STATS = 8'h41; + + parameter ADDR_ENTROPY1_RAW = 8'h50; + parameter ADDR_ENTROPY1_STATS = 8'h51; + + parameter ADDR_ENTROPY2_RAW = 8'h60; + parameter ADDR_ENTROPY2_STATS = 8'h61; + + + parameter TRNG_NAME0 = 32'h74726e67; // "trng" + parameter TRNG_NAME1 = 32'h20202020; // " " + parameter TRNG_VERSION = 32'h302e3031; // "0.01" + + + parameter CSPRNG_DEFAULT_NUM_ROUNDS = 5'h18; + parameter CSPRNG_DEFAULT_NUM_BLOCKS = 64'h1000000000000000; + + + //---------------------------------------------------------------- + // Registers including update variables and write enable. + //---------------------------------------------------------------- + reg [4 : 0] csprng_num_rounds_reg; + reg [4 : 0] csprng_num_rounds_new; + reg csprng_num_rounds_we; + + reg [31 : 0] csprng_num_blocks_low_reg; + reg [31 : 0] csprng_num_blocks_low_new; + reg csprng_num_blocks_low_we; + + reg [31 : 0] csprng_num_blocks_high_reg; + reg [31 : 0] csprng_num_blocks_high_new; + reg csprng_num_blocks_high_we; + + reg entropy0_enable_reg; + reg entropy0_enable_new; + reg entropy0_enable_we; + + reg entropy1_enable_reg; + reg entropy1_enable_new; + reg entropy1_enable_we; + + reg entropy2_enable_reg; + reg entropy2_enable_new; + reg entropy2_enable_we; + + reg enable_reg; + reg enable_new; + reg enable_we; + + reg csprng_seed_reg; + reg csprng_seed_new; + + reg csprng_rnd_ack_reg; + reg csprng_rnd_ack_new; + + + + //---------------------------------------------------------------- + // Wires. + //---------------------------------------------------------------- + wire entropy0_enable; + wire [31 : 0] entropy0_raw; + wire [31 : 0] entropy0_stats; + wire entropy0_enabled; + wire entropy0_syn; + wire [31 : 0] entropy0_data; + wire entropy0_ack; + + wire entropy1_enable; + wire [31 : 0] entropy1_raw; + wire [31 : 0] entropy1_stats; + wire entropy1_enabled; + wire entropy1_syn; + wire [31 : 0] entropy1_data; + wire entropy1_ack; + + wire entropy2_enable; + wire [31 : 0] entropy2_raw; + wire [31 : 0] entropy2_stats; + wire entropy2_enabled; + wire entropy2_syn; + wire [31 : 0] entropy2_data; + wire entropy2_ack; + + reg mixer_enable; + wire [511 : 0] mixer_seed_data; + wire mixer_seed_syn; + wire mixer_seed_ack; + + wire csprng_enable; + wire csprng_debug_mode; + wire [4 : 0] csprng_num_rounds; + wire [63 : 0] csprng_num_blocks; + wire csprng_seed; + wire csprng_more_seed; + wire csprng_ready; + wire csprng_error; + wire [31 : 0] csprng_rnd_data; + wire csprng_rnd_syn; + + reg [31 : 0] tmp_read_data; + reg tmp_error; + + + //---------------------------------------------------------------- + // Concurrent connectivity for ports etc. + //---------------------------------------------------------------- + assign read_data = tmp_read_data; + assign error = tmp_error; + assign security_error = 0; + + assign csprng_num_blocks = {csprng_num_blocks_high_reg, + csprng_num_blocks_low_reg}; + + assign entropy0_enable = entropy0_enable_reg; + assign entropy1_enable = entropy1_enable_reg; + assign entropy2_enable = entropy2_enable_reg; + + + //---------------------------------------------------------------- + // core instantiations. + //---------------------------------------------------------------- + trng_mixer mixer( + .clk(clk), + .reset_n(reset_n), + + .enable(mixer_enable), + .more_seed(csprng_more_seed), + + .entropy0_enabled(entropy0_enabled), + .entropy0_syn(entropy0_syn), + .entropy0_data(entropy0_data), + .entropy0_ack(entropy0_ack), + + .entropy1_enabled(entropy1_enabled), + .entropy1_syn(entropy1_syn), + .entropy1_data(entropy1_data), + .entropy1_ack(entropy1_ack), + + .entropy2_enabled(entropy2_enabled), + .entropy2_syn(entropy2_syn), + .entropy2_data(entropy2_data), + .entropy2_ack(entropy2_ack), + + .seed_data(mixer_seed_data), + .seed_syn(mixer_seed_syn), + .seed_ack(mixer_seed_ack) + ); + + trng_csprng csprng( + .clk(clk), + .reset_n(reset_n), + + .enable(csprng_enable), + .debug_mode(csprng_debug_mode), + .num_rounds(csprng_num_rounds_reg), + .num_blocks(csprng_num_blocks), + .seed(csprng_seed), + .more_seed(csprng_more_seed), + .ready(csprng_ready), + .error(csprng_error), + + .seed_data(mixer_seed_data), + .seed_syn(mixer_seed_syn), + .seed_ack(csprng_seed_ack), + + .rnd_data(csprng_rnd_data), + .rnd_syn(csprng_rnd_syn), + .rnd_ack(csprng_rnd_ack_reg) + ); + + pseudo_entropy entropy0( + .clk(clk), + .reset_n(reset_n), + + .enable(entropy0_enable), + + .raw_entropy(entropy0_raw), + .stats(entropy0_stats), + + .enabled(entropy0_enabled), + .entropy_syn(entropy0_syn), + .entropy_data(entropy0_data), + .entropy_ack(entropy0_ack) + ); + + avalance_entropy entropy1( + .clk(clk), + .reset_n(reset_n), + + .enable(entropy1_enable), + + .noise(avalanche_noise), + + .raw_entropy(entropy1_raw), + .stats(entropy1_stats), + + .enabled(entropy1_enabled), + .entropy_syn(entropy1_syn), + .entropy_data(entropy1_data), + .entropy_ack(entropy1_ack) + ); + + ringosc_entropy entropy2( + .clk(clk), + .reset_n(reset_n), + + .enable(entropy2_enable), + + .raw_entropy(entropy2_raw), + .stats(entropy2_stats), + + .enabled(entropy2_enabled), + .entropy_syn(entropy2_syn), + .entropy_data(entropy2_data), + .entropy_ack(entropy2_ack) + ); + + + //---------------------------------------------------------------- + // reg_update + // + // Update functionality for all registers in the core. + // All registers are positive edge triggered with asynchronous + // active low reset. All registers have write enable. + //---------------------------------------------------------------- + always @ (posedge clk or negedge reset_n) + begin + if (!reset_n) + begin + entropy0_enable_reg <= 1; + entropy1_enable_reg <= 1; + entropy2_enable_reg <= 1; + enable_reg <= 1; + csprng_rnd_ack_reg <= 0; + csprng_seed_reg <= 0; + csprng_num_rounds_reg <= CSPRNG_DEFAULT_NUM_ROUNDS; + csprng_num_blocks_low_reg <= CSPRNG_DEFAULT_NUM_BLOCKS[31 : 0]; + csprng_num_blocks_high_reg <= CSPRNG_DEFAULT_NUM_BLOCKS[63 : 32]; + end + + else + begin + csprng_rnd_ack_reg <= csprng_rnd_ack_new; + csprng_seed_reg <= csprng_seed_new; + + if (entropy0_enable_we) + begin + entropy0_enable_reg <= entropy0_enable_new; + end + + if (entropy1_enable_we) + begin + entropy1_enable_reg <= entropy1_enable_new; + end + + if (entropy2_enable_we) + begin + entropy2_enable_reg <= entropy2_enable_new; + end + + if (enable_we) + begin + enable_reg <= enable_new; + end + + if (csprng_num_rounds_we) + begin + csprng_num_rounds_reg <= csprng_num_rounds_new; + end + + if (csprng_num_blocks_low_we) + begin + csprng_num_blocks_low_reg <= csprng_num_blocks_low_new; + end + + if (csprng_num_blocks_high_we) + begin + csprng_num_blocks_high_reg <= csprng_num_blocks_high_new; + end + end + end // reg_update + + + //---------------------------------------------------------------- + // api_logic + // + // Implementation of the api logic. If cs is enabled will either + // try to write to or read from the internal registers. + //---------------------------------------------------------------- + always @* + begin : api_logic + entropy0_enable_new = 0; + entropy0_enable_we = 0; + entropy1_enable_new = 0; + entropy1_enable_we = 0; + entropy2_enable_new = 0; + entropy2_enable_we = 0; + enable_new = 0; + enable_we = 0; + csprng_seed_new = 0; + csprng_rnd_ack_new = 0; + csprng_seed_new = 0; + csprng_num_rounds_new = 5'h00; + csprng_num_rounds_we = 0; + csprng_num_blocks_low_new = 32'h00000000; + csprng_num_blocks_low_we = 0; + csprng_num_blocks_high_new = 32'h00000000; + csprng_num_blocks_high_we = 0; + tmp_read_data = 32'h00000000; + tmp_error = 0; + + if (cs) + begin + if (we) + begin + case (address) + // Write operations. + ADDR_TRNG_CTRL: + begin + enable_new = write_data[TRNG_CTRL_ENABLE_BIT]; + enable_we = 1; + entropy0_enable_new = write_data[TRNG_CTRL_ENT0_ENABLE_BIT]; + entropy0_enable_we = 1; + entropy1_enable_new = write_data[TRNG_CTRL_ENT1_ENABLE_BIT]; + entropy1_enable_we = 1; + entropy2_enable_new = write_data[TRNG_CTRL_ENT2_ENABLE_BIT]; + entropy2_enable_we = 1; + csprng_seed_new = write_data[TRNG_CTRL_SEED_BIT]; + end + + ADDR_CSPRNG_NUM_ROUNDS: + begin + csprng_num_rounds_new = write_data[4 : 0]; + csprng_num_rounds_we = 1; + end + + ADDR_CSPRNG_NUM_BLOCKS_LOW: + begin + csprng_num_blocks_low_new = write_data; + csprng_num_blocks_low_we = 1; + end + + ADDR_CSPRNG_NUM_BLOCKS_HIGH: + begin + csprng_num_blocks_high_new = write_data; + csprng_num_blocks_high_we = 1; + end + + default: + begin + tmp_error = 1; + end + endcase // case (address) + end // if (we) + + else + begin + case (address) + // Read operations. + ADDR_NAME0: + begin + tmp_read_data = TRNG_NAME0; + end + + ADDR_NAME1: + begin + tmp_read_data = TRNG_NAME1; + end + + ADDR_VERSION: + begin + tmp_read_data = TRNG_VERSION; + end + + ADDR_TRNG_CTRL: + begin + tmp_read_data[TRNG_CTRL_ENABLE_BIT] = enable_reg; + tmp_read_data[TRNG_CTRL_ENT0_ENABLE_BIT] = entropy0_enable_reg; + tmp_read_data[TRNG_CTRL_ENT1_ENABLE_BIT] = entropy1_enable_reg; + tmp_read_data[TRNG_CTRL_ENT2_ENABLE_BIT] = entropy2_enable_reg; + tmp_read_data[TRNG_CTRL_SEED_BIT] = csprng_seed_reg; + end + + ADDR_TRNG_STATUS: + begin + + end + + ADDR_TRNG_RND_DATA: + begin + csprng_rnd_ack_new = 1; + tmp_read_data = csprng_rnd_data; + end + + ADDR_TRNG_RND_DATA_VALID: + begin + tmp_read_data[TRNG_RND_VALID_BIT] = csprng_rnd_syn; + end + + ADDR_CSPRNG_NUM_ROUNDS: + begin + tmp_read_data[4 : 0] = csprng_num_rounds_reg; + end + + ADDR_CSPRNG_NUM_BLOCKS_LOW: + begin + tmp_read_data = csprng_num_blocks_low_reg; + end + + ADDR_CSPRNG_NUM_BLOCKS_HIGH: + begin + tmp_read_data = csprng_num_blocks_high_reg; + end + + ADDR_ENTROPY0_RAW: + begin + tmp_read_data = entropy0_raw; + end + + ADDR_ENTROPY0_STATS: + begin + tmp_read_data = entropy0_stats; + end + + ADDR_ENTROPY1_RAW: + begin + tmp_read_data = entropy1_raw; + end + + ADDR_ENTROPY1_STATS: + begin + tmp_read_data = entropy1_stats; + end + + ADDR_ENTROPY2_RAW: + begin + tmp_read_data = entropy2_raw; + end + + ADDR_ENTROPY2_STATS: + begin + tmp_read_data = entropy2_stats; + end + + default: + begin + tmp_error = 1; + end + endcase // case (address) + end + end + end // addr_decoder +endmodule // trng + +//====================================================================== +// EOF trng.v +//====================================================================== |