aboutsummaryrefslogblamecommitdiff
path: root/src/rtl/trng.v
blob: 0d6b7b0de75ef4d2be68a2da5a757972d95f6fb6 (plain) (tree)
1
                                                                         


















































                                                                           

                                       
















































































































                                                                    
                              

                                 






                                   
                                 














                                                                    
                            







                                                         





                                             



























                                                                    
                                             






































                                                        


                                                   
 
                                                          
 
                                                         
 

                                                            
 




                                                              































































































































































































































































                                                                                   
 //======================================================================
//
// 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  [7 : 0] debug,

            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;

  wire           mixer_enable;
  wire [511 : 0] mixer_seed_data;
  wire           mixer_seed_syn;

  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_seed_ack;
  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 debug          = 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;

  assign mixer_enable  = enable_reg;

  assign csprng_enable     = enable_reg;
  assign csprng_seed       = csprng_seed_reg;
  assign csprng_debug_mode = 0;


  //----------------------------------------------------------------
  // 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(csprng_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_core 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
//======================================================================