aboutsummaryrefslogblamecommitdiff
path: root/src/rtl/trng.v
blob: 7a15e7e54acb223fb7514dd3b5cf082561beb18b (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                                                                        






                                                          

                            
  


                                                                  
  

                                                                    
  



                                                                       
  











                                                                       











                                                                        
                                         



                                            
                                       
                                              
 






                                                                    
                                            



                                            










                                             
                                             


                                         

                                             




                                                              
                                                              
 
                    
                                                    
 



                                                                    

                  
 


                    
 


                            

                            
                           
 







                                   



                                                                    

                                                                    
                                    
                                
 
                                 

                                 
                                

                                                                      

                                     
                                      

                                    
 
                                  
                                 

                                                                        

                                      

                                     
                                       





                                          

                                                                            





                                          
                                      



                                         

                                                                            





                                          
                                      


                                         
 
                                             

                               
                           






                                                                    
                                                                            
                                        
 
                                              


                                                 
 
 







                                                                    

 


                                                                    































































                                                                    
 


                                               
 
                                                     
 





                                                                
 


                                                                      
 



                                                                        
 


                                                                 
 


                                          
 





                                                           
 


                                                                 
 



                                                                   
 


                                                            


                                                                    





































                                                                    











                                                                    
                                               




































                                                                    



















                                                                    
              


                                                          




                                                                    

                                
 
                        
 





                                                   
 




                                                   
 











                                               




                                     
                    
 

                                                                    
                   
    
                                               

                                                                    
                          






                                            
                                            
                                 

                      
             
                          
                 
                                

                               


                                                                        

                     
                                
                       

                                                      

                     





                                                 
                        
                                     




                                       
                                
                           
                                                  

                           
                                                  

                             
                                                    

                               
                                                                                 


                                 
                                                         

                     
                                
                                                                    
 
                                 
                                                       
 
                        
                                     


                                       
                         




                                                                        
//======================================================================
//
// trng.v
// --------
// Top level wrapper for the True Random Number Generator.
//
//
// Author: Joachim Strombergson
// Copyright (c) 2014, SUNET
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or
// without modification, are permitted provided that the following
// conditions are met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// 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 OWNER 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  [11 : 0] address,
            input wire  [31 : 0] write_data,
            output wire [31 : 0] read_data,
            output wire          error,

            output wire  [7 : 0] debug,
            input wire           debug_update,

            output wire          security_error
           );


  //----------------------------------------------------------------
  // Internal constant and parameter definitions.
  //----------------------------------------------------------------
  localparam TRNG_PREFIX             = 4'h0;
  localparam ENTROPY1_PREFIX         = 4'h1;
  localparam ENTROPY2_PREFIX         = 4'h2;
  localparam MIXER_PREFIX            = 4'h3;
  localparam CSPRNG_PREFIX           = 4'h4;

  localparam DEBUG_ENTROPY0          = 3'h0;
  localparam DEBUG_ENTROPY1          = 3'h1;
  localparam DEBUG_ENTROPY2          = 3'h2;
  localparam DEBUG_MIXER             = 3'h3;
  localparam DEBUG_CSPRNG            = 3'h4;

  localparam ADDR_NAME0              = 8'h00;
  localparam ADDR_NAME1              = 8'h01;
  localparam ADDR_VERSION            = 8'h02;

  localparam ADDR_TRNG_CTRL          = 8'h08;
  localparam TRNG_CTRL_DISCARD_BIT   = 0;
  localparam TRNG_CTRL_TEST_MODE_BIT = 1;

  localparam ADDR_TRNG_STATUS        = 8'h09;

  localparam ADDR_DEBUG_CTRL         = 8'h12;
  localparam ADDR_DEBUG_DELAY        = 8'h13;

  localparam TRNG_NAME0              = 32'h74726e67; // "trng"
  localparam TRNG_NAME1              = 32'h20202020; // "    "
  localparam TRNG_VERSION            = 32'h302e3531; // "0.51"

  // 20x/s @ 50 MHz.
  localparam DEFAULT_DEBUG_DELAY     = 32'h002625a0;


  //----------------------------------------------------------------
  // Registers including update variables and write enable.
  //----------------------------------------------------------------
  reg discard_reg;
  reg discard_new;

  reg test_mode_reg;
  reg test_mode_new;
  reg test_mode_we;

  reg [7 : 0] debug_out_reg;
  reg         debug_out_we;

  reg [2 : 0] debug_mux_reg;
  reg [2 : 0] debug_mux_new;
  reg         debug_mux_we;

  reg [31 : 0] debug_delay_ctr_reg;
  reg [31 : 0] debug_delay_ctr_new;
  reg          debug_delay_ctr_we;

  reg [31 : 0] debug_delay_reg;
  reg [31 : 0] debug_delay_new;
  reg          debug_delay_we;


  //----------------------------------------------------------------
  // Wires.
  //----------------------------------------------------------------
  wire           trng_api_cs = cs && (addr_core_num == TRNG_PREFIX);
  wire           trng_api_we = we;
  reg [31 : 0]   trng_api_read_data;
  reg            trng_api_error;

  wire           mixer_more_seed;
  wire [511 : 0] mixer_seed_data;
  wire           mixer_seed_syn;
  wire           mixer_seed_ack;
  wire           mixer_api_cs = cs && (addr_core_num == MIXER_PREFIX);
  wire           mixer_api_we = we;
  wire [31 : 0]  mixer_api_read_data;
  wire           mixer_api_error;
  wire           mixer_security_error;
  wire [7 : 0]   mixer_debug;
  reg            mixer_debug_update;

  wire           csprng_more_seed;
  wire           csprng_seed_ack;
  wire           csprng_api_cs = cs && (addr_core_num == CSPRNG_PREFIX);
  wire           csprng_api_we = we;
  wire [31 : 0]  csprng_api_read_data;
  wire           csprng_api_error;
  wire [7 : 0]   csprng_debug;
  reg            csprng_debug_update;
  wire           csprng_security_error;

  wire           entropy0_entropy_enabled;
  wire [31 : 0]  entropy0_entropy_data;
  wire           entropy0_entropy_syn;
  wire           entropy0_entropy_ack;

  wire           entropy1_api_cs = cs && (addr_core_num == ENTROPY1_PREFIX);
  wire           entropy1_api_we = we;
  wire [31 : 0]  entropy1_api_read_data;
  wire           entropy1_api_error;
  wire           entropy1_entropy_enabled;
  wire [31 : 0]  entropy1_entropy_data;
  wire           entropy1_entropy_syn;
  wire           entropy1_entropy_ack;
  //wire           entropy1_test_mode;
  wire [7 : 0]   entropy1_debug;
  reg            entropy1_debug_update;
  wire           entropy1_security_error;

  wire           entropy2_api_cs = cs && (addr_core_num == ENTROPY2_PREFIX);
  wire           entropy2_api_we = we;
  wire [31 : 0]  entropy2_api_read_data;
  wire           entropy2_api_error;
  wire           entropy2_entropy_enabled;
  wire [31 : 0]  entropy2_entropy_data;
  wire           entropy2_entropy_syn;
  wire           entropy2_entropy_ack;
  //wire           entropy2_test_mode;
  wire [7 : 0]   entropy2_debug;
  reg            entropy2_debug_update;
  wire           entropy2_security_error;

  wire [7 : 0]   api_address = addr_core_reg;
  reg [31 : 0]   tmp_read_data;
  reg            tmp_error;
  reg [7 : 0]    tmp_debug;


  //----------------------------------------------------------------
  // Concurrent connectivity for ports etc.
  //----------------------------------------------------------------
  assign read_data      = tmp_read_data;
  assign error          = tmp_error;
  assign security_error = entropy1_security_error | entropy2_security_error;
  assign debug          = debug_out_reg;

  // Patches to get our first version to work.
  assign entropy0_entropy_enabled = 0;
  assign entropy0_entropy_syn     = 0;
  assign entropy0_entropy_data    = 32'h00000000;


  //----------------------------------------------------------------
  // Address Decoder
  //----------------------------------------------------------------
  // upper 4 bits specify core being addressed.
  wire [3 : 0] addr_core_num = address[11 : 8];

  // lower 8 bits specify register offset in core.
  wire [7 : 0] addr_core_reg = address[7 : 0];


  //----------------------------------------------------------------
  // core instantiations.
  //----------------------------------------------------------------
  trng_mixer mixer_inst(
                        .clk(clk),
                        .reset_n(reset_n),

                        .cs(mixer_api_cs),
                        .we(mixer_api_we),
                        .address(api_address),
                        .write_data(write_data),
                        .read_data(mixer_api_read_data),
                        .error(mixer_api_error),

                        .discard(discard_reg),
                        .test_mode(test_mode_reg),
                        .security_error(mixer_security_error),

                        .more_seed(csprng_more_seed),

                        .entropy0_enabled(entropy0_entropy_enabled),
                        .entropy0_syn(entropy0_entropy_syn),
                        .entropy0_data(entropy0_entropy_data),
                        .entropy0_ack(entropy0_entropy_ack),

                        .entropy1_enabled(entropy1_entropy_enabled),
                        .entropy1_syn(entropy1_entropy_syn),
                        .entropy1_data(entropy1_entropy_data),
                        .entropy1_ack(entropy1_entropy_ack),

                        .entropy2_enabled(entropy2_entropy_enabled),
                        .entropy2_syn(entropy2_entropy_syn),
                        .entropy2_data(entropy2_entropy_data),
                        .entropy2_ack(entropy2_entropy_ack),

                        .seed_data(mixer_seed_data),
                        .seed_syn(mixer_seed_syn),
                        .seed_ack(csprng_seed_ack),

                        .debug(mixer_debug),
                        .debug_update(mixer_debug_update)
                       );

  trng_csprng csprng_inst(
                          .clk(clk),
                          .reset_n(reset_n),

                          .cs(csprng_api_cs),
                          .we(csprng_api_we),
                          .address(api_address),
                          .write_data(write_data),
                          .read_data(csprng_api_read_data),
                          .error(csprng_api_error),

                          .discard(discard_reg),
                          .test_mode(test_mode_reg),
                          .security_error(csprng_security_error),

                          .more_seed(csprng_more_seed),

                          .seed_data(mixer_seed_data),
                          .seed_syn(mixer_seed_syn),
                          .seed_ack(csprng_seed_ack),

                          .debug(csprng_debug),
                          .debug_update(csprng_debug_update)
                         );

  avalanche_entropy entropy1(
                             .clk(clk),
                             .reset_n(reset_n),

                             .noise(avalanche_noise),

                             .cs(entropy1_api_cs),
                             .we(entropy1_api_we),
                             .address(api_address),
                             .write_data(write_data),
                             .read_data(entropy1_api_read_data),
                             .error(entropy1_api_error),

                             .discard(discard_reg),
                             .test_mode(test_mode_reg),
                             .security_error(entropy1_security_error),

                             .entropy_enabled(entropy1_entropy_enabled),
                             .entropy_data(entropy1_entropy_data),
                             .entropy_valid(entropy1_entropy_syn),
                             .entropy_ack(entropy1_entropy_ack),

                             .debug(entropy1_debug),
                             .debug_update(entropy1_debug_update)
                            );

  rosc_entropy entropy2(
                        .clk(clk),
                        .reset_n(reset_n),

                        .cs(entropy2_api_cs),
                        .we(entropy2_api_we),
                        .address(api_address),
                        .write_data(write_data),
                        .read_data(entropy2_api_read_data),
                        .error(entropy2_api_error),

                        .discard(discard_reg),
                        .test_mode(test_mode_reg),
                        .security_error(entropy2_security_error),

                        .entropy_enabled(entropy2_entropy_enabled),
                        .entropy_data(entropy2_entropy_data),
                        .entropy_valid(entropy2_entropy_syn),
                        .entropy_ack(entropy2_entropy_ack),

                        .debug(entropy2_debug),
                        .debug_update(entropy2_debug_update)
                       );


  //----------------------------------------------------------------
  // reg_update
  //
  // Update functionality for all registers in the core.
  // All registers are positive edge triggered with asynchronous
  // active low reset.
  //----------------------------------------------------------------
  always @ (posedge clk or negedge reset_n)
    begin
      if (!reset_n)
        begin
          discard_reg            <= 0;
          test_mode_reg          <= 0;
          debug_mux_reg          <= DEBUG_CSPRNG;
          debug_delay_reg        <= DEFAULT_DEBUG_DELAY;
          debug_delay_ctr_reg    <= 32'h00000000;
          debug_out_reg          <= 8'h00;
        end
      else
        begin
          discard_reg            <= discard_new;
          debug_delay_ctr_reg    <= debug_delay_ctr_new;

          if (debug_out_we)
            debug_out_reg <= tmp_debug;

          if (test_mode_we)
            test_mode_reg <= test_mode_new;

          if (debug_mux_we)
            debug_mux_reg <= debug_mux_new;

          if (debug_delay_we)
            debug_delay_reg <= debug_delay_new;
        end
    end // reg_update


  //----------------------------------------------------------------
  // core_mux
  //
  // This is a simple decoder that looks at the top 4 bits of
  // the given api address and selects which of the sub modules
  // or the top level mux that gets to handle any API
  // operations.
  //----------------------------------------------------------------
  always @*
    begin : core_mux
      case (address[11 : 8])
        TRNG_PREFIX:
          begin
            tmp_read_data = trng_api_read_data;
            tmp_error     = trng_api_error;
          end

        ENTROPY1_PREFIX:
          begin
            tmp_read_data   = entropy1_api_read_data;
            tmp_error       = entropy1_api_error;
          end

        ENTROPY2_PREFIX:
          begin
            tmp_read_data   = entropy2_api_read_data;
            tmp_error       = entropy2_api_error;
          end

        MIXER_PREFIX:
          begin
            tmp_read_data = mixer_api_read_data;
            tmp_error     = mixer_api_error;
          end

        CSPRNG_PREFIX:
          begin
            tmp_read_data = csprng_api_read_data;
            tmp_error     = csprng_api_error;
          end

        default:
          begin
            tmp_read_data = {32{1'b0}};
            tmp_error     = 0;
          end
      endcase // case (address[11 : 8])
    end // core_mux


  //----------------------------------------------------------------
  // debug_update_logic
  //
  // Debug update counter and update logic.
  //----------------------------------------------------------------
  always @*
    begin : debug_update_logic
      if (debug_delay_ctr_reg == debug_delay_reg)
        begin
          debug_out_we        = 1;
          debug_delay_ctr_new = 32'h00000000;
        end
      else
        begin
          debug_out_we        = 0;
          debug_delay_ctr_new = debug_delay_ctr_reg + 1'b1;
        end
    end // debug_update


  //----------------------------------------------------------------
  // debug_mux
  //
  // Select which of the sub modules that are connected to
  // the debug port.
  //----------------------------------------------------------------
  always @*
    begin : debug_mux
      entropy1_debug_update = 0;
      entropy2_debug_update = 0;
      mixer_debug_update    = 0;
      csprng_debug_update   = 0;

      tmp_debug = 8'h00;

      case(debug_mux_reg)
        DEBUG_ENTROPY1:
          begin
            entropy1_debug_update = debug_update;
            tmp_debug             = entropy1_debug;
          end

        DEBUG_ENTROPY2:
          begin
            entropy2_debug_update = debug_update;
            tmp_debug             = entropy2_debug;
          end

        DEBUG_MIXER:
          begin
            mixer_debug_update = debug_update;
            tmp_debug          = mixer_debug;
          end

        DEBUG_CSPRNG:
          begin
            csprng_debug_update = debug_update;
            tmp_debug           = csprng_debug;
          end

        default:
          begin

          end
      endcase // case (debug_mux_reg)
    end // debug_mux


  //----------------------------------------------------------------
  // trng_api_logic
  //
  // Implementation of the top level api logic.
  //----------------------------------------------------------------
  always @*
    begin : trng_api_logic
      discard_new            = 0;
      test_mode_new          = 0;
      test_mode_we           = 0;
      debug_mux_new          = 3'h0;
      debug_mux_we           = 0;
      debug_delay_new        = 32'h00000000;
      debug_delay_we         = 0;
      trng_api_read_data     = 32'h00000000;
      trng_api_error         = 0;

      if (trng_api_cs)
        begin
          if (trng_api_we)
            begin
              case (api_address)
                ADDR_TRNG_CTRL:
                  begin
                    discard_new   = write_data[TRNG_CTRL_DISCARD_BIT];
                    test_mode_new = write_data[TRNG_CTRL_TEST_MODE_BIT];
                    test_mode_we  = 1;
                  end

                ADDR_DEBUG_CTRL:
                  begin
                    debug_mux_new = write_data[2 : 0];
                    debug_mux_we  = 1;
                  end

                ADDR_DEBUG_DELAY:
                  begin
                    debug_delay_new = write_data;
                    debug_delay_we  = 1;
                  end

                default:
                  trng_api_error = 1;
              endcase // case (address)
            end // if (we)

          else
            begin
              case (api_address)
                ADDR_NAME0:
                  trng_api_read_data = TRNG_NAME0;

                ADDR_NAME1:
                  trng_api_read_data = TRNG_NAME1;

                ADDR_VERSION:
                  trng_api_read_data = TRNG_VERSION;

                ADDR_TRNG_CTRL:
                  trng_api_read_data = {30'h0000000, test_mode_reg, discard_reg};

                ADDR_TRNG_STATUS:
                  begin
                    // No error caused by reading status.
                  end

                ADDR_DEBUG_CTRL:
                  trng_api_read_data = {29'h0000000, debug_mux_new};

                ADDR_DEBUG_DELAY:
                  trng_api_read_data = debug_delay_reg;

                default:
                  trng_api_error = 1;
              endcase // case (address)
            end
        end
    end // trng_api_logic
endmodule // trng

//======================================================================
// EOF trng.v
//======================================================================