123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- //
- // 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
|