| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| // -------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------- // |
| // PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED. |
| // |
| //############################################################################ |
| // *Name: rng |
| // *Module Description: Random (bit/s) Generator (Pseudo Model) |
| //############################################################################ |
| |
| `include "prim_assert.sv" |
| |
| module rng #( |
| parameter int EntropyStreams = 4 |
| ) ( |
| input clk_i, // Non-Jittery Clock (TLUL) |
| input rst_ni, // Non-Jittery Reset (TLUL) |
| input clk_ast_rng_i, // Jittery Clock (RNG) |
| input rst_ast_rng_ni, // Jittery Reset (RNG) |
| input rng_en_i, // RNG Enable |
| input rng_fips_i, // RNG FIPS Enable |
| input scan_mode_i, // Scan Mode |
| output logic [EntropyStreams-1:0] rng_b_o, // RNG Bus/Bits Output |
| output logic rng_val_o // RNG Bus/Bits Valid |
| ); |
| |
| /////////////////////////////////////// |
| // RNG Bus using LFSR |
| /////////////////////////////////////// |
| logic rst_n; |
| logic[EntropyStreams-1:0] lfsr_val; |
| |
| assign rst_n = scan_mode_i ? rst_ni : rst_ni && rng_en_i; |
| |
| // These LFSR parameters have been generated with |
| // $ ./util/design/gen-lfsr-seed.py --width 64 --seed 15513 --prefix "Rng" |
| localparam int RngLfsrWidth = 64; |
| typedef logic [RngLfsrWidth-1:0] rng_lfsr_seed_t; |
| typedef logic [RngLfsrWidth-1:0][$clog2(RngLfsrWidth)-1:0] rng_lfsr_perm_t; |
| localparam rng_lfsr_seed_t RndCnstRngLfsrSeedDefault = 64'h1d033d20eed3b14; |
| localparam rng_lfsr_perm_t RndCnstRngLfsrPermDefault = { |
| 128'h98c2c94ab5e40420ed73f6c7396cd9e1, |
| 256'h58c6d7435ddb2ed1f22400c53a5aaa796ef7785e120628fbabc87f0b3928550f |
| }; |
| |
| prim_lfsr #( |
| .LfsrDw ( RngLfsrWidth ), |
| .EntropyDw ( 1 ), |
| .StateOutDw ( EntropyStreams ), |
| .DefaultSeed ( RndCnstRngLfsrSeedDefault ), |
| .StatePermEn ( 1'b1 ), |
| .StatePerm ( RndCnstRngLfsrPermDefault ), |
| .ExtSeedSVA ( 1'b0 ) // ext seed is unused |
| ) u_rng_lfsr ( |
| .clk_i ( clk_i ), |
| .rst_ni ( rst_n ), |
| .lfsr_en_i ( rng_en_i ), |
| .seed_en_i ( 1'b0 ), |
| .seed_i ( '0 ), |
| .entropy_i ( 1'b0 ), |
| .state_o ( lfsr_val ) |
| ); |
| |
| logic srate_rng_val; |
| logic [12-1:0] srate_cnt, srate_value; |
| logic [EntropyStreams-1:0] rng_b; |
| |
| `ifndef SYNTHESIS |
| logic [12-1:0] dv_srate_value; |
| // 4-bit rng_b needs at least 5 clocks. While the limit for these min and max values is 5:500, the |
| // default is set to a shorter window of 32:128 to avoid large runtimes. |
| logic [12-1:0] rng_srate_value_min = 12'd32; |
| logic [12-1:0] rng_srate_value_max = 12'd128; |
| |
| initial begin : rng_plusargs |
| void'($value$plusargs("rng_srate_value_min=%0d", rng_srate_value_min)); |
| void'($value$plusargs("rng_srate_value_max=%0d", rng_srate_value_max)); |
| `ASSERT_I(DvRngSrateMinCheck, rng_srate_value_min inside {[5:500]}) |
| `ASSERT_I(DvRngSrateMaxCheck, rng_srate_value_max inside {[5:500]}) |
| `ASSERT_I(DvRngSrateBoundsCheck, rng_srate_value_max >= rng_srate_value_min) |
| dv_srate_value = 12'($urandom_range(int'(rng_srate_value_min), int'(rng_srate_value_max))); |
| void'($value$plusargs("rng_srate_value=%0d", dv_srate_value)); |
| `ASSERT_I(DvSrateValueCheck, dv_srate_value inside {[5:500]}) |
| end |
| |
| assign srate_value = dv_srate_value; |
| `else |
| assign srate_value = 12'd120; |
| `endif |
| |
| logic src_busy; |
| |
| always_ff @( posedge clk_i, negedge rst_n ) begin |
| if ( !rst_n ) begin |
| srate_cnt <= 12'h000; |
| srate_rng_val <= 1'b0; |
| end else if ( (srate_cnt == srate_value) && src_busy ) begin |
| srate_rng_val <= 1'b0; |
| end else if ( srate_cnt == srate_value ) begin |
| srate_cnt <= 12'h000; |
| srate_rng_val <= 1'b1; |
| end else begin |
| srate_cnt <= srate_cnt + 1'b1; |
| srate_rng_val <= 1'b0; |
| end |
| end |
| |
| |
| //////////////////////////////////////// |
| // Sychronize Bus & Valid to RNG Clock |
| //////////////////////////////////////// |
| logic sync_rng_val, srate_rng_val_en; |
| |
| ast_pulse_sync u_rng_val_pulse_sync ( |
| .scan_mode_i ( scan_mode_i ), |
| // source clock domain |
| .clk_src_i ( clk_i ), |
| .rst_src_ni ( rst_n ), |
| .src_pulse_i ( srate_rng_val ), |
| .src_pulse_en_o ( srate_rng_val_en ), |
| .src_busy_o ( src_busy ), |
| // destination clock domain |
| .clk_dst_i ( clk_ast_rng_i ), |
| .rst_dst_ni ( rst_ast_rng_ni ), |
| .dst_pulse_o ( sync_rng_val ) |
| ); |
| |
| // Sanple & Hold the rng_b value until the sync completes |
| always_ff @( posedge clk_i, negedge rst_n ) begin |
| if ( !rst_n ) begin |
| rng_b <= {EntropyStreams{1'b0}}; |
| end else if ( srate_rng_val_en ) begin |
| rng_b <= lfsr_val[EntropyStreams-1:0]; |
| end |
| end |
| |
| //Sync to RNG clock domain |
| always_ff @( posedge clk_ast_rng_i, negedge rst_ast_rng_ni ) begin |
| if (!rst_ast_rng_ni ) begin |
| rng_b_o <= {EntropyStreams{1'b0}}; |
| rng_val_o <= 1'b0; |
| end else if ( sync_rng_val ) begin |
| rng_b_o <= rng_b[EntropyStreams-1:0]; |
| rng_val_o <= 1'b1; |
| end else begin |
| rng_val_o <= 1'b0; |
| end |
| end |
| |
| |
| /////////////////////// |
| // Unused Signals |
| /////////////////////// |
| logic unused_sigs; |
| assign unused_sigs = ^{ |
| rng_fips_i // Used in ASIC implementation |
| }; |
| |
| endmodule : rng |