// // Simple hardware random number generator // module rng #(parameter nclocks = 1, // Asynchronous clocks width = 32 // Output bus width ) ( // System reset and clock input rst_n, input sys_clk, input read_stb, input latch_stb, output ready, output reg [width-1:0] q, // Randomness inputs input [nclocks-1:0] clocks, // Random input synchronized to sys_clk (* keep = 1 *) inout [2:0] rngio // Unconnected pins with pullups ); // Number of internal oscillators localparam n_osc = 2; wire [n_osc:1] osc; wire [n_osc:1] osc_s; // // Latch control and enable logic // reg [n_osc:1] osc_q; reg [n_osc:1] osc_e; // Edge detected typedef enum logic [2:0] { st_starting, // Powering up oscillators st_started, // Oscillators running st_strobed, // Starting strobe received st_latch, // Ending strobe received, latch output data st_ready, // Output data available st_stopped // Data available, powered down due to idle } state_t; state_t state = st_starting; // Number of ticks before shutting down localparam shutdown_ticks_lg2 = 1; reg [shutdown_ticks_lg2-1:0] shutdown_tmr; assign ready = (state == st_ready) | (state == st_stopped); wire running = (state != st_stopped); wire [width-1:0] random_data; always @(posedge sys_clk or negedge rst_n) if (~rst_n) begin state <= st_starting; osc_q <= 'b0; osc_e <= 'b0; end else begin osc_q <= ~osc_s; osc_e <= 'b0; shutdown_tmr <= 'b0; case (state) st_starting: begin osc_e <= osc_e | (osc_s & osc_q); if (&osc_e) state <= st_started; end st_started: begin if (latch_stb) state <= st_strobed; end st_strobed: begin if (latch_stb) state <= st_latch; end st_latch: begin // Wait here if read_stb is still active from previous read if (~read_stb) begin q <= random_data; state <= st_ready; end end st_ready: begin shutdown_tmr <= shutdown_tmr + latch_stb; // If shutdown_tmr is nonzero, then we have had at least // one latch_stb already while waiting here, and so we // can use that data immediately. if (read_stb) state <= |shutdown_tmr ? st_latch : latch_stb ? st_strobed : st_started; else if (latch_stb & &shutdown_tmr) state <= st_stopped; end st_stopped: begin // Data is available, but haven't been consumed for // a long time, so we have shut down the ring oscillators. // When a read happens, start them up again. if (read_stb) state <= st_starting; end endcase // case (state) end // else: !if(~rst_n) // // Internal oscillators: allow them to be stopped to save power // if we have had multiple ticks with no data accesses. // // Internal on-chip oscillator int_osc int_osc ( .clkout ( osc[1] ), .oscena ( running ) ); // Ring oscillator using the rngio pins assign rngio[0] = ~rngio[2] & running; assign rngio[1] = ~rngio[0] & running; assign rngio[2] = ~rngio[1] & running; assign osc[2] = rngio[0]; synchronizer #(.width(n_osc)) synchro ( .rst_n ( 1'b1 ), .clk ( sys_clk ), .d ( osc ), .q ( osc_s ) ); // LFSR randomness accumulator // See http://users.ece.cmu.edu/~koopman/crc/crc36.html for // choice of polynomial. The x^poly_width term in the polynomial // is implicit. localparam poly_width = 33; localparam [poly_width-1:0] poly = 33'h0_0000_009d; localparam lsfr_max = width > poly_width ? width-1 : poly_width-1; wire lsfr_input = ^{osc_s, clocks}; reg [lsfr_max:0] lsfr; always @(posedge sys_clk) lsfr <= ({lsfr[lsfr_max-1:0], lsfr_input} ^ {{(lsfr_max+1){lsfr[poly_width-1]}} & poly}); assign random_data = lsfr[width-1:0]; endmodule // rng